goal-loop
A thin, modeless orchestrator that closes the loop the three existing skills leave open:
[[goal-elicit]] writes a verifiable artifact and stops; [[goal-drive]] drives it to verified done;
[[prism]] reviews from many models. goal-loop sequences elicit → [spec-review] → drive → review → fix → re-review and owns the one thing none of the three can: the loop edge — turning review
findings into the next drivable unit, gated by you. It composes the three skills; it never modifies,
re-implements, or absorbs them.
Two modes. Interactive (default): both human gates (spec sign-off, fix classification) call
AskUserQuestion and need a live operator. Autonomous (--auto): for headless/unattended runs under
the native /goal command, where a blocking AskUserQuestion would deadlock the turn (the /goal
evaluator fires only after a turn finishes). --auto replaces both gates with fail-closed policies,
auto-fixes only the frozen-oracle-RED subset, and defers everything needing scope judgment to a morning
report — see § Autonomous mode (--auto) and references/loop-protocol.md § Autonomous mode.
Two non-negotiables (the design hinges on these)
- You decide which findings become fixes — goal-loop never blind-applies them. This is not
caution; it's measured. On a real run only ~17% of review findings mapped cleanly to an existing
acceptance criterion; the rest were defects with no acceptance line, out-of-scope improvements, or
scope calls only a human can make (a human out-scoped the loudest finding and vetoed a
multi-reviewer refactor). Two harnesses confirm a mechanism can't safely auto-apply them:
scripts/empirical_gate.py (a router false-applies F1/F16 — identifier-collision, semantic not
lexical) and scripts/oracle_gate.py (verification-anchoring is safe but auto-applies ~nothing
without strong pre-signed oracles). So goal-loop routes mechanically and proposes; you
classify the actionable batch. The path to real auto-apply is oracle-gating — see Report-only.
- The original goal artifact is binding authority. Every accepted fix maps to an existing
acceptance /
done_when / constraint, or a new acceptance line you author. A real defect with no
acceptance line (in_scope-unmapped) is surfaced in the actionable batch — to accept it you
author the new acceptance line first; out-of-scope and could findings are deferred to the loop
ledger (never written into the source artifact); scope changes require explicit promotion. (The one
exception is the spec-review phase, which edits the artifact before it locks; once you sign off,
it's frozen.)
Modeless & stepped — one phase per invocation
The artifact + the loop ledger on disk are the state; "continue" means "advance the next phase the
ledger says is unfinished." Each invocation advances exactly one phase — elicit, spec-review,
drive, review, classify, or fix — persists current_phase, and stops. It does not
chain phases. That's deliberate: a long inline run triggers auto-compaction, which can drop the
orchestration instructions; because state lives on disk, re-invoking re-reads this file and the ledger
says exactly where you are. Resume the way goal-drive resumes — reconcile against the repo, trust
verified facts. No Stop hook, no plugin, no humanize coupling: it's a portable skill.
Read references/loop-protocol.md in full before entering any phase — it is the authoritative
source for the ledger schema, the exact router procedure, normalization, crash-safety write ordering,
the review-packet template, and the per-backend resume contracts; the tables here are summaries only.
The two human gates (spec-review sign-off, classify disposition) each contain exactly one user
interaction and remain the active phase until the answer is captured: render the choices, call
AskUserQuestion, and only after the reply write the durable artifacts (spec edits + spec_approved,
or the disposition + fix-rN.checklist.json) and then advance current_phase. If re-entered before the
reply (interrupted/compacted), re-present the same batch — never advance or write a fix on a partial
disposition.
Runtime portability & the review backend
Portable; never detects its runtime. Only the review backend is Claude-specific, and it's pluggable:
--review prism (default) — multi-model review (Claude-only). Resolved by capability, not runtime:
if the prism skill is unavailable or refuses (off-Claude), goal-loop writes
.goals/<id>.review-rN.request.md and stops (review_backend_unavailable).
--review external — write the review packet and stop; you review elsewhere, place the synthesis,
and continue resumes at classify.
--review local — single-agent skeptical self-review in-session; portable, weaker.
--review none — elicit + drive only; GOAL-LOOP COMPLETE after the drive marker, no loop.
Spec-review (mod #1 — on by default)
Runs by default (config 1): before driving, review the goal spec itself — acceptance
criteria testable/complete? gaps, contradictions, untestable done_when, likely findings that won't map
later? You approve/edit the strengthened spec (the one pre-lock edit point), which then freezes as the
binding authority. Spec quality is the single biggest lever — it raises the actionable fraction and
is the path toward safe auto-apply — so it is the default, not opt-in. --no-spec-review skips it,
and goal-loop auto-skips for a Clear-domain artifact (a one-shot contract goal-elicit fast-laned —
no review tax on trivial goals). Override the depth with --spec-review "<config>". On reject at
sign-off → GOAL-LOOP STOPPED (spec_rejected); re-run goal-elicit. Details:
references/loop-protocol.md § Spec review.
Durability triage — tune autonomy to the goal's shelf life
The loop reads the artifact's durability field (goal-elicit's Phase 0 axis: mechanical | disposable | load_bearing; default load_bearing if absent). It encodes how trustworthy a hands-off loop is for
this output — drawing on the post's distinction (where-loops-work vs. lasting-code authorship): loops are
reliable transforming existing code (mechanical) or making short-lived artifacts (disposable), and risky
authoring lasting code (load_bearing) unattended. It tunes
exactly two levers and nothing else (it never widens what's fixable or relaxes the two non-negotiables):
spec-review auto-skips for mechanical/disposable, and the legibility lens + regression guard are
mandatory for load_bearing but advisory otherwise. Full table: references/loop-protocol.md § Durability.
Autonomous mode (--auto) — summary; mechanism in the reference
--auto runs the loop unattended under Claude Code's native /goal. Because the /goal evaluator
fires only after a turn finishes and is tool-less, a blocking AskUserQuestion would deadlock — so
--auto replaces both human gates with fail-closed policies and terminates on printed markers.
It changes only gate behavior, termination, and handoff, composes the same three skills, and is strictly
more conservative than interactive mode, never less. The load-bearing invariants: spec-review runs
report-only (elicited spec frozen as-is, never auto-edited); classify AUTO-FIXes only the
in_scope-mapped finding whose frozen oracle is RED and DEFERs/HALTs everything else (cross-model
consensus may reorder the queue, never authorize a fix; no new acceptance line is ever auto-authored —
scope mutation, invariant #2). Oracle coverage is ~empty by default, so a first run typically
auto-fixes nothing and just produces the morning queue — correct, not a failure. Off-Claude / no review
backend ⇒ no auto-fix (defer all); never fakes cross-model review. The run ends on
GOAL-LOOP AUTO-COMPLETE / AUTO-HANDOFF / AUTO-HALTED: <id> — <reason>, each with an evidence block +
the .goals/<id>.auto-report.md report.
Read references/loop-protocol.md § Autonomous mode before any --auto run — it is authoritative for
the Gate A / Gate B policy clauses, the frozen-oracle manifest (.goals/<id>.oracles.json, authored at
sign-off and validated via scripts/oracle_manifest.py), the termination set, the morning report, and the
optional --worktree / Stop-hook hardening.
What it produces
.goals/<id>.loop.json — an index-only ledger (round, phase, prism config, artifact paths,
review/findings paths, dispositions, round_start_ref, stop reason). Schema: references/loop-protocol.md.
.goals/<id>.spec-review.md — the spec-review synthesis (unless --no-spec-review / Clear-domain).
.goals/<id>.review-rN.md / .review-rN.findings.json — the review synthesis + normalized findings.
.goals/<id>.oracles.json — (optional) the frozen-oracle manifest authored at sign-off; what --auto
consults to find auto-fixable RED oracles. Schema + use: references/loop-protocol.md § The frozen-oracle manifest.
.goals/<id>.auto-report.md — (under --auto) the morning report: outcome, auto-applied fixes, and the
pre-classified decision queue. Written before the terminal marker.
.goals/<id>.fix-rN.checklist.json — a child fix artifact per round, built from the findings you
accepted. The source artifact stays immutable; findings never patch it.
Invocation
/goal-loop [--auto] [--prism "<config>"] [--no-spec-review | --spec-review "<config>"]
[--review prism|external|local|none] [--max-rounds N] [--artifact <path>] -- <request>
/goal-loop continue [<id>]
--auto — unattended mode (see § Autonomous mode): both human gates become fail-closed policies, no
AskUserQuestion, terminates on the AUTO-* markers. Intended to run under the native /goal command.
Requires a status: ready artifact (--artifact <path> or a pre-existing .goals/<id>.goal.md) — it
never interviews; with no ready spec it emits GOAL-LOOP AUTO-HALTED: <id> — needs_artifact before any
AskUserQuestion. Since it cannot ask for the review depth, it uses --prism if given, else the ledger's
prism_config, else defaults to 2.
--prism "<config>" — forwarded verbatim to prism (2, 2 2, …; prism syntax is N [M] — N parallax, M gpt-pro, no effort token). Omitted (interactive) →
goal-loop asks at the review gate; omitted under --auto → defaults to 2 (above).
--max-rounds N — review/fix cycles (default 2; loops oscillate). continue --max-rounds <N> extends.
--no-spec-review / --spec-review "<config>" — skip the (default-on) spec review, or override its
depth. (Auto-skipped for a Clear-domain one-shot artifact.)
--artifact <path> — start from an existing artifact (skip elicit). continue [<id>] resumes the
sole non-terminal .loop.json (lists candidates if more than one; if none, say so and offer to start one).
Invocation mechanics
Invoke goal-elicit, goal-drive, and prism via the Skill tool, inline in this owning session —
never via Agent/Task/subagent. A Skill-invoked goal-drive is inline and retains full edit
authority (its leaf/read-only contract applies only when spawned as a subagent, which goal-loop
never does). Invoke Skill(prism, "<config> <review packet>") at top level; prism owns its own
read-only-leaf fan-out. Wait for the invoked skill's terminal marker before advancing the ledger.
The loop
State = the source artifact + .goals/<id>.loop.json. Advance exactly one phase per invocation,
persist the ledger, STOP. On (re)entry, read current_phase, reconcile against the repo, run only it:
elicit no ready artifact → goal-elicit (once). Stop after: ready → read `durability` (default
load_bearing); current_phase = spec-review (default; → drive directly if --no-spec-review,
a Clear-domain one-shot artifact, or a mechanical/disposable artifact); draft/blocked → stopped. ← ends invocation
spec-rev (default; skipped by --no-spec-review / Clear-domain / mechanical|disposable) freeze a SPEC packet {objective ·
acceptance/done_when · scope · constraints}; run the review backend; persist .spec-review.md;
present findings; YOU approve/edit the spec (pre-lock); on sign-off freeze → current_phase=drive;
on reject → stopped (spec_rejected). STOP. [human gate]
drive **record round_start_ref FIRST** (on entering drive — the diff baseline), then goal-drive
(Skill, inline). On GOAL-DRIVE COMPLETE + verification → current_phase=review. On STOPPED →
stopped. STOP. ← ends invocation
review if round > max_rounds → stopped (max_rounds), do not dispatch. Else if `prism_config` is empty,
ask the user for it now (under `--auto`: do not ask — default to `2`); freeze the review packet {artifact · diff since round_start_ref ·
COMPLETE marker · verification + the legibility lens}; run the backend; persist .review-rN.md,
record this round's `legibility_delta`, normalize → .findings.json, set current_phase=classify
LAST. STOP. (load_bearing: 2nd consecutive `worse` → stopped (legibility_regression)) ← ends invocation
classify the router mechanically **disposes the non-actionable bulk** (you never see it):
out-of-scope/`could` → DEFER (ledger), needs_user/ambiguous/one-way-door/recurrence → HALT
(GOAL-LOOP STOPPED). Only the remaining **actionable batch** (in_scope-mapped +
in_scope-unmapped) is surfaced — a separate step. YOU disposition that batch via
AskUserQuestion (accept/defer/reject per item; for an in_scope-unmapped accept, author the new
acceptance line first). Capture the reply, write .fix-rN.checklist.json from accepted findings,
THEN set current_phase=fix. `reject` → discard the round → review gate. STOP. [human gate]
fix **record round_start_ref FIRST** (on entering fix — the pre-patch baseline for the re-review),
then goal-drive (Skill, inline) on .fix-rN.checklist.json. On COMPLETE → current_phase=review,
round+1. STOP. ← ends invocation
The unit of iteration is one review/fix round. The two human gates are the spec sign-off /
artifact and review→fix (classify); the per-phase STOPs keep any one invocation short enough to
survive compaction. The router shrinks the classify gate from "every finding" to "the small actionable
batch" — that's the ergonomic win over a raw per-finding gate, kept honest by leaving you the decision.
Under --auto, the same phase sequence runs, but spec-rev and classify execute the autonomous
policies instead of AskUserQuestion — spec-review is report-only (freeze elicited spec), and classify
auto-fixes only the oracle-RED subset while deferring/halting the rest — and the loop ends on an AUTO-*
marker. See § Autonomous mode and references/loop-protocol.md § Autonomous mode.
Composition wiring
| Phase |
Skill |
Dispatcher |
Rail |
| Elicit |
goal-elicit |
goal-loop (once) |
writes one artifact, stops, never re-invoked |
| Spec-review (opt) |
prism |
goal-loop, top-level |
reviews the spec; you approve edits pre-lock; not re-elicitation |
| Implement / Fix |
goal-drive |
goal-loop, Skill-inline |
inline retains edit authority (a subagent goal-drive would be a leaf and lose it) |
| Review |
prism (default) |
goal-loop, top-level only |
Claude-only; prism owns its own read-only single-model-lens dispatch |
| Review → fix |
goal-loop itself |
— |
routes mechanically; you classify the actionable batch |
Rails goal-loop enforces on itself: never asks goal-drive to invoke prism; never re-elicits mid-loop
(if review shows the goal is wrong, stop and tell the user to re-run goal-elicit); top-level
user-invocable only.
Review → fix (the router proposes; you decide)
After review, the router mechanically disposes the bulk so you don't have to: out_of_scope and
could → DEFER (recorded in the ledger, a suggested ## Emergent line printed, source untouched);
needs_user / one-way-door / recurrence → STOP. It then prints a one-line deferred/stop audit
(counts by scope+severity + the titles of any deferred blocker/should, with expand <id> to read
one) so the bulk is auditable, not invisible, and surfaces only the remaining actionable batch
as a numbered list — each {severity, claim, proposed fix, proposed acceptance, proposed verification, nominated AC} — and you reply defaults, 1a 2c …, reassign <id>→<AC> (correct a wrong nomination),
reject, or approve. The router's maps_to is a nominee, not an authority — its lexical mapping
errs in both directions, so confirm or reassign it. Nothing is written to a fix checklist until you approve. Buckets, the finding schema, the normalization procedure, and the
fix-checklist template: references/loop-protocol.md.
Stop / convergence / resumption
- GOAL-LOOP COMPLETE — the latest review surfaces no accepted
blocker/should finding, every fix
artifact is verified done, and the ledger points to the evidence. Echo the marker last. (If you
approve a round with zero accepted but some deferred, ask whether to mark it clean → COMPLETE or
return to review — don't assume done.)
- GOAL-LOOP COMPLETE (no-review) — with
--review none, after the drive marker (no loop).
--auto markers — under --auto the loop ends instead on GOAL-LOOP AUTO-COMPLETE: <id> (drive done,
oracles GREEN, decision queue empty), GOAL-LOOP AUTO-HANDOFF: <id> (converged, a deferred queue awaits —
the common case), or GOAL-LOOP AUTO-HALTED: <id> — <reason>, each preceded by an evidence block and
paired with .goals/<id>.auto-report.md. Details + the /goal condition: references/loop-protocol.md § Autonomous mode.
- GOAL-LOOP STOPPED — with
stop_reason ∈ {goal_drive_stopped, review_backend_unavailable,
needs_user, spec_rejected, review_rejected, scope/authority-exceeded, one-way-door, max_rounds,
oscillation (same finding recurs), normalization_failed (extraction incomplete/invalid),
findings_escalating (each round surfaces more/higher-severity findings than the last — the work is
regressing), legibility_regression (two consecutive rounds make load_bearing code less
comprehensible while appearing more robust — the loop's amplified failure mode; see the legibility
ratchet)} — under --auto the AUTO-HALTED set adds several --auto-specific reasons (artifact,
baseline, lock, path, oracle-manifest, oracle-timeout, spec-contradiction), drops the interactive-only
spec_rejected (--auto freezes the spec, never rejects), folds findings_escalating into the --auto
regression guard, and keeps legibility_regression as a named AUTO-HALTED reason (the delta has no
oracle to fold into); full list:
references/loop-protocol.md § Termination. Print the marker first, then hand back.
- Resume — read
current_phase, reconcile against verified artifacts + repo (files over the
pointer; if review-rN.findings.json exists, skip re-review → classify). Crash-safety write order:
references/loop-protocol.md § Crash safety.
Report-only today — and the one upgrade path
Interactive mode ships report-only (route, auto-handle the 83% DEFER/STOP, confirm only the small
actionable batch). The only fundamentally-safe way to remove that confirm is oracle-gating, not a
smarter router — verify each change against a pre-signed, frozen executable oracle (auto-actionable
only when its acceptance oracle is RED; apply only on RED→GREEN + no regression + anti-overfit; F1/F16
STOP by construction). --auto is the opt-in that enables exactly this gate (and nothing more):
unattended, it AUTO-FIXes only the oracle-RED subset and defers the rest to a morning queue. oracle_gate.py
PASSES (false-auto=0) but shows the covered subset is ~empty until you author stronger oracles at sign-off —
so --auto with no oracles auto-fixes nothing and is review-plus-queue, by design. Full mechanism + the
15-perspective verdicts: references/loop-protocol.md § Autonomous mode and § The path beyond report-only,
`/.ai/reports/20260616-2243-goalloop-auto-design.md, and ~/.ai/reports/20260612-2230-goal-loop-fundamental-verdict.md`.
Single biggest risk
Scope mutation through review-to-fix conversion — under load a review always produces plausible
improvements; if they silently become work, the loop stops driving your goal and lets reviewers
redefine it. Defense is the two non-negotiables: you classify the actionable batch (nothing written
until approve) + binding-authority (fixes map to acceptance or you author it; out-of-scope never
touches the source), plus the round cap and oscillation guard.
The legibility ratchet (the second risk)
A fix loop amplifies the model's worst structural habit: each round answers a local failure with a local
defense — a fallback for an impossible state, a guard, duplicated machinery — so the code grows more
robust-looking and less comprehensible every iteration, the failure Karpathy frames as models being
"mortally terrified of exceptions." Severity escalation and scope mutation guards don't catch this: the
diff stays in-scope and each finding looks reasonable. Two specific defenses, both load_bearing-only
(see § Durability) and detailed in references/loop-protocol.md:
- Legibility lens — the review packet asks the reviewer to flag exactly these loop-amplified
anti-patterns (fallbacks where an invariant would do, handling of impossible states, defensive
duplication, complexity with no error class removed), rate them
should+ so the router can't auto-defer
them, and propose fixes that remove machinery / make the bad state unrepresentable. They surface to
you (as in_scope-unmapped, or as a needs_user scope call when the fix exceeds the unit's paths) — the
in-loop human-judgment jolt the post argues for. This in-loop jolt is interactive only; under --auto
the findings defer to the morning report / AUTO-HANDOFF queue, not an in-loop prompt.
- Legibility regression guard — each review ends with a
legibility_delta; two consecutive worse
rounds HALT (legibility_regression) so a human re-reads the cumulative diff before the ratchet
compounds. The delta is a coarse, reviewer-judged liveness heuristic — not an objective bound (the
real defense is the per-round lens above; this just caps continued compounding). (goal-drive carries the
executor-side half: prefer invariants over fallbacks while building.)
Must not
- Do not blind-apply review findings; route mechanically, surface the actionable batch, write nothing
until the user
approves.
- Under
--auto: never call AskUserQuestion (it deadlocks the /goal turn); never auto-edit or
auto-strengthen the frozen spec, and never auto-author a new acceptance line (that is scope mutation);
AUTO-FIX only the oracle-RED subset (DEFER/HALT everything else); cross-model consensus may reorder
the morning queue but never authorize a fix; fail toward HALT, not toward applying.
- Do not let findings patch the source artifact (including out-of-scope
## Emergent); record those
in the ledger. Fixes land in child fix-rN artifacts.
- Do not chain phases; advance one phase per invocation, persist, stop. Do not re-elicit mid-loop or
enter a "mode".
- Do not embed review inside goal-drive, ask goal-drive to dispatch prism, or spawn goal-drive as a
subagent for the work.
- Do not fake cross-model review off Claude — degrade to
external/local/none and say so.
- Do not push/deploy/one-way-door without explicit assent (inherit goal-drive's rail).
Files in this skill
SKILL.md — this file.
references/loop-protocol.md — the .loop.json ledger schema, crash-safety, the finding schema +
four-bucket classification, the normalization procedure, oscillation, the fix-checklist template, the
spec-review front gate, the per-backend resume contracts, the review-packet template, and the
oracle-gating upgrade path.
scripts/empirical_gate.py — replays the roadmap review through a lexical router; FAILS
(false-auto F1/F16) — the evidence that a router can't safely blind-apply.
scripts/oracle_gate.py — replays it through oracle-gating; PASSES (false-auto=0) — the evidence
that the safe auto-apply path is verification against pre-signed oracles, and that it covers ~nothing
without strong oracles.
scripts/oracle_manifest.py — the live frozen-oracle manifest validator + RED/GREEN evaluator that
--auto consults (oracle_gate.py is the offline safety proof; this runs the operator's real oracles).
validate / evaluate / selftest.
1---2name: goal-loop3description: Drive a goal through review→fix iteration by composing goal-elicit, goal-drive, and multi-model review (prism, Claude-only). A thin, modeless, stepped loop — one phase per invocation (elicit → spec-review → drive → review → you pick which fixes apply → fix → re-review) — with state on disk so it resumes after interruption or compaction. It auto-handles the ~83% of out-of-scope/unmapped findings (you never see them) and surfaces only the small actionable batch to confirm — never blind-applies (unsafe). Use for "loop this to done with review", "close the review-fix loop", "goal-loop". Review needs Claude (prism), degrades off-Claude. Interactive by default; **`--auto`** runs it unattended/headless under Claude Code's native `/goal` — both gates become fail-closed policies (oracle-gated safe-subset auto-fix + a deferred morning queue), never blind-apply. Does NOT interview (that's goal-elicit). Skip for one-off edits and lone reviews.4---56# goal-loop78A thin, **modeless** orchestrator that closes the loop the three existing skills leave open:9[[goal-elicit]] writes a verifiable artifact and stops; [[goal-drive]] drives it to verified done;10[[prism]] reviews from many models. goal-loop sequences `elicit → [spec-review] → drive → review →11fix → re-review` and owns the **one thing none of the three can**: the **loop edge** — turning review12findings into the *next* drivable unit, gated by you. It composes the three skills; it never modifies,13re-implements, or absorbs them.1415> **Two modes.** *Interactive (default):* both human gates (spec sign-off, fix classification) call16> `AskUserQuestion` and need a live operator. *Autonomous (`--auto`):* for headless/unattended runs under17> the native `/goal` command, where a blocking `AskUserQuestion` would deadlock the turn (the `/goal`18> evaluator fires only **after** a turn finishes). `--auto` replaces both gates with fail-closed policies,19> auto-fixes only the frozen-oracle-RED subset, and defers everything needing scope judgment to a morning20> report — see **§ Autonomous mode (`--auto`)** and `references/loop-protocol.md` § Autonomous mode.2122## Two non-negotiables (the design hinges on these)23241. **You decide which findings become fixes — goal-loop never blind-applies them.** This is not25 caution; it's measured. On a real run only ~17% of review findings mapped cleanly to an existing26 acceptance criterion; the rest were defects with no acceptance line, out-of-scope improvements, or27 scope calls only a human can make (a human out-scoped the *loudest* finding and vetoed a28 multi-reviewer refactor). Two harnesses confirm a mechanism can't safely auto-apply them:29 `scripts/empirical_gate.py` (a router false-applies F1/F16 — identifier-collision, semantic not30 lexical) and `scripts/oracle_gate.py` (verification-anchoring is safe but auto-applies ~nothing31 without strong pre-signed oracles). So goal-loop **routes** mechanically and **proposes**; you32 classify the actionable batch. The path to real auto-apply is oracle-gating — see *Report-only*.332. **The original goal artifact is binding authority.** Every accepted fix maps to an existing34 acceptance / `done_when` / constraint, or a new acceptance line you author. A real defect with **no**35 acceptance line (`in_scope-unmapped`) is **surfaced in the actionable batch** — to accept it you36 author the new acceptance line first; out-of-scope and `could` findings are **deferred** to the loop37 ledger (never written into the source artifact); scope changes require explicit promotion. (The one38 exception is the `spec-review` phase, which edits the artifact *before* it locks; once you sign off,39 it's frozen.)4041## Modeless & stepped — one phase per invocation4243The **artifact + the loop ledger on disk are the state**; "continue" means "advance the next phase the44ledger says is unfinished." Each invocation advances **exactly one phase** — `elicit`, `spec-review`,45`drive`, `review`, `classify`, or `fix` — persists `current_phase`, and **stops**. It does **not**46chain phases. That's deliberate: a long inline run triggers auto-compaction, which can drop the47orchestration instructions; because state lives on disk, re-invoking re-reads this file and the ledger48says exactly where you are. Resume the way goal-drive resumes — reconcile against the repo, trust49verified facts. No Stop hook, no plugin, no humanize coupling: it's a portable skill.5051**Read `references/loop-protocol.md` in full before entering any phase** — it is the authoritative52source for the ledger schema, the exact router procedure, normalization, crash-safety write ordering,53the review-packet template, and the per-backend resume contracts; the tables here are summaries only.5455**The two human gates** (spec-review sign-off, classify disposition) each contain **exactly one user56interaction** and remain the active phase until the answer is captured: render the choices, call57`AskUserQuestion`, and only **after** the reply write the durable artifacts (spec edits + `spec_approved`,58or the disposition + `fix-rN.checklist.json`) and then advance `current_phase`. If re-entered before the59reply (interrupted/compacted), re-present the same batch — never advance or write a fix on a partial60disposition.6162## Runtime portability & the review backend6364Portable; **never detects its runtime**. Only the *review backend* is Claude-specific, and it's pluggable:65- `--review prism` (default) — multi-model review (Claude-only). Resolved by **capability, not runtime**:66 if the prism skill is unavailable or refuses (off-Claude), goal-loop writes67 `.goals/<id>.review-rN.request.md` and stops (`review_backend_unavailable`).68- `--review external` — write the review packet and stop; you review elsewhere, place the synthesis,69 and `continue` resumes at classify.70- `--review local` — single-agent skeptical self-review in-session; portable, weaker.71- `--review none` — elicit + drive only; `GOAL-LOOP COMPLETE` after the drive marker, no loop.7273## Spec-review (mod #1 — on by default)7475**Runs by default** (config `1`): before driving, review the **goal spec itself** — acceptance76criteria testable/complete? gaps, contradictions, untestable `done_when`, likely findings that won't map77later? You approve/edit the strengthened spec (the one pre-lock edit point), which then **freezes as the78binding authority**. Spec quality is the single biggest lever — it raises the actionable fraction *and*79is the path toward safe auto-apply — so it is the default, not opt-in. **`--no-spec-review` skips it**,80and goal-loop **auto-skips for a Clear-domain artifact** (a one-shot contract goal-elicit fast-laned —81no review tax on trivial goals). Override the depth with `--spec-review "<config>"`. On **reject** at82sign-off → `GOAL-LOOP STOPPED` (`spec_rejected`); re-run goal-elicit. Details:83`references/loop-protocol.md` § Spec review.8485## Durability triage — tune autonomy to the goal's shelf life8687The loop reads the artifact's `durability` field (goal-elicit's Phase 0 axis: `mechanical | disposable |88load_bearing`; **default `load_bearing` if absent**). It encodes how trustworthy a hands-off loop is for89*this* output — drawing on the post's distinction (where-loops-work vs. lasting-code authorship): loops are90reliable transforming existing code (`mechanical`) or making short-lived artifacts (`disposable`), and risky91authoring lasting code (`load_bearing`) unattended. It tunes92**exactly two levers** and nothing else (it never widens what's fixable or relaxes the two non-negotiables):93spec-review **auto-skips** for `mechanical`/`disposable`, and the legibility lens + regression guard are94**mandatory for `load_bearing`** but advisory otherwise. Full table: `references/loop-protocol.md` § Durability.9596## Autonomous mode (`--auto`) — summary; mechanism in the reference9798`--auto` runs the loop **unattended** under Claude Code's native `/goal`. Because the `/goal` evaluator99fires only **after a turn finishes** and is **tool-less**, a blocking `AskUserQuestion` would deadlock — so100`--auto` replaces **both** human gates with **fail-closed policies** and terminates on **printed markers**.101It changes only gate behavior, termination, and handoff, composes the same three skills, and is **strictly102more conservative than interactive mode, never less**. The load-bearing invariants: spec-review runs103**report-only** (elicited spec **frozen as-is**, never auto-edited); classify **AUTO-FIXes only** the104`in_scope-mapped` finding whose **frozen oracle is RED** and **DEFERs/HALTs everything else** (cross-model105consensus may reorder the queue, never authorize a fix; no new acceptance line is ever auto-authored —106scope mutation, invariant #2). Oracle coverage is **~empty by default**, so a first run typically107**auto-fixes nothing** and just produces the morning queue — correct, not a failure. Off-Claude / no review108backend ⇒ **no auto-fix** (defer all); never fakes cross-model review. The run ends on109`GOAL-LOOP AUTO-COMPLETE` / `AUTO-HANDOFF` / `AUTO-HALTED: <id> — <reason>`, each with an evidence block +110the `.goals/<id>.auto-report.md` report.111112**Read `references/loop-protocol.md` § Autonomous mode before any `--auto` run** — it is authoritative for113the Gate A / Gate B policy clauses, the frozen-oracle manifest (`.goals/<id>.oracles.json`, authored at114sign-off and validated via `scripts/oracle_manifest.py`), the termination set, the morning report, and the115optional `--worktree` / Stop-hook hardening.116117## What it produces118119- `.goals/<id>.loop.json` — an **index-only** ledger (round, phase, prism config, artifact paths,120 review/findings paths, dispositions, `round_start_ref`, stop reason). Schema: `references/loop-protocol.md`.121- `.goals/<id>.spec-review.md` — the spec-review synthesis (unless `--no-spec-review` / Clear-domain).122- `.goals/<id>.review-rN.md` / `.review-rN.findings.json` — the review synthesis + normalized findings.123- `.goals/<id>.oracles.json` — (optional) the **frozen-oracle manifest** authored at sign-off; what `--auto`124 consults to find auto-fixable RED oracles. Schema + use: `references/loop-protocol.md` § The frozen-oracle manifest.125- `.goals/<id>.auto-report.md` — (under `--auto`) the morning report: outcome, auto-applied fixes, and the126 pre-classified decision queue. Written before the terminal marker.127- `.goals/<id>.fix-rN.checklist.json` — a child fix artifact per round, built from the findings **you128 accepted**. The source artifact stays immutable; findings never patch it.129130## Invocation131132```133/goal-loop [--auto] [--prism "<config>"] [--no-spec-review | --spec-review "<config>"]134 [--review prism|external|local|none] [--max-rounds N] [--artifact <path>] -- <request>135/goal-loop continue [<id>]136```137138- `--auto` — **unattended mode** (see § Autonomous mode): both human gates become fail-closed policies, no139 `AskUserQuestion`, terminates on the `AUTO-*` markers. Intended to run under the native `/goal` command.140 **Requires a `status: ready` artifact** (`--artifact <path>` or a pre-existing `.goals/<id>.goal.md`) — it141 never interviews; with no ready spec it emits `GOAL-LOOP AUTO-HALTED: <id> — needs_artifact` before any142 `AskUserQuestion`. Since it cannot ask for the review depth, it uses `--prism` if given, else the ledger's143 `prism_config`, else defaults to `2`.144- `--prism "<config>"` — forwarded **verbatim** to prism (`2`, `2 2`, …; prism syntax is `N [M]` — N parallax, M gpt-pro, no effort token). Omitted (interactive) →145 goal-loop asks at the review gate; omitted under `--auto` → defaults to `2` (above).146- `--max-rounds N` — review/fix cycles (default **2**; loops oscillate). `continue --max-rounds <N>` extends.147- `--no-spec-review` / `--spec-review "<config>"` — skip the (default-on) spec review, or override its148 depth. (Auto-skipped for a Clear-domain one-shot artifact.)149- `--artifact <path>` — start from an existing artifact (skip elicit). `continue [<id>]` resumes the150 sole non-terminal `.loop.json` (lists candidates if more than one; if none, say so and offer to start one).151152### Invocation mechanics153154Invoke goal-elicit, goal-drive, and prism via the **Skill tool, inline in this owning session** —155never via Agent/Task/subagent. A `Skill`-invoked goal-drive is **inline and retains full edit156authority** (its leaf/read-only contract applies only when spawned as a subagent, which goal-loop157never does). Invoke `Skill(prism, "<config> <review packet>")` at top level; prism owns its own158read-only-leaf fan-out. Wait for the invoked skill's terminal marker before advancing the ledger.159160## The loop161162State = the source artifact + `.goals/<id>.loop.json`. **Advance exactly one phase per invocation,163persist the ledger, STOP.** On (re)entry, read `current_phase`, reconcile against the repo, run only it:164165```166elicit no ready artifact → goal-elicit (once). Stop after: ready → read `durability` (default167 load_bearing); current_phase = spec-review (default; → drive directly if --no-spec-review,168 a Clear-domain one-shot artifact, or a mechanical/disposable artifact); draft/blocked → stopped. ← ends invocation169spec-rev (default; skipped by --no-spec-review / Clear-domain / mechanical|disposable) freeze a SPEC packet {objective ·170 acceptance/done_when · scope · constraints}; run the review backend; persist .spec-review.md;171 present findings; YOU approve/edit the spec (pre-lock); on sign-off freeze → current_phase=drive;172 on reject → stopped (spec_rejected). STOP. [human gate]173drive **record round_start_ref FIRST** (on entering drive — the diff baseline), then goal-drive174 (Skill, inline). On GOAL-DRIVE COMPLETE + verification → current_phase=review. On STOPPED →175 stopped. STOP. ← ends invocation176review if round > max_rounds → stopped (max_rounds), do not dispatch. Else if `prism_config` is empty,177 ask the user for it now (under `--auto`: do not ask — default to `2`); freeze the review packet {artifact · diff since round_start_ref ·178 COMPLETE marker · verification + the legibility lens}; run the backend; persist .review-rN.md,179 record this round's `legibility_delta`, normalize → .findings.json, set current_phase=classify180 LAST. STOP. (load_bearing: 2nd consecutive `worse` → stopped (legibility_regression)) ← ends invocation181classify the router mechanically **disposes the non-actionable bulk** (you never see it):182 out-of-scope/`could` → DEFER (ledger), needs_user/ambiguous/one-way-door/recurrence → HALT183 (GOAL-LOOP STOPPED). Only the remaining **actionable batch** (in_scope-mapped +184 in_scope-unmapped) is surfaced — a separate step. YOU disposition that batch via185 AskUserQuestion (accept/defer/reject per item; for an in_scope-unmapped accept, author the new186 acceptance line first). Capture the reply, write .fix-rN.checklist.json from accepted findings,187 THEN set current_phase=fix. `reject` → discard the round → review gate. STOP. [human gate]188fix **record round_start_ref FIRST** (on entering fix — the pre-patch baseline for the re-review),189 then goal-drive (Skill, inline) on .fix-rN.checklist.json. On COMPLETE → current_phase=review,190 round+1. STOP. ← ends invocation191```192193The **unit of iteration** is one review/fix round. The two human gates are the **spec sign-off /194artifact** and **review→fix** (classify); the per-phase STOPs keep any one invocation short enough to195survive compaction. The router shrinks the classify gate from "every finding" to "the small actionable196batch" — that's the ergonomic win over a raw per-finding gate, kept honest by leaving you the decision.197198**Under `--auto`,** the same phase sequence runs, but `spec-rev` and `classify` execute the **autonomous199policies** instead of `AskUserQuestion` — spec-review is report-only (freeze elicited spec), and classify200auto-fixes only the oracle-RED subset while deferring/halting the rest — and the loop ends on an `AUTO-*`201marker. See **§ Autonomous mode** and `references/loop-protocol.md` § Autonomous mode.202203## Composition wiring204205| Phase | Skill | Dispatcher | Rail |206|---|---|---|---|207| Elicit | goal-elicit | goal-loop (once) | writes one artifact, stops, never re-invoked |208| Spec-review (opt) | prism | goal-loop, top-level | reviews the *spec*; you approve edits pre-lock; not re-elicitation |209| Implement / Fix | goal-drive | goal-loop, **Skill-inline** | inline retains edit authority (a subagent goal-drive would be a leaf and lose it) |210| Review | prism (default) | goal-loop, **top-level only** | Claude-only; prism owns its own read-only single-model-lens dispatch |211| Review → fix | **goal-loop itself** | — | routes mechanically; **you** classify the actionable batch |212213Rails goal-loop enforces on itself: never asks goal-drive to invoke prism; **never re-elicits** mid-loop214(if review shows the *goal* is wrong, stop and tell the user to re-run goal-elicit); top-level215user-invocable only.216217## Review → fix (the router proposes; you decide)218219After review, the router **mechanically** disposes the bulk so you don't have to: `out_of_scope` and220`could` → **DEFER** (recorded in the ledger, a suggested `## Emergent` line printed, source untouched);221`needs_user` / one-way-door / recurrence → **STOP**. It then prints a one-line **deferred/stop audit**222(counts by scope+severity + the titles of any deferred `blocker`/`should`, with `expand <id>` to read223one) so the bulk is auditable, not invisible, and surfaces only the remaining **actionable batch**224as a numbered list — each `{severity, claim, proposed fix, proposed acceptance, proposed verification,225nominated AC}` — and you reply `defaults`, `1a 2c …`, `reassign <id>→<AC>` (correct a wrong nomination),226`reject`, or `approve`. The router's `maps_to` is a **nominee, not an authority** — its lexical mapping227errs in both directions, so confirm or `reassign` it. **Nothing is written to a fix checklist until you `approve`.** Buckets, the finding schema, the normalization procedure, and the228fix-checklist template: `references/loop-protocol.md`.229230## Stop / convergence / resumption231232- **GOAL-LOOP COMPLETE** — the latest review surfaces no accepted `blocker`/`should` finding, every fix233 artifact is verified done, and the ledger points to the evidence. Echo the marker last. (If you234 `approve` a round with zero accepted but some *deferred*, ask whether to mark it clean → COMPLETE or235 return to review — don't assume done.)236- **GOAL-LOOP COMPLETE (no-review)** — with `--review none`, after the drive marker (no loop).237- **`--auto` markers** — under `--auto` the loop ends instead on `GOAL-LOOP AUTO-COMPLETE: <id>` (drive done,238 oracles GREEN, decision queue empty), `GOAL-LOOP AUTO-HANDOFF: <id>` (converged, a deferred queue awaits —239 the common case), or `GOAL-LOOP AUTO-HALTED: <id> — <reason>`, each preceded by an evidence block and240 paired with `.goals/<id>.auto-report.md`. Details + the `/goal` condition: `references/loop-protocol.md` § Autonomous mode.241- **GOAL-LOOP STOPPED** — with `stop_reason` ∈ {`goal_drive_stopped`, `review_backend_unavailable`,242 `needs_user`, `spec_rejected`, `review_rejected`, scope/authority-exceeded, one-way-door, `max_rounds`,243 `oscillation` (same finding recurs), `normalization_failed` (extraction incomplete/invalid),244 `findings_escalating` (each round surfaces more/higher-severity findings than the last — the work is245 regressing), `legibility_regression` (two consecutive rounds make `load_bearing` code less246 comprehensible while appearing more robust — the loop's amplified failure mode; see the legibility247 ratchet)} — under `--auto` the AUTO-HALTED set adds several `--auto`-specific reasons (artifact,248 baseline, lock, path, oracle-manifest, oracle-timeout, spec-contradiction), drops the interactive-only249 `spec_rejected` (`--auto` freezes the spec, never rejects), folds `findings_escalating` into the `--auto`250 regression guard, and keeps `legibility_regression` as a **named AUTO-HALTED reason** (the delta has no251 oracle to fold into); full list:252 `references/loop-protocol.md` § Termination. Print the marker first, then hand back.253- **Resume** — read `current_phase`, reconcile against verified artifacts + repo (files over the254 pointer; if `review-rN.findings.json` exists, skip re-review → classify). Crash-safety write order:255 `references/loop-protocol.md` § Crash safety.256257## Report-only today — and the one upgrade path258259**Interactive mode ships report-only** (route, auto-handle the ~83% DEFER/STOP, confirm only the small260actionable batch). The **only** fundamentally-safe way to remove that confirm is **oracle-gating, not a261smarter router** — verify each change against a *pre-signed, frozen executable oracle* (auto-actionable262only when its acceptance oracle is RED; apply only on RED→GREEN + no regression + anti-overfit; F1/F16263STOP by construction). **`--auto` is the opt-in that enables exactly this gate** (and nothing more):264unattended, it AUTO-FIXes only the oracle-RED subset and defers the rest to a morning queue. `oracle_gate.py`265PASSES (false-auto=0) but shows the covered subset is ~empty until you author stronger oracles at sign-off —266so `--auto` with no oracles auto-fixes nothing and is review-plus-queue, by design. Full mechanism + the26715-perspective verdicts: `references/loop-protocol.md` § Autonomous mode and § The path beyond report-only,268`~/.ai/reports/20260616-2243-goalloop-auto-design.md`, and `~/.ai/reports/20260612-2230-goal-loop-fundamental-verdict.md`.269270## Single biggest risk271272**Scope mutation through review-to-fix conversion** — under load a review always produces plausible273improvements; if they silently become work, the loop stops driving *your* goal and lets reviewers274redefine it. Defense is the two non-negotiables: you classify the actionable batch (nothing written275until `approve`) + binding-authority (fixes map to acceptance or you author it; out-of-scope never276touches the source), plus the round cap and oscillation guard.277278## The legibility ratchet (the second risk)279280A fix loop amplifies the model's worst structural habit: each round answers a local failure with a local281defense — a fallback for an impossible state, a guard, duplicated machinery — so the code grows **more282robust-looking and less comprehensible** every iteration, the failure Karpathy frames as models being283"mortally terrified of exceptions." Severity escalation and scope mutation guards don't catch this: the284diff stays in-scope and each finding looks reasonable. Two specific defenses, both `load_bearing`-only285(see § Durability) and detailed in `references/loop-protocol.md`:2862871. **Legibility lens** — the review packet asks the reviewer to flag exactly these loop-amplified288 anti-patterns (fallbacks where an invariant would do, handling of impossible states, defensive289 duplication, complexity with no error class removed), rate them `should`+ so the router can't auto-defer290 them, and propose fixes that **remove** machinery / make the bad state unrepresentable. They surface to291 you (as `in_scope-unmapped`, or as a `needs_user` scope call when the fix exceeds the unit's paths) — the292 in-loop human-judgment jolt the post argues for. **This in-loop jolt is interactive only**; under `--auto`293 the findings defer to the morning report / `AUTO-HANDOFF` queue, not an in-loop prompt.2942. **Legibility regression guard** — each review ends with a `legibility_delta`; two consecutive `worse`295 rounds HALT (`legibility_regression`) so a human re-reads the cumulative diff before the ratchet296 compounds. The delta is a **coarse, reviewer-judged liveness heuristic — not an objective bound** (the297 real defense is the per-round lens above; this just caps continued compounding). (goal-drive carries the298 executor-side half: prefer invariants over fallbacks while building.)299300## Must not301302- Do not blind-apply review findings; route mechanically, surface the actionable batch, write nothing303 until the user `approve`s.304- **Under `--auto`:** never call `AskUserQuestion` (it deadlocks the `/goal` turn); never auto-edit or305 auto-strengthen the frozen spec, and never auto-author a new acceptance line (that is scope mutation);306 AUTO-FIX **only** the oracle-RED subset (DEFER/HALT everything else); cross-model consensus may reorder307 the morning queue but never authorize a fix; fail toward HALT, not toward applying.308- Do not let findings patch the **source** artifact (including out-of-scope `## Emergent`); record those309 in the ledger. Fixes land in child `fix-rN` artifacts.310- Do not chain phases; advance one phase per invocation, persist, stop. Do not re-elicit mid-loop or311 enter a "mode".312- Do not embed review inside goal-drive, ask goal-drive to dispatch prism, or spawn goal-drive as a313 subagent for the work.314- Do not fake cross-model review off Claude — degrade to `external`/`local`/`none` and say so.315- Do not push/deploy/one-way-door without explicit assent (inherit goal-drive's rail).316317## Files in this skill318319- `SKILL.md` — this file.320- `references/loop-protocol.md` — the `.loop.json` ledger schema, crash-safety, the finding schema +321 four-bucket classification, the normalization procedure, oscillation, the fix-checklist template, the322 spec-review front gate, the per-backend resume contracts, the review-packet template, and the323 oracle-gating upgrade path.324- `scripts/empirical_gate.py` — replays the roadmap review through a lexical router; **FAILS**325 (false-auto F1/F16) — the evidence that a router can't safely blind-apply.326- `scripts/oracle_gate.py` — replays it through oracle-gating; **PASSES** (false-auto=0) — the evidence327 that the safe auto-apply path is verification against pre-signed oracles, and that it covers ~nothing328 without strong oracles.329- `scripts/oracle_manifest.py` — the **live** frozen-oracle manifest validator + RED/GREEN evaluator that330 `--auto` consults (oracle_gate.py is the offline safety proof; this runs the operator's real oracles).331 `validate` / `evaluate` / `selftest`.