Drive the Anvil loop¶
Anvil has two front doors. The first is the PRD: author requirements, and
Anvil turns them into a governed, ready-to-execute task queue. The second is the
loop: drive that queue from whatever automation a runtime gives you — a shell
while, a Claude Code /loop, a scheduled Codex automation — so each step runs
Anvil's governed transitions instead of ad-hoc script state.
The PRD is the spec. You do not author a workflow file from scratch for the common case — Anvil already produced the ready queue. The loop's only job is to transfer that queue into a runtime and run the body once per task.
New to terms like the loop, packet, or claim? See the glossary.
1. PRD → ready queue¶
Get a queue of ready tasks before any loop runs:
anvil init # one-time: create .anvil/ state
anvil prd parse # PRD markdown -> features + tasks
anvil prd assess # optional advisory behavior/testability feedback
anvil plan # generate the task graph (deps, conflict groups)
anvil score # score each task on the six dimensions
After this, anvil list --status ready shows claimable work. (See
docs/how-to/authoring-a-prd.md for the PRD step and
docs/how-to/claiming-and-shipping-a-task.md for the manual single-task flow.)
2. The seam — anvil next -q¶
anvil next picks the highest-priority claimable task (dependency-, claim-,
conflict-group- and file-overlap-aware) without claiming it. The -q/--quiet
flag turns that into a branchable exit code so any shell or automation can loop
without parsing JSON:
| exit | meaning |
|---|---|
0 |
a task is ready |
3 |
the queue is empty (success — not an error) |
| other | a real error (no state dir, broken backend) |
Need the task fields too? anvil next --json returns
{"ok":true,"command":"next","data":{"task":{…}}}, or {"data":{"task":null}}
on an empty queue (exit 0). Use -q for control flow, --json for the id.
3. The loop body (already exists)¶
One governed task = the same five steps everywhere. /anvil:execute wraps them.
claim -> packet -> do the work -> submit --commands --files-changed -> apply
anvil claim T001 # single-winner lease + file-conflict check
anvil packet T001 # the contract: criteria, files, verify cmds
# ... implement against the packet, run its verification commands ...
anvil submit T001 \
--commands "uv run pytest -x" \
--files-changed "src/anvil/foo.py" # the evidence; auto-releases -> needs_review
anvil apply T001 --approve --strict # the gate; --strict refuses unverified work
submit's evidence (--commands, --files-changed, optional --output-file,
--pr-url) is the typed proof. apply is the gate: with --strict it refuses
--approve when required evidence is missing. Leasing + evidence gating are why
parallel loops cannot double-claim or fake "done".
4. Two modes, one primitive¶
Both modes run the same body; they differ only in cadence.
One-per-invocation¶
Run the body once for anvil next's task, then exit. The cursor is Anvil's
durable state, so the next invocation resumes from the next ready task. Fits a
scheduled fire (Codex automation), a cron job, or a single CI step.
# exit 3 = empty (nothing to do, clean); any other non-zero = real error -> propagate
anvil next -q || { rc=$?; [ "$rc" -eq 3 ] && exit 0; exit "$rc"; }
task="$(anvil next --json | jq -r '.data.task.id')" # read the id, then run the body once
Drain until empty¶
Loop the body until the queue empties. Fits a self-paced Claude /loop or any
shell:
while true; do
# exit 3 = drained (clean stop); other non-zero = real error -> propagate
anvil next -q || { rc=$?; [ "$rc" -eq 3 ] && break; exit "$rc"; }
# run the body for the recommended task
done
# queue drained
The committed packaging/loops/ci-drain.sh
is the full version (also skips a lost lease so concurrent drainers don't abort).
Durable, leased state makes both resumable and safe to run concurrently:
single-winner leases mean two runners never claim the same task, and a crashed
run loses no progress — re-run and it continues from whatever is still ready.
Milestone-sized work¶
When several related tasks should produce one reviewed delivery, use a coordinator-first execution bundle instead of forcing one conversational handoff per task. The coordinator keeps integration in the main loop and may delegate bounded work without transferring Anvil ownership. See Coordinating a milestone bundle.
5. Per-runtime adapters¶
Committed, copy-ready adapters for each mode:
| Runtime | Mode | File |
|---|---|---|
| POSIX shell / CI / cron | drain | packaging/loops/ci-drain.sh |
Claude Code /loop |
drain | packaging/loops/claude-loop.md |
| Codex automation | one-per-invocation | packaging/loops/codex-automation.md |
Each adapter references this seam and this body — they only change the cadence
and the per-runtime wiring. For declarative loops not derived from a PRD,
anvil run-workflow <name> loads .anvil/workflows/<name>.yaml and drives each
step through the same governed transitions (create → claim → run → submit
evidence → apply) to completion, then exits — no background process.