Terminal Deck

Features

Everything below is in the app today. What is not built yet has its own section at the bottom, and the roadmap keeps the full list.

Sessions and status

A project holds as many sessions as you want, each one a real process in its own terminal. Tabs live in the window header; scrollback is replayed when you switch back, so leaving a tab does not lose what happened while you were away. Sessions can be started with Claude Code, Codex CLI, Gemini CLI or a plain shell, chosen per session, per project or globally.

Every tab carries a status dot. The classification does not read the output stream — agent CLIs repaint by moving the cursor, so the tail of the stream has no relationship to the bottom of the screen. Each session instead feeds a headless terminal emulator in the main process and the status is read from that emulator's viewport, which means background tabs are classified as accurately as the visible one.

Around that: ⌘⇧T for the new-session dialog, where continuing a project's last conversation is one of the choices. A tab is named for its project folder.

Not built, despite having code in the repository: unread indicators, and desktop notifications or sounds when a session finishes. renderer/unread.ts has no importers, and renderer/notifications.ts is reached only by the Test button in settings — nothing fires a banner when a session actually finishes.

Chat mode

The same session, read as a conversation. Chat mode reads Claude Code's own transcript and shows only what a person said and what the agent said back — tool calls, usage blocks and compaction markers are thrown away, because hiding them is the entire point of the view.

The rules for what counts as a typed prompt were measured against the transcripts on a real machine rather than assumed. A user line is only a prompt when its content is a string; the array form is almost always tool results, and rendering those turns the agent's own output into fake user messages.

The composer at the bottom writes to the session's terminal exactly as if you had typed there, because that is where the agent is listening. There is no second channel to keep in sync, and a message sent from chat appears in the terminal view too.

Cost and context

Claude Code writes JSONL transcripts under ~/.claude/projects/. That is the source for all of this — nothing is scraped from terminal output. A watcher tails the file per session and the numbers follow: spend per session, per project and per day, token counts, and how full the context window is with a warning when it bloats.

Cache traffic is priced properly. A cache read is a tenth of the input rate, a five-minute cache write is 1.25×, and a one-hour write — which is what Claude Code actually writes — is 2×. Charging every write at the five-minute rate under-reports a long session's spend by 37.5% on the cached portion.

Inspector, search and alerts

The project workspace

Dashboard and board

Each project gets a drag-and-drop widget grid — sessions, cost, git, GitHub, AI readiness and the Kanban board — and a Kanban board of its own with search and tag filtering. A card can start or resume a session, and moves to Done when that session completes.

Many sessions at once

Profile isolation was checked against the real CLI, not assumed. Credentials live in the macOS Keychain under a service name derived from the config directory, so a second login cannot overwrite the first one's token — and deleting a profile's folder does not log it out.

The embedded browser

A browser tab lives in the same window as the sessions. Load a page, turn on inspect, click an element, and the app hands the agent a CSS selector, a label and one line of context.

The guest page is untrusted, so it only reports facts about the clicked element — tag, id, whether that id is unique, position among its siblings. Every judgement about which selector wins and what is safe to paste into a terminal happens on the trusted side, where it is tested against hostile input rather than hoped about.

The browser also carries a device bar that resizes the real Chromium view rather than scaling a screenshot, so a 390px phone frame is a 390px viewport and media queries actually fire; a step recorder that turns what you did into a readable flow you can send to the agent; per-tab session isolation; and an import of your existing Chrome configuration.

Integrations

Not built yet

Named here so nothing above has to be read hopefully:

See the roadmap →