@promptia-labs/agent-receipt
v0.24.0
Published
AI work audit receipts — verifies and records what an AI coding agent actually changed in your local git tree. Provides git-based evidence for compliance review (not a compliance guarantee).
Readme
agent-receipt
npm
@promptia-labs/agent-receipt· CLIagent-receipt· local-first, no account, no server
Contract an AI coding session → verify what actually happened → keep a sealed receipt.
agent-receipt is a local audit tool for AI coding sessions (Claude Code / Cursor): declare what the agent may touch (a scope contract — allowed / denied paths), let it work, then close the session with a verdict backed by the real git diff — never the agent's own claims:
agent-receipt done: my-task
판정: PASS ✅ (게이트 판정 — 점수 아님) # a gate — PASS / PASS_WITH_WARNINGS / FAIL / INCOMPLETE. Not a score.
계약: kind=implementation · allowed 1 globs · denied: .env*
· 계약 준수 · 필수 검사 통과 · 경고 신호 없음 # every verdict is backed by per-item factsThree audits, one receipt:
| Audit | Question it answers | Receipt it produces |
|---|---|---|
| Change Audit | What did the AI actually do to my git repo? — did it stay inside the contract, what landed, what was bypassed, plus beyond-git actions (even failed/denied attempts) | Work Receipt — schemaVersion: "1.0", git-measured, tamper-evident |
| Evidence Audit | Is what the AI said actually true? — quotes, numbers, dates, git facts, versions, cited receipts… 15 deterministic check kinds, no LLM judging LLMs | kind: "verification-receipt" (evidence/1) |
| Cost Audit (supporting) | What did this session actually cost? — real per-message usage from the local transcript, where it leaks, when a fresh session is cheaper | agent-receipt cost — an estimate, not an invoice |
Why trust it: deterministic verdicts (same input → same verdict) · sealed receipts (sha256, replayable) · third-party seal (Rekor) · in-toto attestation · Merkle transparency log — all local, no account, no server.
Honest scope on cost:
costreads Claude Code's local transcript (real per-message usage) and applies list pricing — an estimate, not an invoice (no discounts/intro). It shows where the money goes and signals when a fresh session would be cheaper; it does not cut your bill directly, and it never shows a made-up "savings" number. High cache-read is not waste — the cache saved you ~90%.
agent-receipt proves — and, if you opt in, prevents. Its core job is mechanical, after-the-fact evidence — of what landed in git, and of whether stated evidence matches its sources (git-based evidence for compliance review — not a compliance guarantee). On top of that, an opt-in real-time scope guard (
policy guard: block) stops writes to contract/policy-forbidden paths before the tool runs — the denied attempt itself becomes chained evidence. Default stays warn-only: nothing blocks unless you ask it to.
The receipt is review-ready (v0.20): it opens with a ten-second executive block (plain-sentence contract KO/EN · four review buckets in the reviewer's reading order · session timeline), carries an optional self-reported --objective, and closes with a recorded human decision — review approve | reject | note. The recipient re-checks the whole hand-off offline in one command (verify-proof), and the pile becomes a filterable local inbox.
One-page setup (contract → guard → receipt → PR comment): docs/QUICKSTART.md
Quick Start
Install globally — first time? agent-receipt quickstart prints exactly what each setup step writes (and only writes under --write). The everyday flow is four verbs:
npm install -g @promptia-labs/agent-receipt
cd <your repo>
agent-receipt quickstart --write # contract + policy + capture hooks (print-first; idempotent)
agent-receipt begin --kind implementation --objective "refund API, no billing-model changes"
# … the agent works …
agent-receipt done # 4-value verdict + receipt + ordered next steps ①②③
agent-receipt share # ten-second proof HTML (= share-proof · --client / --bundle)
agent-receipt review approve --receipt <p> # or: reject / note — recorded on the receipt (self-reported)
agent-receipt inbox # the pile, filterable (FAIL only · denied-path · unreviewed …)
agent-receipt verify-proof <bundle-dir> # recipient side: re-check a hand-off bundle offlineThe longer loop is still there when you want it — commit-check (pre-commit gate), audit-pack (evidence bundle), reset (clear baseline):
Re-verify a saved bundle later with agent-receipt replay --pack <dir>. Full command list: agent-receipt help --all.
The lower-level commands (
start/prompt/verify/check/claims/receipt) still exist —beginanddonesimply compose them. See Commands below. Feature coverage vs the design docs: coverage; recipes (worktree/CI/hooks): recipes.
Once installed, the CLI is invoked as agent-receipt. (The single-letter ag alias was dropped to avoid clashing with other tools.)
Verification engine quick start
The second track — checking whether an AI's stated evidence holds up — is a separate loop, independent of git. A 60-second real example (markdown input, frozen grammar; JSON works identically):
cat > vendor-notes.md <<'EOF'
# Vendor security review — Acme Cloud
Acme Cloud completed a SOC 2 Type I audit in March 2026. A Type II audit
is scheduled for Q1 2027 but has not started.
EOF
cat > report.md <<'EOF'
# Is Acme Cloud safe to send customer data to?
- statement: Acme completed a SOC 2 Type I audit in March 2026
quotedText: "completed a SOC 2 Type I audit in March 2026"
sourceFile: vendor-notes.md
- statement: Acme has passed a SOC 2 Type II audit
quotedText: "has passed a SOC 2 Type II audit"
sourceFile: vendor-notes.md
EOF
agent-receipt research verify --file report.md --out vr/r1.jsonClaim 1 checks out. Claim 2 — the classic quiet upgrade from Type I completed to Type II passed — is not in the source:
[2] Acme has passed a SOC 2 Type II audit
인용 : has passed a SOC 2 Type II audit → not-found
✗ FAIL — 근거가 출처와 불일치(날조/수치·날짜오류)
결과: verified 1 · FAIL 1 · advisory 0
$ echo $? # → 1 (a real CI gate, not a report you must remember to read)(The CLI prints in Korean; the JSON receipt and exit codes are language-neutral.) Then read what accumulates:
agent-receipt graph view --dir vr --out browser.html # Evidence Browser (self-contained HTML)
agent-receipt graph failures --dir vr --by check # triage
agent-receipt graph diff --base-dir vr-before --head-dir vr-after # CI regression gate (exit 1 on new failures)Checks go far beyond quotes — git facts (statedCommit / statedChangedFile / statedDiffText: "commit X changed file Y" verified against actual history), semver-range version, JSON schema, file existence, cited-receipt seal replay, artifact shape. Full table: EVIDENCE_SPEC.md. Every flag: Verification engine commands.
Verify your install (real-use smoke check)
Before relying on it, confirm which binary/version you are actually running:
npm install -g @promptia-labs/agent-receipt@latest
agent-receipt --version # prints the version (works with no contract / no git repo)
which agent-receipt # which binary is on PATH
agent-receipt doctor # shows binary path, current version, npm latest, update statusDogfood principle. Real-world verification is done against the global install or npx ... @latest — that is what your agents actually invoke. Calling a local node dist/cli.js directly is developer-internal verification only; do not report it as real-use verification. If doctor reports a newer npm latest, run npm install -g @promptia-labs/agent-receipt@latest.
SDK surface & stability tiers (Stable / Provisional / internal, semver promise, examples): see docs/SDK.md.
This repo also dogfoods its own verification engine: every npm test run verifies fixed fixtures (fixtures/dogfood/) and accumulates verification receipts locally (npm run dogfood to run it alone), so graph history / diff / the tampered flag are continuously exercised against real self-produced data (non-blocking; correctness is gated by test/dogfood.test.mjs).
Recommended .gitignore (tool outputs)
init never edits your .gitignore (guidance only). Add this block so .agent-guard/ tool outputs stay out of git — keeping verify / status / close-recon noise-free. The contract (contract.yaml), policy (policy.yaml), and the agent README are committable and intentionally not ignored.
# agent-receipt local tool outputs
.agent-guard/session.json
.agent-guard/receipts/
.agent-guard/audit-packs/
.agent-guard/anchors/
.agent-guard/notes/
.agent-guard/decisions/
.agent-guard/keys/
.agent-guard/dashboard.html
.agent-guard/**/*.sig.json
.agent-guard/**/*.approval.jsonExamples — see it work in 30 seconds
Three runnable examples show the verification engine catching real problems — each exits 1 on a fabricated claim, so it drops straight into CI:
examples/ai-coding-audit— verify what an AI coding agent (Cursor / Claude Code / Copilot) claimed it changed against real git history. Catches scope violations and hallucinated commits.agent-receipt research verify --file examples/ai-coding-audit/agent-report.mdexamples/rag-grounding— verify that a RAG answer's claims are literally grounded in the retrieved context (deterministic faithfulness — no LLM judge).agent-receipt research verify --file examples/rag-grounding/answer-claims.mdexamples/audit-journal-entry— verify AI-generated accounting entries by recomputing debit = credit balance and checking the cited evidence.agent-receipt research verify --file examples/audit-journal-entry/entries.md
Each prints per-claim verified / FAIL with the deterministic evidence (expected ↔ actual), and seals the result into a receipt you can replay to detect tampering.
Why this exists
When an AI agent edits your repo, "it said it only changed the auth module" is a claim, not a fact. agent-receipt turns the claim into a checkable receipt:
- Hooks / permissions are preventive — they block a command at the moment it runs.
- agent-receipt is evidentiary — it reads the resulting git diff and reports what was actually changed, staged, or left untracked, and whether any forbidden path was touched.
It is local-first by design:
- No code upload. Everything runs on your machine.
- No account, no API key. The core flow makes no network call; the only network is opt-in —
anchor --upload(registers a hash to the public Rekor log) anddoctor's version check (disable withAGENT_RECEIPT_NO_NET=1). - Operates on your local git working tree via ordinary git commands.
The model — six objects, not fifty commands
This describes the Work track — proving what an AI did to your git repo. A second, independent track — proving whether an AI's stated evidence is true — is covered in Verification engine below; it has its own receipt kind.
Under the ~50 Work-track commands there is one pipeline over six objects. The commands are just verbs that produce or transform them:
AI Session ─▶ Evidence ─▶ Verification ─▶ Receipt ─▶ Ledger ─▶ Audit ─▶ Publication
begin capture verify receipt ledger risk share-proof
start claims check done controls anchor
git diff reconcile insights export- Session — one unit of AI work (
begin/start). - Evidence — what happened: the agent's claim, the git diff, and beyond-git actions (
capture). - Verification — is it true?
verify+check, and reconcile the claim against git. - Receipt (a Work Receipt) — the sealed fact + integrity hash (
receipt/done). A verified, tamper-evident record, not a bare note. - Ledger — append-only, hash-chained trail (
ledger). - Audit — read-only judgment:
risk·controls·insights. - Publication — how a fact leaves your machine:
share-proof·anchor.
Full mapping to the actual code: docs/EVIDENCE_MODEL.md.
AI work audit protocol
Beyond a single receipt, agent-receipt closes the evidence loop with a short, git-native audit flow:
begin → (agent works) → done → explain (if FAIL)
→ audit-pack → attest (in-toto style) → commit with trailer
→ ledger appends one line → later: replay re-verifies the pack
↑ if something breaks, incident scans the trailbegin/donecollapse the everyday loop into two commands.policy.yamlholds standing rules (forbidAlways/requireApprovalFor/protectAlways); the contract scopes one task, the policy governs the project.commit-checkgates the moment before you commit (it never commits for you) and prints aAgent-Receipt:/Agent-Contract:/Agent-Policy:trailer.audit-packbundles the evidence;replay --pack <dir>re-checks it later (content hash + commit existence = tamper-evident, not "non-forgeable").ledger.jsonlis an append-only local trail (metadata only — no diffs/values). Flat file only.
Scope of evidence. This tool is git-working-tree based. It cannot see
.gitignored files, files outside the repo, OS commands, DB writes, or external-service changes. It provides git-based evidence for compliance review — it is not a compliance guarantee. An AI's completion report is always a claim; only git state is measured.
Full command list: agent-receipt help --all.
Verification engine
Is the AI's evidence — a citation, a number, a date, a hash, a signature, a git fact, a schema, a version — actually true against its source?
Everything above (the Work track) proves what an AI did to your git repo. This second, independent track proves whether what the AI said is true. It takes any JSON report of claims and checks each one deterministically — no LLM judgment, no network required unless you ask for it.
research/council verify --file <report.json|report.md> ─▶ Evidence Kernel ─▶ --out Verification Receipt ─▶ graph {query,view,failures,diff,history,subjects}
(claims + sources in; (evaluateClaim: 15 check kinds — (a separate, (read model: triage,
.md = frozen grammar) citation/number/date/link/ sealed receipt kind) regression gate, timelines,
hash/signature/commit/ a status board, exceptions)
fileChanged/diffContains/
schema/version/file/receipt/artifact)research verify --file <report.json>— check a set of claims (quotes, numbers, dates, hashes, signatures, git facts, schemas, dependency versions) against their sources.council verify --file <decision.json>— check a set of decisions' supporting claims the same way. It verifies decisions already made; it does not run a meeting.- Both call the same Evidence Kernel (
evaluateClaim) — deterministic, model-agnostic checks across 15 kinds (full table: EVIDENCE_SPEC.md). citation/number/range/date/hash/signature/commit/fileChanged/diffContains/schema/version are positive evidence (they can make a claimverified);linkis well-formedness only (advisory). Each positive check also carries an evidence grade — A (recompute: number/hash/signature) > B (compare: citation/git/schema/…) > C (form) — and a claim with no basis to judge abstains rather than being over-assured. The three git-fact kinds (commit/fileChanged/diffContains) let a claim be checked against actual repository history, not just static documents — e.g. catching "the config already supports X" when no commit ever changed the config that way. --out <path>seals the result into a Verification Receipt — a receipt kind separate from the Work Receipt above:schemaVersion: "evidence/1",kind: "verification-receipt". Its provenance is tiered:verified= this tool recomputed the fact itself (e.g. re-hashed an input file and it matched);reported= a self-reported field (a model name, a commit, a timestamp) — never laundered intoverified.graphreads accumulated Verification Receipts — see Verification engine commands below for the full list (query/view/failures/diff/history/subjects).specpublishes the check format as a machine-readable JSON Schema — the code generates the schema from the same registryevaluateClaimuses, so the code is the spec.
Two receipt kinds, one CLI. The Work track and the Verification track share one CLI, one deterministic-checking philosophy, and the same honesty rules (self-reported fields are always labeled; a check either passed, failed, or had no basis to judge — never a score). They do not share a receipt schema, a replay target, or downstream readers:
| | Work Receipt | Verification Receipt |
|---|---|---|
| Produced by | done / receipt --committed | research verify --out / council verify --out |
| Proves | the AI kept the contract in this git repo | the AI's stated evidence matches its source |
| Schema | schemaVersion: "1.0" | schemaVersion: "evidence/1", kind: "verification-receipt" |
| Re-verified by | replay --pack <audit-pack-dir> | replay --receipt <path> |
| Consumed by | share-proof · ledger · controls · insights · risk · anchor | graph query/view/failures/diff/history/subjects · the SDK |
SDK. import { evaluateClaim, buildGraphDiff, buildHistory, ... } from "@promptia-labs/agent-receipt" exposes the Verification-track functions directly — Stable (semver-promised) and Provisional (may change without notice) tiers. See docs/SDK.md and the runnable examples/.
Honest limits. Fingerprints (cfp1:) are text-identity v1 — a reworded claim is a different claim, not a semantic match. "Resolved" in diff/history means no failure with that key at this point, not proof of a fix. Full spec: docs/EVIDENCE_SPEC.md.
Core workflow
- Create a contract —
agent-receipt init --preset genericwrites.agent-guard/contract.yaml(and an agent-facing.agent-guard/README.md). - Brief the agent —
agent-receipt promptprints a paste-in instruction block listing the allowed/denied paths and rules. - Let the agent work.
- Verify state —
agent-receipt verifychecks the working tree (branch / scope / denied paths / staged / untracked / NUL). It does not run your tests. - Run required checks —
agent-receipt checkruns the contract'srequired_checks.commands(tsc/tests/etc.). - Only when both pass, stage the allowed files yourself and commit.
verify and check are deliberately separate: verify inspects state (fast, no command execution); check runs commands. A passing verify is not "tests passed."
If you omit --contract, the contract is auto-discovered (see below).
Commands
| Command | What it does | Needs git repo |
|---|---|---|
| presets | List the built-in presets (generic / nextjs-supabase / promptia / strict / relaxed) with when-to-use notes. | no |
| init --preset <generic\|nextjs-supabase\|promptia\|strict\|relaxed> | Create .agent-guard/contract.yaml + .agent-guard/README.md. Refuses to overwrite existing files. | no |
| draft-contract [--preset <name>] [--out <path>] [--print] | Generate a contract draft (non-interactive): scans the repo's top-level dirs for allowed_paths candidates, or copies a preset. Defaults to stdout; writes only with --out (never overwrites). | no |
| review | Commit-time human checklist (read-only): scope tight enough? denied covers .env/lock/migrations/deploy? receipt at default location? Distinct from lint. | no |
| start | Record a baseline of the current working tree to .agent-guard/session.json (see Baseline mode). Refuses if a denied path is already dirty, or if a session already exists. | yes |
| status | Print a read-only summary: contract scope, baseline (session) state, branch, current changes. | yes |
| reset | Remove the baseline .agent-guard/session.json (leaves contract.yaml/README.md intact). | no |
| verify [--json] | State checks only (no commands run). Human report, or a stable one-line JSON with --json. | yes |
| check | Run required_checks.commands; all must match their required_exit. | no |
| prompt [--cursor\|--claude] | Print a paste-in instruction block for the agent. Variants differ only in header/tone; the completion-claim JSON is identical (so claims works either way). | no |
| report [--type developer\|client\|audit] [--out <file>] | Run verify and write a Markdown report — developer (default, detailed), client (trimmed), or audit (contract/policy/receipt/environment-centric). | yes |
| receipt [--format json\|md\|client-md] [--redact] [--committed] [--out <file>] | Run verify + check and save an AI Work Receipt to .agent-guard/receipts/ (change magnitude, critical-path attestation, environment/provenance, integrity contentHash). client-md is a trimmed client-facing render; --redact best-effort masks secret-looking values. --committed measures the just-made commit (parent..HEAD, first-parent for merges; empty-tree base for the root commit) instead of the working tree — a measuredFrom: committed:<base> marker is added (metadata, excluded from contentHash → default receipts stay byte-identical). This is the mode the post-commit evidence hook uses, so a receipt is produced even for a commit made with git commit --no-verify. Saving outside the default dir warns (verify won't exclude it). | yes |
| receipts [--latest\|--cat\|--dir] | Find saved receipts under .agent-guard/receipts/: list newest-first (default), --latest summary (ok/contractId/timestamp/contentHash/magnitude), --cat latest content, --dir directory path. No receipts → guidance, exit 0. | no |
| mode | Read-only explanation of whether you're in task or daily flow (contract/session/baseline state + recommended next command). No file written. | no |
| claims --file <claim.json> | Compare an agent's completion report (JSON) against the actual git state — surfaces hidden/over-claimed changes as AI said / Git says. Mismatch → exit 1. | yes |
| explain | Explain why the tree is PASS/FAIL (branch / scope / denied / magnitude / critical paths) with recovery hints. Exit mirrors verify. | yes |
| audit [--json] | Local audit summary over .agent-guard/receipts/: count, latest, PASS/FAIL, critical-touched, unique contentHash. Read-only (no auto-append). | no |
| insights [--since <n>] [--format md\|json] | Read-only local trend & recurrence over saved receipts that audit doesn't give: prior-vs-recent FAIL-rate / critical-touched, per-contract recurring failures, and a descriptive watch list. Descriptive only — no scores, grades, or predictions; prints a small-sample / directional-only caveat at low counts. Team/org aggregation is out of scope (local, single-repo). | no |
| risk [--receipt <p>] [--format md\|json] | Read-only AI-work risk signals for one receipt — surfaces, from data the receipt already holds, what landed in git with review/scope/stability risk: denied-path & out-of-scope & critical-path touches, unreviewed-acceptance (large change + no passing checks + zero test-path files added — paths only, never judging test quality), and capture's sensitive/unstable actions (secret read / external call / created-then-deleted). NOT a code-quality or technical-debt measurement (that's static-analysis/AST territory) — provenance facts only, no scores/grades. Points to claims/capture show/insights for the rest. | no |
| dashboard [--out <path>] | Render a single self-contained static HTML (no CDN/network) of all receipts. Default .agent-guard/dashboard.html (excluded by verify). | no |
| keys init | Generate an ed25519 key pair under .agent-guard/keys/ (Node built-in crypto). Warns to gitignore the key dir (does not edit .gitignore). | no |
| sign --receipt <path> | Sign a receipt's bytes (ed25519); writes sidecar <receipt>.sig.json. | no |
| verify-signature --receipt <path> | Verify the sidecar signature with the public key. PASS → 0, FAIL → 1. | no |
| approve --receipt <path> [--note <text>] | Record a local approval sidecar <receipt>.approval.json (approver from git config, timestamp, contentHash, note). No git commit, no network. | no |
| approvals | List local approval sidecars. | no |
| export --format <slack\|json\|github-pr\|otel\|langfuse> --receipt <path> | Print an external-transport payload preview to stdout only (Slack blocks / summary JSON / PR-comment markdown / OTLP log / Langfuse trace). Never POSTs; no token/URL. | no |
| pre | Pre-start check (correct branch, nothing already staged). | yes |
| doctor | Environment/setup health check (git / contract / baseline). | no |
| lint | Advisory contract-quality checks (scope / denied / forbidden_actions). | no |
| help | Usage. | no |
| run | Alias for the no-args single-command routing below. | — |
| (no args) | Single-command routing: inspects state and points to the next step (init / start / check), or runs verify when a baseline exists; on PASS it suggests check / receipt / claims, on FAIL it suggests explain / status / reset. | — |
Audit workflow commands
| Command | What it does | Needs git repo |
|---|---|---|
| begin [--cursor\|--claude\|--generic] | Start a task in one step: check policy, record the baseline (start), and print the paste-in agent instructions (prompt). | yes |
| done [--claim <c.json>] [--client] [--ledger] | Finish a task in one step: verify + check, save the receipt, summarize, optionally reconcile a --claim and append to the ledger. | yes |
| policy init [--profile <solo-founder\|vibe-coder\|agency-client\|team-strict\|promptia>] \| check \| show | Manage .agent-guard/policy.yaml — standing project rules (forbidAlways / requireApprovalFor / protectAlways / requireReceipt …). The contract scopes one task; the policy governs the project. | check: yes |
| commit-check | Gate just before you commit: verify PASS, check PASS, a receipt matching the current change, and policy rules satisfied. Never commits. On pass, prints an Agent-Receipt: / Agent-Contract: / Agent-Policy: commit trailer. | yes |
| trailer | Print the commit trailer only (hashes/paths, no values) to paste into a commit message. | yes |
| audit-pack [--out <dir>] [--claim <c.json>] [--redact] [--ledger] | Bundle the evidence (contract, policy, receipt, claim+verify, approval, signature, environment, manifest) into .agent-guard/audit-packs/<ts>/. A review bundle — tamper-evident, not a non-forgeable proof. | yes |
| replay --pack <dir> (alias verify-pack) | Re-verify a saved audit-pack (Work Receipt) against the current repo: recompute the receipt contentHash, confirm the commit exists. Detects tampering. Cannot reproduce external DB/OS effects. (A Verification Receipt has its own replay --receipt <path> mode — see Verification engine commands.) | yes |
| ledger [--json] · ledger rebuild | Append-only local trail .agent-guard/ledger.jsonl — one metadata line per receipt (no diffs/values). rebuild regenerates it from receipts/. | no |
| attest --receipt <p> \| --pack <dir> | Emit an in-toto style Statement (draft) to stdout — provenance over the receipt + commit. Not an SLSA-level claim; tamper-evident, not non-forgeable. | no |
| anchor [--receipt <p>] · anchor --upload | Wrap a receipt in a DSSE-signed in-toto Statement (auto-generates an ed25519 key) and either print Rekor-registration instructions (default, offline) or, with --upload, register it to the public Rekor transparency log in one command (Node fetch + built-in crypto — no external tools), then write a <receipt>.rekor.json sidecar. Seals time & existence via a third party; not a keyless identity proof. | no |
| controls [--receipt <p>] [--format md\|json] [--redact] | Read-only projection of a saved receipt → evidence relevant to security/AI controls (SOC 2 TSC, EU AI Act Art 12/19/26(6), ISO/IEC 42001 — the last marked likely, verify against the purchased standard). It maps signals (secret-file reads, external calls, denied-path hits, required checks, critical paths, the tamper-evident log, a Rekor anchor) to control families with a per-signal "does not prove" caveat. Never asserts compliance — wording is limited to evidence relevant to / supports; consult your assessor. Each signal is tagged with an evidence-reliability tier (audit-evidence hierarchy, AS 1105/ISA 500: A external/Rekor > B git-measured > C capture self-reported). Does not modify the receipt. | no |
| incident [--since <n>] | Scan recent receipts/ledger for failures, critical-path changes, missing approvals, last PASS. Read-only; no auto-recovery, no scoring. | no |
Retention & independent verification are provided by the commands above — there is no separate
archive/verify-proofcommand (it would duplicate them). Retention:ledgeris the append-only, hash-chained long-term trail andaudit-packbundles per-task evidence; the retention period (e.g. EU AI Act's ≥6-month floor) is an operational policy you set, not a tool feature. Independent verification by a recipient:replay --packre-checks a bundle'scontentHash+ commit,verify-signaturechecks the ed25519 sidecar, and a Rekor-anchored receipt is verifiable in the public transparency log without trusting the issuer.
Convenience & release commands
These shorten the real-world loop. None of them run git, npm, or any deploy — they print paste-in blocks or read-only analysis. verify --json's 14 keys are unchanged. Git is the only evidence; note, release-check, policy mode, and a claim's modeClaims/externalActions are advisory / self-report — never PASS/FAIL inputs.
| Command | What it does | Needs git repo |
|---|---|---|
| begin --kind <recon\|implementation\|docs\|test\|measure-first\|observe-only\|release-check> | Tag the session's kind (stored in session.json / receipt sidecar — never in the 14 keys). Prints kind-specific operating rules + end command, and a strong warning if a baseline already exists (recon→implementation transitions must reset first). | yes |
| close-recon | Close a read-only recon session in one step. Only when there are zero changes (touched/staged/untracked/denied/out-of-scope all 0): save a receipt, build an audit-pack, and reset. Refuses (no reset) if anything changed, or if the session is kind=implementation. | yes |
| prepare-commit [--message <m>] [--include-linked-tests] | Generate a safe copy-paste commit block — git add candidates + message + Agent-Receipt trailer — with the commit block and reset block physically separated (no EOF+reset on one line). Never commits. Suppresses the block on denied / true out-of-scope / branch mismatch / NUL. | yes |
| finish [--message <m>] [--client] | Implementation wrap-up in one step: done → commit-check → audit-pack → commit block, with per-stage PASS/FAIL labels and a single "next command" on failure. No auto add/commit/reset/push. | yes |
| note --type <recon\|contract-draft\|no-code-decision\|next-options> [--message <m>] | Record a no-code recon/decision as a note/claim — not git-verified evidence (.agent-guard/notes/ or /decisions/, pinned to headHash). Included in audit-packs as a user memo. Tool output — excluded from verify. | yes |
| release-check --base <ref> [--failed-tests <file>] [--observe <event>] | Pre-deploy read-only, advisory analysis: base/head, ahead/behind, rollbackBase, changed files, commits, a heuristic risk class (labeled — not a score), failed∩changed (heuristic, only if the file is given), and post-deploy events to watch. Never push/deploy/checkout/reset; does not approve a deploy — a human decides. | yes |
| next | Recommend the single next command for the current state. | (discovers) |
| tap install [--write] [--except <n>...] · tap probe / status / show / verify / uninstall | MCP observation proxy (alpha). Wrap stdio MCP servers so every tools/call is recorded — value-free (key names · size · digest only), hash-chained, vendor-neutral — as a new observation source in the receipt (tapSummary). Not a gateway, not a blocker, fail-open. HTTP/SSE is out of v1 scope and confessed in coverage.unwrapped (never silently skipped). Compat table + recipes · design spec. | yes |
Contracts may also declare linked_test_paths / expected_linked_tests (optional) so a guard test outside allowed_paths is shown as a linked guard test (human-confirm) in commit-check/prepare-commit — verify's outOfScope meaning is unchanged. Policies may set mode: measure_first | observe_only to print a self-report checklist in commit-check (display only — the tool sees git diffs, not intent).
Verification engine commands
research / council / graph / spec — these check whether an AI's stated evidence — a quote, a number, a date, a hash, a signature — matches its source, independent of git. They produce a separate Verification Receipt (see Verification engine above). None of them need a contract or a git repo (they take a JSON report as input, though graph/replay --receipt will use git opportunistically to recheck a commit if one is present).
| Command | What it does | Needs git repo |
|---|---|---|
| research verify --file <report.json|report.md> [--fetch] [--out <p>] [--decompose] | Check each claim (15 kinds: citation/number/range/date/hash/signature/link/commit/fileChanged/diffContains/schema/version/file/receipt/artifact — full table) against its source; .md input uses a frozen markdown grammar with verdicts pinned identical to JSON. --fetch re-fetches sourceUrl live — an independent source, over the network. Any failed check → exit 1. --out seals a Verification Receipt. | no |
| council verify --file <decision.json> [--log <path>] [--out <p>] | Check a decision's supporting claims the same way. Does not run a meeting — only verifies decisions already made. --log appends the result to a hash-chained, append-only DecisionLog. | no |
| spec [--format json] | Publish the check format: a human summary, or (--format json) a machine-readable JSON Schema (draft-07) generated from the same check registry evaluateClaim uses. | no |
| graph query --dir <d> [--commit\|--input\|--model\|--receipt-id] [--format json] | Filter accumulated Verification Receipts; neutral pass/fail counts. No relationships shown — see graph view for that. | no |
| graph view --dir <d> [--out <html>] [--format json] | The main consumer surface. Default: a self-contained, failure-first Evidence Browser HTML — Dashboard → failure tabs (by check/model/subject/commit/reason) → reason + evidence (expected↔actual) → affected claim → 1-click claim history → the receipt itself, last. --format json: {summary, indexes, graph:{nodes,edges}, failures, receipts, subjects, histories} — graph.edges (asserts/checked_by/same_input/same_commit/reverifies) each carry a machine-readable basis and a verified/reported tier (verified only for facts this tool recomputed itself). | no |
| graph failures --dir <d> [--by check\|reason\|subject\|model\|commit] [--check <k>] [--status <s1,s2>] [--sealed] [--since <iso>] [--limit <n>] [--format json] | Triage: pull just the failures, grouped/filtered. --limit always prints "N of M" (no silent truncation). Always exits 0 — a query, not a gate. | no |
| graph diff (--base-dir <d1> --head-dir <d2> \| --dir <d> --base-commit <c1> --head-commit <c2>) [--match statement\|fingerprint] [--sealed] [--format json] | Compare two receipt sets: new / resolved / status-changed / persisting failures, per-subject deltas, per-input verdict changes. Exits 1 when there are new failures — usable as a CI regression gate. "Resolved" means no failure with that key in head — not proof of a fix. | no |
| graph history --dir <d> (--claim <cfp1:…\|prefix> \| --input <sha256> \| --subject <s>) [--format json] | Timeline for the same claim/input/subject: first appearance, then per-step new/resolved/status/evidence changes. Claim prefixes resolve git-style — unique → used, ambiguous → candidates listed. | no |
| graph subjects --dir <d> [--format json] | A per-subject (project/question) status board — receipt counts, pass/fail, failing checks, date range. Counts only; trend comparison is graph diff's job. | no |
| replay --receipt <path> [--fetch] | Re-verify a saved Verification Receipt: recompute contentHash/receiptId (tamper detection), re-hash the input file if still present (drift), re-check the commit if one was reported (link rot). --fetch (opt-in network) re-downloads each sealed fetched.textSha256 source and reports SOURCE DRIFT if the cited page changed since verification. A separate mode of the replay command above (replay --pack is for Work Receipts' audit-packs). | no |
CI (GitHub Action, repo-local):
- uses: koscom2023-beep/[email protected]
with:
report: docs/research-claims.md # or .json
base-dir: .agent-guard/vreceipts-main # optional: regression gate (exit 1 on NEW failures)SDK: import { evaluateClaim, buildGraphDiff, buildHistory, buildSubjects, ... } from "@promptia-labs/agent-receipt" — see docs/SDK.md for the Stable/Provisional tiers and runnable examples.
Contract discovery
When --contract / -c is not given, the first existing file wins, in this order:
--contract/-cvalue (explicit; auto-discovery is skipped entirely).agent-guard/contract.yaml.agent-guard/contract.jsonagent-guard.yamlagent-guard.json
Exit codes
0— pass1— violation (verifystate violation,checkcommand failure,preproblem)2— loading/usage error (missing/unreadable contract, schema error, not a git repo, unknown command/preset)
Git hooks (install-hooks) — gate and evidence are decoupled
agent-receipt install-hooks writes three hooks into .git/hooks/ (it never touches core.hooksPath, and refuses when husky is present):
- Gate —
pre-commit/pre-pushruncommit-checkand block on a violation. A gate is meant to be bypassable:git commit --no-verify/git push --no-verify. - Evidence —
post-commitrunsreceipt --committedand never blocks (always exits0). Because git does not skippost-commiton--no-verify, an evidence receipt for the just-made commit is recorded even when the gate was bypassed. Evidence and gate live in separate hooks on purpose — bypassing the gate no longer discards the receipt.
uninstall-hooks removes only the hooks agent-receipt installed (it preserves any pre-existing hook). Hooks aren't tracked by git, so a fresh clone needs install-hooks once.
Wiring it into a worktree sandbox, CI, or a pre-push hook? See recipes.
Baseline mode (start)
Real repos are rarely clean — there are often pre-existing untracked files (docs, exports, scratch) unrelated to the current task. Without a baseline, verify flags all of them, drowning the real signal.
agent-receipt start records the working tree at the start of a task into .agent-guard/session.json (a baseline). After that:
- Ambient noise is removed. Files that were already unstaged/staged/untracked at
startare excluded from scope checks —verifyreports only what changed since the baseline. - New violations are still caught. A new out-of-scope or denied file created after
startis flagged normally. denied_pathsis never hidden by a baseline. Denied matching runs against the full current working tree, not the baseline-relative subset. You cannot bury a denied path by baselining it.- Tool-generated outputs are ignored by
verify—.agent-guard/session.json,receipts/,keys/,audit-packs/,ledger.jsonl, anddashboard.html. The rest of.agent-guard/(e.g.contract.yaml,policy.yaml) is treated normally. - Stale baselines are ignored, safely. If you switch branches, or the recorded
baselineHeadis no longer an ancestor ofHEAD, the baseline is dropped andverifyfalls back to full-tree checking (noisier, but it never hides changes). Runagent-receipt resetthenagent-receipt startto re-baseline. Useagent-receipt statusto see the current baseline state.
start refuses when a denied path is already dirty
If any already-dirty file (unstaged/staged/untracked) matches denied_paths, start fails and writes no session. Baselining a dirty denied path would "bury" a dangerous change as if it had always been there.
This is a safety condition, not something to work around. Resolve it by one of:
- clean up /
git add+ commit / gitignore the offending untracked files, or - narrow the
denied_pathsglobs so they don't overlap pre-existing ambient files.
There is deliberately no flag to bypass this check — refusing is the correct behavior.
Baseline mode compares path sets, not content hashes. If a file already existed as untracked at
start, later content edits to that same untracked path may not be detected — unless it matchesdenied_paths, which is always checked against the full tree.
Contract example
YAML and JSON are parsed by the same schema. The full schema is documented in CONTRACT.md (source of truth: src/schema.ts).
id: example
title: example patch-only guard
mode: patch_only
branch:
expected: main
scope:
# If allowed_paths is empty, positive scope-checking is disabled — protect via denied_paths instead.
allowed_paths:
- "src/**"
denied_paths:
- ".env*"
- "package.json"
forbidden_actions: # advisory only — NOT mechanically enforced (see CONTRACT.md §7)
- push
- deploy
required_checks:
commands:
- name: typecheck
command: "npx tsc --noEmit"
required_exit: 0
git:
require_no_staged_untracked: false # default
require_only_allowed_files_staged: false # default
require_no_denied_path_diff: true # default (on)
require_no_push: false # defaultThe minimal valid contract is just id plus a scope key:
id: minimal
scope: {}scope is required (even if empty); only scope.allowed_paths / scope.denied_paths default to [].
Scaffolding a contract (init)
agent-receipt init --preset <generic|nextjs-supabase> creates a starter setup so you don't write a contract from scratch (it needs neither a contract nor a git repo):
.agent-guard/contract.yaml— a starter contract from the chosen preset (see Presets below)..agent-guard/README.md— a short agent-facing note describing the rules and how to runverify/check.
After it runs, the new contract.yaml is auto-discovered by every other command, so you can run agent-receipt verify with no --contract.
Safety: init never overwrites. If either .agent-guard/contract.yaml or .agent-guard/README.md already exists, init fails (exit 1) and writes nothing — remove the existing file(s) first if you really want to regenerate. An unknown or missing --preset is a usage error (exit 2).
Typical flow:
npx agent-receipt init --preset generic # scaffold .agent-guard/{contract.yaml,README.md}
# edit .agent-guard/contract.yaml for your project
npx agent-receipt start # (optional) record a baseline — see Baseline mode
# … let the agent work …
npx agent-receipt verify # state checks (auto-discovers the contract)
npx agent-receipt check # run required_checks.commandsIn short: init creates the contract; start (optional) records a baseline on top of it; verify / check evaluate against it.
Note — running
verifybeforestart: the filesinitwrites (.agent-guard/contract.yaml,.agent-guard/README.md) are themselves untracked, andverifydoes not exclude them — only tool-generated outputs (session.json,receipts/,keys/,audit-packs/,ledger.jsonl,dashboard.html) are excluded. So with a restrictiveallowed_paths, runningverifybeforestartmay report them asoutOfScope. This is normal. Avoid it by following the recommended order (init→ edit →start→verify/check, which baselines them away), or by adding.agent-guard/contract.yaml/.agent-guard/README.mdtoallowed_paths(or committing / gitignoring them).
Presets
generic— a starter patch-only contract: emptyallowed_pathswith protectivedenied_paths(.env*, key/cert files).nextjs-supabase— adds denied paths typical for a Next.js + Supabase app (migrations, lockfiles,vercel.json) and atsc --noEmitcheck.promptia— tuned for the Promptia app (Next.js + Supabase + Vercel). Denies.env*, lockfiles,supabase/migrations/**,vercel.json,.vercel/**,exports/**, anddocs/arch/json/**; uses a broadallowed_paths(app/,src/,components/,lib/, …) so everyday source edits pass;required_checks.commandsis left empty with commented examples (uncommentpnpm tsc --noEmit/pnpm lintfor your project).lintanddoctorrecognize this preset and warn if a key denied path is missing.strict— for risky changes or external-contractor review: narrowallowed_paths, strongdenied_paths, andrequire_no_staged_untracked+require_only_allowed_files_stagedturned on, plus atsccheck.relaxed— for exploration/prototyping:denied_paths-only (emptyallowed_paths, positive scope off), tolerant of ambient untracked noise.
All five are starting points — edit the generated .agent-guard/contract.yaml for your project. Run agent-receipt presets to list them, or agent-receipt draft-contract to generate a repo-scanned draft.
What agent-receipt catches
Run by verify against the combined set of unstaged + staged + untracked changes:
- Files changed outside
allowed_paths(whenallowed_pathsis non-empty) - Changes to
denied_paths - Out-of-scope files staged (when
require_only_allowed_files_staged) - Untracked files present (when
require_no_staged_untracked) - NUL bytes in declared paths (corrupted files)
- Wrong branch (vs
branch.expected)
Run by check:
required_checks.commandswhose exit code doesn't matchrequired_exit
What agent-receipt does not do
Read this before relying on it:
- Not a real-time blocker. It runs after the agent works, on git state. It does not intercept or block destructive shell commands as they happen.
- Not a security scanner or platform. No vulnerability detection.
- No code-quality or security review. It does not read your code for bugs.
- No semantic / AST review. It checks which files changed, not whether the change is good.
forbidden_actionsis advisory. It is surfaced inpromptoutput but is not mechanically enforced byverify. Real prevention comes fromdenied_paths+ git checks + human review (and, for push, a git pre-push hook).- Push is only reported, not blocked.
verifyshows ahead/behind vsorigin/mainfor information.
JSON output (verify --json)
For CI/automation, verify --json prints a single stable JSON line to stdout and suppresses the human note. The key set is fixed:
{"ok":true,"contractId":"example","title":null,"branch":{"current":"main","expected":null,"ok":true},"touched":[],"staged":[],"untracked":[],"outOfScope":[],"deniedHits":[],"stagedOutOfScope":[],"nulBad":[],"violations":[],"headHash":"...","aheadBehind":null}- Optional values (
title,branch.expected,aheadBehind) keep their key with anullvalue. - On a
2error there is no JSON on stdout (message goes to stderr). - Depend on
okand the exit code, not on incidental field shapes.
Completion claims (claims)
An agent's "I changed only X, tests pass" is a claim. agent-receipt claims --file <claim.json> checks that claim against the actual git state — it never trusts the claim itself. The most useful catch is a change the agent didn't mention.
The claim file is plain JSON; every field is optional and only provided fields are compared:
{
"changedFiles": ["src/auth.ts"],
"newFiles": [],
"deniedHits": [],
"tests": true,
"summary": "fixed the token refresh"
}changedFiles/newFiles/deniedHitsare compared (as sets) to git's actual touched / untracked / denied paths.tests(boolean) is compared to runningcheck(the contract'srequired_checks.commands).summaryis informational only (echoed, not verified).- Exit
0= claim matches git ·1= mismatch ·2= file missing / not valid JSON.
agent-receipt prompt already tells the agent to emit exactly this JSON, so the loop is: brief with prompt → agent works → agent pastes the claim → claims --file reconciles it with git.
Capture & share-proof (alpha)
Two newer commands extend receipts beyond the git working tree.
capture — what the agent did that git can't see. Wire it into Claude Code's PreToolUse/PostToolUse hooks and it records, append-only, the agent's actions — reading a .env, calling an external host, creating-then-deleting a file — none of which leave a git trace. Values are never stored (paths / hosts / classification only, redacted). It never blocks (evidence, not a gate).
agent-receipt capture install # preview the hooks snippet (no file change)
agent-receipt capture install --write # merge hooks into ./.claude/settings.json (idempotent, preserves existing)
agent-receipt capture show # git saw: N ⟷ actions recorded: M (+ git-changed paths with no capture record)
agent-receipt capture verify # hash-chain integrity check (tamper / deletion / reorder / gap)When a capture log exists, done / receipt embed an actions / actionsSummary block in the receipt — additive: the 14-key verify --json and the existing contentHash are unchanged, and receipts produced without capture are byte-identical. agent-receipt begin clears the log for a fresh audit boundary.
Completeness — what it can and can't promise. The capture log is a hash-chain (each record carries seq + prevHash + entryHash), so capture verify detects tampering, deletion, reorder, and internal gaps; a failed ingest writes an explicit capture-degraded marker instead of silently dropping. share-proof / capture show also surface git-changed paths that have no capture record (the hook blind spot) and the captured tool surface. It is honest about its ceiling: proving every action was captured is impossible for a single local observer, so the claim is tamper-evident & gap-evident within the configured hook surface — not "complete." Out of scope (known blind spots): tail-truncation, --dangerously-skip-permissions (hooks fully off), sub-agent / MCP / pipe / OS-level actions, concurrent-hook races.
share-proof — a one-page evidence file for your client. Renders a receipt as a self-contained HTML page (no network, no external resources) you can send to a client: scope result, change magnitude, beyond-git actions, and the integrity hash.
agent-receipt share-proof # render the latest saved receipt
agent-receipt share-proof --receipt <p> # render a specific saved receiptanchor — a third-party seal (Rekor transparency log). A local receipt is your statement about your work — useful, but self-issued. anchor --upload wraps the receipt in a DSSE-signed in-toto Statement and registers its hash to the public Rekor transparency log, so a client can confirm the receipt existed at that time without trusting you. One command, no external tools (Node fetch + built-in crypto); it auto-generates an ed25519 key on first use.
agent-receipt anchor # offline: build the DSSE bundle + print how to register
agent-receipt anchor --upload # one command: sign + register to Rekor + write the sidecarOn success it writes a <receipt>.rekor.json sidecar next to the receipt (entry UUID, logIndex, verification URL). share-proof then auto-embeds a "Verify in the public transparency log" link — a receipt with no sidecar renders byte-identically to before. The link is click-only (an href, never an auto-loaded resource), so opening the proof still leaks nothing.
Honest scope: git-based evidence, tamper-evident — not non-forgeable, and not a compliance guarantee. Capture ingests Claude Code hooks natively; Codex / GitHub Copilot / Cursor hooks are normalized into the same record shape via a vendor-neutral envelope normalizer (best-effort — verify your agent's payload with
captureapply_patchand Cursor's dedicated events are not yet mapped). A receipt may optionally be anchored to the public Rekor log (anchor, above) — that seals time & existence via a third party, but is not a keyless (identity) proof. Cloud / hosted SaaS verification pages remain out of scope.
Local-first / privacy
- Runs entirely locally; no code or diff ever leaves your machine.
- No API key, no account, no telemetry. The core verify/receipt flow makes no network requests — the only network is opt-in:
anchor --upload(sends a hash to the public Rekor log, never your code) anddoctor's npm-version check (disable withAGENT_RECEIPT_NO_NET=1). - Uses your installed
gitto read the working tree.
Package status
Current version 0.24.0 (@promptia-labs/agent-receipt). 0.24.0: seal integrity fix (breaking) (2026-07-10, from an external code review). The receipt seal (contentHash) now covers the human-readable verdict (ok, violations, branch, contractId, plus verdict/contractSnapshot and an actions/reconciliation digest when present), so a forged PASS can no longer survive verify-proof. done re-seals after attaching the verdict so the stored hash and the recompute agree. This changes the hash format: receipts made before 0.24 show as mismatched and must be re-issued. The schema marker bumps 1.0 to 1.1, and verify-proof reads it to say "pre-0.24 format, re-issue" instead of "tampered" (it still fails, so the old weak seal is never honored). Also in this release: the decision-log hash-chain uses RFC 8785 JCS canonicalization (a replacer-array bug had dropped the nested grounding from the hash); a stored-XSS in the dashboard label is escaped; JSON masking now catches KEY=value, key: value, and PEM blocks inside string values; deny globs match case-insensitively on case-insensitive filesystems (one pathmatch SSOT) and every profile's .env* becomes **/.env*; gate allows only pass/abstain; git reads get a maxBuffer so a huge diff is not silently read as "0 changes"; hashStatus accepts only collision-resistant algorithms and fileChanged matches by exact line; and the offline verify-proof headline no longer claims "unchanged since creation" for a self-managed key (only a third-party Rekor anchor earns the stronger line, and even then it defers the real check to the human link). 0.23.0 — terminal verdict card (2026-07-08, a CLI/TUI council): the first-three-seconds verdict hero from the HTML proof now renders in the terminal too. done prints a boxed verdict card when stdout is a TTY — the verdict as a triple signal (color + icon + text: ✅ PASS green, ❌ FAIL red, ◌ INCOMPLETE grey), plus the contract, magnitude, checks, and seal, with a "run explain for the rest" pointer where the HTML folds. Piped/CI/non-TTY output is byte-for-byte unchanged (the card is TTY-gated, so every existing test and script sees the same text as before), and color is emitted only when stdout.isTTY && !NO_COLOR (or FORCE_COLOR=1) so nothing leaks escape codes into logs. agent-receipt share --term reprints the card for a saved receipt without writing HTML. A src/termcard.ts pure renderer does the drawing with East-Asian-width-aware padding (CJK and emoji count as two columns, so the box borders align with Korean text) and clips overlong lines with …; the verdict icon and label come from the same verdictVisual SSOT the HTML uses, so the meaning stays in one place. No new dependency, honest labels intact (FAIL is shown red and large, never softened). 0.22.0 — UX pass: onboarding, one face, first three seconds (2026-07-08, a UI/UX council — all surfacing/reorganizing, zero new features, identity untouched): the tool has many commands, so this release makes the common path obvious without hiding the power. (Onboarding) the no-args first run now welcomes a new user (contract-less) with a one-line mental model and points at quickstart, instead of a bare "no contract" line; quickstart names the three core verbs begin → done → share up top and demotes capture to optional/later (it no longer auto-runs on --write — the shared-settings hook shouldn't scare a first session). (One mental model) a single sentence now leads help and the welcome: this tool leaves two things — what the AI did (Work Receipt) and what the AI said (Verification Receipt) — dissolving the "why are there two receipts" confusion. (One face) the four HTML outputs (share-proof · inbox · dashboard · Evidence Browser) now share one style SSOT (src/htmlstyle.ts) — a warm-paper palette, one type set, and a verdict-hierarchy color that matches the landing site's thermal-receipt world; the Evidence Browser's mature token set was absorbed as the shared superset. (First three seconds) share-proof opens with a verdict hero (icon + color + label, scroll-zero) carrying the contract sentence and change magnitude, for the recipient who opens the page without a CLI. (Accessibility) every verdict is a triple signal — color + icon + text (a single verdictVisual source; never color alone), on a contrast-checked palette, HTML still self-contained (no external resources). (Honesty, folded not removed) the "tamper-evident / not a compliance guarantee" caveats move into a one-click <details> so a green result reads big while the full scope stays a click away — honesty by placement, not by shouting. (i18n skeleton) a core-path bilingual layer (--lang en / AGENT_RECEIPT_LANG=en, default ko = byte-identical for existing users) so the onboarding path speaks English for global npm users; full translation is a later train. 0.21.0 — MCP tap (observation proxy, alpha) (2026-07-08, three design councils + code-vs-spec reconciliation): a new observation source — mcp-tap sits between the agent and its stdio MCP servers and records every tools/call value-free (top-level key names · byte size · a canonical digest — never the argument values, never the env block), hash-chained like capture, vendor-neutral. It surfaces in the receipt as tapSummary (metadata, excluded from contentHash — receipts without tap stay byte-identical). Design honesty is enforced in code: the JCS (RFC 8785) canonicalizer earns the name jcs/sha256 only if the frozen official test vectors all pass (a test demotes it to sorted/1 otherwise); reads coalesce losslessly (repeat:N, closed by input-events only — never a timer — so it stays deterministic) while writes/exec/network/deploy are never merged; a crash is confessed by a missing cleanShutdown marker; the session boundary is a cursor snapshot (a long-lived proxy can't truncate its own log without breaking the chain); URIs are split by scheme (file=path / else scheme+host, userinfo stripped) with a uriDigest; HTTP/SSE servers are out of v1 scope and confessed in coverage.unwrapped rather than silently skipped. tap install / probe / status / show / verify / uninstall manage the wiring (preview by default; restore truth = a self sidecar, not a key in someone else's config). Verified on 5 real servers (filesystem · memory · everything · sqlite · git — compat table); a CI-witness workflow re-runs the release commit under a separate identity (a witness, not a key-trust proof). db-write classification proven on a live sqlite server (lead-token parse). Guard integration is warn-only (no tap-path deny), overhead micro-bench is not yet measured, and English CLI output is a later train — all stated, none faked. Full design: MCP_TAP_SPEC.md. 0.20.2 — integrity patch (2026-07-07, from a full self-audit): a review reject / needs-review sidecar is no longer counted as an approval — hasApproval was existence-only, so a rejected receipt read as approved in four consumers (attest in-toto approval count · ledger · commit-check · incident); status reading is now a single SSOT (approvalStatusFor: legacy sidecars without status still count as approved, a broken sidecar counts as nothing), with a 4-case regression test (rejected / needs-review / legacy / corrupt). Also: the site-parity and replay-equivalence tests joined npm test (they were manually-run only), and the historical feature-snapshot doc now carries a "not current" banner. No new features. 0.20.1 — docs & polish patch (2026-07-07): republishes with the review-ready README/site copy that landed after 0.20.0 shipped, the em-dash-free site copy, a gen-claim usage line covering all three modes (--transcript | --llm-prompt | --from-llm), and the GitHub Action default version pin corrected to the published 0.20.0 (was a stale 0.14.0 — pin = consumer reproducibility, kept at a version guaranteed to exist). No engine change. 0.20.0 — review-ready receipts (2026-07-07 — three council batches in one version; versions bump once per publish): the release closes the loop the market names as the bottleneck — where did it come from · what was it meant to do · who is responsible. (Ten-second proof) share-proof opens with an executive block above the tabs: the verdict, the contract restated as plain sentences (KO+EN, fixed slots, zero LLM), magnitude straight from receipt fields (a test forbids summary-vs-receipt drift), guard-denied count, and the verdict's [rule-id] facts regrouped into four review buckets in the reviewer's real reading order — Scope / Critical paths (as designated by the contract) / Validation / Agent behavior
