Blog

What a signed receipt proves — and why logs can't

A CI log says a command ran once, somewhere, and can be edited afterward. A signed receipt binds the command, its output, its coverage, and the exact repository tree into one artifact anyone can verify and nobody can quietly alter.

2026-08-18 · Sathwik R

A signed receipt is a small artifact that answers one question a log cannot: did this exact evidence come from this exact command, run against this exact code, unmodified since? Relay wraps every measured test run in one, signs it with Ed25519, and computes verdicts only from receipts that verify. This post is what's inside one and why each piece is there.

Why isn't a CI log enough?

A log is a byproduct. It shows that a command produced some output at some point — but it does not bind that output to the code it ran against, it can be edited after the fact, it can be cherry-picked from a different run, and nothing about it fails loudly when any of that happens. For human-written code this was mostly fine, because the person who wrote the code also had little reason to fool themselves. An AI agent changes the economics: it produces the code, the tests, *and* the report of success, at a rate nobody reviews. Evidence about that work needs to be the kind that cannot be produced by the thing it is evidence about.

What is inside a receipt?

Five things, each closing a specific hole:

  • The command, exactly as executed — argv, exit code, duration, and sha256 hashes of its stdout and stderr. Not a summary of the run; the identity of the run.
  • The coverage report of that run — so "the tests passed" and "the tests executed these lines" travel together, and the second claim is measured rather than asserted.
  • A snapshot hash of the repository tree — the receipt describes *this* code. Edit a file after signing, and the snapshot no longer matches: the evidence is visibly stale rather than silently wrong. This closes the in-place-edit hole where code introduced after evidence was signed still looked verified.
  • The producer's identity — which key signed this, so trust decisions attach to signers, not files.
  • The Ed25519 signature over all of it — the receipt's id is a hash of its canonical content, and the signature covers that content. Change any byte and verification fails.

Who can and cannot make one?

Anyone can *run* the signing command — but the key that signs must have been approved by a human, in a terminal, once per machine. That approval is the one step Relay's agent loop cannot perform for itself, and it is what makes the signature mean something: the agent whose work is being judged cannot mint the evidence that judges it. The loop's contract is explicit — never write, edit, or fabricate receipts — and a fabricated file without a valid signature simply fails verification.

What does verification require?

The public key. Nothing else — no account, no server, no secrets. A receipt produced on a laptop verifies in CI, and one produced in CI verifies on a laptop. That is what makes receipts *transferable* evidence: they carry their own checkability. It is also why Relay's own verdict artifacts are deliberately unsigned — a verdict is a computation over receipts that any party should re-run for itself, not an assertion to be trusted. Receipts are the evidence; the verdict is arithmetic.

What does a receipt not prove?

The usual honest limits. A receipt proves the command ran, what it printed, what the coverage measured, and that nothing changed since — on the machine where it ran. It does not prove the tests are good tests, that the code is correct, or that the machine itself was trustworthy beyond the key a human vouched for. Relay states which trust boundary each profile carries rather than papering over it, because evidence that overstates its own strength is the exact failure the product exists to catch.

Receipts are produced by relayevals receipt run and consumed by relayevals verdict — the CI guide shows both in a pipeline, and the docs cover the full trust model.