⚙️ Ratchet
Verified, resumable engineering loops for Claude Code.
A ratchet only turns forward. Every unit of work is gated by acceptance criteria and locked in as one atomic commit — the loop never slides back, never wanders off-spec, and never loses its place.
Point it at a codebase → get a reviewable backlog → let the loop work through it, one verified commit at a time. Walk away. Come back to a ledger of what shipped, what's blocked, and what needs you.
Why
Agentic coding is great at bursts and terrible at campaigns:
- State lives in the context window. Kill the session and the plan dies with it.
- "Done" is vibes. The agent says fixed; nothing proved it.
- Scope creeps. One fix becomes a refactor becomes a mess.
- Autonomy is all-or-nothing. Either you babysit every step, or you hand over the keys and pray.
Ratchet's answer is one structural move: the loop's entire state lives in a markdown file — BACKLOG.md — that is git-tracked, human-readable, and human-editable. The agent is stateless; the file is the state.
That one move buys everything else:
| Property | How |
|---|
| Resumable | Any new session reads the ledger + journal and continues where the last one died. Context resets are a non-event. |
| Verified | An item is done only when its acceptance criteria pass. The agent may not edit the criteria to make them pass — that's moving the goalposts, and it's banned. |
| Atomic | One item = one commit, containing the change and its ledger update. Every ratchet click is self-documenting and individually revertable. |
| Safe | Items tagged [USER-DECISION], [OPS], or [RISKY] are never executed — the loop parks them as needs-human and moves on. |
| Reviewable | The backlog is a file. It goes through PR review like any other code. No tracker, no API, no lock-in. |
| Parallel | Format v2 splits the state into one file per lane, so several agents run the same backlog at once without a merge conflict. |
The loop
flowchart TD
A[BACKLOG.md] --> B{next eligible item?}
B -- none left --> Z[report: backlog dry ✅]
B -- human-gated tag --> H[ledger: needs-human] --> B
B -- yes --> C[re-verify evidence in code]
C --> D[implement the Spec — nothing more]
D --> E{acceptance + global checks green?}
E -- red, attempts left --> F[diagnose, fix] --> E
E -- red, attempts exhausted --> G[revert item's changes<br/>ledger: blocked + journal why] --> B
E -- green --> I[atomic commit: code + ledger update<br/>🔒 the ratchet clicks] --> B
Three nested loops:
- Inner — per item: implement → verify → fix, with a bounded attempt count (no infinite thrashing).
- Outer — item → item until the backlog is dry, a stop condition fires, or everything left needs a human.
- Meta — re-run the audit to grow a fresh backlog. Schedulable (cron, CI, or Claude Code's own
/loop) for standing "keep this repo healthy" automation.
60-second quickstart
Install as a plugin (one command, updates included):
/plugin marketplace add afrizzal/ratchet
/plugin install ratchet@ratchet
Plugin installs namespace the commands: /ratchet:ratchet-audit, /ratchet:ratchet-loop, …
Prefer bare names? Copy the skills instead (they then work as /ratchet-audit etc.):
git clone https://github.com/afrizzal/ratchet
cp -r ratchet/skills/* ~/.claude/skills/ # macOS/Linux
Copy-Item -Recurse ratchet/skills/* "$env:USERPROFILE\.claude\skills\" # Windows
Then, inside any project in Claude Code:
/ratchet-audit # deep multi-agent audit → ratchet/BACKLOG.md
# ...review & edit the backlog like code — delete items, adjust specs, add tags...
/ratchet-recommend # routed plan → ratchet/NEXT.md (what next + who does it)
/ratchet-loop --only SEC-01 --verify fresh # paste the wave commands NEXT.md prescribes
/ratchet-ship # preflight → push → watch CI → smoke checklist
(Installed as a plugin? Prefix each command: /ratchet:ratchet-audit, /ratchet:ratchet-loop, …)
NEXT.md is your plan — the loop reads it and refuses to silently downgrade its verification
routing, but you issue the wave commands. Bare /ratchet-loop is the no-routing shortcut:
file-order execution of everything eligible. Run the loop on a work branch — the loop offers to
create one, and /ratchet-ship opens the PR.
Running the plan with a cheaper model
This is the core motion: the expensive model audits and routes; a cheap model executes.
/ratchet-audit and /ratchet-recommend with your strongest model (Opus/Fable).
- Switch:
/model sonnet in the same session, or start a fresh one with claude --model sonnet.
- Paste each wave's command from
ratchet/NEXT.md. The loop makes the handoff safe by
construction: it loads its own executor-rules.md (13 do-this-exactly rules for smaller
models), honors NEXT.md's verify assignments, and hard-parks anything high-stakes that wasn't
explicitly routed to it.
Don't want a full audit? Build a backlog from anything:
/ratchet-backlog create from TODO comments
/ratchet-backlog create from github issues
/ratchet-backlog add "rate-limit the /export endpoint"
The format is the product
A ratchet backlog is plain markdown with a tiny contract (full spec):
### SEC-01 — Scope item lookups by tenant [P0]
- Tags: —
- Evidence: api/items/[id]/route.ts:16 — GET/PATCH/DELETE filter by group only, not space
- Spec: add spaceId (from the session helper) to all three where-clauses; use updateMany/deleteMany
- Acceptance:
- [ ] `npx tsc --noEmit --incremental false` exits 0
- [ ] request against another space's item id returns 404
- [ ] existing save/delete flow in the UI still works
## Ledger
| ID | Status | Attempts | Commit | Note |
|---|---|---|---|---|
| SEC-01 | todo | 0 | — | — |
## Journal
- (the loop appends what it learned here — this is what makes resume cheap)
Spec and state are separated by design. Items are the immutable what; the Ledger + Journal are the mutable where are we. Humans edit items; the loop edits the ledger. Merge conflicts stay boring.
The format is agent-agnostic on purpose: these skills are the Claude Code implementation, but nothing stops a Cursor rule, a Codex prompt, or a bare script from executing the same file. Ports welcome — see CONTRIBUTING.
Parallel lanes (format v2)
One file, one writer — which means one executor at a time. Format v2 (spec, worked example) relocates the mutable state so several agents can work the same backlog concurrently:
ratchet/
BACKLOG.md # human-owned: Global checks + Lanes + Items. Executors never write it.
lanes/core.md # default lane — shared paths, dependencies, integration fixes
lanes/api.md # ledger + journal for Lane: api ← one writer
lanes/ui.md # ledger + journal for Lane: ui ← one writer
Each item declares a Lane:; each lane owns a disjoint slice of the tree and runs in its own worktree on ratchet/<lane>. Two executors, two lane files, two source scopes — nothing to merge-conflict over.
/ratchet-loop --lane api --only SEC-02 --verify fresh # worktree A
/ratchet-loop --lane ui --only UI-07 --verify inline # worktree B, same time
gitGraph
commit id: "recommend → NEXT.md"
branch api
checkout main
branch ui
checkout api
commit id: "ratchet(api): run open"
checkout ui
commit id: "ratchet(ui): run open"
checkout api
commit id: "ratchet(SEC-02): scope by owner"
checkout ui
commit id: "ratchet(UI-07): empty state"
commit id: "ratchet: sync ledger"
checkout main
merge ui
checkout api
commit id: "ratchet: sync ledger"
checkout main
merge api
commit id: "npm test @ merge"
(The branches are really named ratchet/api and ratchet/ui.) Each lane opens with a committed marker, lands each item as one atomic commit — source change plus its own ledger row — and closes with ratchet: sync ledger. A human merges, then re-runs the Global checks. The worked example is this repo captured mid-wave, with both lanes open at once.
| v1 | v2 |
|---|
| Executors at once | one | one per lane |
| Mutable state | one ## Ledger + ## Journal in BACKLOG.md | one file per lane, single writer |
| Coordination cost | none | one merge per lane, plus a barrier for shared paths |
| Ledger merge conflicts | n/a (one writer) | none — no two writers share a file |
| Source merge conflicts | n/a | none within the format's rules; the barrier lane exists because scopes alone can't cover shared files |
| Semantic conflicts | n/a | still possible — lanes green apart can be red together, which is why the Global checks re-run at the merge |
| When to use | the default | the backlog is large and the work genuinely partitions |
What keeps it honest — every one of these exists because the naive version breaks:
-
Run markers. A run opens its lane with a committed run started journal line and closes it with run ended. That is how a resuming agent tells crash debris (recover it) from a live parallel run (hands off), which a clean-tree check cannot do across worktrees.
-
The default lane is a barrier. Anything whose diff escapes every named scope — a new dependency and its lockfile, generated files, a post-merge integration fix — lives in the (rest) lane, which runs alone, with every other lane closed and merged. Lane assignment follows the diff, not the theme.
-
Scope binds the diff, not just the Spec. Before committing, the executor checks its diff's paths against its lane; a stray path parks the item rather than poisoning a merge.
-
Reads are global, writes are local. A lane run reads every lane's ledger and journal — lessons don't respect scope boundaries — and writes exactly one file.
-
Humans get a write window. Unparking, adding items, and grooming touch lane files only on the integration branch while that lane is closed. BACKLOG.md is frozen while any lane is open, so a Spec can't change under a done row that was earned against the old one.
-
Merging is a human step, merge-commit or fast-forward only. Squash and rebase-merge rewrite shas and orphan every Commit: cell in the ledger. Lanes green apart can be red together, so the Global checks run again at the merge.
-
Stop conditions are per lane. Two consecutive blocked items stop that lane's run; the sibling agent keeps going. A sick lane doesn't halt a healthy wave.
v1 is not deprecated and stays the default: one agent, one file, zero coordination. Reach for v2 when the backlog is big enough that parallelism beats simplicity and the work actually partitions — if every item touches src/core/, lanes buy you nothing. /ratchet-backlog migrate converts in one commit, preserving every ID, row, and journal line (migration guide); going back is just as cheap.
The skills
| Skill | What it does |
|---|
ratchet-audit | Fans out parallel subagents across your codebase (data layer, API/auth, business logic, tests/CI, frontend), verifies every finding down to file:line, and emits ratchet/AUDIT.md + a prioritized, acceptance-gated ratchet/BACKLOG.md. |
ratchet-backlog | Creates, validates, grooms, and migrates backlog files — from audits, TODO comments, GitHub issues, PRDs, or plain conversation. Enforces the invariant: no acceptance criteria, no item. Owns lane files in v2 (creation, rows, unparking). |