Receipts & audit chain

Every mutation produces a tamper-evident receipt. Receipts form a hash-linked chain.

What's in a receipt

Each receipt is an immutable JSON blob with:

{
  "receipt_id": "rcpt_2026_04_25_…",
  "timestamp": "2026-04-25T18:42:13Z",
  "user_id": "u_…",
  "workspace_id": "ws_…",
  "run_id": "run_…",
  "action": "apply",                    // or "rollback"
  "files": [
    { "path": "services/auth.py", "before_hash": "…", "after_hash": "…" }
  ],
  "diffs": [ { "path": "…", "hunks": [...] } ],
  "snapshot_id": "snap_…",
  "symbols_checked": 42,
  "guards": {
    "write": "pass",
    "hallucination": "pass",
    "egress": "pass"
  },
  "cost": { "usd": 0.0123, "tokens_in": 8412, "tokens_out": 2103 },
  "models": ["claude-sonnet-4-5", "gpt-4o-mini"],
  "prev_receipt_hash": "abc123…",
  "self_hash": "def456…"
}

The chain

self_hash of receipt N becomes prev_receipt_hash of receipt N+1. This is what makes the trail tamper-evident — flipping a single byte in any receipt invalidates every receipt after it.

GET /api/receipts/chain-head?ws_id=… returns the latest hash. Anyone with read access to the receipts can recompute the chain and verify integrity.

Verification

POST /api/receipts/<run_id>/verify:

  • Re-reads the receipt from disk.
  • Recomputes its hash.
  • Re-checks prev_receipt_hash against the actual previous receipt.
  • Returns { valid: true/false, mismatch: <field> }.

Re-grounding

POST /api/receipts/<run_id>/reground:

  • Re-runs the security/correctness checks against the current state of the files.
  • Returns a reground_id plus a diff of findings (new findings, resolved findings, unchanged).
  • Useful for: "this change passed checks 6 months ago — does it still?"

Where to view receipts

The Budget panel has a Receipts tab. Each row is a receipt with timestamp, action, files touched, cost, and a "Why?" disclosure that breaks down the cost into input/output tokens, model used, and reasoning chains.

Storage

Receipts live in workspaces/<slug>/receipts/ as one JSON file per receipt, plus an INDEX.jsonl for fast iteration. They are never deleted by KrowForge — even when a workspace is archived. If you need to comply with right-to-erasure (GDPR), the receipts and snapshots are removed only as part of full account deletion.

Why this exists

Three reasons:

  1. Trust — you can prove what the agent did and didn't do.
  2. Compliance — audit trails for regulated industries.
  3. Debugging — when something breaks, the receipt is your starting point.