Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ClaudeZero - Todo-list sensei for Claude Code

Todo-list sensei for Claude Code. Zeros your list.

Loops Claude until every todo is done, committed, and checked off.
Restarts the coding session on a fresh context before rot.
You can spawn multiple instances to parallelize.

It's for practical Loop engineering.

License: MIT

Runs claude on a predefined prompt in a loop on the given todo list file. Makes it complete, commit, and check off each todo. The session stays interactive, so you can add prompts and make choices as it runs. Launches claude in auto permission mode by default, and restarts it on a fresh context before rot sets in.

Contents

What it does

  • Guides Claude to zero a todo list unattended — one task at a time until all are completed, committed, and checkmarked.
  • Beats context rot — session Stop hook SIGTERMs claude at ~80% of the context window and restarts clean. Fresh context, no quality decay.
  • One task per sessionclaude exits once it has zeroed a single todo and the script restarts it, so every task runs on a context isolated from the task before it, which cuts token spend (~20% on a working instance). An instance that has nothing to claim waits in the shell without launching claude at all, spending nothing.
  • Parallel by default — run many instances at once; they coordinate via git worktrees, each claiming todos the others haven't taken.
  • Safe merges — cross-instance merge-back serialized through flock; no races, no corrupted base.
  • Crash resilient — if claude crashes or is killed mid-task, its half-done work isn't lost. The next instance to come by — a peer switching to its next task, or the same loop restarted — reclaims the branch, finishes it, and merges it back. Work only counts as done once it lands on the base branch and its box is checked there.
  • Named sessions — every claude session is named (<instance id>) <nick> · <activity>, shown in the prompt box, the /resume picker, and the terminal title. The nickname is a short word no live peer holds, so you can say "kill moss" instead of reading eight hex characters. Both id and nick head the instance's report, and survive context restarts.
  • Ctrl+C window — 5s pause between runs to stop cleanly.

Quickstart

brew install IvanRublev/tap/claudezero

Change to your repo root with a todo-list file, and make sure the working tree is in a clean state (commit or stash any changes) and the todo file itself is committed on that branch.

Then run claudezero pointing to your todo-list:

claudezero todo.md

You can run that command in multiple parallel terminals to work through the todos faster.

⚠️ ClaudeZero runs claude unattended with permissions auto-approved and commits on its own to the branch you launch it on. Only ever point it at a todo file you wrote or reviewed, on a branch with a clean, committed tree — git is your only undo.

Sample output

Representative zero-mode run (agent output between the markers elided):

$ claudezero todo.md

❄ ClaudeZero 0.0.15
  zero mode · base master · fork → implement → commit → merge

… claude works a task: forks a worktree, implements, commits, merges, ticks its box …

❄ claude exited with code 0 after 1 runs · restarting in 5s · press Ctrl+C to stop

… fresh context, next task …

❄ execution stats (instance a1b2c3d4 · moss)
  Todos:               12m 30s  ·  5 completed
  ClaudeZero run loop: 48m 15s

  Tokens: 5.8M Total
  in 2.1k · out 84.3k · cache write 312k · cache read 5.4M

-----------------------------------------------
❄ TOTAL (3 instances)
  Todos:               41m 12s  ·  14 completed

  Tokens: 17.4M Total
  in 6.3k · out 251.9k · cache write 903k · cache read 16.2M

❄ ClaudeZero surveys the frozen field, and is proud.

The TOTAL block sums every instance of the run on this base branch — a crashed peer counts too, since its merged work did land. It prints on solo runs as well, with a singular heading. ClaudeZero run loop stays per-instance: parallel wall times overlap, so their sum is not a duration anything took.

Install (for the Claude coding agent)

Supported on macOS and Linux (the script is bash-3.2-safe, so stock macOS bash works).

Get the script

macOS (Homebrew)

brew install IvanRublev/tap/claudezero

Linux (curl)

sudo curl -fsSL https://raw.githubusercontent.com/IvanRublev/claudezero/refs/heads/master/claudezero.sh -o /usr/local/bin/claudezero
sudo chmod +x /usr/local/bin/claudezero

Prerequisites

bash, git, claude CLI, plus:

  1. flock — merge/worktree locking. Must be runnable, not just present.

    brew install flock          # macOS; Linux ships it in util-linux
  2. suggest-compact hook — the context-full restart signal. Install globally in ~/.claude/settings.json. Requires node.

    • Source: https://github.com/affaan-m/ECC — pin commit 7777656 (known-good with this release; later commits may change the state-file name or path).
    • ClaudeZero only reads the hook's state file — no hook edits needed.

    State-file contract. ClaudeZero couples to one artifact the hook produces: a per-session file at $TMPDIR/claude-context-bucket-<session_id> (<session_id> is the Claude session id; $TMPDIR matches node's os.tmpdir()). The hook must create this file once the context bucket crosses its threshold. Content is not parsed — presence alone is the "context full, restart" signal. Any hook that writes that file, at that path, on threshold works; the pinned commit is just the version verified to do so.

Both prerequisites are guard-checked at startup; the script exits with a clear message if either is missing.

Transcript-schema contract. The token figures in the execution-stats report are a second coupling to Claude Code internals, alongside the state file above. ClaudeZero's own Stop hook records each session's transcript_path (a field of the hook payload it already parses session_id from), and after claude exits the loop reads those session JSONL transcripts and sums the message.usage fields of every assistant line: input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens — the four categories Anthropic bills separately. One API request is written as several transcript lines, one per content block, each repeating the same usage object verbatim, so records are deduped by the line's requestId, and only the first (parent) match of each field name on a line is taken: usage.iterations[] repeats all four names one level down, and usage.cache_creation carries the ephemeral_5m/ephemeral_1h leaves that already sum into the parent. Transcripts are only ever read, and no schema change can fail a run — any parse miss prints Tokens: n/a and the run continues.

Two limits: subagent tokens are invisible — a session that used the Agent tool writes no isSidechain usage lines, so anything the task prompt spawns is missing from the totals, and the size of the under-count is not measurable from inside; and the figures are per instance run, for this repo only, unlike whole-machine tools such as ccusage, whose denominator is every Claude Code session on the box.

Todo file format

GitHub-style Markdown checkboxes, one task per line. Each line carries a unique id as the first whitespace-delimited token right after the checkbox — it names the task's branch and worktree:

- [ ] SMTH-855 Add retry logic to the sync endpoint
- [ ] 7 Extract validation into its own module
- [ ] 7.a Cover validation with unit tests
- [x] SMTH-140 Set up CI pipeline

```
- [ ] EXAMPLE-1 An illustrative example, not a task
```

[ ] = still to do, [x] = done (skipped). Before zeroing, the LLM validates the whole file: a task missing an id, or a duplicate id, stops the loop with a report. Checkboxes inside fenced code blocks (```) are ignored.

Loop engineering

Loop engineering shapes an agent's iteration cycle so it gets better across turns, not just runs once. It is the outermost of three nested levels — each one only works because the one under it holds:

  1. Spec — what to build. Expected outputs, constraints, acceptance criteria, done-conditions. The contract everything downstream enforces. Without it the layers above have nothing to check against. Here: the todo file, one task per line, each referencing a separate issue file with the details of the specification.
  2. Harness — how to keep the agent on the spec, in two directions. Feedforward guides steer before it acts (CLAUDE.md, conventions, templates); feedback sensors catch after (tests, linters, type checks, review). Feedback alone repeats the same mistakes; feedforward alone never proves it worked. Here: the per-iteration algorithm below, plus whatever guides and checks your repo already has.
  3. Loop — who does the prompting. The harness on a timer: self-triggering runs, isolated worktrees, subagents that verify and feed back. You stop prompting turn by turn and start designing the thing that prompts itself. Here: ClaudeZero with --taskprompt instruction on how to learn by prompting itself.

Levels 1 and 2 are yours; ClaudeZero supports level 3. Together they steer: when a mistake recurs, you don't only fix the code, you sharpen the spec and/or the harness, and the loop needs you less each pass due to the learning instruction.

Loop engineering has two halves:

  1. Mechanics — a durable loop over external state; disposable runs that restart before context rots.
  2. Learning — each turn carries a lesson forward, so the agent stops repeating mistakes.

ClaudeZero owns the mechanics and leaves the learning to you. It drills the form precisely — how to claim, zero, commit, and check off a todo without collision or rot. You bring the material — what this codebase's tasks should teach. Sensei drills the kata; you bring the fight.

The kata is a strict algorithm every instance runs, one task per claude session:

  1. Find & validate — collect tasks; a missing or duplicate id stops the loop.
  2. Judge independence by evidence — blocked only if the body quotably consumes an unchecked task's output; adjacency is not a dependency.
  3. Claim & re-check — one task per git worktree (branch = claim), then guard against a peer who already landed it.
  4. Implement & check off — scoped to that task, tick only its box, commit.
  5. Merge serially — on a conflict or over-check, self-heal once, else stop and hand off to the user rather than corrupt the base.
  6. End the session — the shell starts a fresh one for the next task, or waits without spending a token while peers hold the rest; when every box is checked, announce done and stop.

Closing the loop

Learning rides inside this form. A restart is amnesiac by design — it throws away rotten context; only durable external state survives: git, the todo file, and CLAUDE.md, one of several steering channels Claude re-reads on every fresh run.

ClaudeZero never writes CLAUDE.md — the harness stays learning-agnostic, so you choose what's remembered.

Bake a reflection step into the task prompt; the lesson lands in a committed CLAUDE.md, survives the restart, and reaches peers after their next merge:

claudezero todo.md --taskprompt 'Implement the task following your setup.
When done, if you learned something that will help future tasks — a gotcha, a
project convention, a command that worked — append one concise bullet under a
"## Learnings" heading in the project CLAUDE.md, and include that edit 
in the task commit.'

Now "the leopard remembers what the last winter taught him."

Tune the reflection instruction to your project

The prompt above is the smallest version. Levers:

  • Where lessons land — redirect to a dedicated docs/learnings.md (imported into CLAUDE.md via @docs/learnings.md) to keep the setup file lean.
  • When to reflect — gate on non-obvious tasks; most teach nothing, and unconditional reflection just grows noise.
  • Keep it bounded — have Claude prune stale bullets, not only append; an ever-growing file is context rot itself. Under parallel zeroing, though, appending one distinct bullet conflicts far less than rewriting a shared block — prune when contention is low.
  • Shape the lesson — fix a form ("symptom → cause → rule") so entries stay scannable, not diary prose.
  • Aim past learnings — promote a lesson into a test or lint rule; it enforces itself where a bullet only advises.

Under parallel zeroing, every instance edits the same CLAUDE.md — expect merge churn, and lessons reach a peer only after its next merge-back.

The loop is yours to teach.

Usage

claudezero [path-to-todo.md] [-t, --taskprompt "how to process ONE todo" | -l, --loopprompt "literal loop prompt"]
claudezero -h

-t and -l are mutually exclusive. Zero mode forks a worktree per task off the current branch.

-t task prompt — Zero mode processes each task with the given prompt. Defaults to implementing the task following Claude's own setup (CLAUDE.md).

-l loop prompt — skips zeroing entirely when set. Instead of walking a todo file, it loops claude on one literal prompt you supply, restarting on fresh context each time. Any todo-file-path you pass is ignored. This mode creates no worktree branches, so run just one instance at a time.

CLAUDEZERO_MAX_LOOPS — cap the number of context-reset iterations. Unset or 0 loops forever (until Ctrl+C); set >0 to exit the script after N restarts of claude.

CLAUDEZERO_MAX_LOOPS=3 claudezero todo.md

CLAUDEZERO_WATCHDOG — how long one claude may make no progress before it is killed. Default 15m; accepts plain seconds or an s/m/h suffix (900, 90s, 15m, 1h), and 0 disables it. A claude that stops making progress never exits, so without the timer the loop parks on it forever — no restart, no report, and nothing left to stop but the whole run. Progress is measured as claude's own cumulative CPU time, not wall clock: one that is thinking, streaming, or running tools burns CPU and keeps resetting the window however long the task takes, while one blocked on a dead socket burns none. When the timer fires it says so on its own console line, then SIGTERMs claude (the same signal the Stop hook uses, so the restart path is the usual one) and escalates to SIGKILL 10s later. The task worktree survives the kill: the next session reclaims it through the crash-recovery path.

CLAUDEZERO_WATCHDOG=45m claudezero todo.md

CLAUDEZERO_LINK — comma-separated top-level names symlinked from the repo root into every task worktree. Unset by default. A worktree is a checkout of tracked files only, so anything gitignored is absent there: if your todo lines point at spec files you keep in another git repository — issues/ISSUE-031.md holding the acceptance criteria for - [ ] ISSUE-031 … — the session never sees them and works from the one-line title alone. Listing the directory here links it in, so the criteria are readable and a tick lands in the real file rather than in a copy the worktree removal deletes. Each linked name is added to .git/info/exclude, so it stays out of the session's git add -A and out of this repository.

CLAUDEZERO_LINK=issues claudezero todo.md

Logging a run

claude's TUI is written to fd 4, which stays on the terminal, so a pipe captures only ClaudeZero's own reports instead of every TUI redraw:

claudezero todo.md 2>&1 | { trap '' INT; tee ../run.log; }

The trap keeps tee alive through Ctrl+C, so the final report and the TOTAL block land in the file. Without a redirect — or when stdin is not a terminal — the TUI falls back to stdout as before.

Cleanup

Normal exits tidy up after themselves. But a crash, a kill, or Ctrl+C mid-task can leave a claim branch and its worktree behind — by design, so the next run can reclaim and finish them. These leftovers are exactly what crash-recovery reattaches to, so only remove them once you've stopped every instance and are done zeroing the unchecked todos.

The easiest way is to let Claude Code walk the cleanup and confirm each removal with you. From the repo root:

claude "ClaudeZero left stray git worktrees and branches behind. Clean them up
interactively. Zero-mode worktrees are siblings of this repo named
../ts-<base>-task-<id>-<hex>; claim branches are named <base>-task-<id> (e.g.
master-task-7). Steps: (1) list them with 'git worktree list' and
'git branch --list \"*-task-*\"'; (2) for EACH one, show it to me and ask me to
confirm before deleting — never delete without my yes; (3) warn me before
deleting any branch whose commits are not merged into its base, since that
discards work; (4) after removals, run 'git worktree prune'. Do nothing
destructive without my explicit confirmation."

To do it by hand:

git worktree list                                       # find ../ts-<base>-task-<id>-<hex>
git worktree remove --force ../ts-master-task-7-a1b2c3d   # each one you no longer want
git worktree prune                                      # drop stale admin entries

git branch --list '*-task-*'                            # claim branches: <base>-task-<id>
git branch -D master-task-7                               # each unmerged claim you're discarding

Only delete a branch whose work you've already merged or intend to throw away.

Tests

End-to-end tests live in TEST.md — written to be executed by an LLM agent. Point the coding agent at the file and it runs all scenarios autonomously: claude --permission-mode auto "execute TEST.md and return a report".

Security

ClaudeZero runs claude unattended with auto-approved permissions and commits on its own. Read SECURITY.md for the trust boundaries and how to bound the blast radius before running. Report vulnerabilities privately per that file — not via public issues.

Contributing

Fork, branch, run the tests, open a PR. Full steps in CONTRIBUTING.md.

Commercial Support

Built and maintained by Ivan Rublev. Need integration help, Loop Engineering training for the team, or a one-time "office hours" consultation? See services.

Copyright

Copyright © 2026 Ivan Rublev.

This project is licensed under the MIT license.

About

Supervisor script builds a software specification into a product using Claude Code. It loops over the to-do list until each item is implemented, committed, and checked off. Multiple instances can claim to-dos in parallel and are synchronized through the Git repository.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Contributors

Languages