Loop protocol / In practice
A week of loops on an internal web SaaS tool
Four Claude Code loops on one repository, measured from the transcript catalogue: what landed, what parked, what the reviewers caught and what changed between runs.
Between 16 and 21 October 2026 I ran four loops on Claude Code against one repository: an internal web SaaS tool with a Go API and worker, Postgres, a browser front end and Helm charts, deployed to a dev environment on every push to main. The three finished runs landed 439 tasks through 922 lanes in about 122 hours of wall time. Every number here comes from the agent-history catalogue and the runs' closeouts.
The repository
Its gate is just check plus about a dozen integration shards and a browser suite: on the first landing of the week, 3,656 unit tests, 14 integration shards and 101 browser tests. Its LOOP.md marks it guarded, requires two CI checks, and states that a release is cut and dev redeployed on every push. Heavy gates run on remote runners with 36 slots shared between whatever sessions are working.
The runs
| Loop | Dates | Wall hours | Lanes | Tasks landed | Operator messages | Compactions |
|---|---|---|---|---|---|---|
| 84 | 16 to 18 Oct | 55 | 306 | 202 | 68 | 7 |
| 85 | 17 to 18 Oct | 15 | 91 | 57 | 6 | 1 |
| 86 | 18 to 20 Oct | 52 | 525 | 180 | 106 | 11 |
| 87 | from 21 Oct | running | 307 so far | not closed | 43 so far | 3 so far |
- 84 was a wide sweep: a UI redesign, performance and correctness fixes, landed as sixteen batches. It started with a root on GPT models through Claude Code; I paused that after eleven hours and restarted it on Opus, which reconciled git, the board and running processes before doing anything else. The numbers above are the restart.
- 85 ran alongside 84, at most ten lanes at a time, on one narrow quality problem, with me present throughout.
- 86 was the widest: 525 lanes, 17 landings and 1,051 commits on
main, 507 of them code rather than board or generated-file commits. Its 180 is tasks with a commit onmain; 11 more have landed work but stay open because a named piece of evidence is missing. - 87 runs real end-to-end workloads on dev and fixes what they break.
Who did the work
Across the four runs, workers on Sonnet 5.5 took 592 lanes, seniors on Opus 5.5 took 287, reviewers on Opus 239 and scouts on Sonnet 72; escalations were rare, four in one run. About one lane in sixteen came back partial and one in a hundred blocked. The root's own output was 38 to 53 per cent of each run's output tokens, which is the cost of one session reading every return.
What review caught
CodeRabbit ran on 423 candidates and reported 54 major findings. Opus reviewers failed a candidate at least 47 times; the true number is higher, because half the returns don't state the verdict in a form the catalogue can read. dsreview arrived in loop 87: see How a change is proven for its numbers.
Three defects a reviewer caught that the lane's gate passed:
- During a mixed-version rollout an old worker would drop a phase marker, rerun the first phase and fail on a cursor conflict. The fix split the change into an expand half that landed and a contract half held until every worker runs the new code.
- Once composed with another change already on
main, resumed work would lose its ordering and fail every retry past a size threshold. - A rollback path could delete a hand-made alert rule. The ruling since: no rollback deletes anything a person made.
How landing changed
84 landed in batches: stack the accepted candidates, regenerate shared code once, gate the top, push. During 86 I switched it to continuous landing. A gated candidate never waits for its siblings; one lander lane at a time takes everything queued, gates the composed tree once and the root pushes. Then the gate legs went parallel, from a committed tree only, which took a landing from about 90 minutes to about 20.
Red main stops the line. In 86 an automated dependency merge, not the loop's, turned main red; the loop held its queue for a little over two hours while four failures were fixed in one commit. In 87 a vulnerability scan failed every gate on the base itself, so a dependency-only commit had to land first.
Cost
At list-price equivalent, not what was billed: about $3 to $4.50 per lane, and per landed task about $5 in 84 and 85 and between $7 and $13 in 86. 86 cost more per task because it did live performance and data work and many tasks needed several review rounds, nearly three lanes per task against one and a half in 84.
What a charter looks like
Every run starts from a frozen charter of at most 8 KB that the preparation skill writes after asking its questions. This is loop 87's, with the product's names taken out:
# Charter: <repository> loop87
harness: claude
root: claude-opus-5-5 / medium
aim: Run real end-to-end workloads on dev and fix what they break, beside closing landed
work on the board and the next screens
priorities: <board sweep> > <the bug blocking live runs> > <live runs> > label:live-finding > ...
exclude: <tasks another loop owns>; <tasks waiting on an owner question>
lanes: 15
gate: just check
gate-route: gaterun-slot LANE -- gaterun --log LOGFILE -- just check (shards: just
integration-shard-ci <shard>; browser: --kind browser), stdin /dev/null, 36 shared slots;
local only on exit 70, 124 or host unreachable
guarded-paths: internal/auth/**, internal/api/authz*, internal/db/migrations/**, deploy/**,
<the infrastructure repository>/**
standing: <standing authority file> sha256=<hash>
authority:
- Deploy dev and test; merge the release pull request with `just release-when-green`; no production.
- Infrastructure: edit, push, targeted apply after a saved and read plan; a destroy or replace
of a database, bucket or database instance parks.
- Live data: read in model calls and machine-local files; never in a commit, fixture or source,
never to CodeRabbit or another third party.
- LLM spend authorised.
overnight: on "overnight mode": keep the live runs and the waves moving in priority order, hold
questions in QUESTIONS.md, rule what evidence decides, park only what needs the owner.
budget: none
## First wave
| Task | Scope | Route | Note |
|------------------------------|--------------------------|---------------------|------------------------|
| <board sweep> | landed-but-open list | scout, then worker | close what has landed |
| <push refuses old results> | mapping, push plan load | worker | before re-runs reach it|
| <bulk preview, apply, undo> | review API, queries | senior | undo is a data model |
| <token endpoint> | internal/machinetoken | senior (guarded) | reviewer mandatory |priorities and exclude are how two loops share one board without colliding.guarded-paths adds this repository's sensitive code to the protocol's own list, and authority says exactly which live actions are allowed, including what stops a run: an infrastructure apply that would destroy a database parks rather than proceeding.
What a closeout looks like
The run ends with a closeout the next charter starts from. Its four sections are fixed, and the plugin's Stop hook keeps the root working until the closeout exists:
# Closeout: <repository> loop85 ยท Charter: <sha256 of the charter>
## Landed
- <task> (<what it was>): <commit>; Board: Done
...
## Parked
- <task>: AC1 landed; AC2 and AC3 are outside this loop's owned paths.
## For ratification
- Q6 (<a pinned vulnerability exception>): the one-week acceptance in .trivyignore expires on
<date>. Recommendation: rebuild the mirror before then, or every publish fails again.
- D5 (<a design call the root made>): recommendation ratify; it matches decision 35.
## Notes
- Live defects found on the way to the first live render, all fixed and landed: ...Every item under For ratification carries a recommendation, so reading it takes minutes, not a meeting. Loop 85's had thirteen.
What I'd tell a teammate
- The gate slot is the throttle, not the lane count. Lanes waiting for a slot is normal. The root admits more work when slot use stays low, and abandoning a wait for a local run is wrong.
- A root's caution costs hours. After one refused command a root briefed its lander to run gate legs one at a time, which cost an hour before anyone noticed. That's now a line in
LOOP.md. - Check the unit a limit counts. A root sized a change against a node-pool limit using pod requests; the limit counts whole nodes, and the rollout sat pending until the pool was raised.
- Every lane stops at once when a spend limit hits. In 86 every subagent failed on an account spend limit. Their work was in their worktrees and transcripts, and all nineteen resumed within about ten minutes once the limit was raised.
- Two loops on one repository need agreements. 84 and 85 collided on new task IDs and migration numbers. Push board-only commits at once to claim IDs, and agree migration numbers between sessions.
- Each closeout lists the calls I haven't seen. The root makes design calls overnight and writes each one, with its recommendation, under For ratification. Read that section first.
Method: run totals, lane roles, models and review fields come from the agent-history catalogue; landed counts from each closeout, which attributes tasks by commit trailers; cost from the catalogue's list-price estimate. Loop 87 was still running when this was written.