A cockpit for your Claude Code sessions.
Launch several Claudes at once, watch them work in real time, and get pinged the
moment one finishes or needs you — all from one localhost dashboard.
Launch a session, watch it work, and get pinged when it needs you — all on localhost.
If you've ever juggled three terminal tabs trying to remember which Claude was waiting on you, this is for you.
- Launch sessions from a project picker — no typing absolute paths. Pick a folder, choose a model and permission mode, optionally seed it with a prompt or a saved task template, and go.
- Watch them stream. Assistant text, tool calls, and results show up live as each session works.
- Stay in the loop. When a session finishes its turn, gets blocked on a permission prompt, or errors out, you get a browser notification and the tab title updates with a count of how many need you. Routine streaming output stays quiet.
- Answer permission prompts right from the dashboard — approve or deny without switching windows.
- Run many at once. A sidebar gives you every session at a glance, each with a status dot and the project name front and center (not a cryptic UUID).
- Pick up where you left off. Resume previous Claude Code conversations, import projects from your existing Claude history, and recover gracefully: sessions and transcripts are persisted, so a server restart doesn't lose your work.
- Private by default. The server binds to
127.0.0.1only, with a second layer of defense that rejects any non-loopback request. Nothing is exposed to your network.
You'll need Python 3.12+,
uv, and the claude CLI on your PATH.
uv sync
uv run mission-control serve
# then open http://127.0.0.1:8765That's it. Add a project from the picker, click + New session, and you're flying.
All settings are environment variables — no config files to manage.
| Variable | Default | What it does |
|---|---|---|
MC_PORT |
8765 |
Port to bind on. |
MC_DB_PATH |
~/.mission-control/state.db |
Where sessions, transcripts, projects, and templates are stored (SQLite). The parent directory is created on first run. |
MC_CLAUDE_EXECUTABLE |
claude |
Override the claude binary. Shlex-split, so a multi-word command works — handy for pointing at the bundled fake Claude (see below). |
mission-control is a single Python process:
- FastAPI + WebSockets serve the HTTP/WS API and stream events to the browser.
- Each session is a
claudesubprocess driven overstream-json, which gives clean, parseable signals for turn completion, tool calls, permission requests, and errors — the foundation for those "needs attention" notifications. - An SQLite store (WAL mode) keeps sessions, transcripts, projects, and templates so nothing is lost across restarts.
- The frontend is vanilla JS served as static assets from the same process — no build step, no bundler.
# Run the test suite
uv run pytest -q
# Lint (auto-fix, then verify clean)
uv run ruff check --fix .
uv run ruff check .The web assets (mission_control/web/*.{html,js,css}) are bundled into the
package at uv sync time, so uv run mission-control serve reads them from the
installed package — not your source tree. While iterating on the UI, run the
dev server with live reload instead:
uv run uvicorn mission_control.server:app --reloadIf you'd rather use the regular serve command, re-bundle after each asset edit:
uv sync --reinstall-package mission-controlA bundled fake Claude lets you drive the whole UI end-to-end without making
real API calls. Point MC_CLAUDE_EXECUTABLE at it (replace <repo> with your
absolute project path):
MC_CLAUDE_EXECUTABLE="python <repo>/tests/fakes/fake_claude.py --scenario assistant_then_result" \
uv run mission-control serveThen open http://127.0.0.1:8765 and:
- Add a project — click + New session → + Add project → navigate to a folder → Use this folder.
- Launch a few sessions — click + New session a few times. Watch each card appear with its own status dot, and the header badge / tab title update as sessions go idle.
- Get notified — the first click on the page asks for browser notification permission. Grant it, then watch a session finish.
- Answer a permission prompt — try the
permissionscenario. - Terminate — use the per-card hover button or the detail-pane button; the
card flips to
terminated. - Resume — relaunch against the same project and pick a past session from "Resume previous session."
Swap the scenario between restarts to exercise different behaviors:
| Scenario | What it emits |
|---|---|
init_then_idle |
An init line, then idles. |
assistant_then_result |
Assistant text, then a result. |
permission |
A permission request the UI can resolve. |
error_exit |
An error event, then a non-zero exit. |
To confirm clean shutdown, run ps -ef | grep fake_claude after Ctrl-C'ing the
server — you should see nothing left behind.
Built and tested against its full spec: session launch, terminate, interact, attention notifications, the concurrent dashboard, localhost-only binding, and restart persistence all pass their scenario tests, with the linter clean and no orphaned subprocesses after shutdown.
Released under the MIT License.