Skip to content

Reference

Receipt format

The schema a receipt conforms to, and a verifier you can run on one without installing Excellent.

On this page

A receipt is what a verification run leaves behind. It binds the work, the evidence, the policy and the verdict into one document, hashes that document canonically, and signs the hash with an Ed25519 key. The point of it is that you do not have to trust the machine that produced it, or us.

That claim is only worth something if you can check it. This page publishes the format — a JSON Schema — and a verifier you can read in one sitting and run on a machine that has never had Excellent on it. Both are served from this site:

Check one in under a minute

curl -fsSLO https://www.excellent.so/verify-receipt.mjs
curl -fsSLO https://www.excellent.so/receipt-example.json
curl -fsSLO https://www.excellent.so/receipt-example-key.pub.pem
 
node verify-receipt.mjs receipt-example.json --pubkey receipt-example-key.pub.pem

Real output, from that exact command:

Excellent receipt check — receipt-example.json
 
  PASS  pack shape
        schemaVersion 1, envelope and trust root present
  PASS  signature algorithm is Ed25519
        signature.algorithm = ed25519
  PASS  canonical binding present
        the receipt is bound to a work snapshot, contract, evidence snapshot, evaluator, determination, enforcement decision, review and build
  PASS  payload matches its hash
        recomputed sha256:ee27611cb8b1d02d3edca0ad12308a64409930de759f7fc64c9f39042387b5bc from the receipt content and it matches envelope.payloadHash
  PASS  envelope summary agrees with the receipt
        publicVerification restates the receipt id, run, tenant, key and hash without contradicting them
  PASS  receipt and envelope carry the same signature
        receipt.signature mirrors envelope.signature
  PASS  Ed25519 signature verifies
        the signature over sha256:ee27611cb8b1d02d3edca0ad12308a64409930de759f7fc64c9f39042387b5bc checks out against the public key you supplied
  PASS  signing key is declared by the pack
        trustRoot declares key_example_2026_09
  PASS  key fingerprint matches the one you pinned
        sha256 over your PEM file is sha256:7e7b79a7135e246e76931580fd56a5d49fe94b2024c18dc81157038822bd1b4c, which is the fingerprint the pack declares for key_example_2026_09
  PASS  ledger anchor
        the ledger and audit log match anchor sha256:ba2658d08481e61503a281a16ab83a37edcd54521475e33d5571fc6809258c0f, recorded to operator-held-file at 2026-09-23T17:05:00.000Z
 
RESULT: VERIFIED

The script then prints what that result does and does not establish. It exits 0 when the pack verifies, 8 when it does not, and 2 on a usage error — the same contract as the shipped CLI. Add --json for one machine-readable line instead.

Then break it, and watch it fail. Change any character of the receipt's content — the verdict, a timestamp, one hex digit of an evidence hash — and run it again:

  FAIL  payload matches its hash
        envelope.payloadHash is sha256:ee27611cb8b1d02d3edca0ad12308a64409930de759f7fc64c9f39042387b5bc but the content canonicalizes to sha256:7930319d69b2c1fceb5c0a4bc0187b57789c55df8a2dbc523685827afa6a08e2 — the receipt body has been altered since it was hashed
 
RESULT: NOT VERIFIED

The signature is still a valid signature — of the original payload. What no longer holds is that the document in front of you is the document that was signed. Reformatting is a different matter: minify the file, reorder its keys, change its indentation, and it still verifies, because the signature covers a canonical rendering rather than the bytes on disk.

What the verifier checks

In order, and each one independently:

  1. The pack is the right shape. schemaVersion 1, with an envelope and a trust root.
  2. The signature algorithm is Ed25519. An authoritative receipt signed any other way is refused rather than downgraded.
  3. A binding is present. Without one, a PASS is a verdict about nothing in particular.
  4. The payload matches its hash. The canonical payload is rebuilt from the receipt and the binding, hashed, and compared to envelope.payloadHash. This is the tamper check.
  5. The envelope's summary agrees with the receipt. publicVerification is a convenience copy and is not signed, so it is treated as a claim and cross-checked.
  6. The receipt and the envelope carry the same signature.
  7. The Ed25519 signature verifies against the public key you passed on the command line — never a key read out of the pack itself.
  8. The pack declares the signing key, and
  9. the key's fingerprint matches the one you pinned: sha256 over the bytes of your PEM file, compared to the fingerprint the pack states.
  10. The ledger anchor holds. The anchor's id is recomputed from its contents, and the ledger and audit log are compared entry by entry against what it commits to.

Only the first nine are about the receipt. The tenth is about whether the chain it sits in has been rewritten.

The schema

receipt-schema.json describes the whole pack: the signed envelope, the receipt inside it, the binding that says what the receipt is about, the trust root, and the ledger anchor. Every field in it exists in the code that mints receipts; optional fields are marked optional, and fields whose meaning is not obvious from their name carry a description.

Four things the schema says that are easy to miss, and that matter if you are writing your own verifier:

The signature does not cover the file. It covers a canonical rendering of a fixed field list: predicate, schemaVersion, id, tenantId, runId, parentReceiptId, status, checkResultIds, evidenceHashes, policyVersionRefs, engineVersion, issuedAt, binding, and decision when the receipt carries one. Object keys are sorted, id arrays are sorted, there is no whitespace, and absent optional keys are omitted rather than written as null. Everything else in the file is outside the signature.

publicVerification is outside it. It restates the receipt id, run, tenant, key and hash so a third party can check the signature without parsing the rest — but nothing stops someone editing it. A verifier has to re-derive those facts from the receipt and reject a document where the two disagree.

Absent is not the same as empty, except where it is. In the binding, an absent obligationResultIds canonicalizes to [], so absent and empty hash identically. An absent decision is omitted from the payload entirely, so absent and present-but-empty do not. That asymmetry is deliberate: receipts issued before decision existed are signed and immutable, and emitting the key unconditionally would have stopped every one of them verifying.

status is an aggregate, decision is not. A run whose predicate was evaluated and came back false, and a run where nothing evaluated the predicate at all but one evidence artifact was unregistered, both aggregate to FAIL. decision is the field that separates them. When it is absent, the receipt does not disclose whether anything was decided — which is not the same as saying nothing was.

The example receipt

The document below is the file at receipt-example.json. It is a synthetic example, and the line between what is invented and what is not matters here. The work it describes is invented: a throwaway task, a throwaway tenant, ids that point at nothing. The document around that work is not. It was produced by the same envelope builder, the same canonical hash, the same Ed25519 signing convention and the same anchor construction that a customer's receipts go through, signed with a keypair generated for this page and then discarded, and it verifies both under the script above and under Excellent's own offline verifier.

A receipt from real work names a real repository, a real commit and a real task. Publishing one of those is a separate decision, and this page is built so that such a receipt can take this slot without anything else here changing.

{
  "schemaVersion": 1,
  "generatedAt": "2026-09-23T17:05:00.000Z",
  "envelope": {
    "schemaVersion": 1,
    "serviceVersion": "2026-08-16.v1",
    "receipt": {
      "schemaVersion": 1,
      "id": "receipt_example_a1b2c3",
      "tenantId": "tenant_example",
      "runId": "run_example_7f3a",
      "parentReceiptId": null,
      "status": "PASS",
      "decision": {
        "decided": true,
        "decidedBy": "excellent.evaluator.unit-test-predicate@1.4.0",
        "predicateStatus": "PASS",
        "undecidedReasonCode": null
      },
      "checkResultIds": [
        "check_example_unit_tests",
        "check_example_typecheck",
        "check_example_evidence_integrity"
      ],
      "evidenceHashes": [
        "sha256:0ae18d55145fdfa9be069b98ea6afa2e16070cba8b2b025c76dea1b6ed52d35e",
        "sha256:70d6383e2b282c115efcac1f436506827d7d01964f5a95645b1b7dfd51d18976",
        "sha256:db792624ecd6a865a2155a8bbf457f33c7b11fa8a47bc1a38118ddaa641f2b44"
      ],
      "policyVersionRefs": [
        "excellent.policy.agent-work@2026-08-16",
        "sha256:9f2c1d6b5a4e38f70c1b2d3e4f50617283940a1b2c3d4e5f60718293a4b5c6d7"
      ],
      "engineVersion": "excellent-verification-engine@2026-08-16.v1",
      "issuedAt": "2026-09-23T17:04:11.000Z",
      "signature": {
        "keyId": "key_example_2026_09",
        "algorithm": "ed25519",
        "value": "ed25519:nAAB2y8VQ5kvh5md75R42aIcMhfsKBlVEPP_kmhuYcN9VdiQn3x-fh8AvtZTmRfBJr-lqP4-uGNY2hD9TAHdDg"
      }
    },
    "binding": {
      "predicate": "excellent.verification.agent-work-receipt.v1",
      "workItemId": "work_example_add_retry",
      "workSnapshotId": "snapshot_example_0f11",
      "attemptId": "attempt_example_01",
      "runManifestId": "manifest_example_01",
      "contractId": "contract_example_unit-tests-must-pass@3",
      "evidenceSnapshotId": "evidence_snapshot_example_51ab",
      "evidenceGraphDigest": "sha256:06e23d6cc15f57df2d8e123fbe2520e8291472fa4f2dcc573aa18a903e93d598",
      "obligationResultIds": [
        "obligation_example_tests",
        "obligation_example_types"
      ],
      "evaluatorRefs": [
        "excellent.evaluator.unit-test-predicate@1.4.0"
      ],
      "determinationId": "determination_example_9c2",
      "validityStateId": "validity_example_current",
      "enforcementDecisionId": "enforcement_example_promote",
      "enforcementEffectIds": [
        "effect_example_merge_allowed"
      ],
      "reviewDecisionIds": [
        "review_example_auto_accept"
      ],
      "outcomeObservationIds": [
        "outcome_example_no_regression_7d"
      ],
      "auditEventIds": [
        "audit_example_mint"
      ],
      "buildRef": "build_example_2026-09-23.1",
      "subject": {
        "treeHash": "sha1:4d9f1c0b7a6e5d4c3b2a19087f6e5d4c3b2a1908",
        "commitSha": "c0ffee1234567890abcdef1234567890abcdef12",
        "buildId": "build_example_2026-09-23.1",
        "imageDigest": "sha256:1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809",
        "tenantId": "tenant_example",
        "environmentId": "env_example_ci",
        "policyDigest": "sha256:9f2c1d6b5a4e38f70c1b2d3e4f50617283940a1b2c3d4e5f60718293a4b5c6d7"
      }
    },
    "payloadHash": "sha256:ee27611cb8b1d02d3edca0ad12308a64409930de759f7fc64c9f39042387b5bc",
    "signature": {
      "keyId": "key_example_2026_09",
      "algorithm": "ed25519",
      "value": "ed25519:nAAB2y8VQ5kvh5md75R42aIcMhfsKBlVEPP_kmhuYcN9VdiQn3x-fh8AvtZTmRfBJr-lqP4-uGNY2hD9TAHdDg"
    },
    "publicVerification": {
      "algorithm": "sha256",
      "payloadHash": "sha256:ee27611cb8b1d02d3edca0ad12308a64409930de759f7fc64c9f39042387b5bc",
      "signatureAlgorithm": "ed25519",
      "keyId": "key_example_2026_09",
      "receiptId": "receipt_example_a1b2c3",
      "runId": "run_example_7f3a",
      "tenantId": "tenant_example",
      "issuedAt": "2026-09-23T17:04:11.000Z",
      "parentReceiptId": null
    }
  },
  "trustRoot": {
    "tenantId": "tenant_example",
    "generatedAt": "2026-09-23T17:05:00.000Z",
    "declaredKeys": [
      {
        "keyId": "key_example_2026_09",
        "fingerprint": "sha256:7e7b79a7135e246e76931580fd56a5d49fe94b2024c18dc81157038822bd1b4c",
        "algorithm": "ed25519"
      }
    ],
    "signedByKeyId": "key_example_2026_09",
    "signatureAlgorithm": "ed25519"
  },
  "ledgerAnchor": {
    "schemaVersion": 1,
    "id": "sha256:ba2658d08481e61503a281a16ab83a37edcd54521475e33d5571fc6809258c0f",
    "target": "operator-held-file",
    "anchoredAt": "2026-09-23T17:05:00.000Z",
    "ledgerHead": "sha256:fabe76b800f3d84dde97be85a1e32b72c096491d02f4c826400d54a207ba6e33",
    "ledgerLength": 2,
    "ledgerEntryHashes": [
      "sha256:91ba2f9aa2f63fa36df1bb719959bcaebb8034852886bbee141b2a5825a059d3",
      "sha256:fabe76b800f3d84dde97be85a1e32b72c096491d02f4c826400d54a207ba6e33"
    ],
    "auditLogHead": "sha256:033be47f7c89645acecf79fd7f6976622c62f18dd105331dd1771c8d2d03a5f4",
    "auditLogLength": 1,
    "auditLogEntryHashes": [
      "sha256:033be47f7c89645acecf79fd7f6976622c62f18dd105331dd1771c8d2d03a5f4"
    ]
  },
  "ledger": [
    {
      "id": "ledger_example_1",
      "entryHash": "sha256:91ba2f9aa2f63fa36df1bb719959bcaebb8034852886bbee141b2a5825a059d3"
    },
    {
      "id": "ledger_example_2",
      "entryHash": "sha256:fabe76b800f3d84dde97be85a1e32b72c096491d02f4c826400d54a207ba6e33"
    }
  ],
  "auditLog": [
    {
      "id": "audit_example_1",
      "entryHash": "sha256:033be47f7c89645acecf79fd7f6976622c62f18dd105331dd1771c8d2d03a5f4"
    }
  ],
  "legacyReadOnly": false
}

Checking a receipt of your own

The script takes any receipt pack, not just this one. Excellent writes them; point the script at yours and pin your own key:

node verify-receipt.mjs my-receipt-pack.json --pubkey my-key.pub.pem

If you also hold an anchor id from outside the pack, supply it and rollback becomes detectable too. Both flags are required together — an anchor id with no time cannot tell a pack that is merely out of date from one attesting a different ledger:

node verify-receipt.mjs my-receipt-pack.json --pubkey my-key.pub.pem \
  --expect-anchor-id sha256:… --expect-anchored-at 2026-09-23T17:05:00.000Z

verify-receipt.mjs is a second, independent implementation of the format described here. The reference implementation is excellent-mcp receipt verify <pack.json> --pubkey <key.pem>, which runs the same checks from inside the product and reports them as one JSON line. The two agreeing is the useful signal. The two disagreeing would be a bug worth telling us about, in whichever one turns out to be wrong.

What a valid signature does not establish

A valid signature means the receipt has not been altered since the holder of that key signed it, and that the verdict is bound to a named work snapshot, contract, evidence snapshot and build. That is tamper-evidence, and it is real.

It does not establish that the work was good. A receipt records that checks ran and what they concluded. Whether those were the right checks — whether they test anything worth testing — is a judgement the signature cannot make for you. The receipt names its checks by id precisely so that you can go and look.

It does not establish who signed. A signature proves custody of a key, never an identity. If you obtained the key from the same system that issued the verdict, a forged receipt re-signed under an attacker's key verifies exactly as cleanly as a genuine one. Confirm the key's fingerprint through a channel that system does not control, then pin it — which is what --pubkey is for, and why the script refuses to read a key out of the pack it is checking.

And with no independently held anchor, it does not establish that you are holding the current pack. A genuine anchor from an earlier state, presented with the ledger rewound to match it, verifies exactly like a current one.