CLI reference¶
Audience: users running
anvilday-to-day — flags, exit codes, and command behavior.CLI: 87 executable leaf commands.
Single-page reference for the
anvilCLI, including the milestone bundle and coordinated-root lifecycles. The most-used lifecycle commands get full Synopsis/Flags/Exit-codes treatment below; Additional commands (index) covers the rest with a one-line entry each. For narrative context on common workflows, seehow-to/getting-started.md,how-to/authoring-a-prd.md,how-to/claiming-and-shipping-a-task.md, andhow-to/syncing-with-github.md.
Table of contents¶
- Conventions
- Global flags
- Project lifecycle
anvil initanvil statusanvil project snapshotanvil scan- PRD authoring
anvil prd parseanvil prd showanvil prd source-nameanvil prd assessanvil prd review- Planning
anvil plananvil scoreanvil expandanvil review tasksanvil listanvil show- Claims and work
anvil nextanvil claimanvil releaseanvil renewanvil packet- Coordinated roots
- Execution bundles
- Submit and apply
anvil submitanvil apply- Sync
anvil syncanvil sync githubanvil sync provider- Cross-harness
anvil mcp-config- Hook subcommands (internal)
anvil hook check-claimanvil hook record-file-changeanvil hook capture-evidence- Additional commands (index)
Conventions¶
- Every command supports
--help. Runanvil <command> --helpto see the live Typer-generated output. - Every command that needs a project directory accepts a hidden
--cwd PATHoverride — it points at your project directory, from which anvil derives the state location. Without it, the command resolves the project from the current working directory. - There is no
--workspaceflag. In the default HOME-workspace layout, state lives at~/.anvil/workspaces/<key>/.anvil/keyed by the project — you select it by project (run inside the project, or pass--cwd <project-dir>), never by pointing a flag at the workspace path directly.anvil statusechoes the resolved.anvildirectory on itsPath:line, soanvil status --cwd <project>is how you inspect a specific project's state. (Passing a workspace path where a project is expected — e.g.anvil status --workspace …— fails withNo such option '--workspace'.) - In the path examples below,
.anvil/...means a path relative to that resolved state directory unless the text explicitly says<cwd>/.anvil/...for local layout. - Mutating commands use a locked, log-first critical section: append the event
to
events.jsonl, then apply it tostate.dbinsideBEGIN IMMEDIATE. If SQLite fails after the append, it rolls back and the next initialization forward-catches up from the retained log line. The event log is the source of truth;state.dbis a derived projection that can be rebuilt by replayingevents.jsonl. Seearchitecture.mdfor the replay contract. - Actor identity for claims, submissions, and reviews defaults to
$USER, thenagent(orhumanforapply). Override with--actor,--reviewer, etc. --jsonis near-universal: almost every command accepts it and, when passed, emits exactly one line of JSON to stdout —{"ok": true, "command": "<name>", "data": {...}}on success or{"ok": false, "command": "<name>", "error": {"code": "...", "message": "..."}}on failure (printed to stdout even on failure, so a consumer piping stdout always gets parseable JSON) — with no Rich tables, color, or warnings mixed in, so output is safe to pipe intojq/json.load.--prd/ANVIL_PRDscope a command to one PRD partition on a multi-PRD project (most mutating PRD/planning/claim commands accept it — e.g.prd review,plan,score,claim,next). Precedence: the--prdflag > theANVIL_PRDenvironment variable > the project's single PRD or marked default PRD. With several non-default PRDs and neither selecting one, the command errors rather than guessing. Single-PRD projects can omit it entirely for unchanged behaviour.- Exit codes (consistent across the CLI):
0— success (including informational no-op states like "no tasks to score" orstatus --hook-formaton an uninitialised project).1— state / gate / validation error (task not found, gate failed,--use-llmwith an explicitly-pinned provider that can't be built, parse errors, mutually exclusive flag conflicts, missing required--reason, etc.).2— meaning is command-specific: forsync/sync github/sync providerit means one or more tasks parked awaitingmanual_mergeresolution; a handful of other commands (mcp-config,install,deps, the native-harness gates) reuse2for their own bad-request / block outcomes — see each command's own Exit codes.
Global-config layer¶
Configuration is resolved from up to four layers, lowest precedence to highest:
- Built-in defaults — the dataclass defaults baked into the engine (e.g. a 240-minute lease).
- Global config —
~/.config/anvil/config.yaml. User-wide defaults that every project on the machine inherits, so settings need not be copied into each project. The location honours$XDG_CONFIG_HOME($XDG_CONFIG_HOME/anvil/config.yaml) and can be pinned outright with theANVIL_GLOBAL_CONFIGenvironment variable. This file is optional — most projects never need one. - Project config —
<resolved-state-dir>/config.yaml. Per-project overrides. Any key set here wins over the same key in the global config. The project config is the one that must carry the requiredproject_name/project_id(though the global layer may supply a defaultproject_name).db_path/events_pathalways resolve next to the project config, never under~/.config. - Explicit CLI flag — e.g.
claim --lease 15. Always wins.
So a global default lease of 45 is overridden to 30 by a project
config.yaml and to 15 by claim --lease 15. The same precedence applies
to ANVIL_ROOT (which selects which project's resolved state the
merge reads) and every other config key. A broken or missing global config
never blocks a command: a missing/empty file means "no global defaults", and
a malformed one surfaces a warning while the command proceeds on the
remaining layers.
Global flags¶
These appear on the root anvil invocation, before any subcommand.
--version,-V— print the version (e.g.anvil 0.6.13 (schema 22)) and exit.--help— show root help and exit. Listing the registered commands and sub-apps; equivalent toanvilwith no arguments (no_args_is_help=True).
Project lifecycle¶
anvil init¶
Synopsis: Scaffold the resolved state directory for the project selected by
the current working directory (or ANVIL_ROOT). By default this is a
per-project HOME workspace; ANVIL_STATE_LAYOUT=local opts into
<project>/.anvil/. Creates config.yaml, state.db (SQLite, with the
canonical schema), an empty append-only events.jsonl, and an empty
packets/ subdirectory. Emits project.created and state.initialized events
to seed the project row.
Flags:
--name TEXT(optional) — human-readable project name. Defaults to the basename of the current directory.--id TEXT(optional) — project identifier slug (e.g.my-project). Defaults to a slug derived from--name.--force(flag) — overwrite an existing resolved state directory. Wipesstate.db(including the-wal/-shmsidecars),events.jsonl, andconfig.yaml. Preservespackets/andsnapshots/(user-generated).--with-sample(flag) — seed a runnable toy project (sampleprd.md+ parsed/planned/scored task graph) soanvil nextworks immediately.--from-repo(flag) — brownfield ingest: after scaffolding, runanvil scanon the existing working tree to persist a re-scannable codebase model, write a draftprd.md, and seed an initial feature/task graph offline. Mutually exclusive with--with-sample.
Exit codes:
0— initialisation succeeded.1— the resolved state directory already exists and--forcewas not passed; or local layout would scaffold inside the anvil plugin root.
Example:
cd ~/projects/acme-api
anvil init --name "Acme API"
See also: how-to/getting-started.md for the
end-to-end first-project walkthrough; anvil status to
inspect the result.
anvil status¶
Synopsis: Show the current anvil summary for this project.
Default output is a human-readable multi-line block (project name, id, path,
initialised-at, PRD status, task counts by status, active claim count, sync
configuration). Pass --hook-format for the single-line compact format
consumed by the SessionStart detect-state.sh hook.
Pass --path-only to print the absolute state-directory path without opening
the database. It works for uninitialised projects and incompatible schemas and
does not create state.
Flags:
--hook-format(flag) — emit a single compact line for hook consumption (e.g.active-claims:0 ready-tasks:5 blockers:0 prd-status:approved). Exits 0 even whenanvilis not initialised — hooks must never fail the session.--path-only(flag) — resolve and print the absolute state-directory path without opening or creating the database. Cannot be combined with--hook-format.--json(flag) — emit the standard machine-readable command envelope.--cwd PATH— project directory to inspect. Defaults to cwd.
Exit codes:
0— status printed successfully;--path-onlyalso exits 0 for an uninitialised project, and--hook-formatprintsuninitializedand exits 0.1— ordinary status could not open valid state, or a JSON request was rejected (including--path-only --hook-format --json).2— incompatible human-readable CLI flags, such as--path-only --hook-format.
Example:
anvil status
anvil status --path-only # resolve state without opening its database
anvil status --hook-format # for SessionStart hooks
See also: anvil init to create the directory;
anvil list for the per-task view.
anvil project snapshot¶
Synopsis: Return one atomic, bounded, allowlisted project hierarchy through
provider operation state.project.snapshot version 1. This command is
JSON-only and read-only: it never initializes, migrates, repairs, catches up, or
mutates state. The response includes exact PRD/feature/task references,
provider-owned verification summaries, the event frontier, applied limits, and
a deterministic payload digest. It excludes full PRD Markdown, source paths,
raw commands/manual steps, proof/evidence bodies, claims, and secrets.
Flags:
--json(required) — emit the one-line success/error envelope.--limit NAME=VALUE(repeatable) — lower a published version-1 ceiling. Unknown names, malformed values, and attempts to raise a ceiling refuse.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— a complete snapshot was returned withtruncated: false.1— state/schema/convergence/hierarchy/limit validation refused; no partial snapshot is returned.
Examples:
anvil project snapshot --json
anvil project snapshot --json --limit max_tasks=1000 --limit max_dependency_edges=5000
Consumers must first pin describe API 14, operation version 1, and the exact packaged schema resource. See Provider read contracts for limits, digest framing, fixtures, and the Workbench mapping.
anvil scan¶
Synopsis: Brownfield ingest of an existing repository. Walks the working
tree (preferring git ls-files, which honours .gitignore; falling back to a
pruned os.walk), persists a re-scannable codebase model in its own
.anvil/scan.db (kept separate from the event-sourced state.db so
replay is never touched), and — on the first scan of a project with no PRD
yet — synthesises a draft prd.md plus an initial feature/task graph by driving
the same offline parse → plan → score → review pipeline that
init --with-sample uses. Re-running scan reconciles against the persisted
model and reports the delta (added / removed / changed files) instead of
overwriting the seeded graph.
Flags:
--json(flag) — emit the standard single-line envelope.datacarriesfiles_scanned,components,languages,first_scan,delta(added/removed/changed/unchanged_count), andseeded(feature/task/ready counts on the run that seeded, elsenull).--force(flag) — re-seed the draft PRD and task graph even when a PRD already exists. Without it, a re-scan never clobbers an authored PRD.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— scan completed (first-seed or delta report).1— bounded refusal. JSON callers receive a stable code such asscan_locked(another scan owns the project),scan_artifact_error(unsafe or malformed scan/recovery storage),scan_recovery_incomplete(durable recovery could not finish),path_identity_error, or a seed/initialization refusal.
Before mutating scan.db or prd.md, scan creates an opaque
.anvil/recovery/scan-<token> record and holds a project-wide scan lock. A retry
automatically restores an uncommitted record or retires a state-bound committed
record. Treat the token as opaque: do not rename, edit, or manually copy its marker
files. If recovery cannot complete, preserve the directory and retry after removing
the external lock/contention; the command fails closed instead of guessing which
artifact is authoritative.
Example:
anvil init --from-repo # scaffold + first scan in one step
# ... edit code ...
anvil scan # refresh the model, see what changed
anvil scan --json | jq .data.delta
See also: anvil init (--from-repo runs scan for you);
anvil drift for intent↔state↔fs divergence on an active
project.
PRD authoring¶
anvil prd parse¶
Synopsis: Parse the managed default or named PRD source (or --file PATH).
A first parse emits a create-if-absent prd.parsed event; re-parsing an
existing partition emits the non-destructive prd.revised event. The resolver
normally selects
~/.anvil/workspaces/<key>/.anvil/prd.md, shared by the repository's
worktrees; ANVIL_STATE_LAYOUT=local opts into <cwd>/.anvil/prd.md. Calls
the template parser, validates the required sections, and persists the full
PRD payload (canonical title, summary, goals, non-goals, requirements,
acceptance criteria, risks, open questions, and typed assumptions).
Flags:
--file PATH(optional) — explicit PRD markdown path. When omitted, uses the managed source under the resolver-selected state directory (normally the HOME workspace;<cwd>/.anvil/prd.mdonly withANVIL_STATE_LAYOUT=local).--prd ID(optional) — named PRD identity; reads its portable managed source and scopes the parsed partition.--json(optional) — emit one standard Anvil JSON envelope. Failure codes includenot_found,read_error,invalid_encoding,parse_error,invalid_revision, andevent_rejected.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— PRD parsed/revised and its event recorded. Human output prints the requirement, feature, and task counts plus the stable source identity (default, the named ID, orcustom), never an absolute path.--jsonreturns those counts plus the PRD id, lifecycle status, source, and event action.1— PRD file not found, unreadable/non-UTF-8, contains parse errors, or its optimistic create/revision precondition became stale. Human errors are bounded and traceback-free;--jsonwrites one typed envelope to stdout. Public parser diagnostics show at most 20 entries (1,024 UTF-8 bytes per message), escape terminal-active controls, and report total/shown/omitted counts when the complete in-process error list is larger.
Example:
anvil prd parse
anvil prd parse --file ./drafts/v2-prd.md
anvil prd parse --prd v0.2 --json
See also: how-to/authoring-a-prd.md;
docs/prd-template.md for the required section structure;
anvil prd review for the next step.
anvil prd show¶
Synopsis: Return exact revision-bound persisted PRD source through provider
operation state.prd.content version 1. This command is JSON-only and never
rereads the mutable authoring file. A full or selected read that exceeds its
limit refuses without returning a prefix and reports truncated: false.
Arguments and flags:
PRD_ID(required) — exact default or named PRD partition identifier.--json(required) — emit the one-line success/error envelope.--section PATH(repeatable) — exact case-sensitive slash-delimited ATX heading path. Sections must be known, unique, and non-overlapping; output is returned in source order. JSON-Pointer escapes are~0for~and~1for/.--expected-digest HEX— require the exact lowercase 64-hex persisted source digest; mismatch returnsstale_digestand no content.--limit BYTES,--max-bytes BYTES— lower the immutable 2 MiB content ceiling.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— exact persisted UTF-8 bytes were returned in JSON with digests, revision, selector, sizes, applied limit, andtruncated: false.1— invalid ID/digest/selector, missing or legacy-unbound content, source drift, schema/convergence failure, stale digest, or limit refusal; no content or prefix is returned.
Examples:
anvil prd show default --json
anvil prd show default --json --section Summary --section Goals
anvil prd show default --json --expected-digest 2b1b3fab185e4627f05131d808c1844c1a0b1ac908b5c2495a9a4f0afe323b49
See Provider read contracts for exact selector grammar, digest framing, schemas, fixtures, and refusal behavior.
anvil prd source-name¶
Synopsis: Print the portable relative source name used to author a default
or named PRD. Join this value with the .anvil directory from anvil status;
do not derive an editable path from prd parse output.
Flags:
--prd ID(optional) — named PRD identity; omit for the default.--json(optional) — returnprd_sourceplusrelative_name.
Example:
anvil prd source-name
anvil prd source-name --prd CON
anvil prd assess¶
Synopsis: Read and parse a PRD, then report deterministic, location-aware behavioural-readiness findings. It is advisory and read-only: it does not write events or block parsing, review, approval, planning, claims, or autonomous execution.
Flags:
--file PATH(optional) — PRD markdown to assess.--prd ID(optional) — named PRD source to assess; omit for the default.--json(optional) — emit the standard Anvil JSON envelope with ordered finding records and challenge questions.--cwd PATH(hidden) — project directory.
Example:
anvil prd assess
anvil prd assess --prd v0.2 --json
See also: anvil prd parse and
how-to/authoring-a-prd.md.
anvil prd review¶
Synopsis: Transition the PRD through the review lifecycle. Without
--approve: draft → reviewed (emits prd.reviewed). With --approve:
reviewed → approved (emits prd.approved).
Both transitions bind the exact persisted revision, source digest, canonical
material digest, and content event. The command refuses if the selected source
file no longer matches that persisted content; run anvil prd parse first,
then repeat review and approval. A title-only revision may retain an existing
lifecycle binding because the canonical material is unchanged; any other
material change returns the PRD to draft.
Flags:
--approve(flag) — approve the PRD (transitionreviewed→approved). Without this flag the command performs thedraft→reviewedtransition.--reviewer TEXT(default:human) — identity of the reviewer recorded in the event payload.--notes TEXT(optional) — optional review notes (recorded on theprd.reviewedevent).--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— transition recorded successfully.1— no PRD in state (runprd parsefirst); or the PRD is in the wrong status for the requested transition (e.g.--approveinvoked while the PRD is stilldraft); or a concurrent same-revision lifecycle transition made the optimistic status precondition stale; or the source file no longer matches the persisted revision. Refusals are atomic and use a bounded, traceback-free diagnostic.
Example:
anvil prd review --reviewer "alex" --notes "scope looks good"
anvil prd review --approve --reviewer "alex"
See also: anvil prd parse;
anvil plan for the next step.
Planning¶
anvil plan¶
Synopsis: Generate features and tasks from the parsed PRD. Re-reads
prd.md, runs dependency and conflict-group inference, then persists the
complete canonical graph as one planning.batch_applied event and SQLite
transaction. The batch contains the ordered feature/task/status/conflict
operations and binds them to the exact persisted PRD source digest, so a later
refusal or stale sibling revision cannot expose a partial or mismatched graph. Freshly
proposed tasks advance to drafted; re-running does not duplicate tasks or
regress tasks that have already advanced past drafted.
Flags:
--use-llm(flag) — augment planning with an LLM. Defaults to your Claude subscription via the Agent SDK (no API key; needs theclaudeCLI on PATH); pinanthropic/bedrock/customviallm_provider:in.anvil/config.yaml. Deterministic output is always produced first; LLM enrichment is additive (it enriches task descriptions shorter than the 50-character threshold). LLM failures fall back to the deterministic description with a stderr warning —plannever aborts on LLM failure.--model NAME(default: unset) — override the LLM model for this run (wins overllm_model/llm_tier); applies to both--use-llmaugmentation and the no-tasks backstop. For agent-sdk a CLI name likesonnet/opusor a full id; for anthropic/bedrock a model id; for custom the route name your endpoint serves.--prd TEXT(optional) — named PRD to plan (multi-PRD). Reads its portable source under.anvil/prds/and scopes feature/task creation, orphan-prune, dependency inference, andproposed→draftedpromotion to that PRD's partition (conflict-group inference still spans all PRDs). Omit for the default PRD (.anvil/prd.md).--no-llm(flag) — disable the LLM task-generation backstop. When the PRD has features + requirements but no## Taskssection, the default behaviour calls the LLM to generate tasks and append them toprd.md; with--no-llmthe command fails loudly instead so tasks can be authored manually.--prune-force(flag) — force-delete orphan tasks (removed fromprd.md) that have already advanced pastreadystatus (claimed / in_progress / needs_review / etc.). Without it, such orphans makeplanfail loudly so the user can release/complete them first; events/evidence/ reviews are preserved as audit history either way — only the task row is deleted.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— planning succeeded. PrintsPlanned N features, M tasks.and any detected conflict-group count.1—prd.mdnot found or unreadable; an explicitly-pinned provider (llm_provider: bedrock/custom) could not be built (missing extra or config); the LLM task-generation backstop failed; or an orphan task pastreadystatus was found without--prune-force. The default agent-sdk provider needs no key, so a missingANTHROPIC_API_KEYis not an error.
Example:
anvil plan
anvil plan --use-llm # default: your Claude subscription (no API key)
See also: anvil score and
anvil review tasks for the next steps in the
planning lifecycle; docs/llm.md for the LLM augmentation
contract.
anvil score¶
Synopsis: Score tasks across six rule-based dimensions (complexity,
parallelizability, context_load, blast_radius, review_risk,
agent_suitability). By default it resolves one PRD through --prd,
ANVIL_PRD, or the default/single partition and keeps scoring, skipped work,
and the expansion queue inside that partition. Pass --all-prds for an
explicit project-wide run. With a task id: scores that single task after
verifying it belongs to the selected PRD. Emits one task.scored event per
task and prints the effective scope plus a summary table.
Positional arguments:
TASK_ID(optional) — task id to score. Omit to score all tasks whose scores are currently incomplete.
Flags:
--use-llm(flag) — append the rule-based explanation with a 1-3 sentence trade-off summary from the LLM. Defaults to your Claude subscription via the Agent SDK (no API key; needs theclaudeCLI); pin a different provider viallm_provider:. The numeric scores themselves are never modified by the LLM.--model NAME(default: unset) — override the LLM model for this run (wins overllm_model/llm_tier). Seeanvil planfor the per-provider name conventions.--prd ID— select one PRD partition. Precedence is the explicit flag,ANVIL_PRD, then default/single-PRD resolution.--all-prds— explicitly score every partition. Mutually exclusive with a command-line--prd; it overrides an environment-onlyANVIL_PRD.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— scoring completed (including the "no tasks require scoring" no-op).1— specifiedTASK_IDnot found; or an explicitly-pinned (bedrock/custom) provider could not be built. The default agent-sdk provider needs no key. A scoring implementation that returns an incomplete or out-of-range dimension also exits withscore_incomplete; when scoring a batch, Anvil validates every result before appending anytask.scoredevent.
Example:
anvil score # score unscored tasks in the resolved PRD
anvil score T003 --prd default
anvil score --all-prds # explicit project-wide pass
anvil score T003 --use-llm
See also: anvil show for the per-task scores breakdown;
anvil expand to decompose high-complexity tasks.
anvil expand¶
Synopsis: Expand a high-complexity task into 2-5 sub-task proposals via
the LLM. Requires --use-llm — the deterministic engine never invents
sub-tasks; the deterministic path is manual authoring of T001.1, T001.2
entries in prd.md. Only tasks with complexity >= 4 are decomposed;
lower-complexity tasks return no proposals. This command does not mutate
state — proposals are printed for the human to paste into prd.md.
Positional arguments:
TASK_ID(required) — task id to expand into subtasks.
Flags:
--use-llm(required) — without this flag,expandexits 1 with the message pointing at the manual-authoring fallback. With it, the LLM is asked for 2-5 independently-claimable sub-task proposals. Defaults to your Claude subscription via the Agent SDK (no API key; needs theclaudeCLI); pin a provider viallm_provider:.--model NAME(default: unset) — override the LLM model for this run (wins overllm_model/llm_tier). Seeanvil planfor the per-provider name conventions.--format {text,prd}(default:text) —textprints a human-readable per-subtask block;prdrenders markdown blocks matchingdocs/prd-template.md— paste-ready into the## Taskssection of.anvil/prd.md, inheriting the parent'sfeature_idand priority.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— proposals printed (or the task is below the complexity threshold — this is a non-error no-op).1—--use-llmwas not passed; or--formatwas not one oftext/prd; orTASK_IDnot found; or an explicitly-pinned (bedrock/custom) provider could not be built.
Example:
anvil expand T012 --use-llm
anvil expand T012 --use-llm --format prd >> .anvil/prd.md
See also: anvil score (run first to populate the
complexity score); docs/llm.md;
anvil prd parse to re-parse after pasting blocks.
anvil review tasks¶
Synopsis: Promote tasks in one resolved PRD through the review lifecycle in two stages:
drafted → reviewed, then reviewed → ready. The drafted → reviewed
gate requires non-empty acceptance_criteria AND non-empty
verification.commands. Prints a summary of how many tasks were promoted at
each stage and lists any blocked tasks with the gate-failure reason. Selection
uses --prd, then ANVIL_PRD, then the single/default PRD. Project-wide
mutation requires the explicit --all-prds flag. Both promotion passes and
risk-score confirmation remain inside the reported scope.
Flags:
--prd ID— review one PRD partition. Also readsANVIL_PRD.--all-prds— explicitly review every PRD partition. This overrides an environment-onlyANVIL_PRDbut cannot be combined with a command-line--prd.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— pass completed. Tasks that failed the gate are listed in the output but do not change the exit code (this is a batch operation; per-task failures are informational).
Example:
anvil review tasks
anvil review tasks --prd v0.2
anvil review tasks --all-prds
See also: anvil list to inspect the current statuses;
anvil plan for the prior step.
anvil list¶
Synopsis: List tasks with optional status, feature, and type filters.
Prints a table with columns: TaskID, Title, Status, Priority, Type, Score
(complexity/agent_suitability or unscored), Feature.
Flags:
--status TEXT(optional) — filter by task status (e.g.ready,drafted,reviewed,in_progress,needs_review,done).--open(optional) — show only unfinished tasks: hides the terminal statusesdoneandaccepted. A task resting atrejectedawaits rework, so it counts as open.--summary(optional) — roll tasks up per PRD instead of listing each one: table columnsPRD | Open | Total | Breakdown, PRDs with open work first.Totalis always the true per-PRD count; combining with--openonly hides PRDs that have nothing open. With--jsonthedatapayload is{"summary": [{"prd", "open", "total", "by_status"}, ...], "prd_count", "open", "total", "filters"}.--feature TEXT(optional) — filter by feature id (e.g.F001).--type TEXT(optional) — filter by task type:feature(default),bugfix,refactor, ormodify.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— table printed, or the friendly "No tasks found" message.
Example:
anvil list
anvil list --status ready
anvil list --open --summary # "what's left, per PRD?" in one call
anvil list --feature F001 --status drafted
anvil list --type bugfix
See also: anvil show for the per-task detail;
anvil next for the recommendation.
anvil show¶
Synopsis: Print full task detail in a human-readable multi-section format. Sections: title, feature, status, priority, review tier, scores breakdown (all six dimensions plus explanation), dependencies, conflict groups, acceptance criteria, verification commands, likely files, active claim (if any), and the 10 most recent events targeting this task.
Positional arguments:
TASK_ID(required) — task id to display (e.g.T001).
Flags:
--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— task printed.1—TASK_IDnot found.
Example:
anvil show T001
See also: anvil list for the table view;
anvil claim once you have decided to pick it up.
Claims and work¶
anvil next¶
Synopsis: Pick the highest-priority claimable task without claiming
it. Prints the recommended task id, title, priority, review tier, complexity,
and the complete accept-rate governor calculation. Run
anvil claim TASK_ID to acquire the lease after reviewing the
recommendation. Reaps any stale claims (expired leases) before recommending.
Flags:
--actor TEXT(optional) — actor identity; defaults to$USERoragent. Selects the finalized-review history used by the accept-rate governor.--type TEXT(optional) — only recommend tasks of this type:feature,bugfix,refactor, ormodify.--max-blast INTEGER(optional,$ANVIL_MAX_BLAST) — [EXPERIMENTAL] risk ceiling for a low-risk runner: only recommend tasks whoseblast_radiusis confirmed (viaanvil review tasks) and<= N. Unconfirmed/unscored tasks are ineligible even below the ceiling, so the filter fails safe rather than open.--max-review-risk INTEGER(optional,$ANVIL_MAX_REVIEW_RISK) — [EXPERIMENTAL] same semantics as--max-blastfor the confirmedreview_riskdimension.--prd TEXT(optional,$ANVIL_PRD) — scope the candidate pool to one PRD partition; coordination (conflict-group checks) still spans all PRDs.-q,--quiet(flag) — print nothing; use the exit code as the signal only (see Exit codes below). Loop seam forjq-less shells, e.g.while anvil next -q; do ...; done.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— recommendation printed, or "No claimable tasks available." printed (human mode); or, with--jsonand no--prdscoping, the{"task": null}envelope is emitted — an empty queue is not an error here.3— with-q/--quiet: prints nothing and exits 3 whenever the queue is empty (the loop-seam signal). Also returned when--prdscopes the candidate pool and that PRD has no claimable task (both human and--jsonmodes print/emit a PRD-specific message first).
Governor output: Human and JSON output report the calculation boundary
(as_of), inclusive window and window_days, accepted-review numerator,
counting-attempt denominator, rate (null when the denominator is zero),
configured or task-escalated floor, review-queue depth/cap, and whether an
empty result was actually throttled. One accepted finalized review contributes
1/1; one quality rejection contributes 0/1; evidence-resubmission and
process rejections contribute neither. Decisions exactly at either window
boundary count, future decisions do not, and equal timestamps use event ID as
the stable tiebreak.
Clearing the review queue alone does not repair a low accept rate. Offer
eligibility recovers through accepted finalized reviews, expiry of older
reviews from the configured window, or a configured floor change. A direct
anvil claim KNOWN_TASK_ID bypasses only this offer throttle; ownership,
conflict, PRD, risk, and evidence gates still apply.
Example:
anvil next
anvil next --type bugfix
while anvil next -q; do anvil claim "$(anvil next --json | jq -r .data.task.id)"; done
See also: anvil claim to actually pick up the task;
anvil list for the broader view.
anvil claim¶
Synopsis: Acquire an exclusive lease on TASK_ID and create an
agent/<task>-<slug> git branch. Reaps stale claims, runs the pre-claim
conflict check (file overlap with active claims and conflict-group
membership), and records a claim.created event. Optionally creates a git
worktree at ../wt-<task_id>/.
New task and bundle claims require the owning PRD to be approved for its
exact current persisted revision, source digest, canonical material digest,
and content event. If the source changed, run anvil prd parse, review, and
approve again before claiming. This gate does not revoke an existing active
claim.
Positional arguments:
TASK_ID(required) — task id to claim (e.g.T001).
Flags:
--worktree(flag) — also create a git worktree at../wt-<task_id>/. For a repository created with--separate-git-dir, invoke this flag from the main checkout so Anvil can preserve project-adjacent placement. A linked caller cannot reconstruct that unrecorded main-checkout path and refuses withworktree_placement_unavailable; use the main checkout or an explicit shared-tree claim instead.--shared-tree(flag) — claim into the shared checkout even underworktree_isolation: require(read-only/docs work); also silences the advisory shared-checkout warning. A compatible existing branch/worktree is revalidated and reused; an occupied, dirty, stale, or differently owned target is refused before mutation.--force(flag) — override the pre-claim conflict warnings. Without--force, file overlap or group conflicts cause the command to exit 1 after listing every conflicting claim.- A known task ID is not subject to the
nextaccept-rate offer throttle. This is not a general override: all claim ownership, status, conflict, PRD, and risk checks remain active, and later evidence gates remain unchanged. --actor TEXT(optional) — local audit actor. Precedence: explicit flag >ANVIL_ACTOR> legacyANVIL_GATE_ACTOR> derived local identity. Claim output includes structured continuation argv/environment data. Actor identity is not cryptographic authentication.--lease FLOAT(optional) — lease duration in minutes for this claim. Overridesdefault_lease_minutesfrom config. Lease precedence: this flagproject
config.yaml> globalconfig.yaml> built-in240(see Global-config layer).--branch TEXT(optional) — attach the claim to an existing or caller-named branch instead of generating the defaultagent/<task>-<slug>name. An existing branch is checked out; a new one is created. The resolved branch name is recorded on the claim. Omit for the default auto-generated branch (unchanged behaviour).--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— claim acquired. Prints the claim id, lease expiry, branch name, and optional worktree path.1—TASK_IDnot found, pre-claim conflicts detected without--force, or theClaimManagerrejected the claim (task in wrong status, already claimed by another actor, lease overlap, or its PRD lacks an exact current approval, etc.).
Example:
anvil claim T001
anvil claim T001 --worktree --actor "alex"
anvil claim T001 --force # override conflict warnings
anvil claim T001 --lease 15 # 15-minute lease (overrides config)
anvil claim T001 --branch my-existing-branch
See also:
how-to/claiming-and-shipping-a-task.md;
anvil release, anvil renew,
anvil submit.
anvil release¶
Synopsis: Release a claim by CLAIM_ID, returning the task to ready.
Emits a claim.released event with the optional reason.
Positional arguments:
CLAIM_ID(required) — claim id to release (e.g.C001).
Flags:
--force(flag) — force release even if the claim belongs to another actor. Without--force, releasing someone else's claim fails.--reason TEXT(optional) — human-readable reason for the release (recorded on the event).--actor TEXT(optional) — actor identity under claim's precedence. Without--force, it must exactly match the persisted owner.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— claim released.1—CLAIM_IDnot found, already released, or owned by another actor without--force.
Example:
anvil release C001 --reason "blocked on upstream PR"
anvil release C002 --force --reason "actor abandoned"
See also: anvil claim, anvil renew.
anvil renew¶
Synopsis: Extend the lease heartbeat on CLAIM_ID. Prints the new lease
expiry and last-heartbeat timestamp. Use this from a long-running agent loop
to prevent the stale-claim reaper from reclaiming the task mid-flight.
Positional arguments:
CLAIM_ID(required) — claim id to renew (e.g.C001).
Flags:
--actor TEXT(optional) — actor identity under claim's precedence; it must exactly match the persisted owner.--lease FLOAT(optional) — lease extension in minutes. Overridesdefault_lease_minutesfrom config (same precedence asclaim --lease).--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— lease renewed.1—CLAIM_IDnot found, already released, expired beyond recovery, or owned by another actor.
Example:
anvil renew C001
anvil renew C001 --lease 30 # extend by 30 minutes
See also: anvil claim, anvil release.
anvil packet¶
Synopsis: Render a work packet for TASK_ID and write it to
.anvil/packets/. The packet bundles task definition, parent
feature, completed dependencies, open dependencies, related decisions, and
active claim metadata into a single self-contained artefact for an agent to
execute against.
Positional arguments:
TASK_ID(required) — task id to render a work packet for (e.g.T001).
Flags:
--format {md,json},-f(default:md) — output format.mdwritespackets/<TASK_ID>.md;jsonwritespackets/<TASK_ID>.json. Stdout echoes the rendered content matching the selected format.--cwd PATH(hidden) — project directory. Defaults to cwd.
Review tier. Every packet carries a derived review tier —
light / standard / max — with one line of reviewer guidance
(markdown header + review_tier JSON key). The tier is a pure projection
over the six-dimension score plus the risk-confirmation flags, recomputed at
every read (never persisted): max when any dimension is unscored or
review_risk/blast_radius ≥ review_tier_max_min; light only when the
task passes the fast-lane gate AND review_risk ≤
review_tier_light_risk_max AND both the blast_radius and
review_risk scores are confirmed (via anvil review tasks); standard
otherwise. Two
config.yaml knobs move the boundaries (1–5 score scale, global-config
mergeable):
review_tier_max_min: 4 # DEFAULT; review_risk/blast_radius at/above → max
review_tier_light_risk_max: 2 # DEFAULT; highest confirmed review_risk still light
The same tier appears on anvil next, anvil show, and the MCP
get_task / get_next_task responses.
Exit codes:
0— packet written and echoed.1—TASK_IDnot found.
Example:
anvil packet T001
anvil packet T001 --format json
See also: anvil claim (typically run before
generating the packet); the rendered packet feeds directly into Claude Code,
Cursor, or any MCP-aware agent.
Coordinated roots¶
roots is the CLI-only owner surface for one task that must reserve several
repositories. Enroll each exact checkout once, then submit a request file
whose roots and verification commands match the declared policy:
anvil roots enroll --repository-id app --path /work/app --origin https://example.test/org/app.git
anvil roots claim T001 --request-file root-set.json --actor agent --json
The request uses anvil.root-set-request/v1 with a stable request_id, one
primary_root_id, and 1–16 roots. Each root declares root_id,
repository_id, absolute path, expected_files, and
verification_commands. The primary must be the State checkout and use the
task's declared verification commands; secondary commands come from enrollment.
If a claim response is lost, derive its lookup identity from the retained original inputs without reading the owner registry:
anvil roots request-digest T001 --request-file root-set.json --actor agent --json
anvil roots status --request-id ID --request-digest SHA256 --actor ACTOR and
anvil roots reconcile require that original actor and immutable digest. A
claim is ready only after every retained Git target and its canonical claim
facts match. Enrolled repositories reject ordinary and bundle claims, including
--force; use this surface to coordinate them. Root-set renew and release use
the existing anvil renew and anvil release commands. Release records a
release_pending global overhold until runner-stop reconciliation can prove no
write authority remains. MCP intentionally does not create, renew, or release
coordinated root-set claims.
Per-root evidence remains root-qualified through the owner surface. Submit a
retained anvil.root-set-evidence/v1 manifest, then use its read-only status
command after an interrupted response:
anvil roots submit-evidence T001 --request-file root-set.json --manifest-file evidence.json --actor agent --json
anvil roots evidence-status T001 --request-file root-set.json --manifest-file evidence.json --actor agent --json
This records evidence for the one frozen coordinated claim and leaves acceptance to the existing independent review flow.
Execution bundles¶
Bundle commands coordinate an ordered milestone through one coordinator claim, member
evidence, a bounded multi-angle review, and delivery reconciliation. All accept --json
and hidden --cwd PATH. Mutating commands accept --actor; when omitted, Anvil uses its
normal actor resolution. Errors use the stable bundle_error code except an unready
completion, which uses bundle_not_ready.
anvil bundle create¶
anvil bundle create B001 T001 T002 --prd release --coordinator lead creates a planned
bundle with ordered member tasks. Policy flags are --max-tasks (12),
--max-serial-stages (6), --max-reviews (3), --max-rereviews (1), and repeatable
--required-angle.
anvil bundle show¶
anvil bundle show B001 prints the bundle, coordinator claim, review count, checkpoint,
and supersession state. JSON mode returns bundle, claim, and reviews.
anvil bundle list¶
anvil bundle list [--prd PRD_ID] lists bundles in stable ID order, optionally filtered
to one PRD.
anvil bundle claim¶
anvil bundle claim B001 atomically creates the coordinator claim and member task
authorizations. --shared-tree explicitly accepts a shared checkout; required worktree
isolation otherwise directs callers to the top-level Git-aware bundle claim path.
The owning PRD must remain exactly approved for its canonical source at the pre-log
claim boundary; drift refuses without a claim, bundle-status change, or Git mutation.
JSON output includes the exact coordinator identity plus structured renew, release,
progress, and complete argv/environment continuations; no task-submit command is emitted.
anvil bundle renew¶
anvil bundle renew B001 renews the active coordinator lease after stale-claim reaping.
anvil bundle release¶
While a bundle is active, anvil bundle release B001 [--reason TEXT] releases the
coordinator claim and marks the bundle replan_required. Only members with active
authorizations return to ready; already-submitted members remain needs_review.
Releasing after completion does not reset the review-state bundle or its submitted
members, and the public surface cannot reacquire that coordinator claim. Release is not
pause/resume; see the recovery guide below.
anvil bundle packet¶
anvil bundle packet B001 [--format markdown|json] renders the aggregate coordinator work
packet.
anvil bundle progress¶
anvil bundle progress B001 PHASE [--detail TEXT] [--member-task TASK_ID ...] records an
audited coordinator heartbeat for the active bundle.
anvil bundle complete¶
anvil bundle complete B001 opens bundle review only when every member has completion
evidence bound to its current member claim and all enforceable evidence claims pass. It is
retry-safe. Failure returns bundle_not_ready with per-member blockers and does not append
a progress event.
anvil bundle status¶
anvil bundle status [BUNDLE_ID] reports claimability, rollups, refusal codes, and concrete
remediation for one or all bundles.
anvil bundle review¶
anvil bundle review B001 --round 1 --angle security --decision approve records one
independent adversarial verdict. --decision accepts approve, reject, or
needs_changes; --notes records reviewer context.
anvil bundle finalize-review¶
anvil bundle finalize-review B001 advances only after the configured number of unique
reviewers and required angles pass with no blocking verdict.
anvil bundle checkpoint¶
anvil bundle checkpoint B001 [--commit SHA] [--pr-url URL] records canonical delivery
metadata; at least one delivery identifier is required.
anvil bundle reconcile¶
anvil bundle reconcile B001 [--commit SHA] [--pr-url URL] [--merged] idempotently
reconciles checkpoint and integration state. At least one of --commit or --pr-url is
required; --merged alone is not a delivery reference.
anvil bundle supersede¶
anvil bundle supersede B001 --replacement B002 marks B001 superseded by replacement B002 while
retaining the original audit history. A replacement created after the source reaches
replan_required may retain the same members; supersession reopens shared
needs_review tasks to ready while preserving their prior evidence.
The normal lifecycle is:
create -> claim -> packet/progress -> member submit -> complete
-> review (independent reviewers) -> finalize-review
-> checkpoint/reconcile
See Coordinating a milestone bundle for runnable coordinator-only and bounded-delegation flows, replan recovery, adoption, and delivery semantics.
Submit and apply¶
anvil submit¶
Synopsis: Record completion evidence for TASK_ID; auto-releases the
active claim and transitions the task to needs_review. Emits an
evidence.submitted event with the commands run, files changed, optional
output excerpt (truncated to 8000 chars), PR url, commit SHA, and known
limitations. Prints separate gate diagnostics for descriptive
required_evidence and typed required_proofs.
Positional arguments:
TASK_ID(required) — task id to submit evidence for (e.g.T001).
Flags:
--commands TEXT(required) — comma-separated verification commands that were run.--files-changed TEXT(required) — comma-separated file paths modified.--category TEXT(optional, defaultcompletion) — the evidence role (evidence contracts, issue #153):completion,diagnostic,blocked,advisory, orpromotion_quality.diagnostic/advisoryevidence can never satisfy a completion claim;blockedrecords that the claim could not be proven (and refuses the claim gate). An invalid value exits 1 with codeinvalid_category. See the evidence-contract gate underanvil apply.--output-file PATH(optional) — path to a file whose content is used as the output excerpt (read witherrors="replace", truncated to 8000 chars). Descriptive only: it never creates a typed command proof or satisfiesrequired_proofs.--command-proof-file PATH(optional, repeatable) — import a bounded, versioned claim-bound command-proof artifact. Every artifact in the batch must match the explicit active claim, exact actor, generation, task/PRD revision, repository and canonical cwd, and one exact--commandsvalue. Validation is all-or-nothing before evidence is recorded. For signed proofs, current issuer membership inANVIL_TRUST_LISTor~/.anvil/trust.txtis required at append and replay; preserve and restore that trust configuration with state or replay fails closed. Self-attested replay is trust-list independent.--pr-url TEXT(optional) — pull request URL.--commit-sha TEXT(optional) — commit SHA associated with this submission.--known-limitations TEXT(optional) — known limitations or caveats.--screenshots TEXT(optional) — comma-separated paths to screenshot files. Required when the task'sverification.required_evidenceincludes an item matching "screenshot" (the gate checksevidence.screenshotsis non-empty). Default:[].--actor TEXT(optional) — actor submitting evidence under claim's precedence. An active claim requires its exact owner; mismatch refuses before evidence is appended.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— evidence recorded and claim auto-released. The "evidence gate" summary may report INCOMPLETE without changing the exit code (gate feedback is informational; the human reviewer decides atapplytime).1— no active claim found forTASK_ID(runclaimfirst).
With --json, additive proof receipts are returned as
claim_bound_command_proofs and hook_command_proofs. Hook receipts include
the exact claim ID, generation, actor, and semantic digest. Missing typed command
requirements are listed in missing_claim_bound_proofs; descriptive legacy
gaps remain separate in missing_legacy_evidence while the historical
evidence_gate envelope is preserved.
Example:
anvil submit T001 \
--commands "pytest tests/test_auth.py, ruff check src/auth" \
--files-changed "src/auth/login.py, tests/test_auth.py" \
--pr-url "https://github.com/acme/api/pull/42" \
--commit-sha "abc123def"
For a task whose required_evidence includes a "screenshots" item, attach
the captures with --screenshots:
anvil submit T002 \
--commands "pytest tests/test_ui.py" \
--files-changed "src/ui/login_page.py" \
--screenshots "docs/images/login-before.png,docs/images/login-after.png"
See also: anvil claim for the prior step;
anvil apply for human review;
docs/evidence-buffer.md for the hook-captured evidence
buffer, descriptive --output-file behavior, and claim-bound proof import.
anvil apply¶
Synopsis: Human review gate. Without --approve / --reject: review-only
mode — prints the evidence-gate summary and the current status. With
--approve: transition needs_review → accepted → done. With
--reject: transition needs_review → drafted (rework path). Emits a
task.applied event with the reviewer, decision, notes, and immutable
engine-derived rejection provenance.
Positional arguments:
TASK_ID(required) — task id to apply a review decision to (e.g.T001).
Flags:
--approve(flag) — approve: transitionneeds_review→accepted→done.--reject(flag) — reject: transitionneeds_review→drafted. Requires--reason. Mutually exclusive with--approve.--reason TEXT(required with--reject, optional with--approve) — review notes.--reason-code CODE(optional;--rejectonly) — bounded reviewer assertion. The engine derivesquality,evidence_resubmission, orprocessfrom persisted evidence and claim state; callers cannot select the category.--quality-finding CODE(repeatable;--rejectonly) — typed quality finding such ascorrectness,security, ortests. Any typed quality finding forces the rejection to count as quality.--reviewer TEXT(optional) — reviewer identity; defaults to$USERorhuman.--cwd PATH(hidden) — project directory. Defaults to cwd.
Merge check. Review-only mode and --approve also run a cheap
base-freshness probe against the task's claim branch (behind-count vs
origin/<default>, textual-conflict check; never the heavy merged-tree run
— that is anvil merge-check --run-checks). The
merge_check config knob sets the mode:
merge_check: advisory # DEFAULT — report staleness, approval proceeds
# merge_check: strict # refuse --approve (exit 1, code base_stale) when the
# # branch is VERIFIABLY behind its base or conflicted
# merge_check: "off" # skip the probe entirely
Worktree isolation. The worktree_isolation config knob sets the claim
isolation mode:
worktree_isolation: advisory # DEFAULT — warn when a new claim would share
# # the working tree with another active claim
# worktree_isolation: require # every claim isolates into a git worktree by
# # default (as if --worktree); --shared-tree is
# # the explicit opt-out. Fail-closed: if the
# # worktree cannot be created the claim is
# # released and refused (--force keeps it).
# worktree_isolation: "off" # flag-only (--worktree) behavior
The MCP claim_task tool honors the same policy: under require it refuses
unless shared_tree=true (the MCP server cannot create worktrees itself);
under advisory the shared-checkout warning is returned in the response
warnings list.
Local-first: offline / no-remote projects degrade to the local default
branch and are never refused; an unverifiable probe never gates (a probe
error under strict prints a stderr warning and skips the gate rather
than blocking). --reject is never affected. The JSON envelope carries the
report under data.merge_check (and inside error.merge_check on a strict
refusal).
Ordering caveat — apply before you merge. The probe measures the task's local claim branch against the base. In a merge-first workflow (PR squash-merged, then
apply), the surviving local branch is behind the base by its own merge commit and reads asSTALE— a false positive (there is no reliable git signal for "already squash-merged"). Runapply --approvebefore merging the PR, or expect the advisory note; do not enablemerge_check: strictin a merge-first workflow.
Evidence-contract gate (auto-strict). A task that declares an evidence
contract — named claims and/or Artifact assertions in its PRD block (see
docs/prd-template.md) — is held to it at --approve independent of
strict_evidence. apply re-evaluates the artifacts at approval time and
prints a per-claim verdict (claim_verdict JSON key; human Claim <id>:
<VERDICT> lines). Per-claim verdict vocabulary:
| Verdict | Meaning |
|---|---|
passed |
every bound assertion/proof satisfied on completion-category evidence |
failed |
an artifact assertion contradicted the claim on an existing artifact |
incomplete |
a required proof is unmet, the artifact is not yet written, a named claim binds no contract, or no evidence was submitted |
blocked |
the evidence's category is blocked — the claim could not be proven |
diagnostic_only |
assertions pass but the evidence is diagnostic/advisory — excellent context, proves no completion claim |
The overall verdict is the worst per-claim one (failed > blocked >
incomplete > diagnostic_only > passed). When any enforceable
unproven claim remains, --approve refuses with exit 1 and error code
claim_unproven; the task stays in needs_review. Named claims always
enforce; on the implicit task-level claim, an unmet command proof alone
stays governed by strict_evidence — everything else on that claim (an
artifact-assertion contradiction, an unwritten or missing artifact, no
evidence submitted, or a blocked/diagnostic_only category) always
enforces regardless of strict_evidence. --reject is never gated. An advisory Intent check block
(intent_warnings) additionally flags task intents that no claim or
assertion covers — never blocking.
Exit codes:
0— review decision recorded, or review-only mode (neither--approvenor--reject) printed the summary.1—TASK_IDnot found; task is not inneeds_reviewstatus; both--approveand--rejectwere passed;--rejectwas passed without--reason;merge_check: strictrefused a stale/conflicted branch (codebase_stale); or the claim gate refused a task whose evidence contract has an unproven claim (codeclaim_unproven, see below).
Example:
anvil apply T001 # review-only
anvil apply T001 --approve --reviewer "alex"
anvil apply T001 --reject --reason "missing tests for edge case X"
anvil apply T001 --reject --reason "security boundary" --quality-finding security
See also: anvil submit for the prior step;
anvil show to inspect the submitted evidence.
Sync¶
anvil sync¶
Synopsis: Run the ReconciliationEngine and print a report of any
discrepancies between local state, configured providers, and the event log.
With --fix, additionally apply each suggested fix; combine with --yes for
CI / non-interactive contexts. Named subcommands (github, provider) take
over when invoked — this bare form only runs when no subcommand is supplied.
Flags:
--fix(flag) — after scanning, apply each suggested fix. Requires--yesin non-interactive mode (stdin/stdout not a tty).--yes(flag) — skip the confirmation prompt before applying fixes.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— scan completed; or scan completed and operator declined the apply prompt; or--fix --yesapplied all fixes successfully.1—--fixwas passed without--yesin non-interactive mode.
Example:
anvil sync # scan + print report
anvil sync --fix --yes # scan + auto-apply
See also: anvil sync github;
anvil sync provider;
docs/sync-providers.md for the provider contract.
anvil sync github¶
Synopsis: Sync tasks against GitHub Issues. Convenience alias for
anvil sync provider github_issues. Default (neither --push nor
--pull) runs both directions. Conflict resolution honours each
SyncMapping's conflict_resolution_strategy
(local_wins, remote_wins, prompt, manual_merge); --fix forces
remote_wins on every conflict for this run.
Flags:
--push(flag) — push local tasks to GitHub only (skip pull).--pull(flag) — pull remote issues to local only (skip push).--watch(flag) — long-running poll loop; Ctrl-C to exit. Each iteration is isolated (per-task failures do not kill the daemon).--fix(flag) — reconcile remote state into local on conflicts (forces a pull for tasks whoseSyncMappingis inconflictstate).--task TEXT(optional) — scope sync to a single task id (e.g.T001).--yes(flag) — auto-confirm conflict prompts; defaults tolocal_winsin non-interactive mode.--health(flag) — probe provider reachability and auth; print status; exit. Does not require an initialised project (useful for pre-init connectivity sanity checks).--interval INTEGER(default:60) — poll interval seconds with--watch. Use0for a single iteration (test seam).--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— sync iteration completed successfully.1— provider cannot be instantiated (e.g. missingGITHUB_REPOSITORYorGITHUB_TOKEN); audit emission catastrophic failure.2— one or more tasks parked awaitingmanual_mergeresolution. Inspect files under.anvil/.sync-conflicts/<TASK_ID>.md, resolve, delete, re-run sync.
Example:
anvil sync github --health
anvil sync github --push --task T001
anvil sync github --watch --interval 30
See also: how-to/syncing-with-github.md;
docs/github-sync.md;
anvil sync provider for the generic form.
anvil sync provider¶
Synopsis: Push/pull against a registered sync provider by id. Same
mechanics as sync github, but the provider id is supplied as a positional
argument so contributor-registered providers (Monday, Linear, custom
trackers, etc.) can be invoked without a dedicated alias.
Positional arguments:
PROVIDER_ID(required) — sync provider id (e.g.github_issues,monday,linear). On miss, prints the list of registered providers.
Flags:
--push(flag) — push local tasks only (skip pull).--pull(flag) — pull remote tasks only (skip push).--watch(flag) — long-running poll loop; Ctrl-C to exit.--fix(flag) — reconcile remote → local on conflicts (forces a pull on conflict).--task TEXT(optional) — scope sync to a single task id.--yes(flag) — auto-confirm conflict prompts.--health(flag) — probe provider; print status; exit.--interval INTEGER(default:60) — poll interval seconds with--watch.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— sync iteration completed.1— unknownPROVIDER_ID, provider instantiation failed, or audit emission catastrophic failure.2— one or more tasks parked awaitingmanual_mergeresolution.
Example:
anvil sync provider github_issues --health
anvil sync provider monday --push --task T015
See also: docs/sync-providers.md for the provider
registration contract; anvil sync github for the
GitHub-specific alias.
Cross-harness¶
anvil mcp-config¶
Synopsis: Print the paste-ready MCP server config block for a target MCP
client, with the anvil server pointed at this checkout's bin/anvil-mcp by
absolute path (not ${CLAUDE_PLUGIN_ROOT}). Generated config exposes the
lean 24-tool execution surface by default. Add ANVIL_MCP_PLANNING=1 to the
emitted server environment when the client needs all 36 tools. The command is
read-only and project-free (mirrors anvil describe):
it never opens a backend, runs from any directory, and only prints config — it
never mutates the client's own settings file. In text mode the config goes to
stdout (paste-clean) and a one-line # paste into <file> hint goes to stderr.
Argument:
CLIENT(required) — one ofclaude-code,cursor,windsurf,cline,vscode,zed,codex,opencode,roo,amp,continue,goose(12 clients). The envelope differs per client: top keymcpServers/servers/context_servers/mcp/amp.mcpServers/extensions, and the format is JSON for most clients, TOML forcodex, and YAML forcontinueandgoose. The inner server spec is usually{command, args[, env]};opencode,continue, andgoosehave their own client-specific shapes (e.g.opencodenests env vars underenvironment, notenv;gooseusescmd/envs).
Flags:
--uv-run(flag) — emit the explicituv run --quiet --project <bin> python -m anvil.mcp_serverinvocation instead of thebash <bin>/anvil-mcpwrapper (use on hosts without bash, e.g. Windows).--root PATH(option) — inject"env": {"ANVIL_ROOT": "<dir>"}to pin the project root. Omitted by default (the client's cwd decides).--json(flag) — emit the standard single-line envelope;datacarries{client, target_file, format, config_text}and nothing goes to stderr.
Exit codes:
0— config printed.2— unknown client (under--json,error.codeisbad_request).
Example:
anvil mcp-config cursor # prints the mcpServers JSON block
anvil mcp-config codex # prints the [mcp_servers.anvil] TOML block
anvil mcp-config continue # prints the .continue/mcpServers/anvil.yaml block
anvil mcp-config --uv-run vscode # explicit uv invocation (no bash)
anvil mcp-config --json cursor | jq -r .data.config_text
See also: AGENTS.md for the MCP-tool ⇄ CLI-command table;
docs/how-to/using-anvil-on-any-harness.md
for the full cross-harness walkthrough.
Hook subcommands (internal — invoked by hooks.json)¶
These commands are called by the shell-free Python dispatcher wired in
hooks/hooks.json; retained bash wrappers in hooks/ call the same
subcommands for compatibility. They are not end-user commands. They are
documented here because contributors writing custom hooks need the flag list.
Every hook subcommand always exits 0: hook
failures must never block the calling tool or session.
anvil hook check-claim¶
Synopsis: Used by hook dispatch check-claim (PreToolUse on Edit / Write /
NotebookEdit) and its legacy hooks/check-claim.sh wrapper. Checks whether
FILE is within the scope of an active claim.
If FILE is in the expected_files of a claim owned by a different actor,
warns to stderr. Silent in every other case.
Flags:
--file TEXT(required) — path of the file about to be modified.--actor TEXT(required) — session actor /session_id.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— always. Errors are silently swallowed; hooks must never block the tool.
Example (equivalent legacy-wrapper call):
anvil hook check-claim --file "src/auth/login.py" --actor "$SESSION_ID"
See also: docs/architecture.md for the hook contract;
bin/src/anvil/cli/hooks.py for the active dispatcher; hooks/check-claim.sh
for the legacy wrapper.
anvil hook record-file-change¶
Synopsis: Used by hook dispatch record-file-change (PostToolUse on Edit /
Write / NotebookEdit) and its legacy hooks/record-file-change.sh wrapper.
Appends a file_changed event to both the SQLite
events table and events.jsonl so the audit log has a record of every file
mutation made during a session.
Flags:
--file TEXT(required) — path of the file that was modified.--tool TEXT(required) — tool name (e.g.Edit,Write,NotebookEdit).--actor TEXT(required) — session actor /session_id.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— always. Errors are silently swallowed.
Example (equivalent legacy-wrapper call):
anvil hook record-file-change \
--file "src/auth/login.py" --tool "Edit" --actor "$SESSION_ID"
See also: bin/src/anvil/cli/hooks.py for the active dispatcher;
hooks/record-file-change.sh for the legacy wrapper.
anvil hook capture-evidence¶
Synopsis: Used by the shell-free PostToolUse dispatcher and the legacy
hooks/capture-evidence.sh wrapper. Appends an attributed JSON record of the
command, exit code, output digest/excerpts, actor, claim identity, and timestamp
to .anvil/.evidence-buffer/<CLAIM_ID>.json. The process must carry the work
packet's exact ANVIL_CLAIM_ID and ANVIL_ACTOR; the active claim owner and
persisted session must match. Missing, stale, or mismatched context writes only
to .evidence-buffer/orphan.json. Stdout/stderr excerpts are truncated to 4000
chars each, while the digest covers full output. Git claims bind their immutable
repository context; non-Git claims bind the current task/PRD snapshot and omit
repository identity.
Flags:
--command TEXT(required) — full bash command string that was run.--exit-code INTEGER(required) — exit code of the command.--stdout-file PATH(optional) — path to a temp file containing the command's stdout.--stderr-file PATH(optional) — path to a temp file containing the command's stderr.--actor TEXT(required) — session actor /session_id.--cwd PATH(hidden) — project directory. Defaults to cwd.
Exit codes:
0— always. Errors are silently swallowed.
Example (legacy wrapper; the shipped manifest dispatches directly):
anvil hook capture-evidence \
--command "pytest tests/test_auth.py" \
--exit-code 0 \
--stdout-file "$STDOUT_TMP" \
--stderr-file "$STDERR_TMP" \
--actor "$SESSION_ID"
ANVIL_CLAIM_ID is intentionally inherited rather than accepted as a command
option: callers cannot select a claim by adding an untrusted argv value. The
subcommand resolves the persisted active claim and derives all durable
attribution from state.
See also: docs/evidence-buffer.md for the buffer
format, descriptive output attachment, and claim-bound proof import;
hooks/capture-evidence.sh.
Additional commands (index)¶
The sections above give full Synopsis/Flags/Exit-codes treatment to the core
lifecycle commands. Anvil ships additional commands — every one real,
--help-documented, and exercised by the test suite — indexed here one line
at a time so this page's single-reference claim holds. Run
anvil <command> --help (or anvil <group> <command> --help) for the live
flag list; full prose treatment may follow in a later pass.
Self-description and cross-harness delivery
anvil describe— Emit a machine-readable manifest of the CLI/MCP command surface: release and source-build identity, schema/API versions, the versioned provider-read operation catalog with packaged schema/fixture resources, every command/tool name, and the exact long options owned by the root, each group, and each leaf command (--human,--json); read-only, needs no project. Release tooling uses the node-levelcli.contractsinventory to validate shipped skill invocations against an independently installed wheel.anvil install <harness>— Deliver anvil's MCP config and instructions to a target harness (codex/openclaw drive their own CLI; pi installs the anvil-pi package viapi install -l; others get a merged MCP block) (--write,--rollback,--root,--automations,--cron-recipes,--finish-gate); dry-run by default. For pi, setANVIL_PI_PACKAGEto a pinnednpm:/git:spec when no anvil checkout is present.anvil repair projection— Rebuild a diverged local projection from the immutable event log after an explicit--yes, retaining an online backup; it verifies the staged and published projections before reporting success.anvil repair project— Dry-run a missing project registration from unanimous immutable PRD-content ownership; with--yes, retain an online backup and append one currentproject.createdevent after replay verification. It refuses existing project history, malformed or divergent owners, and unsafe state artifacts.anvil repair local-event --receipt recovery.json --json— Preview restoring one interior local event omitted after an audited write failure. The original line must come from a matching historical backup. The live projection must equal baseline replay, apart from the precisely recognized legacyroot_setdefault/column-placement representation. Recovery preserves the live schema and every existing row, including those legacy representations; only the missing event row is added. The strict reader remains unchanged.
A reviewed receipt has exactly schema_version (integer 1), project_id,
event_id, log_sha256, event_line_sha256, backup_path, and
audit_record_sha256. Digests are lowercase SHA-256: log/line digests cover
their exact bytes (including the line ending); the audit digest covers Anvil's
canonical JSON encoding of the matching write_failed_after_log record.
Keep operator receipts and backups outside public Git. A supplied hash alone
is not evidence of provenance; review the original backup and matching audit.
After independent review, --apply --exclusive-access publishes the verified
recovery. --exclusive-access attests that ALL other Anvil clients and
operations, including backup/restore, are stopped for the entire operation;
the command does not stop them. Upgrading a peer alone is insufficient.
Keep peers stopped after an interruption until explicit resume finishes.
Pending-marker guards reject newly started accesses; they do not cancel
operations already in flight. Older MCP servers must be replaced before
reconnecting. Unrelated serving processes do not need restarting.
Publication retains the live log and database inodes and durable before/after
copies. An interruption leaves .local-event-recovery.json; normal access
refuses until anvil repair local-event --resume --exclusive-access --json
safely completes the recorded operation. Do not delete the marker or run
another repair around it. Unexpected state or unsafe artifacts cause refusal.
Current bounds are 64 MiB per input artifact, 2 MiB per event/audit line, and
64 KiB per receipt. No S3 upload, invented event, or PRD approval occurs.
PRD authoring extras
anvil prd list— List every PRD in the project (the multi-PRD entry point), marking the default with*(--json). Human output omits an empty legacy title; JSON always includestitleand returns""for such rows. Listing is read-only and never backfills title data from source; re-runprd parseexplicitly to persist a canonical title.anvil prd find-decisions— Scan a PRD for[NEEDS DECISION]markers, open questions, and missing acceptance-criteria/verification fields (--prd/ANVIL_PRD,--file,--json); read-only, always exits 0.--fileselects markdown content while--prdremains the task/state partition used for missing-field detection and reported scope.anvil prd resolve-decision DECISION_ID— Back-propagate a resolved decision into the PRD source and record aprd.decision_resolvedevent bound to the effective partition (--resolution/-r,--by,--prd/ANVIL_PRD,--file,--json). The returned parse continuation repeats both the effective PRD and custom file selection.
Planning extras
anvil assumptions— Rank PRD requirements byblast_radius x uncertaintyso the riskiest, least-certain requirements surface before planning (--limit/-n,--json); advisory only, never mutates state. This is a requirement-uncertainty report, distinct from the typedA###records authored under a PRD's## Assumptionssection.anvil deps— Validate a batch of dependency-edge edits before mutation, rejecting the whole request with no changes on any cycle, unknown task, or self-loop. Use repeatable--add SOURCE->TARGET/--remove SOURCE->TARGET; the arrow form is required when either scoped task ID contains:. TheSOURCE:TARGETshorthand remains supported only where both IDs are unscoped and the separator is unambiguous. Select the source-task owner with--prd <id>(orANVIL_PRD; a single/default PRD resolves when omitted). Sources must belong to that PRD; targets may belong to another PRD. After prevalidation, onetask.dependencies_batch_editedevent carries every changed task plus its exact prior ordered dependencies. State revalidates ownership, endpoints, stale preconditions, and the final graph under the append lock, then commits every edit together. A no-op batch emits no event. JSON success includes the resolvedprd_idwithchanged,added, andremoved. If the backend refuses the atomic append,deps --jsonreturns the fixedevent_rejectedmessagedependency update was rejected by state validation.; human output uses the same text. Neither surface exposes the raw backend reason. Malformed edges, unknown tasks, self-loops, and cycles likewise return fixed, bounded diagnostics on both surfaces; raw edge and task values are never reflected in an error. A batch is capped at 10,000 total--addplus--removeedges; cap+1 is rejected with fixedbad_requestoutput before state access.
Dependency-batch refusals are bounded and do not expose raw payload or
backend validation details. A rejected batch adds nothing to events.jsonl
and leaves the complete dependency projection unchanged.
Optional Jev assistance (default off; never proof or action authority)
anvil jev status— Inspect effective, non-secret policy without reading a credential or probing the provider (--json).anvil jev enable CAPABILITY— Enable one capability in project config;--allow-apiexplicitly grants API permission without changing the planner.anvil jev disable [CAPABILITY]— Disable all Jev calls or one capability; preserves the configured provider and unrelated settings.anvil jev evaluate CAPABILITY --input FILE— Evaluate deliberately selected JSON only with--allow-export;--no-jevoverrides enablement. Results include typed answers, model/rubric/input provenance, and attempted-egress status.anvil jev assess --file FILE— Keep local PRD findings separate from optionally enabled, explicitly exported semantic acceptance-criterion advice.anvil jev audit --input FILE— Evaluate up to 16 selected advisory items, preserving independent results, source/policy checks, and a request count.anvil jev bridge— Stateless bounded stdin/JSON contract for a trusted local consumer that owns authorization and export policy; not a network authorization service. No project initialization or state mutation.
All seven accept --json. See Optional Jev advice
for schemas, privacy, provenance, and explicit enable/disable workflows.
Diagnostics and health (read-only)
anvil doctor— One-shot health diagnosis: schema/db reachability, config parse status, active/stale claims, replay integrity, reconciliation drift (--json); exits non-zero when any finding is ERROR-level. With--preflight [--prd <id>], adds PRD-parse, unresolved-decision, and git tree-state probes plus a finalPREFLIGHT: GO/NO-GOverdict line (JSON:data.preflight/data.go) — the GO/NO-GO gate to run before a long workflow.anvil merge-check <task>— Pre-merge freshness report for the task's claim branch: behind-count vsorigin/<default>(offline degrades to the local base) and agit merge-treetextual-conflict probe; with--run-checks, runs the task's verification commands against the would-be merge result in a throwaway worktree (--json); exit 1 when stale, conflicted, or a merged-tree check fails. See also themerge_checkconfig knob onanvil apply.anvil progress <task> <phase>— Record a structured progress phase (build,tests, …) as aprogress.notedaudit event; task status never changes and no claim is required (--detail,--actor,--json). For a context-bearing active claim,--attestation-file <path>instead verifies and records one canonical claim-bound progress artifact. An accepted artifact reports its digest, generation, and trust mode and is consumed once by the next renewal; free-textprogress.notedevents never authorize renewal. See Attesting progress from an external writer for the exact canonical envelope and a reproducible generator.anvil statusshows each active claim's latest phase, elapsed time, and lease-expiry countdown.anvil drift— Report intent/state/filesystem-git divergence (orphan branches, orphan worktrees, orphan packets, stale claims, vanished expected files) (--json); always exits 0 — a report, not a gate.anvil graph— Emit the task dependency/state graph as Mermaid, JSON, or a text summary (--format text|mermaid|json,--scope all|feature|taskwith--target,--json).anvil conflicts— List persisted conflict groups — tasks whoselikely_filesoverlap (--format text|json).anvil notify-digest— Print a one-line needs-review/blocked/ leases-expiring-soon summary, staying silent when the queue is clean; built for cron--announcejobs (--json, incl.expiring_soon); always exits 0.
Native-harness gates (read-only, default-open; built for
OpenClaw/Codex-style before_tool_call / before_agent_finalize hooks)
anvil claim-guard— Check whether an actor holds a claim covering the file(s) it is about to edit before a mutating tool runs (--actor,--filerepeatable,-q/--quiet,--json; exit 2 = block, no claim held).anvil gate-check— Finish-gate: block an agent from ending its turn while any of its claimed tasks has incomplete verification evidence (--actor,-q/--quiet,--json; exit 2 = block).
Data lifecycle and maintenance
anvil replay --from-events PATH --into PATH— Rebuild canonical state from an events log into a scratch SQLite database; refuses to target the livestate.db.anvil run-workflow NAME— Run a declarative.anvil/workflows/<name>.yamlworkflow to completion through anvil's governed create → claim → run → submit → apply transitions, then exit. The owning PRD must be exactly approved for its current canonical source before workflow task creation and at each task-claim pre-log boundary.anvil backup— Pushevents.jsonl(and, with--include-db,state.db) to the configured S3durable_store.anvil restore— Pullevents.jsonlfrom S3 and replay it intostate.db(destructive;--yes/-yskips the confirmation prompt).anvil migrate-events --to git— Rewriteevents.jsonlinto hash-chained, merge-friendly git-backed storage (dry-run by default;--yesapplies).anvil migrate state— Upgrade.anvil/state.dbto the current engine schema version, backing it up first (dry-run by default;--yesapplies;--json).anvil migrate-workspace— One-time copy of legacy in-repo.anvil/state into the HOME-workspace layout; never clobbers an existing workspace, copies rather than moves (dry-run by default;--yesapplies;--json).
Proof verification
anvil proof verify PROOF_FILE— Verify a signedAcceptanceProofoff-host: detached Ed25519 signature, signer fingerprint, and trust-list membership (--trust,--project,--json).
Additional hook subcommands (internal — see Hook subcommands above for the contract)
anvil hook dispatch NAME— Shell-free dispatcher forhooks/hooks.json(detect-state,check-claim,record-file-change,capture-evidence,heartbeat); parses the hook JSON payload from stdin and calls the matching subcommand. Always exits 0.anvil hook stop-gate— Opt-in Stop-hook evidence gate for Codex/Claude Code: blocks ending the turn (exit 2,{"decision":"block",...}on stdout) while a claimed task has no submitted evidence; not wired by default (--actor).anvil hook heartbeat— PostToolUse lease heartbeat: renews the actor's active claim lease(s) on tool activity so a lazy lease stays fresh (--actor); always exits 0.