180checks in the deck smoke suite, run against a real production build1
10 sinterval at which core reconciles every session2
70commits on main3
CIlint, typecheck, format, roadmap and tests run as one gate4
- README.md, "npm run build && npm run smoke"
- README.md, "The deck updates itself"
- git rev-list --count main in the flightdeck repo
- README.md, "npm run check" (same as CI)
The problem
Running Claude Code on several projects means sessions scattered across terminals. Which one is blocked on me? Which one is burning quota? Which one finished an hour ago?
Flightdeck puts every session on one screen.
What I built
A local web app and a small Node core service.
- A live deck. Lists every session on the machine and updates itself over server-sent events, so the page never polls. Core re-checks every session on a 10 second sweep, and the page recovers on its own when core restarts.
- Background sessions. Start one from the deck and attach to it.
- A real terminal in the browser. A pty on the machine, streamed to xterm.js over a WebSocket, so you can type into a Claude Code session from the page.
- Hook and status line receivers. Endpoints that Claude Code’s hooks and status line can post to, so a blocked session shows up in about a second instead of waiting for the next sweep.
Architecture
AI design
Flightdeck makes no model calls of its own. Its job is to supervise Claude Code, so the design questions are about control.
- Sessions are data, not a black box. Core reads session state, quota and context percentage from what Claude Code already emits.
- Failure shows up. Hooks pointed at a receiver that is down put an error banner in every session, so the installer refuses to run unless core is up.
- Local by construction. The service binds to loopback and guards its HTTP surface with a token.
How it was built
Written down first: a spec, a threat model with numbered controls, a roadmap in YAML with gates, and a decisions log that points at the research behind each choice. Tasks were built on branches named after their roadmap id, and a single command runs the same checks as CI.
Tradeoffs
- Only background sessions can be attached. Claude Code’s attach command takes background sessions only. A session you started in a terminal yourself shows on the deck read-only, with the reason on the row.
- A web app first, a desktop shell later. The decisions log picks a local web app now and schedules a Tauri shell for when the terminal ships, because a browser eats Ctrl+W. Electron was rejected.
- Collected but not yet drawn. The README says quota gauges, a projects map and search are not built yet.
Next case study
Paperweight