Why this is a deliberate (
disable-model-invocation) skill. A loop edits, commits, and spends tokens on its own. You want to type/loop-controller(or have the orchestrator dispatch it), not have Claude silently start an autonomous loop because a test happened to fail. The discipline below is what makes that safe.
The one rule that governs every loop
A loop is only as good as its stopping condition. Loops converge when "done" is an external signal the agent cannot argue with — a test exit code, a coverage percentage, an empty queue, a fresh evaluator's verdict. They diverge — oscillate, thrash, or run the budget to zero — when "done" is a subjective judgment the agent grades itself on. Agents are pathological optimists about their own work; left to self-assess, they declare victory early.
There is a subtler failure an objective proof does not cure: a signal that is mechanical, default-FAIL, and un-gameable can still measure the wrong thing. A test suite green against a mock, a stub, or a fixture is all three of those — and proves nothing about whether the real product works. That is convergence on a fiction, and because it wears the costume of rigor (an exit code! a number!) it slips past review more easily than a subjective claim would. 65 green tests against a mocked backend look exactly like 65 green tests against the real one. So the proof must measure the real goal, not a stand-in for it (Step 2) — un-gameable and pointed at the thing that actually matters.
So the entire job of this skill is to turn a fuzzy "keep working on X" into a convergent loop: a mechanical proof of the real goal, the right execution primitive, and a guardrail stack that stops the loop whether or not the proof is ever met.
Everything else here — fix-until-green, coverage-loop, perf-loop — is a config of this harness: a specific proof plugged into the same machinery. Author new loops against this skill; don't reinvent the loop engine.
First — does a concrete loop already exist?
Twelve configs of this harness already ship in skills/loops/. Route the intent
to one of them before authoring anything — Steps 0–6 below are for the loop that
doesn't exist yet. (Every one of these is disable-model-invocation: true:
dispatch it by its slash command, or let the orchestrator dispatch the build
loops. None auto-fires.)
| The intent is… | Dispatch |
|---|---|
| "make tests / lint / typecheck pass", red CI, "run until green" | fix-until-green |
| Drain a multi-agent build's shared task list until every task passes its gate (Agent Teams) | orchestrator-task-loop |
| Build until an authored contract's criteria all hold (build-until-spec) | contract-conformance-loop |
| "Keep my PR green / rebased / answer review comments while I'm away" | babysit |
| "Raise test coverage to N%" | coverage-loop |
| "Get this metric under its budget" (latency, bundle size, memory) | perf-loop |
| "Watch the logs / CI and fix what breaks" | self-healing-loop |
| "Migrate / transform every file in this enumerated set" | migration-loop |
| "Keep the docs + changelog from rotting" (nightly) | nightly-docs-and-changelog |
| "Keep dependencies current and audited" | dependency-health-loop |
| "Map this unfamiliar codebase until my questions are answered" | codebase-exploration-loop |
| "Weekly repo hygiene — stale branches, PRs, worktrees" | repo-cleanup-loop |
No row fits → continue below and author the new loop against this harness.
Step 0 — Should this even be a loop?
A loop has real setup cost and its own failure modes; the mistake is looping things that don't earn one. Before building anything, put the task through four questions — a "no" on any of them is a strong signal to just do the work manually (or once) instead:
- Does it repeat? A one-off is usually faster by hand. Loops pay off on work that comes back — every PR, every night, every new ticket.
- Can "done" be verified mechanically? If nothing but a human can reject a bad result, the human is still the real gate and the loop saves little. This is the same requirement as Step 2 — no mechanical proof, no convergent loop.
- Can the agent act end-to-end? If it must stop for permission or missing context every few minutes, that's assisted manual work, not a loop.
- Is "done" objective? "Tests pass" / "queue empty" loops; "the design feels right" / "the strategy is sound" does not. Subjective, high-stakes, judgment- heavy work (architecture rewrites, auth, payments, prod deploys) is where a human stays in the driver's seat — keep it manual, or gate it hard (guardrail 4).
Pass all four and the 5-part contract below will fill in cleanly. Fail one and the honest move is to not build the loop.
The 5-part loop contract (required)
Before running anything, write the loop's contract. A loop that can't fill in all five lines isn't ready — the blank is the bug.
| Part | Question it answers | Example |
|---|---|---|
| trigger | What starts this loop? | "red CI on branch X" / "every 30m" / "user runs /fix-until-green" |
| action | What does one iteration do? | "run the gate, fix one root-cause failure, re-run the whole gate" |
| proof | What mechanical signal proves done? | "npm test exits 0 and lint exits 0 and typecheck exits 0" |
| memory | What state survives between iterations? | "PROGRESS.md, the feature-list JSON, git history" |
| stop | Every way this loop ends | "proof passes OR 20 iterations OR no-progress for 3 rounds OR budget cap" |
The proof and stop lines are load-bearing. Keep this contract in the loop
skill's body (or at the top of the run) so any reviewer can audit convergence at
a glance. This is the Forward Future "loop library" 5-part schema, adopted as the
required contract. The taxonomy of common loop shapes (fix-until-green,
build-until-spec, refine-until-quality, research, review, migration, coverage,
perf, self-healing, exploration) lives in references/authoring.md.
Step 1 — Choose the primitive
The first decision is which engine runs the loop. Get this wrong and you burn money: a scheduler pointed at finishable work re-runs blindly on the clock; a "work until done" wrapper pointed at an external poll spins forever.
The decision rule: Are you pushing work to a finish line, or watching for something to change?
| If the job is… | Use | Because |
|---|---|---|
| Push to a finish line, proof is provable from Claude's own output (test exits 0, git clean) | /goal |
A small fast model judges the transcript each turn; "no" feeds the reason back. The closest native "loop until done." |
| Push to a finish line, proof needs a script/file/tool check the model can't just assert | Stop-hook gate | A hook runs the real check and blocks exit until it passes — ships with the skill. |
| Watch / poll for an external change on a cadence | /loop |
A thin scheduler that re-runs a prompt or slash command on an interval; it does not push to a finish line. |
| One big mechanical change across many files in parallel | /batch / dynamic workflow |
Fans out across worktree-isolated subagents; compose with the orchestrator's Workflow mode. |
| Greenfield, want a fresh context window every iteration | claude -p bash loop (Ralph) |
State lives on disk; each pass starts clean. Needs a sandbox (--dangerously-skip-permissions). |
Do not conflate /goal (finish line) with /loop (watch). They are different
primitives with different failure modes. Full mechanics, constraints, and the
exact invocations for each — including /goal's evaluator-can't-read-files
limit and /loop's session-scope/expiry/no-catch-up rules — are in
references/primitives.md. Read it before authoring.
Step 2 — Make "done" mechanical and default-FAIL
A convergent loop needs a proof signal the agent cannot rationalize past.
- Phrase "done" as an observable. "all tests in
test/authpass and lint is clean," not "the auth code looks correct." If the proof is a number, name the artifact that produces it (coverage report, benchmark output, the gate's exit code). - Default-FAIL. Every criterion starts
falseand only flips on evidence. Store the criteria as JSON, not prose — a model is far less likely to quietly rewrite a JSON"passed": falsethan to soften a sentence. (Anthropic's long-running-agent harness stores the feature list as JSON for exactly this reason.) - Measure the goal, not a stand-in. An objective signal is necessary but not sufficient — it also has to exercise the real thing the loop is for. If the goal depends on a real dependency (a live service, real data, an integration, a deploy) and the proof only touches a mock / stub / fixture of it, the loop will converge — green, confident, and wrong. Either the proof exercises the real path at least once, or it is explicitly labelled scaffold-level ("the mocked build is internally consistent") with a separate goal-level proof named. A green that came from measuring the stand-in instead of the goal is a coverage gap wearing a green badge — the same class of bug as a green that came from moving the number instead of fixing the cause (Step 3, guardrail 6), and just as much a finding.
- Separate the grader from the doer for any subjective bar. When "done"
can't be reduced to an exit code (UI quality, doc clarity, API ergonomics),
the proof is a fresh-context evaluator subagent — spawned with no
Write/Edit tools so it cannot "fix" a failure by lowering the bar, and
blind to how the work was built so it can't rubber-stamp its own reasoning.
This is the GAN / Plan-Generate-Evaluate pattern. A same-model critic that
saw the build approves mediocre work; an external signal (tests) or a fresh
evaluator is what stops the rubber-stamp. See
references/authoring.md.
Step 3 — Install the guardrail stack (mandatory)
Every loop ships with all of these. They are not optional polish — a documented multi-agent loop ran 11 days and burned tens of thousands of dollars because it had observability but no enforcement. Alerting is not a guardrail; termination is.
- Iteration cap. A hard
--max-iterations(or "stop after N turns" baked into the/goalcondition —/goalhas no native cap). This is the primary backstop when the proof is never met. - Token / cost budget with enforcement. A ceiling that terminates the
loop, not just warns.
/goalhas no built-in budget — embed a turn cap and watch/cost; dynamic workflows take an explicit token budget; bash loops need an external counter. A 50-iteration run on a large codebase can cost $50–100+. The number that actually tells you whether the loop is worth running is cost per accepted result, not tokens spent or iterations run: a loop that opens five PRs where you merge one, or emits a daily report no one reads, can cost more than doing the work by hand. Track yield, not spend — a low accept rate means the loop is manufacturing review debt, and the fix is a tighter proof (Step 2), not a bigger budget. - No-progress / oscillation detection. Stop if iterations stop changing state, or if output repeats (≥~90% similarity to a recent iteration), or if token use grows quadratically rather than linearly. Thrashing and budget exhaustion are the two dominant non-convergence modes — detect both.
- HITL checkpoint before anything irreversible. Pause for a human before a DB write, a deploy, an external API call, a force-push. Unattended loops run only what is reversible and has a hard verifier.
- Checkpoint commits. Commit working state every iteration with a
descriptive message. On a wedged codebase,
git reset --hardto the last green checkpoint and re-loop is usually cheaper than rescuing it. - Never let the loop weaken its own gate. Forbid editing or deleting tests to make them pass, silencing a check with an ignore directive, or relocating a violation into the checker's blind spot. A green that came from moving the number instead of fixing the cause is a finding, not a win. When a gate flips red→green, read the diff that did it.
The full stack — including the stop_hook_active guard for Stop-hook loops, the
oscillation thresholds, and the staged-adoption / rollback ladder — is in
references/safety.md.
Step 4 — Externalize state (so iterations are stateless)
A loop that remembers across iterations only through the conversation breaks the moment context compacts or a fresh-context pass starts. Externalize to path-addressable files:
- a progress file (
PROGRESS.md/claude-progress.txt) — what's done, what's next; - a task / feature-list JSON — the default-FAIL criteria;
- a live plan/TODO (
fix_plan.md) — rewritten freely each pass; - an
init.sh— how to build and run; - git history — the durable checkpoint trail.
Each iteration starts by reading these, does one increment, then updates
them and commits. Read the caps (max-iterations, budget) and the state-file
paths from .claude/profile.yaml when present, so the same loop skill works
across projects without hard-coding. (This is the orchestrator/role-skill
convention; loops follow it.)
Step 5 — Run, watch for divergence, know when to kill
- One task per iteration. Trust the loop to pick the most important next thing; don't batch. Spawn subagents for expensive search/verification, but cap build/test parallelism at 1 — two agents building at once destroy the backpressure signal.
- Re-verify the whole, not just the change. After each fix, re-run the entire proof (full suite, every page, the whole rubric), not only the unit you touched. "Restart the streak" is how you catch a fix that broke something else.
- Roll a loop back to attended (or kill it) when any of: token spend grows non-linearly, output similarity >90% across iterations, a fresh evaluator and your own judgment disagree, or it's about to touch an irreversible resource without a checkpoint. A suspiciously easy convergence is itself a finding — inspect before trusting.
Step 6 — Long-run behavioral hygiene (Claude 5 family)
Steps 1–5 make the loop converge. This step keeps the model's behavior honest over
a long run on the Claude 5 family (Fable 5 / Mythos 5), where a single turn can run for
minutes and an autonomous run for hours. These are prompt-level additions to the loop's
brief — the harness enforces convergence; these keep the agent from lying, quitting early,
or panicking about context on the way there. Drop-in instruction text and the 5-part
mapping for each are in model-adaptation/references/long-run-hygiene.md; wire what the
loop needs:
- Evidence-backed progress (anti-fabrication). Instruct the agent to audit each progress claim against an actual tool result before reporting it. This is distinct from guardrail 6: guardrail 6 stops the loop from gaming the mechanical gate; this stops the model from narrating work it never verified. Both matter; neither substitutes.
- Don't end a turn on a promise. Deep in a run the model can say "I'll now run X" with
no tool call, or pause to ask when it already has enough.
/goal+ Stop-hooks catch this mechanically (Step 1); add the prompt-level last-paragraph self-check and, for unattended runs, the autonomous-operation reminder so the agent doesn't lean on the hook. - Don't surface the budget countdown to the model. Guardrail 2 watches
/costfor enforcement — but that number is a harness stop signal, not something to show the model. Seeing a remaining-token countdown makes the Claude 5 family prematurely summarize, offer to hand off, or trim its own work. Read the budget from externalized state (Step 4) and decide in the harness; if a count must be visible, add the "you have ample context, continue" reassurance. - Model & effort per iteration. Effort is the primary intelligence/latency/cost dial:
highdefault,xhighfor the hardest proof/verify steps,medium/lowfor routine passes. Lower effort on the Claude 5 family often beatsxhighon prior models — reduce it if a loop converges but each iteration runs longer than the work needs. Model tiers the same way — pick both permodel-adaptation's Model & effort tiering policy: workers and routine passes tier down, but the fresh-context evaluator (Step 2) stays on the top tier. - Send-to-user for verbatim mid-turn output. A loop otherwise only speaks by ending
its turn for HITL. For long async loops that must surface a deliverable or a direct answer
without stopping, give the agent a client-side
send_to_usertool plus the elicitation line — never route the model's reasoning through it (that's thereasoning_extractionrefusal landmine; seemodel-adaptation).
The fresh-context evaluator (Step 2) is itself one of these patterns — the guide's "fresh verifiers beat self-critique" — so it's already wired; just run it periodically on a long build, not only at the end.
Comprehension debt — the human-side stop condition
Steps 1–6 keep the machine honest. There is one failure they don't catch, because it lands on the human, not the loop: a loop that ships correct, green diffs faster than anyone reads them. Each merge feels like progress, but the codebase starts moving faster than the team's understanding of it — the tests pass, yet nobody can say why the code is shaped the way it is. That's comprehension debt, and it's the antidote's mirror image of convergence-on-a- fiction: there the proof was too weak, here the proof was fine but human understanding silently fell behind. The bill arrives at the next bug, in a module no one can reason about.
The guardrails don't fix this because it isn't a convergence problem — it's a
review problem. Keep it in check by keeping loops on small, readable diffs,
having a human actually read the diff a red→green flip produced (guardrail 6
already asks for this), and — for any substantial or fully agent-driven change —
running a comprehension quiz before merge: find-unknowns owns that move
(explain the diff and what it touches, then test that you can pass a quiz on the
non-obvious behavior). Autonomy that outruns understanding isn't a faster team;
it's a deferred debugging session.
Using it as the harness other loops compose on
Concrete loop skills don't re-implement any of the above — they fill in the contract and inherit the machinery:
fix-until-green— proof = test+lint+typecheck all exit 0; primitive =/goalor a Stop-hook gate; the canonical first instance.- A new loop = a new
skills/loops/<name>/whose SKILL.md states its 5-part contract, names its proof artifact, and points back here for the guardrails. The authoring walkthrough (with the loop taxonomy and a frontmatter template) isreferences/authoring.md.
Under the orchestrator, loops slot in at two levels — and both are built:
orchestrator-task-loop is the outer loop over the shared task list (re-assign
until every task passes its gate), while the inner loops run per role —
fix-until-green at the wave/QA gates, and contract-conformance-loop /
coverage-loop / perf-loop / migration-loop dispatched when the mission
calls for them (see the orchestrator's references/phase-guide.md, Optional
build loops).
Reference files
references/primitives.md—/goal,/loop,/batch, dynamic workflows, Stop-hooks, and the bash-Ralph loop: exact mechanics, constraints, invocations, and the implementation-approach tradeoff table. Read before choosing a primitive.references/safety.md— the full guardrail stack,stop_hook_active, oscillation/no-progress detection, the cost footguns, and the staged-adoption and rollback ladder.references/authoring.md— the 10-archetype loop taxonomy, the fresh-context evaluator / default-FAIL pattern in detail, and a step-by-step template for writing a new loop skill that composes on this one.