Docs The loop
Evidence
Show that someone who does not trust you can check the record without Runback.
Evidence. Every run is kept as a record that anyone can re-check: each event is hash-chained to the one before it, and the record is signed. Change anything and the check fails at the place it changed.
/sample-cassette.json…The record above is /sample-cassette.json, the same file the command below downloads. It is a loan-approval run, not the refund run: a fixed record built by the code that builds every customer export, so it is identical on every deploy. Each check goes to POST /api/audit/verify, which runs the same verification as the CLI and stores nothing.
How to: export and verify a record
Download the record
Open the run in Runs. In the run's own Audit log section, select Download. You get
runback-audit-RUN_ID.json, with the run's id in place ofRUN_ID.Verify it, offline
Anyone can run this, with no Runback account and nothing sent anywhere:
terminalShell npx @runback/verify runback-audit-RUN_ID.jsonExpected outputrunback.audit/v2 — VALID
✓ schema
✓ summary
✓ chain
✓ digest
✓ cassette
✓ signature — Ed25519 — verified against Runback's published key
The command exits 0. A changed record prints INVALID, marks the failed check ✗ and exits 1.
Export the evidence pack for a period
For an auditor, open Evidence, choose the Reporting period, then select Download report. From Enterprise
Check it on your own machine
#!/usr/bin/env bash
# Verify the published sample record on your own machine. Nothing is sent anywhere.
set -euo pipefail
curl -fsSLO https://runback.dev/sample-cassette.json
npx @runback/verify sample-cassette.json
# Exit 0 = VALID, 1 = INVALID (a check failed), 2 = UNVERIFIED (intact, signer not confirmed).The command has its own words for a result. This is what each one means here:
| The command prints | Exit code | In Runback's words |
|---|---|---|
VALID | 0 | Intact and Signed: every check passed, and the signature checks against Runback's published key (or the HMAC key you passed with --key). |
UNVERIFIED | 2 | Intact, signer not confirmed: the record is unchanged, but it is signed by another key, such as a self-hosted deployment's, or not signed at all. Not tampering, and not a pass. |
INVALID | 1 | Changed: a check failed. The ✗ marks which one. |
What is checked
Anyone can author a record that passes the first five checks, because the chain algorithm is public; only the signature says who made it. The exact algorithm, canonical JSON and the signature formats are in the record spec.
The first five say the record is intact. The sixth says who signed it.
| Check | The command prints | What passing it shows |
|---|---|---|
| Format | schema | The record declares a format this verifier knows. |
| Summary | summary | The run id and outcome in the summary agree with the signed events, so a summary cannot misstate the run however intact the chain is. |
| Hash chain | chain | Every event's recomputed hash matches the one stored beside it. |
| Content digest | digest | The last hash in the chain matches the digest in the record's manifest. |
| Recording digest | cassette | The recorded model, tool and environment results still match the digest taken when they were recorded. |
| Signature | signature | Who signed the record. Signed by Runback's published key is a pass; signed by another key, or not signed, leaves the record intact but its signer unconfirmed. |
Signatures
A deployment signs records with Ed25519 when it sets AUDIT_ED25519_PRIVATE_KEY; without it, it falls back to the legacy HMAC-SHA256 over AUDIT_SIGNING_KEY, which only the holder of the secret can check. What the command reports depends on the key:
| The record is signed with | The command's JSON | It prints | In Runback's words |
|---|---|---|---|
| Runback's published Ed25519 key | valid | VALID | Signed |
| Another Ed25519 key, such as a self-hosted deployment's | valid-unpinned | UNVERIFIED | Intact, signer not confirmed |
HMAC, checked with the secret passed as --key | valid | VALID | Signed by the key you passed |
HMAC, without --key | no-key | UNVERIFIED | Intact, signer not confirmed |
| Nothing | unsigned | UNVERIFIED | Intact, signer not confirmed |
Each event's hash covers the one before it, so the record is a chain, not a Merkle tree:
h(i) = SHA-256(h(i-1) + canonical(event i))The rest of Evidence
| In the app, under Evidence | What it holds |
|---|---|
| Evidence | The period's evidence pack, signed |
| Frameworks | The controls each regulation maps to |
| Audit log | Every entry, and the checkpoints that sign them |
| Activity | Admin changes and sign-ins in the workspace |
Outside the app, the verifier page checks any exported record, and Enterprise covers regulator exports and auditor access.