Claude Code, running while you sleep
claude-loop-runner runs the Claude Code CLI unattended, one task at a time: every iteration
is a fresh, non-interactive claude --print call. No --continue, no
--resume, nothing to /clear.
Long-term memory lives in two files inside the target repo — the plan you wrote, and the state the run keeps rewriting. The conversation never has to remember anything, so it never has to be trimmed.
claude --continue
claude --print, once per task
Where the memory actually lives
The memory lives in two markdown files inside the target repository, never in the conversation.
You write macro_plan.md by hand, once — scope, architecture, task list. The run
writes current_state.md after every iteration. Tag a task [low],
[medium] or [high] and the runner passes that straight to
claude --effort. That tag is how you decide, in advance, how much deliberation
each step deserves.
## Scope Ship the export endpoint. ## Tasks - [high] Decide the payload shape - [medium] Add the route - [low] Cover it with a test
Read at the start of every iteration. Never rewritten by the run.
status: in_progress next_effort: medium ## Done - Payload shape decided: NDJSON ## Next - Add the route at /export
Rewritten every iteration. This is the whole handoff between calls.
One iteration
One iteration runs six steps in a fixed order, and each step gates the next: a wrong branch or an unresolved rebase stops the loop instead of guessing past it.
main is checked outIf the target repo is on any other branch, the run errors out instead of guessing.
current_state.mdPicks up status and next_effort. Seeded automatically on the first run.
Calls claude --print with that account's token and the effort the task asked for.
The banner is detected whether it comes back as a non-zero exit or as ordinary stdout with exit 0. That account goes on cooldown and the same iteration retries on the next one. If every account is cooling, the run sleeps until the earliest reset.
origin/main, then pushThe same sync runs before each iteration too, so work never builds on a stale tree. A rebase conflict stops the loop for a human.
done, on blocked, or at the capblocked is a first-class ending, not a failure — it means a human needs to look.
Safety, baked in
claude-loop-runner refuses four things outright, and none of them are configurable: force-push,
hard reset, any branch but main, and an uncapped run. Every commit lands on
main and is pushed immediately — deliberate, since 2026-07. If the target repo
auto-deploys on push, each iteration reaches production with no human review in between.
There is no branch cushion; the guardrails below replaced it.
Hard-blocked through --disallowedTools, whatever --permission-mode says.
Same block. History the run didn't write is not the run's to discard.
Refuses to start, so it can't quietly push to whichever branch you happened to leave checked out.
Required. There is no unlimited default, so a badly-specified task can't burn a weekly quota across every account overnight.
Stops the loop instead of forcing progress.
Review the scope in macro_plan.md before a run — not the diff after.
Run it
claude-loop-runner needs Node 18 or newer, a Claude Code CLI login, and a plan file — nothing else. Point the token pool at one account or at several. Several is the whole reason the cooldown logic exists: when one account hits its limit, the run keeps going on the next instead of stopping for five hours.
# one account export CLAUDE_CODE_OAUTH_TOKEN=... # or a pool — the run rotates when one starts cooling export CLAUDE_CODE_OAUTH_TOKENS=tok1,tok2,tok3 node src/runner.mjs "C:\path\to\target-repo" --max-iterations 20 # optional local UI, bound to 127.0.0.1 only npm run ui # → http://127.0.0.1:4517Read the code on GitHub
Straight answers
claude --print process that reads only two small markdown files, so token usage per iteration stays roughly flat whether the plan has three tasks or thirty. There is no --continue, no --resume, and nothing to clear.macro_plan.md once — scope, architecture, ordered tasks — and the run never rewrites it. The run rewrites current_state.md after every iteration, carrying status, the next effort level, and what was just finished.main is checked out in the target repository, and it pushes after every successful iteration. That is deliberate — the branch-and-worktree cushion was removed in July 2026. If the repository auto-deploys on push, every iteration reaches production unreviewed.--max-iterations is required and has no unlimited default, so a badly specified task cannot burn a weekly quota overnight. The loop also stops the moment current_state.md reports status: done or status: blocked — blocked being an ending, not a failure.CLAUDE_CODE_OAUTH_TOKEN for one account or CLAUDE_CODE_OAUTH_TOKENS for a comma-separated pool, then run node src/runner.mjs <repo> --max-iterations 20. An optional local UI is bound to loopback only.