Terminal Deck

A desktop workspace for AI coding agents

Terminal Deck runs Claude Code, Codex CLI and Gemini CLI as real terminal sessions in one window — each in its own tab, each with a dot that says whether it is working or waiting on you, and, for Claude Code, what it has spent so far.

It is for people who keep three or four agents running at once and lose track of which one stopped to ask a question twenty minutes ago.

Version 0.1.2 · macOS 12+ Apple Silicon, and Windows 10+ x64 · unsigned build · MIT licence · you bring your own agent CLI, already installed and signed in.

The tab strip

api-server web docs infra Browser

Sessions and browser tabs share one strip in the window header. The dot is the whole point of it: at a glance, one session is mid-thought, one has finished and is sitting at its prompt, and one is blocked on a question you have not answered.

A drawing of the strip, not a screenshot. The four states below are the ones the app classifies.

  • Working
  • Waiting at its prompt
  • Needs an answer
  • Idle or exited

Sessions

Every session is a real process in a real terminal. Nothing is emulated, wrapped or proxied.

Status is read from the screen, not the output stream

Agent CLIs are full-screen applications. They repaint by moving the cursor, so the last bytes a process wrote have no relationship to what is at the bottom of the screen — which is why guessing status from the output tail gets it wrong. Each session therefore feeds a headless terminal emulator in the main process, and the status comes from that rendered viewport.

It works for tabs you are not looking at, and it survives the CLI redrawing itself. Claude Code’s prompt is matched as the it actually draws, across a window of lines rather than at the very end, because the prompt is never the last line on screen.

Tabs keep their scrollback

Switching away from a session does not tear it down. The main process holds the scrollback and replays it, so coming back to a tab shows the conversation you left, not an empty screen. The terminal also stays mounted while you are in chat mode.

You choose what a session is before it starts

The new-session dialog picks the agent, the profile it runs as, and whether it continues the last conversation in that folder. What is shown as selected is what will actually be spawned, including when it was chosen by a remembered default — the dialog resolves the decision rather than displaying a guess.

It finds your CLI the way your shell does

A GUI app on macOS inherits a minimal PATH and genuinely cannot see a claude installed by nvm, Homebrew or into ~/.local/bin. Terminal Deck asks your login shell for its real PATH once, and every session spawns with it.

Chat mode

The same session, with the machinery taken out — what you asked and what the agent said.

Read from the transcript, not the terminal

Claude Code writes a JSONL transcript of every session under ~/.claude/projects/. Chat mode reads that file and lays out the prompts and the replies. Tool calls, diffs, spinners and ANSI stay in the terminal view, where they belong.

Because the transcript is the source, this is Claude Code only. Codex and Gemini sessions run fine — they just have no transcript for this view to read.

You can type back

The composer writes into the session’s own terminal, so a message sent from chat mode is the same message the terminal view shows. It is a second view of one session, not a second channel into it.

Replies are rendered as markdown with the code turned down: a fenced block collapses to a one-line summary you can open, and links keep their text but lose their destination — this is an app window, not a browser.

Cost and context

Read from the same transcripts. No scraping of terminal output, no estimate from character counts.

The cache rates are the whole story

A long Claude Code session bills mostly cache, and the two write rates are not the same: a cache read is 0.1× the input rate, a five-minute cache write is 1.25×, and a one-hour write is 2×. Claude Code writes the one-hour kind. Charging every write at the five-minute rate under-reports the cached portion of a session by 37.5%, so the two are tracked separately.

Spend is totalled per session, per project and per day, and the transcript is tailed incrementally — a live session costs a stat plus the bytes that actually arrived.

The session inspector

I opens one session in detail: a timeline of requests, where the money went, which tools were called and which of them kept failing, and how the context window filled up over time. There is a context meter with a bloat warning, and the alerts panel reads its thresholds from the same place so the two can never disagree.

The browser tab

A browser inside the window, so the thing the agent is building and the agent itself are one click apart.

Click an element, and the agent gets a selector

Turn on inspect, click something on the page, and the app builds a CSS selector for it — preferring a test-hook attribute like data-testid, then a unique id, then a positional path — along with the element’s visible label and the URL. That goes into the focused session as context you did not have to type.

The page is treated as hostile throughout. The guest side only reports facts about the clicked element; every decision about what is a safe selector, what gets escaped and what reaches a terminal is made in the main process, against a closed list of attributes.

Dev servers, device sizes and a flow recorder

It looks for the dev servers actually listening on this machine rather than guessing port 3000. Device presets and zoom are there for checking a layout, screenshots are one click, and a flow recorder turns what you did on the page into steps you can hand to the agent.

Logins persist between launches, tabs can be isolated from each other, and if a dev server sits behind a Google sign-in you can import the cookies from your installed Chrome instead of signing in twice.

The panels beside the session

Everything you would otherwise leave the window to check, in the side dock.

Git

Branch, and the four lists that matter — staged, unstaged, untracked, conflicted — with per-file insertions and deletions, a unified diff for any file, and a watcher that keeps it current while the agent works.

Files

A tree that loads a level at a time, a viewer that refuses files over 2 MB rather than freezing on them, and symlinks that leave the project refused outright. .deckignore is honoured by the tree, layered over .gitignore so it can re-include a file git hides.

Session search

Full-text search across past Claude Code transcripts — this project or all of them — with ranked, highlighted snippets. It reads the lines the cost reader throws away, which is where your prompts and the tool results actually are.

GitHub

Open pull requests, issues and notification counts through your own gh CLI. Every failure is a distinct state with the command that fixes it — “you are not signed in” never looks like “this folder has no GitHub remote”.

MCP servers

It reads the MCP configuration you already have, at user, project and local scope, instead of keeping a second list that would drift. Connect to a stdio server, browse its tools, and call one through a form generated from its schema.

Hooks

Installs callbacks into Claude, Codex and Gemini’s real settings files, every entry tagged terminaldeck-hook so it is only ever ours that get removed. Writes are atomic and the file is backed up before it is first touched.

AI readiness

Ten weighted checks on whether a project is set up for an agent — CLAUDE.md, a README, test, typecheck and lint scripts, gitignore, a lockfile, a clean tree — and fixes you can apply one at a time, after reading what each will touch. Committed secrets cap the score outright rather than costing it a few points.

Alerts

Context bloat, a session blocked on a question, an unusually expensive session, a missing CLI, a tree left dirty. Every rule needs positive evidence, so a brand-new project is silent — an alerts panel that cries wolf on day one is ignored by day two.

Overview and board

A per-project dashboard of drag-and-drop widgets (sessions, cost, git, board, AI readiness, GitHub) and a three-column task board whose cards can start or resume a session.

More than one of everything

Profiles: separate logins that cannot mix

Claude Code keeps who-you-are inside one config directory, and CLAUDE_CONFIG_DIR moves that directory. Point two sessions at two directories and they are two different accounts, with separate history and separate transcripts. Pick a profile per session, per project, or as your default.

Credentials stay in the macOS Keychain under a service name derived from the config directory, so signing into a second profile cannot overwrite the first one’s token. Your existing ~/.claude login is shown as a profile the app will not rename, move or delete — and sessions running as it spawn with the variable unset, never set to its own path.

Swarm view

\ puts every running session in one grid, sized so a cell is never narrower than about forty columns. A tidy grid of unreadable slivers is worth less than one tall column you can actually read, so the layout gives up on being square before it gives up on being legible.

Settings that save as you change them

Eleven sections — general, appearance, notifications, agents, setup, browser, shortcuts, profiles, advanced, help, about — with no OK button anywhere. A value on screen is a value on disk, and if a write fails the footer says so instead of quietly reverting the control under your finger.

How it works

The honest version, because the architecture is the reason to trust it with a folder full of your work.

It runs the CLIs, it does not reimplement them

Each session is the real claude, codex or gemini binary, spawned as a subprocess on a pseudo-terminal with your login shell’s PATH. There is no proxy in front of it and no wrapper around it. Whatever your CLI does in your terminal, it does here.

An Electron main process owns every process and every piece of filesystem access; a single preload bridge is the only route between the interface and any of it.

It never handles your credentials

There is no account, no sign-in and no API key field anywhere in this app. The agent signs you in itself, inside the terminal, exactly as it would if you had run it yourself — and its credentials stay wherever it puts them, which on macOS is the Keychain.

One deliberate exception, stated plainly: if you ask it to, the browser tab can import cookies from an installed Chrome so a dev server behind a login does not need signing into twice. That is user-initiated, macOS prompts for keychain access by name, and cookie values are never sent to the interface.

Your data stays where it already is

Cost, context, chat and search all read files the agent already wrote on your machine. There is no telemetry, no analytics and no account service. The app’s own network activity is a local endpoint on 127.0.0.1 that provider hooks call back into, protected by a per-run token, and one request off the machine: a fetch of the public release feed, carrying no identifier. Beyond that it is whatever pages you type into the browser tab, and whatever your agent does on its own.

What is not built yet

Session sharing, translations, and code signing and notarisation are all still to come, and the app says so where it matters: Settings → About reports what this build can actually do rather than spinning and claiming you are up to date. Split panes are in the same category — the layout code is in the repository, but nothing in the app renders it, so the chords for it do nothing. Updating in place works on macOS and is unproven on Windows.

On macOS, Apple Silicon only: there is no Intel build, because macOS 27 does not run on an Intel Mac at all. There is a Windows x64 build, produced natively in CI, and it has now been installed and opened on Windows 11 x64 — where 0.1.2 launches but cannot start a session, and part of the test suite does not pass. No Linux build.

What you need

Operating system
macOS 12 or newer on Apple silicon, or Windows 10 or newer on x64. Both builds are unsigned, so each warns once on first launch. There is no Intel Mac build; Windows on ARM runs the x64 build under emulation rather than natively.
An agent
At least one of Claude Code, Codex CLI or Gemini CLI, installed and already signed in. Terminal Deck does not install or authenticate them for you.
Optional
git for the git panel, the gh CLI for the GitHub panel. Both are only needed by their own panel.
To build from source
Node 22 or newer.