One loop, suddenly cheap
Every method that has ever produced good work runs on the same engine: try something, measure where it failed, update, try again. Evolution runs on it. Science runs on it. An apprentice runs on it. Training a model is the same engine written in math. What separates one era from another is never the principle — it is the price of one lap around that loop.
For most of software history, a lap was expensive. A wrong decision cost weeks of a person’s typing, so we bought insurance against being wrong: design documents, review boards, careful estimates. Think hard first, build once. That posture was not a culture — it was arithmetic, and agents broke it. When a competent agent builds for close to nothing — a token bill, not a salary — faster than any human types, the arithmetic flips: trying three times is now usually cheaper than deliberating once. Design-heavy stops being prudent and starts being the slow way.
But “build is free” does not mean “everything is free.” Two costs survive the flip, and they become the entire critical path: the places where the work has to wait for a human, and the places where the agent has to guess. Loop engineering is a method that does exactly one thing with that fact. It collects all the waiting into a single conversation at the front, and it kills every guess. What remains — the build itself — a team of agents runs alone, in a sprint loop, while you are somewhere else.
The method below was distilled from eight real builds between March and July 2026 — an internal ops tool, two outbound systems (OutboundOS among them), a life-organizer (life-os), a task board (cairn), and the largest, a claude-manager build (CCM). None of its rules was adopted on faith or imported untested; each earned its place through a specific failure, with a date on it. Section five shows those scars, because for a method you are meant to trust, the receipts are the point.
One note on substrate before the tour. Everything here runs on Claude Code — a terminal agent harness that loads a CLAUDE.md from the repo into every session automatically, spawns sub-agents with their own system prompts, and enforces hard permission rules from a settings file. The harness is the runtime around the model; on a different harness the file names change, the method does not.
Why every piece exists
One question first, because its answer organizes everything: why did the try-fail-update loop start running itself in software, before any other kind of work? Not because code is easy. Because software is the one domain where the judgment of “correct” was compressed into machines decades ago. A compiler is fifty years of professional judgment about well-formedness, frozen into a tool that answers in milliseconds, for free. A type checker, a test runner, a linter — each is a verdict that no longer needs a human. The loop runs itself exactly where such frozen verdicts exist, because every attempt can be scored without waiting for anyone.
Where no frozen verdict exists — what counts as “done” for your product, which trade-offs you will accept, what must never happen — the loop has no score, and a human must supply one. That boundary is the design principle of the whole kit: everything a machine can verify goes to the machine, and the file structure exists to route the few genuinely human calls to the human — batched, up front, once.
So when this method bootstraps a project, you get a small kit of files: a CLAUDE.md, a SPEC.md, a DISPATCH.md, a DECISIONS.md, a folder of role playbooks, a locked-down settings.json. It is easy to misread that as bureaucracy. It is the opposite — every artifact is a direct consequence of “batch the waiting, kill the guessing.” If you understand this table, you could throw the kit away and rebuild it from scratch.
| The piece | Why it exists |
|---|---|
| Scaffold first, discuss after | The machine does the cheap part — creating files — and the human steps in only where a human is required: the decisions. |
| 7 slots | The only seven places one project differs from another. Everything else is invariant, so everything else is a template, not a conversation. |
| Resource checklist | Every unresolved line is a future stall with a name — a missing key, an unapproved mock, an undecided port. Resolve them before the loop runs, not during. |
| SPEC.md — one contract, perfect tense | The agent builds from the spec, not from its memory of your chat. Two sources of truth argue; an ambiguous one gets filled with a guess. |
| CLAUDE.md | The shared rules of the loop — the one memory that survives an agent being spawned, compacted, and killed. |
| Per-role playbook | One system prompt per craft, plus a hard boundary on which files each role owns. A role is an agent type, loaded at spawn. |
| DISPATCH.md backlog | A task IS the spec of one unit of work. Handing work over in chat means the agent works from a summary — and summaries drop the load-bearing clause. |
| DECISIONS.md | The off-plan ledger. When the human is away, the agent makes a reversible call and logs it; the human reads it back later. The loop never blocks on a question. |
| .claude/settings.json | A prompt rule is probabilistic — it holds most of the time. A harness deny is mechanical — it holds every time. A rule that must never break has to be mechanical. |
| Stop after scaffold | Taste and irreversible actions belong to the human. The machine is autonomous only inside the reversible zone, so it hands control back before leaving that zone. |
| Author ≠ checker | Whoever wrote the code will pass their own work — they grade it with the same blind spot they wrote it with. Verification is always a fresh agent. |
| Machine-checkable gate | A criterion no machine can run is a criterion that gets skipped the moment someone is tired. If the gate cannot run itself, it is decoration. |
Read the second column top to bottom and it says the same thing twelve ways: the machine holds the cheap, reversible, checkable work; the human holds the expensive, irreversible, taste-bound work; and the artifacts keep the two from bleeding into each other. That separation is the method. The rest is detail.
Two steps to start: scaffold, then decide
Bootstrapping — Phase 0 in the hero diagram — is deliberately two steps, and the seam between them is where the human touchpoint lives.
Scaffold
An agent reads what you handed it — a spec, a mock, sample data — fills the seven slots, generates the kit, and stops. It does not start building. Its output is a report: files created, slots chosen, and a list of blockers it refused to guess through.
Discuss & decide
You read the report, answer the blockers, adjust what you disagree with, and clear the resource checklist. Then you say the one word that starts everything — “go” — and the loop owns the build. The scaffold never rolls into the build on its own — without you, the machine waits at the report forever.
The seven slots are the entire configuration surface — the only places projects genuinely differ:
STACK— language, framework, run/test commands, portsAUTH_POSTURE— single-user-no-auth (default) or multi-user-authMEMORY_BACKEND— where lessons live: agent-memory files, a wiki, or a boardDOMAIN_AGENTS— extra roles beyond the five-role corePRODUCT_NATURE— a human app, or agent-first (the consumer is an agent)AUTONOMY_TIER— sprint-gated (default: the machine gates decide sprint-to-sprint) or never-free (an empty backlog never idles the team — it cascades into scouting, dogfooding, hardening)BUILD_MODE— greenfield or reuse-copy from a pinned source
Filled in, the slots read like this — the running example here and below is a small exam-practice app — a single student drilling mock tests and getting scored:
STACK FastAPI + React · commands and ports from dev-setup.md
AUTH_POSTURE single-user-no-auth # default — a personal tool
MEMORY_BACKEND agent-memory files # lessons live in the repo
DOMAIN_AGENTS none # the five-role core is enough
PRODUCT_NATURE human-app # a person clicks the buttons
AUTONOMY_TIER sprint-gated # gates between sprints; human reads back async
BUILD_MODE greenfieldThe resource checklist is the anti-stall device. Each line names a future human-block before it can happen: is the mock approved and frozen? Are design tokens pointed at, or will the frontend invent them? Is there sample or live data for every screen? Are run commands and ports settled? Is every external key in the environment, not the repo? What is the policy on irreversible actions — deploy, publish, spend? Every unchecked box is a place the loop would otherwise stop and wait for you mid-sprint. You pay that cost once, up front, in one conversation — never as a silent stall three sprints deep.
A blocker done right
The most important thing the scaffold agent does is refuse to guess. Here is the canonical case, and it is a real receipt from training these docs (section six explains that training), not a hypothetical.
For a greenfield project, the boot and test commands cannot be derived from a spec — a spec says what to build, not how it starts on your machine. A reasonable-sounding guess for a Python service is uvicorn app.main:app. In an early training run — the spec had been distilled from an existing production app — the scaffold agent wrote exactly that guess, politely tagged [TENTATIVE]. Review caught it before it ever ran — and the production repo the spec came from proved the guess wrong: that app boots under Docker Compose, on different ports. The fix was not a smarter guess. It was a rule: a value the agent cannot derive gets written as a blocker, in place, and the loop refuses to invent a placeholder — not even a tagged one, because a tentative value gets used silently all the same.
# CLAUDE.md §1 — Stack
Run: [BLOCKER] greenfield boot command not derivable from spec.
Candidates seen: uvicorn (guess) vs docker compose up (repo hint).
Needs a human to confirm at Step 2. Do NOT pick one silently.
Test: [BLOCKER] test runner + command — same, confirm at Step 2.
# DECISIONS.md ②
- Boot/test commands left as blockers — no source in spec/refs;
guessing them proved wrong in a prior run. Human resolves at Step 2.One exception, and it matters: if a document you handed over already states the command — a dev-setup.md in a refs folder, say — that is not a guess. The agent adopts it, cites the source, and flags it for you to confirm. The rule bans fabrication, not the use of a source you provided.
Inside the sprint loop
Once you say “go,” the session you are in becomes the team-lead — it coordinates, it does not code, and it never touches git. It spawns four role agents by type, each with its own playbook loaded as a system prompt: architect, backend, frontend, tester. Five roles, four playbook files — the team-lead is the main session itself and has no agent file. Worth stating plainly, because that count is the one place people trip.
The dispatch is a contract
Work does not move through chat. It moves through a task, and the task is written to be self-sufficient: an intent (what “done” means, written in the perfect tense — as already true, so it can be checked rather than aspired to), the defensive cases the code must survive, and a gate a machine can check. A chat message is only a pointer to the task; the agent reads the whole task before acting.
A3 · POST /exams/{id}/submit — persist a student's answer sheet
Intent Accept { answers[] }, write exactly one submission row,
return 201 { submissionId }.
Defensive Duplicate submit -> 409, not a second row.
Unknown exam id -> 404.
Empty answers[] -> 422.
Gate [ ] integration test: submit twice -> one row, 2nd call 409
[ ] query the row back, assert status='submitted' + count
[ ] typecheck clean · existing suite >= baselineNotice the gate never says “looks right.” Every line is something a machine runs and gets a yes or no from. That is not an accident of this example — it is the rule from section two. A criterion that cannot run itself gets skipped the day someone is tired.
What one sprint looks like
A sprint is a fixed rhythm. This walkthrough is illustrative — assembled from the real flow and gates, not a transcript of one logged sprint — but every beat is a rule with a scar behind it.
- 01Kickoff — The architect edits the sprint plan in place — one source of truth, no second copy to drift.
- 02Build in parallel — Backend and frontend work at once, on different files, because the tasks are independent. Sequential only when a dependency is real.
- 03Verify — fresh agent — The tester runtime-verifies while the architect reads the full functions. Neither wrote the code. Author never checks author.
- 04Three gates — API (every endpoint answers as specified), function (full-function review, suite ≥ baseline), sprint (every plan box ticked). One missed box blocks the commit. 100% or it does not ship.
- 05One commit — The architect makes exactly one commit for the sprint, announces a two-minute freeze so nothing edits mid-commit, and pushes in the background.
- 06Next sprint — The following sprint starts itself — under sprint-gated, the three gates are the green light, not a human sign-off. No one waits for a light that was already green.
Concretely, a gate earns its keep like this. In one real sprint — Sprint A1 of the claude-manager build (CCM) — a stale mock silently broke two integration tests — the kind of failure that reads as green if you only glance at the diff. The function gate’s “existing suite ≥ baseline” box is exactly what catches it: the number went down, the box stays unticked, the commit is blocked until someone finds out why. A gate is not ceremony. It is frozen judgment — a mistake someone already paid for, compressed into a check that runs forever. The same move the compiler made for syntax, made here for your project’s own failure modes.
Why a fresh checker, and not a vote
Author ≠ checker is not politeness; it is about the shape of the errors. An LLM’s mistakes are self-correlated — an agent grading its own work fails the same way it failed writing it, so it certifies its own bug. A fresh agent that did not write the code breaks the context half of that correlation — only half, because both still share one model’s weights and blind spots. The instinct is to buy the rest with volume: add voters, take a majority. That is exactly what does not work — voters who share a blind spot agree on the wrong answer. You fix the cause, or you bring in the one signal that is genuinely uncorrelated: a human who holds a fact the model cannot infer.
Decisions never block the loop
The loop meets ambiguity constantly. What keeps it moving is a clean split by reversibility. A reversible call — one a rollback undoes cheaply — the team-lead just makes, and logs in DECISIONS.md: what it decided, why, and how to change it. You read those back on your own time and override any of them. The human wins, always — but asynchronously. An irreversiblecall — one whose consequence escapes into the world — goes to the decision park and waits for you, while the team picks up other work. “User is away” never means “team is idle.”
The ledger has two sections, and the distinction is worth keeping sharp — one holds cases the spec never foresaw, the other holds calls the agent made in your absence:
① BEYOND-SPEC (the spec never foresaw this)
- An exam with zero questions: reject at creation (422).
Why: cheapest reversible reading of the spec's intent.
To change: lift the check in exams.service — one line.
② SELF-DECIDED (no human around, alternative chosen)
- Chart library not specified. Chose recharts over d3.
Why: already in the lockfile; covers every chart in the mock.
To change: swap the ChartPanel wrapper, nothing else touches it.The kill-rules live in the harness, not the prompt
Some rules must never break — no destructive git, no rm, no blocking question that freezes the loop. Writing those into a prompt is not enough. A prompt rule is a probability, and over a long enough loop, low-probability failures happen. So the non-negotiables are enforced one layer down, in .claude/settings.json, as harness denies. A prompt says “please don’t”; a deny makes the action impossible. When a new hard rule earns its place — always from a real failure — it becomes a new deny line, with the reason written next to it.
This is the difference between a rule and a guardrail. The playbook holds the rules the agent should follow; settings.json holds the handful it cannot break. Anything you would be genuinely upset to see violated belongs in the mechanical layer.
Every rule is a scar
Here is the claim that makes this method worth trusting: not one of its rules was written from imagination. Each traces to a specific failure, in a specific sprint, on a real build. This is a sample of the ledger — the rule on the left, the failure it is made of on the right.
| The rule | The failure it is made of |
|---|---|
| Never ask the user a blocking question mid-loop — route to team-lead, decide-and-log | OutboundOS, 31 May: an AskUserQuestion call froze the whole loop, twice, waiting on an answer nobody was there to give. |
| One committer (the architect); the lead never touches git | cairn: CI broke four times when a commit raced a push and an amend rewrote the SHA. life-os, 21 Jun: a frontend agent self-committed into a race. |
| Verify before you claim (Rule #0) — run it, query it back, paste real output | CCM Sprint 14: a backend agent reported "fixed Docker" without ever running it. Sprint 15A: a tool wrote a row whose output field was NULL while its status read "completed." |
| Never-free — "out of backlog" does not exist; cascade into scout, dogfood, hardening | life-os, 21 Jun: "board complete, team quiet" — while four raised tasks sat unworked. |
| Three quality gates, every sprint | CCM Sprint A1: a stale mock silently broke two integration tests. Sprint 134: five real bugs slipped through review into a "done" sprint. |
| Build the simplest thing the spec asks for — no auth, rate-limit, or queue it did not request | CCM Sprints 4–9: agents added bearer-auth and rate-limiting "for safety" on a single-user tool. All of it was waste; the CEO caught it at Sprint 15A. |
| Architect review reads the full function and traces runtime — not just the diff | CCM Sprint 6 shipped with two endpoints missing; Sprint 13 wrote a task that never reached the DB even though the diff looked correct. |
| Heartbeat from an external clock, not the model’s own sense of time | cairn, 21 Jun: a sticky pause left the loop idle for ~13 ticks because the agent, self-pacing, wrongly concluded it was done. |
| Capture the real payload before you write the schema (empirical-first Phase 0) | CCM Sprint 8C: a schema written from a spec assumption met a real payload, threw a silent 422, and burned weeks before anyone noticed. |
| No self-shutdown without explicit user sign-off | life-os Sprint 0: an orphaned shutdown request killed an agent that was still working. |
This is not record-keeping — it is the pruning mechanism. A rule tied to a pain can be removed when the pain no longer applies: read the scar, check whether it can still happen, drop the rule if it cannot. A rule written from imagination has no off-switch, so it accretes forever. The genealogy is what keeps the kit from turning into a cargo cult.
The method was trained like a model
Here is the part I find most convincing: the documents that describe this method were themselves produced by the engine from section one — try, measure the failure, update — turned on the docs themselves. Not written and polished. Trained, in the literal loop sense.
The setup is a training loop with the docs as the weights. Snapshot the docs. Drop a blank, one-shot agent into a fresh project — a spec and a mock it has never seen — and have it scaffold. Wherever it had to guess, or guessed wrong, that is the loss: a report of exactly where the docs failed to carry it — counted by hand against the run report, which makes it the one non-mechanical gauge in the whole loop. Patch the docs against that report. Then run the next epoch with a brand-new blank agent — the previous one is no longer blank; it has seen the answer, so it would paper over the very gap you need to expose. Two knobs only: the docs and the spawn prompt. No coaching mid-run — a whispered hint is a contaminated sample that no future run reproduces.
The classic loop
- weights
- training data
- loss function
- epoch
- held-out test set
The same loop, renamed
- the docs / the kit
- a spec + mock the agent has never seen
- “where did the blank agent have to guess?”
- one run of a fresh blank agent
- a domain the docs were never tuned on
And it converged like a training run — with one caveat stated up front: converging on the training domain is the cheap half, close to guaranteed by construction, so the held-out pass below is the part that counts as evidence. On the training domain — the life-organizer — guess-behaviors per run went 6 → 8 → 6 → 4 → 1 → 0. (Each point is a single run of a stochastic agent, so read the trend, not the exact values. The bump to 8 is familiar to anyone who has watched a loss curve — patching one gap exposed others underneath — though with one run per epoch, some of it is plain variance.) By epoch five the only thing left was a web-channel wrinkle; patching it took epoch six to zero.
Then the real test: a domain the docs were never tuned on — CCM, whose spec ran to 1,174 lines and was deliberately self-contradictory, with duplicate ADR numbers and a mock that diverged from the spec. (CCM supplied several of the scars in section five, so the method’s rules knew it well — but the docs had never scaffolded it, and scaffolding is what this test measures.) A blank agent scaffolded it correctly. The docs learned a method, not a memory — or, stated at the honesty this post owes you: one pass, hand-graded, as close to a clean held-out test as a one-person lab gets.
What's proven, and what isn't
For a method you are meant to pitch, the honest boundary is the most valuable thing on the page. Here it is, layered by exactly how far the evidence reaches.
- The rules are battle-tested. Every rule above traces to a specific failure across eight real builds. That is not a claim; it is section five. This layer I am sure of.
- The kit is proven at scaffold time. The training loop shows the docs reliably take a blank agent from a spec to a correct, well-stopped kit: six epochs to convergence on one domain, one held-out pass on another. Real — and bounded. It proves the start, not the whole run.
- The fresh sprint loop, end to end, has not been through fire.The part after “go” — a freshly-generated kit driving a real multi-sprint build to completion with a new team — is the piece I have not run to convergence. The sprint engine and the role playbooks are, honestly, the least-tested surface of the whole thing.
And there is a deeper limit, structural rather than a matter of more testing. A try-fail-update loop only learns where a verdict exists — that is its own first principle. The build loop has verdicts everywhere: a test breaks, a claim proves false, a gate stays red. The other loop — validate: does anyone want this? — has no verdicts yet, for a plain reason: none of the repositories behind this method was ever launched at a market — no target segment picked, no distribution, no user ever asked to pay. So the question “did anyone want it?” has produced zero signal — not negative signal, zero. And zero signal means no loss, and no loss means nothing for the loop to learn from. Every gauge on this loop measures whether the build is right; the gauge for whether it was worth building has to be manufactured the same way all the others were — by shipping at a real target and letting the market grade the paper.
When to use it, and how to start
Use this when the work is spec-able and the real bottleneck is your attention, not your typing: a greenfield app or a well-bounded rebuild, where you can say clearly what “done” means and hand over the keys — mocks, data, credentials, the line on what must never happen. Do not reach for it when the hard part is discovery rather than construction; the loop is very good at building the thing you specified and has no opinion on whether it is the right thing.
And schedule it in the right units. The cost of a build here is spec (the human-hours spent deciding) plus verify (the wall-clock time the loop takes to check itself) plus build(≈ 0). Estimating in “engineer-days per feature” imports a number from the world where typing was the cost. The critical path is when you are free to decide and how long verification runs — plan around those.
- The app is spec-able and well-bounded
- You can approve a mock and freeze it
- You hold the data, keys, and boundaries to hand over
- Your attention, not code, is the bottleneck
- The hard part is figuring out what to build
- The spec is still moving under you
- “Done” can’t be written in the perfect tense
- You need proof it sells, not proof it works
Start here: one URL
Starting is one URL. The kit manifest is the raw map of every file, fetchable directly — enough for a single fresh session to reconstruct the whole kit from zero. Point a new Claude Code session at your repo, hand it the manifest, and let it scaffold. It will stop and hand you a report. That report is the discussion — the first, and one of only two, places the loop needs you.
Everything that works runs on try-fail-update, and agents just made one lap nearly free. Engineering now means designing the loop around the two costs that survive: the human’s decisions and the machine’s guesses. Batch the first, kill the second, and put the rules that must never break into the harness instead of the prompt.
That is the whole method, and it is honest about its edge: the rules are scars, the kit is proven at the start, and the full end-to-end run is the frontier still ahead of me. Run it — the manifest above is everything you need — and tell me where it breaks.