receipt dst, a chain audit you can run on a schedule from a source checkout. What makes that record worth showing an auditor is not that a service promises it did not edit the log. It is that every receipt carries the hash of the one before it, so an edit, an insertion or a deletion changes a hash — and the next read refuses to fold the chain.
Where you read the trail
- Agent replay renders a thread’s or a run’s receipts as a session summary, a chronological transcript and a work log, with a per-receipt detail panel that has Overview and Raw receipt views and a Replay to this step control. Open it from a chat thread, or from the Receipts row action on the Beetle Tasks page — Beetle is the assistant’s name in the interface. Replay walks through the dialog.
- Gateway activity, inside an MCP Gateway workspace, describes itself as a “Live view of this workspace’s MCP tool activity, derived from execution receipts.” See Gateway activity.
receipt dstaudits the chains themselves. It ships with the developer CLI you run from a source checkout, and is covered at the end of this page.
What writes a receipt
In the stream names below,<repoKey> is a per-deployment constant and the other angle-bracket segments are ids filled in when the receipt is written.
Two things follow from that list. The Guardrails and Policies modules are configured but never applied to live traffic — yet their configuration is fully audited, so you can always show when a rule was written, changed, switched off or deleted, and by whom. And a gateway receipt carries a bounded preview rather than the payload: the tool output is truncated to 2,000 characters and flagged as truncated, so a full response body is never copied into the chain.
What leaves no receipt
Writing a gateway receipt is deliberately best-effort: recording must never turn a working tool call into a failed request, so a write failure is logged and the call still succeeds. Treat Gateway activity as a near-complete record of REST tool calls, not a guaranteed-complete one.
What the hash covers
A receipt isid, ts, stream, prev, body and hash, plus an optional context and hints. The hash is SHA-256 over the canonical JSON of id, ts, stream, prev (written as null when absent), body, and context when it is present. hints are excluded.
That split is load-bearing for an audit:
contextis authoritative and it is hashed. When a writer sets it, it carries the actor, tenant, organization, objective, task, job, run and branch the receipt belongs to. Changing any of it changes the hash and breaks the chain.hintsare non-authoritative transport metadata and they are not hashed. They drive indexes, tracing and idempotency, not the record of what happened.
localeCompare and honours toJSON(). It refuses to serialize undefined, bigint, function, symbol, non-finite numbers, circular structures and non-plain objects, raising errors prefixed receipt canonicalization.
The three checks that run
On append. Each write takes a per-stream lock, reads the physical tail of the chain, and compares it to the previous hash the writer expected. A mismatch throwsExpected prev hash <x> but head is <y> and nothing is inserted. Unique indexes on the hash — globally, and per stream — mean the same receipt cannot be stored twice.
On replay. Before folding a chain into state, the runtime verifies it. A chain that does not verify is refused with Receipt runtime refused to replay invalid chain for stream '<stream>': <reason> at index <n> rather than being folded over. A corrupt chain fails loudly instead of quietly producing a wrong answer.
On demand. Verification walks a chain and returns either success with the receipt count and head, or a failure with the index at which it broke and one of exactly two reasons: broken prev or hash mismatch.
What the chain proves, and what it does not
It proves that the receipts in a stream stand in the order they were appended and that none of them has been edited, inserted or removed since — any of those changes a hash, and the next verification names the index where the chain breaks. It does not cryptographically prove who wrote a receipt. Many events name their actor in the body — a guardrail rule records itscreatedBy, updatedBy or deletedBy, and that field is hashed like everything else — but nothing signs the record, so treat a hash as tamper detection and never as origin authentication. It also does not prove that a projection table agrees with the receipts, or that an artifact a receipt refers to still exists.
One subtlety if you ever cite a receipt by hash: a branch is metadata, not a copy. Its receipts are re-linked and re-hashed onto the parent’s prefix when the branch is read, so a branch receipt’s hash as read differs from its hash as stored. Hashes are stable to quote within one unbranched stream. Receipts, chains, and streams has the full model.
Auditing the chains with receipt dst
receipt dst is the built-in audit pass over receipt streams. It ships with the developer CLI you run from a source checkout, not with the released binary — see receipts and jobs from source for the full reference.
Issues: as - <stream> [<kind>] integrity=<reason> at receipt <n>, followed by a Streams: listing. Both text listings stop at 20 entries unless you raise --limit; the --json report always contains every stream. --strict turns any failure into a non-zero exit, which is what makes it usable as a scheduled check.
Read the determinism column with care: a stream that is still being written can legitimately differ between the two passes without anything being wrong. And note the audit’s own boundary — it proves a chain is append-valid and still replayable; it does not prove that every projection matches the receipts, or that every referenced artifact still exists.