linear-tui
A TUI client for Linear.app — manage issues, projects, and cycles from your terminal.
Built with ratatui and the Linear GraphQL API.
Features
- Issue management — Browse, search, filter, create, and mutate issues (status, priority, assignee, comments)
- Multiple views — Issues, My Issues, Projects, Cycles with tab-based navigation
- Project & Cycle detail — Drill into projects/cycles to see their issues
- Never blocks — Every API call runs off the UI thread, so navigation and input stay responsive while data loads
- Search — Filter as you type locally, or
Ctrl+Gto search all of Linear - Open & copy — Jump to the issue in your browser, or copy its identifier, URL, or suggested branch name
- Linear's own keybindings —
cto create,s/p/a/ito update,g+key to switch views, plus vim-stylej/kand mouse scrolling - OAuth2 + PKCE authentication — Secure login via browser, or use a personal API key
- Theme support — Default (dark), Light, and Ocean color schemes
- Pagination — Cursor-based infinite scrolling across every list
Installation
From crates.io
From GitHub Releases
Pre-built binaries are available for Linux, macOS (Intel/Apple Silicon), and Windows on the Releases page.
From source
Getting Started
1. Authenticate
OAuth2 (recommended)
Register an OAuth application at Linear Settings > API, then save your credentials:
Tokens are stored locally and refreshed automatically.
Personal API Key
Generate a key at Linear Settings > API, then:
2. Launch
Keybindings
Shortcuts follow Linear's own keyboard shortcuts wherever a terminal allows it, so muscle memory carries over from the web app.
Navigation
| Key | Action |
|---|---|
j / k, ↓ / ↑ |
Move cursor down / up |
g g / G |
Jump to first / last item |
Enter, Space |
Open the issue (Linear: peek) |
Esc |
Back / close |
g e / g m / g p / g c |
Go to All Issues / My Issues / Projects / Cycles |
1-4 |
Same views, by tab number |
Ctrl+d / Ctrl+u |
Half page down / up |
PgDn / PgUp |
Full page down / up |
| mouse wheel | Scroll lists and issue bodies |
Issue actions
| Key | Action |
|---|---|
c |
Create a new issue (Ctrl+Enter to save) |
s |
Change status |
p |
Change priority |
Shift+1 … Shift+4, Shift+0 |
Set priority directly (Urgent → Low, None) |
a |
Assign to someone |
i |
Assign to me |
m |
Add a comment (Ctrl+Enter to send) |
Copy and open
| Key | Action |
|---|---|
Ctrl+. or y |
Copy the issue ID |
Ctrl+Shift+, or Y |
Copy the issue URL |
Ctrl+Shift+. or b |
Copy the suggested git branch name |
o |
Open the issue (or project) on linear.app |
Search and filtering
| Key | Action |
|---|---|
/ |
Filter the visible list as you type |
Ctrl+G |
Search all of Linear for the current query |
f / Shift+F |
Filter by status & priority / clear filters |
t |
Switch team |
Ctrl+r, F5 |
Refresh the current view |
? |
Show all shortcuts |
q, Ctrl+c |
Quit |
Text fields (search, comments, the new-issue form) accept readline-style
editing: Ctrl+w, Ctrl+u, Ctrl+k, Ctrl+a, Ctrl+e, and arrow keys.
Differences from Linear
A terminal cannot deliver every shortcut the web app uses, and a few of Linear's actions have no meaning here. Where they differ:
| Linear | linear-tui | Why |
|---|---|---|
Ctrl+., Ctrl+Shift+., Ctrl+Shift+,, Ctrl+M |
also y, b, Y, m |
Legacy terminals cannot distinguish Ctrl+punctuation, and Ctrl+M is Enter. The originals work in terminals supporting the kitty keyboard protocol (kitty, Ghostty, WezTerm, foot, Alacritty), which is enabled automatically when available. |
r — rename issue |
(unbound) | Renaming isn't supported yet; refreshing uses the terminal's Ctrl+r instead. |
Ctrl+d — set due date |
half page down | The scrolling convention wins in a terminal. |
| — | o, t, q |
Open in browser, switch team, and quit have no web-app equivalent. |
Copying uses the OSC 52 terminal escape, so it works over SSH. If nothing
lands on your clipboard, enable it in your terminal — under tmux that means
set -g set-clipboard on.
Configuration
Config file: ~/.config/linear-tui/config.toml
[]
# OAuth tokens are managed automatically via `linear-tui auth login`
# To use a personal API key instead:
# api_key = "lin_api_xxxxx"
[]
= "Core" # Auto-select this team on startup
= 50 # Issues per page (pagination)
= "default" # "default" | "light" | "ocean"
Themes
| Theme | Description |
|---|---|
default |
Dark theme with cyan accents |
light |
Light background with blue accents |
ocean |
Dark blue palette with soft colors |