{
 "generated_at": "2026-10-08T00:00:00Z",
 "binary": "anvil",
 "port": 8711,
 "global_flags": [
  [
   "--registry <url>",
   "Registry address; also ANVIL_REGISTRY in the environment."
  ],
  [
   "--token <t>",
   "Access token; also ANVIL_TOKEN. Never put it in a repo .anvil.toml."
  ],
  [
   "--channel <c>",
   "Default channel for the command; also ANVIL_CHANNEL."
  ],
  [
   "--json",
   "One JSON object per line on stdout, diagnostics on stderr."
  ]
 ],
 "commands": [
  {
   "name": "push",
   "synopsis": "anvil push <name>@<version> <file> [--meta k=v]... [--channel dev|staging|release]",
   "summary": "Upload a payload and create the immutable artifact record for that coordinate.",
   "group": "write",
   "flags": [
    [
     "--meta k=v",
     "Add one entry to the manifest meta map; repeatable, 4 KiB total."
    ],
    [
     "--channel <name>",
     "Land the artifact directly in that channel instead of dev."
    ],
    [
     "--sign-as <key-id>",
     "Pick the signing key when the store trusts more than one."
    ],
    [
     "--if-absent",
     "Turn a conflict on an existing coordinate into a no-write success."
    ],
    [
     "--progress",
     "Write a byte counter to stderr every 500 ms."
    ]
   ]
  },
  {
   "name": "pull",
   "synopsis": "anvil pull <name>@<version|channel> [--out <path>] [--no-verify]",
   "summary": "Download a payload and check its digest and signature before it is renamed into place.",
   "group": "read",
   "flags": [
    [
     "--out <path>",
     "Destination file or directory; default is the recorded basename."
    ],
    [
     "--no-verify",
     "Skip both checks; reserved for recovering from a lost key, prints a warning."
    ],
    [
     "--manifest",
     "Write manifest.json and manifest.sig next to the payload."
    ]
   ]
  },
  {
   "name": "promote",
   "synopsis": "anvil promote <name>@<version> --to <channel> [--pin] [--note <text>]",
   "summary": "Append a channel move to the artifact history; forward or backward.",
   "group": "write",
   "flags": [
    [
     "--to <channel>",
     "Target channel, required; moving backwards is recorded the same way."
    ],
    [
     "--pin",
     "Mark the artifact exempt from retention until --unpin."
    ],
    [
     "--note <text>",
     "Free text on the history entry, up to 240 characters."
    ],
    [
     "--dry-run",
     "Print the entry that would be appended and exit without writing."
    ]
   ]
  },
  {
   "name": "ls",
   "synopsis": "anvil ls [<name>] [--channel <channel>] [--limit <n>] [--since <date>]",
   "summary": "List artifact names, or the versions of one name, newest first.",
   "group": "read",
   "flags": [
    [
     "--channel <channel>",
     "Restrict output to versions carrying that label."
    ],
    [
     "--limit <n>",
     "Cap the number of rows; default 50, 0 means no cap."
    ],
    [
     "--since <date>",
     "ISO date or a relative span such as 14d, matched against created_at."
    ]
   ]
  },
  {
   "name": "show",
   "synopsis": "anvil show <name>@<version|channel> [--history] [--meta]",
   "summary": "Print one artifact manifest in full, with the digest and the matching key id.",
   "group": "read",
   "flags": [
    [
     "--history",
     "Expand stage_log into one line per move with timestamps and notes."
    ],
    [
     "--meta",
     "Print only the meta map, so a build script need not parse the rest."
    ]
   ]
  },
  {
   "name": "verify",
   "synopsis": "anvil verify <name>@<version> [--local <path>] [--key <key-id>]",
   "summary": "Recompute the digest and check the detached signature against the trusted keys.",
   "group": "read",
   "flags": [
    [
     "--local <path>",
     "Verify a store directory on disk instead of asking a server."
    ],
    [
     "--key <key-id>",
     "Demand a match against that specific key; any other is a failure."
    ],
    [
     "--quiet",
     "Suppress output and leave only the exit code, for a shell conditional."
    ]
   ]
  },
  {
   "name": "prune",
   "synopsis": "anvil prune [<name>] [--channel <channel>] [--yes] [--keep <n>] [--older-than <span>]",
   "summary": "Apply retention rules and delete what they no longer protect.",
   "group": "write",
   "flags": [
    [
     "--yes",
     "Perform the deletion; without it the command only reports."
    ],
    [
     "--keep <n>",
     "Override the channel count rule for this run only."
    ],
    [
     "--older-than <span>",
     "Override the age rule, taking spans such as 90d or 18w."
    ],
    [
     "--include-pinned",
     "Let pinned artifacts be considered; refused unless one name is given."
    ]
   ]
  },
  {
   "name": "import",
   "synopsis": "anvil import --from-dir <dir> --pattern <glob> [--name <name>] [--dry-run]",
   "summary": "Read existing files from a directory and push them with versions from their names.",
   "group": "write",
   "flags": [
    [
     "--from-dir <dir>",
     "Source directory, one level deep by default, recursive with --recursive."
    ],
    [
     "--pattern <glob>",
     "Filename pattern with the capture tokens {name} and {version}."
    ],
    [
     "--mtime-as-created",
     "Use each file's modification time for created_at instead of import time."
    ],
    [
     "--dry-run",
     "Print the derived mapping and write nothing."
    ]
   ]
  },
  {
   "name": "serve",
   "synopsis": "anvil serve --root <dir> [--listen <addr:port>] [--tls-cert <f> --tls-key <f>]",
   "summary": "Run the registry itself from a store directory.",
   "group": "server",
   "flags": [
    [
     "--root <dir>",
     "Store directory, required, and the process must own it."
    ],
    [
     "--listen <addr:port>",
     "Bind address; default 127.0.0.1:8711."
    ],
    [
     "--store <url>",
     "Keep payloads in object storage over HTTP while manifests stay local."
    ],
    [
     "--read-only",
     "Accept reads and refuse every write, including promotion."
    ],
    [
     "--migrate-store",
     "Upgrade a 1.x store directory to format 4 in place, then keep serving."
    ]
   ]
  }
 ],
 "exit_codes": [
  [
   0,
   "success",
   "the command did what it said"
  ],
  [
   1,
   "usage or configuration error",
   "unknown flag, unreadable config, missing registry address"
  ],
  [
   2,
   "coordinate conflict",
   "that name and version already exist and --if-absent was not given"
  ],
  [
   3,
   "digest mismatch",
   "stored bytes do not hash to the recorded digest"
  ],
  [
   4,
   "signature not trusted",
   "no trusted key verifies the manifest, or it is unsigned"
  ],
  [
   5,
   "key file rejected",
   "wrong permissions, wrong length, or a public key where a private one belongs"
  ],
  [
   6,
   "registry refused or unreachable",
   "bad token, request body limit, no route to the host"
  ],
  [
   7,
   "empty selection",
   "the name, version or channel matched nothing"
  ]
 ]
}