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 - One-command sign-in —
linear-tui auth loginopens the browser; no application to register, no client secret, or use a personal API key instead - 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
Building needs only a Rust toolchain — see Development for the mise setup.
Getting Started
Just run it:
On first launch it asks how you want to connect, and nothing else has to be set up beforehand.
Signing in through the browser
This opens Linear in your browser, and the authorization screen appears as k1-c/tui — the application linear-tui is registered as. (Linear does not allow "Linear" in an application's name, which is why it is not called linear-tui there.)
Approving it hands a token back to a local callback on port 53681, 53682, or
53683. Tokens are stored in ~/.config/linear-tui/tokens.json with 0600
permissions and refreshed automatically.
No client secret is involved: Linear's PKCE flow makes one optional, so linear-tui ships as a public OAuth client.
Signing in with a personal API key
Useful when the browser flow cannot reach your terminal — over SSH, for example, where the callback would land on the wrong machine.
Create a key under Settings > Account > Security & access, then:
The key is verified before it is saved.
Checking and clearing credentials
Using your own Linear application
Some workspaces require third-party applications to be approved by an admin. If
that blocks you — or you would simply rather authorize against your own — register
one at Linear Settings > API with
http://localhost:53681/callback (plus 53682 and 53683) as its redirect URIs:
LINEAR_CLIENT_ID and LINEAR_CLIENT_SECRET override the config file.
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"
# To authorize against your own Linear application:
# oauth_client_id = "..."
# oauth_client_secret = "..." # optional — PKCE does not require one
[]
= "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 |
Development
The Rust toolchain is pinned in mise.toml, so mise
is all you need to install:
mise run fmt, lint, test, and build run the steps individually. Without
mise, any stable rustup toolchain works — cargo run, cargo test, and the
rest behave the same.
There is nothing else to install: TLS goes through rustls, so no system OpenSSL
or pkg-config is involved.