Stan Karzhev

projects / mission control

Mission control

A terminal dashboard for keeping track of several projects at once. One row each: how far through it is, what the next unmet goal is, when it was last touched, and whether a Claude Code session is running in it right now.

August 2026 Built with Python 3.12 and Textual for the screens, tomlkit so hand-written config keeps its comments through a round trip, and uv for packaging. It drives git and tmux rather than wrapping them. Source on GitHub.

I had five projects on the go and nowhere that tracked where any of them stood. Opening one meant reading the last commit, trying to remember what "done" was supposed to mean, and losing ten minutes before any work started. The ones I had not touched in a fortnight quietly stopped existing.

The roster: one row per project, each with a status glyph, a progress bar, a week of session activity, and when it was last touched. The highlighted row expands to show its next unmet check and last commit.
The highlighted row expands in place. Choosing what to pick up needs the next action far more than it needs a percentage.

Progress you can't fake

A hand-ticked checklist rots. You tick three boxes in week one, never open it again, and the percentage becomes a lie that is worse than no number. So every item that can be a predicate the app evaluates on open is one:

[[projects."orbital-sim".checks]]
name  = "eval harness green"
type  = "cmd"                       # passes on exit 0
value = "pytest -q tests/test_eval.py"

[[projects."orbital-sim".checks]]
name  = "baseline run"
type  = "path"                      # file exists
value = "results/baseline.json"

[[projects."orbital-sim".checks]]
name  = "picked the reward shaping"
type  = "manual"                    # nothing can measure this one
done  = false

Five types: path, git_tag, cmd, gh_pr, and manual for the rest. Progress is passing divided by total, recomputed every time, so it cannot drift. A project with no checks shows a dash, never 0%.

The upstream benefit is the real one: it forces you to say what done looks like. "Writeup" is not a check. "writeup.md exists and is over 800 words" is.

The detail screen for one project: a large percentage, the full check list with ticks and unresolved circles, a week of commits and sessions as heatmaps, recent commits, and recent session titles.
One project up close. Cheap checks run on open; the ones that shell out or hit the network are cached, and marked as unresolved until you run them.

The rest of it

  • Sends cd <path> && claude --resume <id> to the tmux pane next door, and refuses rather than typing it into a program already running there.
  • Shows which projects have a session running, and which of those have finished and are waiting on you. Useful during a long agent run.
  • Rolls the week or the month up per project, from commit messages and the titles Claude writes for its own sessions. Nothing is summarised by a model.
  • Repairs sessions that lost their project. Claude Code names each session directory after the absolute path you launched from, so moving a project silently breaks --resume. There is no built-in repair, and everything that mutates is a dry run until you pass --go.
The weekly report: three projects, each in its own colour, listing the commits pushed, the session titles worked on, and where the checks stand. A quiet list at the bottom names projects with no activity.
mc week and mc month, one colour per project so a long report stays readable. The commit message is the summary, written by whoever made the change.

Try it

uv tool install git+https://github.com/StanKarz/mission-control
mc init          # writes a starter config
mc doctor        # finds every directory with Claude sessions

Requires Python 3.12 or newer. tmux is optional and only the launcher needs it. The code, a longer guide and the gotchas are on GitHub.

112 tests, weighted towards where a bug is silent and expensive: slug encoding, the checks engine, period arithmetic, tmux target resolution. New behaviour worth trusting gets verified by breaking it on purpose and confirming a test fails, which has caught a test that asserted more than the code guaranteed more than once.