CLI
The receipta CLI (@receipta/cli) verifies chains offline, exports receipts for auditors, and generates signing keys.
verify
receipta verify <store> [--trust-root <dir>] [--format json|text]Verifies a receipt chain offline (no network).
- Exit
0: the chain is fully valid. - Exit
1: a divergence was found (tamper, torn tail, untrusted key). The report names the first divergence — which receipt (seq), whichfield, whatkind, and why. - Exit
2: the trust root could not be established (missing directory, no keys, or a mislabeled key). Fails loud rather than verifying against an untrusted key.
--trust-root defaults to ./keys. --format json emits a machine-readable report.
export
receipta export <store> --format json|csv|ocsf|intoto|dsse [--out <file>] [--key <keyfile>]
[--from-seq <n>] [--to-seq <n>] [--since <iso>] [--until <iso>]
[--actor <id>] [--provider <name>]Exports receipts in an auditor-consumable format without re-signing (the store is never altered; every export is a read-only pass over the log).
json: the raw receipt objects.csv: one row per receipt with flattened key fields.ocsf: OCSF v1.7 API Activity events (class uid 6003) — the shape SIEMs and audit pipelines expect.intoto: an in-toto Statement v1 per receipt (unsigned JSON). The receipt body is the attested artifact;subject.digest.sha256is the body hash, and the statement is pipeable intocosign/another signer.dsse: a DSSE v1 envelope around each in-toto Statement, signed at export time with a key you supply via--key. The signature is over the DSSE PAE of the raw statement bytes (not the base64 payload). The store and every receipt body stay untouched — the DSSE layer is a NEW envelope around the unmodified receipt.
--format dsse requires --key <keyfile> (a receipta key-pair JSON file produced by receipta key gen --out-private). --key is rejected for the other formats. All formats emit a JSON array (one entry per receipt).
Filters
The six filter flags are optional, inclusive, and combine with AND; they apply only to export (using one on any other command exits 2 — verify always verifies the whole chain):
--from-seq <n>/--to-seq <n>— receipt sequence bounds (body.seq).--since <iso>/--until <iso>— timestamp bounds, UTC ISO-8601 withZ(e.g.2026-08-14T20:00:00Z), compared againstbody.timestamp.iso8601_ms.--actor <id>— exact match onbody.actor.id.--provider <name>— exact match onbody.provider.
A filter matching nothing exports an empty set ([], or the CSV header alone) with exit 0 — filters are a projection, not a lookup.
Verifying a DSSE export
A recipient verifies an envelope independently of receipta, using only the trusted public key:
- Decode the base64
payloadto recover the in-toto Statement bytes. - Compute the DSSE PAE:
"DSSEv1 " + len(payloadType) + " " + payloadType + " " + len(bytes) + " " + bytes. - Verify the base64-decoded
sigagainst the PAE under the public key whose id matchessignatures[0].keyid.
show
receipta show <store> <seq>Prints exactly one receipt (pretty JSON) by its sequence number. Read-only: no writer lock, the store is never modified, and torn/malformed frames are skipped rather than shown. Exits 1 naming the requested seq if that receipt is absent (the store may be missing/empty, have fewer receipts, or the record may be torn); exits 2 on a missing or non-integer seq.
tail
receipta tail <store> [n]Prints the last n receipts (default 10) as NDJSON — one compact JSON object per line, ready for jq/scripting. Same read-only and skip-torn-frames rules as show. n=0 prints nothing; a missing/empty store prints nothing with exit 0.
key gen
receipta key gen [--out <dir>] [--out-private <file>] [--format text|json]Generates an Ed25519 key pair, writes the public key to <out>/<key_id>.pub (default <out> is ./keys), and prints the key fingerprint. The fingerprint should be verified on a second channel (this is the trust bootstrap).
By default the private key is held in memory only and discarded — store it securely (env/KMS) for signing. Pass --out-private <file> to also persist the private key to disk in the receipta key-pair JSON format ({keyId, publicKey, privateKey}, hex-encoded byte fields). The file is written with mode 0600 and the write refuses to overwrite an existing file. Protect this file — anyone holding it can sign receipts as this key_id. A persisted key file is what receipta export --format dsse --key consumes.
--format json prints a machine-readable summary ({keyId, publicKey, publicKeyPath} plus privateKeyPath only with --out-private) for scripting; the warning/note prose moves to stderr so stdout stays parseable. The private key material itself is never printed in either stream.