Skip to content

Run Anvil in CI

Run candidate generation, review, assurance, and release planning as separate stages. Preserve the bundle hash and each stage’s evidence so a later check cannot be mistaken for approval of different bytes.

Keep uncertain operations pending review. CI should report a failed gate and its diagnostic rather than approve an operation to make the pipeline pass.

StageAutomatedHuman decision
Capture and compileYesNo
Lint and readiness assessmentYesResolve business-semantic gaps
Operation and capability approvalNo automatic approvalYes
Static and executable assuranceYesReview failures and waivers
Target and deployment input generationYesReview IAM, identity, network, and secrets
Release-plan preparationYes after gatesApply through the existing delivery system

Pin Node.js and the repository’s package manager version, install from the lock file, and build the CLI:

Terminal window
corepack enable
pnpm install --frozen-lockfile
pnpm build

Compile from the reviewed source and manifest:

Terminal window
pnpm anvil compile api/openapi.yaml \
--manifest api/anvil.yaml \
--service inventory \
--out generated/inventory

The compiler captures local source bytes into a content-addressed snapshot before generation. Persist the source snapshot and candidate bundle together if later jobs run in a different workspace.

Terminal window
pnpm anvil lint generated/inventory
pnpm anvil assess generated/inventory --check --fail-on blocked
pnpm anvil status generated/inventory

Choose the readiness threshold intentionally:

  • blocked is the minimum sensible failure threshold;
  • human-decision is useful when every unresolved decision must stop the candidate; and
  • refinement-required is the strictest quality gate.

assess reports blockers even without --check; the flag is what turns the selected threshold into a non-zero exit code.

Do not run anvil approve automatically based only on a successful compile. Approval belongs in a reviewed manifest change or an explicit review workflow.

Run all assurance commands against the same bundle directory:

Terminal window
pnpm anvil certify generated/inventory
pnpm anvil selftest generated/inventory
pnpm anvil conformance generated/inventory
pnpm anvil simulate generated/inventory
pnpm anvil status generated/inventory --require release

The order matters. Each report binds to the bundle’s current content hash. Do not regenerate or patch files between lanes. If the bundle changes, start the assurance sequence again.

What each lane catches:

  • certify: missing, unexpected, or inconsistent generated bytes;
  • selftest: MCP transport, argument fidelity, and runtime refusal behavior;
  • conformance: semantic drift across CLI, MCP, skill, hooks, and runtime;
  • simulate: gaps in the safety matrix and controls that fail to detect injected regressions.

4. Generate deployment inputs outside the compiler output

Section titled “4. Generate deployment inputs outside the compiler output”

Target kits and infrastructure values become part of the release identity. Do not hand-edit the generated bundle after certification.

For durable writes, inspect the ledger contract:

Terminal window
pnpm anvil deploy ledger generated/inventory \
--project example-project \
--database example-anvil-ledger \
--database-mode shared

For an agent platform, generate its target profile with the exact surface, auth, project, and location choices required by that platform. Store secret values in the deployment system, not in AIR or the manifest.

Run the assurance sequence again if target or ledger artifacts are part of the certified hash and changed after certification. anvil status will report stale evidence and name the first required action.

Terminal window
pnpm anvil publish generated/inventory --env prod
pnpm anvil status generated/inventory

publish prepares a plan and records the evidence snapshot. It makes no cloud API calls and does not establish live readiness. The expected final state is operator-action-required until your delivery system applies the plan and live checks complete.

Production should not use --allow-incomplete-evidence. That waiver exists for explicit non-production work and remains visible in the plan.

When an upstream contract changes, detect semantic drift against the stored bundle:

Terminal window
pnpm anvil sync api/openapi.yaml generated/inventory
pnpm anvil drift list generated/inventory

A description edit and a dropped confirmation are different events. Review the drift severity, update the source or manifest, recompile, and rerun assurance. Marking a drift record reviewed does not mutate AIR or restore stale evidence.

name: anvil-contract
on:
pull_request:
paths:
- api/**
- package.json
- pnpm-lock.yaml
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: corepack enable
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: >-
pnpm anvil compile api/openapi.yaml
--manifest api/anvil.yaml
--service inventory
--out generated/inventory
- run: pnpm anvil lint generated/inventory
- run: pnpm anvil assess generated/inventory --check --fail-on blocked
- run: pnpm anvil certify generated/inventory
- run: pnpm anvil selftest generated/inventory
- run: pnpm anvil conformance generated/inventory
- run: pnpm anvil simulate generated/inventory
- run: pnpm anvil status generated/inventory --require release

Adapt artifact retention and deployment to your environment. If jobs are split, transfer the entire candidate bundle and source snapshot without modification; do not reconstruct only selected files.

  • One reviewed source and manifest produce one candidate bundle.
  • No job edits generated files.
  • Approval is never inferred from a green build.
  • All assurance reports refer to the same bundle hash.
  • Secrets are resolved only by the deployment/runtime environment.
  • Release planning and live deployment remain separate states.
  • A source change invalidates dependent evidence until recompilation and assurance complete.