Verbs

agentproto review

agentproto review run    [--binding <name>] [--cwd <dir>] [--manifest <path>]
                         [--base <ref>] [--head <ref>] [--nocache] [--supersede]
                         [--pr <github-pr-url>] [--headless] [--annotate github]
                         [--json]
agentproto review verify [<attestation.json | dir>] [--cwd <dir>]
                         [--manifest <path>] [--base <ref>] [--head <ref>]
                         [--binding <name>] [--verdict pass|block|incomplete|any]
                         [--if-exported] [--allowed-signers <file>]
                         [--require-signed] [--annotate github] [--json]
agentproto review init   [--cwd <dir>] [--ci github] [--pack <ref> [--as <ns>]] [--json]
agentproto review key    [show] [--principal <id>] [--cwd <dir>] [--json]

CLI surface of the review primitive: a repo's REVIEW.md declares check lanes (command lanes and agent reviewer lanes) and named bindings (local, ci, …); a run folds them into a verdict — pass, block, or incomplete — bound to the manifest sha and the git range in an attestation. The daemon side is the review_run / review_status / review_cancel / review_ledger / review_export / review_pr MCP tools.

Exit codes

Hooks and CI key off these, so a rejection is never confused with a review that didn't reach a verdict:

CodeMeaning
0pass
1block — a blocking lane failed
2incomplete — a lane timed out / was skipped, or the daemon wasn't reachable. Not a rejection: fix and retry. A run cancelled by --supersede (or review_cancel) records no verdict or attestation at all and also exits 2.
3the review could not run (bad REVIEW.md, unresolvable range)
4no attestation for the range (verify only)
5--if-exported and the manifest declares no verdict.exportDir (verify only)
6signature invalid, or missing when --require-signed (verify only)
64usage error

Transient reviewer errors

An agent lane whose reviewer turn ends in a transient error (a dropped socket, a 5xx, an overloaded provider) is retried once, in a fresh reviewer session that shares the lane's timeoutMs. Credential, quota and unknown-model errors are never retried. Set review.laneRetries in the daemon config (0 disables, max 5; default 1). A lane that still fails settles skipped with the adapter's own error text and the attempt count.

Reviewer fallback (fallbackPresets)

An agent check may list fallbackPresets: [<preset>, …] next to its preset (also accepted on a uses[] entry and in uses[].overrides.<id>; an override replaces the uses[] value). When the reviewer is unavailable the lane runs on the next preset in [preset, ...fallbackPresets], in order; the per-preset retries above run on each one first, and the whole chain shares the lane's single timeoutMs deadline.

"Unavailable" is transport-class only: a spawn failure, a turn that ended in an error (including quota or auth errors), an empty turn, or a reviewer session that exited before finishing. It never falls back after a reviewer produced a verdict (a block from any reviewer is final), a timeout, a cancel, an unknown preset, or an unreadable verdict file. OpenRouter stays refused: a refused preset is not skipped over, and listing an OpenRouter preset in fallbackPresets fails that step closed — nothing is ever added to the chain implicitly.

The lane's preset, model and sessionId name the reviewer that actually produced the verdict; each unavailable one before it is recorded with its error in the lane's fallbacks: [{ preset, error }] and shown in the review output ([kimi/…] after glm unavailable). If every preset in the chain is unavailable the lane settles skipped (verdict incomplete) and its error lists each preset tried with its error. A preset may appear only once in [preset, ...fallbackPresets] — a duplicate is a manifest error.

run

Runs the binding over merge-base(<target.base>, HEAD)..HEAD (or --base/--head). By default it goes through the local daemon: review_run with wait: false, then review_status polls until the run settles. Agent lanes spawn child reviewer sessions and the attestation is written to the daemon's ledger (~/.agentproto/reviews).

FlagDescription
--binding <name>Binding to run. Default: the sole binding, or default.
--supersedeCancel the daemon's in-flight review of an older head of the same repo + binding + base (same checkout, or an ancestor head). Cancelled runs record nothing. What a pre-push gate wants.
--pr <url>Record the PR (https://github.com/<owner>/<repo>/pull/<n>) in the attestation and as the ledger entry's PR link.
--headlessRun in-process, no daemon: command lanes run; agent lanes settle skipped, so a binding with an agent lane is incomplete. The CI mode.
--annotate githubAlso print GitHub Actions ::error / ::warning lines — block and incomplete are distinct annotations.
--nocacheIgnore a cached ledger verdict for the same key.
--jsonPrint the run view (+ exitCode) as JSON on stdout.

The requesting session is recorded as attestation.requester.sessionId when AGENTPROTO_SESSION_ID is set (MCP callers get their callerSessionId), along with the head commit's author.

verify

Checks an exported attestation against what this checkout sees: the sha of REVIEW.md, the range, the repo remote, internal consistency (range sha, the verdict re-folded from its lanes) and the verdict (default pass). With a directory — default the manifest's verdict.exportDir — it picks the attestation for the range head, or for HEAD^ when HEAD only adds files under that directory (committing the export). Exit 0 verified, 1 invalid, 4 no attestation for the range, 5 (--if-exported) no exportDir declared, 6 signature invalid or missing when --require-signed.

FlagDescription
--allowed-signers <file>SSH allowed_signers file to verify the attestation's signature against. Defaults to .agentproto/allowed_signers in the repo root when the file exists. An invalid signature always exits 6; a missing signature (or no allowed_signers file) only exits 6 when --require-signed is also set.
--require-signedFail (exit 6) if the attestation has no signature, instead of accepting unsigned attestations silently.

init

Wires a repo in, idempotently (a second run reports "already initialized — nothing to do"):

  • REVIEW.md at the repo root if absent — one command lane (<pm> test when package.json has a test script, else git diff --check {base} HEAD), one commented-out agent lane, a local binding on pre-push.
  • A pre-push hook in core.hooksPath (husky's .husky/_ resolves to .husky) or git's hooks dir. The gate is a managed script, agentproto-review-pre-push, called from a marked block in pre-push. An existing shell hook gets the block appended — the original is preserved and runs first; a non-shell hook is left alone with instructions. The gate runs agentproto review run --binding local --supersede over the merge-base with the remote's default branch (AGENTPROTO_REVIEW_BASE overrides the ref). Bypass once with git push --no-verify.
  • --pack <ref> [--as <ns>]: adds a uses: entry for a review pack to REVIEW.md (creating the file first if absent), namespaced <ns> (default: derived from the ref). Idempotent by pack ref — a second --pack with the same ref is a no-op regardless of --as. A git ref must be git+https://<url>#<40-hex-sha>; the pin starts at the FIRST #.
  • --ci github: a ci binding and .github/workflows/review.yml, which runs review run --headless --binding ci on pull_request and then review verify --if-exported. An incomplete headless run (agent lanes can't run in CI) passes only when a verified exported attestation covers the PR range; otherwise it fails with a dedicated review incomplete annotation.

key

agentproto review key
agentproto review key show --json
agentproto review key --principal [email protected]

Prints the daemon install's review signing key: its fingerprint and the allowed_signers line ready to paste into .agentproto/allowed_signers (or pass to --allowed-signers). The keypair is generated at ~/.agentproto/keys/review_ed25519 on first use; it is a shared host file, not per-daemon state, so this command never requires a running daemon.

FlagDescription
--principal <id>Identity claimed in the allowed_signers line (default: git config user.email in --cwd's repo).
--cwd <dir>Repo root for resolving the default principal.
--jsonEmit { fingerprint, principal, publicKeyPath, allowedSignersLine }.

Examples

agentproto review init --ci github
agentproto review run --binding local --supersede
agentproto review run --headless --binding ci --annotate github --pr "$PR_URL"
agentproto review verify --if-exported
agentproto review verify --allowed-signers .agentproto/allowed_signers --require-signed
agentproto review key