A single-user daemon that turns labelled GitHub issues into real, interactive Claude Code sessions in the terminal I already have open.
This is written for my future self. It is public so it can be read, not so it can be
adopted — there is no support, no stable API, and no packaging beyond a local
pyproject.toml. See the constitution.
I label an issue I wrote. Within a couple of minutes, without touching a terminal:
dtach so it survives the terminal dying.active.Issues can also start life as a card on a private Trello board, so I can capture a task from my phone. That path files an issue and stops: labelling it is still mine to do.
These pages follow one issue through the system, in the order the system touches it. When something is not happening, the stage it is stuck at is where to look.
| Stage | Page | What it covers |
|---|---|---|
| — | Setup | Install, the token, the config file, onboarding a repository, and how to try it all without consequences |
| ① Intake | Where work comes from | The label, the Trello board, cards that do not say enough |
| ② Selection | What runs next | Concurrency, serial working, project-board order, holds, pausing |
| ③ Session | What a session is told | The prompt, Spec Kit, previewing, attaching |
| ④ Outcome | What happens after | Issue comments, notifications, cleanup |
And two pages that are not a stage:
| Page | What it covers |
|---|---|
| Operating it | The quick reference: recipes for what to type, every state and what you can do from it, every command and what it refuses, the logs, anomalies, health, the web interface |
| Configuration | Every section and key, and the generated example config |
Two deeper references, linked from the pages above where they matter:
The reasoning lives in specs/001-minimum-daemon/:
research.md
records twenty decisions with their rejected alternatives,
plan.md
carries the constitution check, and
data-model.md
has the state machines and the “interrupted at X → result on next start” table.
Three implementation details are counter-intuitive enough to be worth naming here, because each looks like a bug to a reader who does not know why:
dtach takes no -- separator. It rejects one outright. The wrapper needs its own.exec the worker. exec would replace the shell and the exit
code could never be captured, which is the wrapper’s entire reason to exist.git worktree remove is never given --force by default. Git’s refusal to remove a
dirty worktree is the guard, not an obstacle.