The review gate is what makes vouch vouch. This doc explains it from the operator’s seat — what you do, what the agent does, and what happens on disk. For the normative state machine, see spec/review-gate.md. For why we built it this way, see VEP-0001.

Mental model

   AGENT                          YOU                           DISK
   ─────                          ───                           ────
                                                            (empty)

   kb_propose_claim ──────────►   "you have 1 pending"
                                  vouch pending
                                  vouch show prop-…
                                                            .vouch/proposed/prop-….yaml
                                                                  ↑ gitignored
                                  vouch approve prop-…


                                                            .vouch/claims/auth-uses-jwt.yaml
                                                            .vouch/decided/prop-….yaml
                                                                  ↑ committed
The agent writes immediately (fast). You decide later (in bulk, on your schedule, in a PR-shaped review). The durable artifact appears only after you decide.

The everyday flow

As an operator

vouch status               # snapshot
vouch pending              # what's waiting
vouch show <id>            # full proposal details
vouch approve <id>         # → durable artifact + decided/
vouch reject  <id> --reason "duplicates auth-uses-jwt"
Then commit:
git add .vouch && git commit -m "kb: review batch"
Cadence matters. Approving daily keeps proposals fresh; approving weekly is fine; approving never is the failure mode — your KB just collects noise the agent can’t see (since proposed/ is local).

As an agent

The agent’s tools are kb_propose_* for writes, kb_search / kb_context / kb_read_* for reads, and the lifecycle helpers (kb_supersede, kb_contradict, kb_archive, kb_confirm, kb_cite) for adjustments to already-approved knowledge. Agents don’t have an approve tool. They cannot self-promote.

Self-approval (and how to let it)

By default, a proposal cannot be approved by the same actor that filed it. The server compares VOUCH_AGENT (the env var the host process sets) against the proposal’s proposed_by; matching identities trip the forbidden_self_approval error. In some setups — a fully autonomous agent running in a sandbox — you want self-approval. Flip it in .vouch/config.yaml:
review:
  approver_role: trusted-agent
The audit log still records the actor. You’re trading the gate for auditability-only.

When approvals are wrong

You will approve something you shouldn’t. The remedies:
  • Archive the bad claim (vouch archive <claim-id>). It stays in the file system and audit log but status: archived.
  • Supersede with a corrected version (vouch supersede <old> <new>). Best when the idea was right and the details were wrong.
  • Redact, for the rare case where the content itself is harmful (PII, a leaked secret). Redaction zeros the body and is not reversible.
You cannot un-approve. The decision is part of the record. This is on purpose.

When rejections are wrong

If you reject a proposal that turned out to be correct, the agent (or you) can re-propose. The new proposal gets a new id. The old rejected proposal stays in decided/ — the history shows you rejected once, then accepted later. That’s honest.

Lifecycle methods bypass the gate (and that’s fine)

These methods write directly to disk without going through proposed/:
  • kb.supersede — links an old claim to a new one
  • kb.contradict — marks two existing claims as conflicting
  • kb.archive — flips status
  • kb.confirm — bumps last_confirmed_at
  • kb.cite — appends an evidence id to a claim
Why no gate? Because none of these create new assertions. They metadata-tag already-reviewed knowledge. If the agent wants to assert something new, it must propose. If it wants to mark something it just read as “still true”, kb.confirm is fine — the underlying claim was already approved. This narrow exception keeps the everyday agent UX fluid. Agents constantly need to mark stale claims as such; gating that would create review overhead with no protection benefit.

CI / bots

You can approve from CI:
echo '{"id":"r1","method":"kb.approve","params":{"proposal_id":"prop-…"}}' \
  | vouch serve --transport jsonl
Whether you should is a different question. Auto-approval re-creates the problem the gate solves. If you do it:
  • Restrict to a specific proposed_by (one bot, not all agents).
  • Restrict to a specific kind (e.g. only entity proposals, never claim).
  • Audit weekly.
  • Be ready to revoke when the bot starts proposing nonsense.
See adapters/jsonl-shell/ for an example auto-approver.

Common questions

Q: I committed proposed/ once by accident — does it matter? Mostly cosmetic. The proposals are decided one way or the other on next review; you can remove the entries with git rm afterwards. Update your local .gitignore so it stops happening. Q: Can I approve in bulk? Today, one at a time. --batch is planned for 0.1 (ROADMAP). Until then, vouch pending --json | jq -r '.[].id' | xargs -n1 vouch approve is the workaround — read what you’re approving first. Q: What if I want a softer gate — “warn, don’t block”? You don’t. If you want soft, use a tool without a gate. vouch’s identity is the gate; making it optional makes vouch worse at the one thing it does.