Chio/Docs
LOGIN · JOIN

Evidence Export

Export signed receipts from a known store and check them offline against the operator keys you choose to trust.

Concept chio@5f63e6e

On this page

The records behind agent work leave the operator as one directory, and a reviewer in another organization checks them offline, with no receipt database, control-plane connection, or signing secret.

chio evidence export writes a directory of receipts, capability lineage, checkpoints, and inclusion proofs, and chio evidence verify checks it against the keys the reviewer pins. Export Evidence walks one package end to end, tampering exercise included.

Evidence flowChoose a stage.
ProducerRecipientProducerRecipient

The verifier works from the exported bytes

Export reads receipts and checkpoints from the store into one directory. The verifier checks it with no access to the producer’s kernel. Export and verify evidence.

checkpoint signerbackground · chio-store-sqlite

Every checkpoint_batch_size receipts (100 by default; 0 turns it off), commits the batch’s canonical bytes to an RFC 6962 Merkle root and signs a KernelCheckpoint whose body carries previous_checkpoint_sha256 and a chain_root.

With a checkpoint: whether a receipt was in its batch, from an inclusion proof against merkle_root, and whether checkpoints chain.

evidence packagechio evidence export

A directory holding receipts.ndjson, checkpoints.ndjson, inclusion-proofs.ndjson, capability-lineage.ndjson, the checkpoint transparency records, and retention.json, with manifest.json listing a hash for every file.

From the package alone: whether any file changed since export. The manifest is not authenticated against an outside source.

verifierchio evidence verify

Checks the file hashes, the signatures the package carries, and its inclusion proofs, with no access to the producer’s kernel. The receipt-verification project repeats the receipt checks in Python, JavaScript, and Go.

It computes integrity and inclusion from bytes. Whether an external effect happened is outside what a receipt can show.

In Rust · checkpoint.rs:139
/// A signed kernel checkpoint statement.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct KernelCheckpoint {
    /// The signed body.
    pub body: KernelCheckpointBody,
    /// Ed25519 signature over canonical JSON of `body`.
    pub signature: Signature,
}
The stages in one deployment: one kernel key signs receipts and checkpoints, both stay in the receipt store, and the export reads them from there. The outside commitment is optional. The verifier computes integrity and inclusion from bytes, and the recipient pins its trusted signers independently of the package.Verifiable evidence

An export selects receipts inside an explicit read boundary

Each export reads exactly one source, a local --receipt-db or a remote --control-url, and names its read boundary with --tenant, --admin-all, or an attached federation policy. The CLI requires the boundary on the remote path too, where a tenant token alone leaves it unnamed.

Exported filestranscript
$ chio --receipt-db .chio/receipts.db evidence export --admin-all --output ./evidence
$ ls evidence
README.txt
capability-lineage.ndjson
checkpoint-consistency-proofs.ndjson
checkpoint-equivocations.ndjson
checkpoint-publications.ndjson
checkpoint-witnesses.ndjson
checkpoints.ndjson
child-receipts.ndjson
inclusion-proofs.ndjson
manifest.json
query.json
receipts.ndjson
retention.json
exit 0in my-agent

An attached federation policy is verified first and intersected with the request: exact capability, agent, and tenant constraints must agree, time bounds narrow to their overlap, and a disjoint window fails. Proof requirements combine with logical OR, so omitting --require-proofs keeps a policy's requirement in force.

The HTTP handler resolves the bearer credential to a read principal, the admin service token or a tenant read token, authorizes the requested query, merges the policy, and authorizes the merged query again before collecting anything. A signed policy therefore narrows a tenant token's authority and never extends it. Called directly, the HTTP route fills an omitted boundary from the principal. The selection reference covers sources, filters, and proof assembly.

A package carries each receipt with the lineage and proofs that cover it

A normal export writes twelve data files plus manifest.json: signed tool and child receipts, the checkpoints overlapping their range, Merkle inclusion paths for checkpointed tool receipts, deduplicated capability chains, checkpoint transparency records, retention metadata, and a README. A policy attachment adds two files and a federation-policy attachment one.

Tool proofs and child receipts answer different questions. Child receipts carry no capability, agent, or tenant join, so the query decides whether they appear as the full window, as time-window context, or not at all, and full tool-proof coverage promises no per-child proof. A tenant export narrows the tool receipts, while each covering checkpoint still describes its whole batch, so the package discloses that batch's aggregate metadata under a canonical notice.

Read more in the package files, child scope, and tenant disclosure entries below.

Verification checks the bytes and the keys you pinned

The verifier checks every declared file's SHA-256 and length, re-derives the summaries, verifies tool and child receipt signatures and tool action hashes, validates each capability snapshot, and checks checkpoint signatures and every inclusion proof against its root. Pin the expected operator with --partner, or pass a key with --trusted-kernel-pubkey; the output then states signatures verified against pinned keys.

The manifest is unsigned, so its digests show that the files agree with one another; receipt and checkpoint signatures under your pinned keys carry authenticity. Keep an independently authenticated digest of the directory when your sharing procedure needs provenance for every byte. A package with no checkpoints still verifies and reports its receipts as uncheckpointed, as the captured run shows; --require-proofs at export refuses such a package.

Read more in Verifiable evidence.

Exports read one node, and imports stay on the node that accepts them

POST /v1/evidence/export reads the responding node's local store without leader forwarding, so the package reflects that node's receipts and checkpoints at that moment. A tenant read credential exports within its authority.

POST /v1/evidence/import needs an admin credential, follows leader forwarding and write admission, and requires the package to carry a signed federation policy. Imported tool receipts and lineage go into separate share tables that keep their origin, apart from the local claim log. Cluster replication leaves those tables on the node that handled the import, and a later federated delegation can bridge to the imported lineage through a local anchor.

Read more in Federation Overview.

A scoped graph verifies against the full signed root

Transaction proof bundles let several verifier families share one signed root. One passport signs the digest of a root evidence graph, and each family evaluates only its relevant subgraph and artifact bytes, with no re-signing per projection.

Scoped root graphChoose a check.
full root graphscoped graph⊇full root graphscoped graph⊇

The passport signs the full root

The passport signs the digest of the root evidence graph. The verifier checks that signature on a passport clone with the root digest restored, so the exact signed root bytes travel with every scoped check. Proof Room.

One verifier family checking a transaction proof bundle. The references A to D are illustrative; the two graph inputs and the three checks are the ones the CLI passes, and the verifier policy and the other families are left out.

The CLI keeps the family's nodes and the edges whose endpoints survive, then passes the scoped graph and the untouched signed root to the family verifier. The verifier checks the signature on a passport clone with the root digest restored, checks that every scoped node and edge belongs to the root, and binds artifacts against the scoped graph. Membership is parsed, so object-key order and whitespace may differ, while a node or edge absent from the root fails. Scoping reduces which artifact bytes a family loads, and the omitted nodes' metadata stays readable in the root. The signature check runs against the exact signed root bytes, so preserve them unchanged.

Package and verification reference

Package files

  • manifest.json: schema, export time, query, counts, proof coverage, receipt semantics, child scope, transparency claims, file hashes, and optional attachment and disclosure metadata. Unsigned, and excluded from its own hash inventory.
  • query.json: the normalized selection and read boundary, which must equal the manifest's query.
  • receipts.ndjson: signed tool receipts paired with their combined claim-log sequence numbers.
  • child-receipts.ndjson: signed child request receipts, included or omitted by the child-scope rule.
  • checkpoints.ndjson: signed checkpoint bodies overlapping the exported tool-receipt sequence range.
  • inclusion-proofs.ndjson: Merkle paths for selected tool receipts with covering checkpoints; no per-child proof records.
  • capability-lineage.ndjson: deduplicated capability chains with their ancestors, each snapshot with a provenance class.
  • checkpoint-publications.ndjson, checkpoint-witnesses.ndjson, checkpoint-consistency-proofs.ndjson, checkpoint-equivocations.ndjson: transparency records checked against the checkpoint set and its derived summary.
  • retention.json: export-time retention metadata; tenant-scoped exports omit database-wide size and narrow the oldest-receipt timestamp.
  • README.txt: a readable restatement of counts, scope, disclosure, and the transparency claim boundary.
  • policy/source.<ext> and policy/metadata.json: the optional source policy with its format, source, and runtime hash metadata.
  • federation-policy.json: the optional signed bilateral policy constraining the export, required for import.

Empty NDJSON files are valid when a record class has no entries. The writer requires an absent or empty output directory and checks it when writing the assembled package, after collection. A later write or policy-attachment error can leave partial output, so use a fresh directory for each attempt and verify the completed package before sharing it.

Selection and proof assembly

This request exports one capability from an existing database under admin read authority and requires checkpoint coverage. Set both variables to the database and capability you intend to inspect.

Terminalbash
chio --receipt-db "$RECEIPT_DB" evidence export \
  --admin-all --capability "$CAPABILITY_ID" \
  --require-proofs --output ./evidence-reviewed

The local path opens the SQLite store with its normal opener, which creates an absent database, so check the path: a mistyped one reads as an empty log. Direct export scopes by capability, agent, time, and read boundary; the tool filters of an operator report stay on the report.

The store resolves each tool receipt by id into the combined claim log, and a missing mapping fails the export. It selects overlapping checkpoints, collects and validates the capability chains, and rebuilds Merkle trees from complete checkpoint batches to produce inclusion paths. A tool without a covering checkpoint enters the uncheckpointed list; --require-proofs refuses a nonempty list, naming up to five receipt ids with their sequence numbers. The directory records the count, and the verifier derives the missing-proof count from the receipts and proofs, which is why the operator report's coverage counts never stand in for these proofs.

Child receipt scope

ScopeQueryChild receipts
full_query_window
Admin-all, no tenant, capability, or agent filter
Every child in the window
time_window_context_only
Capability or agent filter plus a time bound
Time-window context, unattributed
omitted_no_join_path
Any tenant scope, or a filter with no time bound
None

A time window alone keeps full_query_window. Verification re-derives the flag and rejects children in an omitted scope.

Tenant exports and aggregate metadata

A tenant-scoped export narrows the tool receipts and omits children. Each covering checkpoint still describes its complete batch, which can include other tenants' records, so its range, size, root, checkpoint sequence, issue time, and previous-checkpoint digest stay visible, with the corresponding publication ranges and log size.

The export attaches a canonical disclosure notice listing those fields and the narrowed retention metadata. Verification requires the expected notice on a tenant-scoped read boundary and refuses it on admin-all.

Verification checks

  • File inventory. Every listed file matches its declared SHA-256 and byte length; duplicate entries and lexically escaping paths are refused.
  • Manifest and selection. Record counts, receipt semantics, the query copy, child scope, disclosure notice, and proof-coverage summaries agree with the data.
  • Receipt signatures. Tool and child signatures and tool action hashes verify, at the AllowHybrid crypto floor.
  • Capability lineage. Each snapshot passes transport validation: SignedToken provenance verifies its token and projected fields, SyntheticAnchor is unsigned structural provenance, and LegacyProjection is refused.
  • Checkpoint evidence. Checkpoint schemas, signatures, and transparency records validate, and each tool proof resolves its receipt and checkpoint, agrees with the root and range, and verifies the canonical receipt bytes.
  • Missing tool proofs. The derived count of tools without a proof matches the manifest; a nonzero count can still verify.

These are the main stages; the loader checks summary consistency before its receipt-signature pass, so a modified receipt can fail at the summary stage first. The hash loop covers entries declared in manifest.files and accepts extra files in the directory, and replacing the unsigned manifest replaces its digests too.

Retention metadata and README text are checked by hash when listed and are not re-derived from a database. Policy attachment validation compares metadata with the manifest and checks that the source file exists, without reloading the policy. A synthetic lineage anchor needs its own authority context; traveling beside a receipt leaves it unsigned.

A verified package without checkpoints

This captured first-call package holds two tool receipts, one authorized decision and one denial, with no checkpoints or inclusion proofs. Ordinary verification succeeds and reports both receipts as uncheckpointed.

Offline verificationtranscript
$ chio evidence verify --input ./evidence
evidence package verified
tool_receipts:          2
child_receipts:         0
checkpoints:            0
checkpoint_publications: 0
checkpoint_witnesses:   0
checkpoint_consistency_proofs: 0
checkpoint_equivocations: 0
capability_lineage:     2
inclusion_proofs:       0
uncheckpointed_receipts: 2
authorized_receipts:     1
trace_observations:      0
advisory_evaluations:    0
verified_files:         12
child_receipt_scope:    FullQueryWindow
transparency_preview_logs: 0
publication_state:      transparency_preview
exit 0in my-agent

evidence package verified here comes with uncheckpointed_receipts: 2 and inclusion_proofs: 0, so the boundary is in the output. Exporting the same log with a proof requirement fails:

Proofs requiredtranscript
$ chio --receipt-db ./.chio/receipts.db evidence export \
  --output ./evidence-proofs --admin-all --require-proofs
error[CHIO-ATTEST-PROVENANCE-MISSING]: evidence export requires checkpoint coverage, but 2 receipt(s) are uncheckpointed: f8128d2289c69d835348f229edfdd2714a8b3c6f064f4f7324b652a299e9a4b3@1, e7a4fc95979cc9b31d8b740c27cd58f1fde209aac323aaeac115544d82be2ee7@2
  help: export again once a checkpoint covers these receipts, or drop --require-proofs
  code: urn:chio:error:attest:provenance-missing
  docs: https://chio.computer/docs/reference/errors#error-attest-provenance-missing
exit 1in my-agent

The package's publication state stays transparency_preview until its publication records satisfy the shared trust-anchor binding. Receipt Aggregation explains how checkpoints are produced.

Tampering failure

This experiment changes the denied receipt into an allow and leaves the manifest unchanged. Verification stops on the file digest, which demonstrates the inventory check before any signature pass.

Tampering rejectedtranscript
$ cp -R ./evidence ./evidence-flipped
$ jq -c 'if .receipt.decision.verdict == "deny" then .receipt.decision = {"verdict": "allow"} else . end' \
    ./evidence/receipts.ndjson > ./evidence-flipped/receipts.ndjson
$ chio evidence verify --input ./evidence-flipped
error[CHIO-ATTEST-PROVENANCE-MISSING]: evidence package file hash mismatch for receipts.ndjson
  help: receipts.ndjson changed after the package was exported; verify the package as exported, or export it again
  code: urn:chio:error:attest:provenance-missing
  docs: https://chio.computer/docs/reference/errors#error-attest-provenance-missing
exit 1in my-agent

Enterprise export artifacts

The enterprise verification family binds five typed artifacts to a transaction passport and one referenced risk comptroller report. It checks the supplied artifacts and their bindings; the export itself is a separate operation.

  • Data governance report. Passport and risk-report identity, permitted region, retention classification, hold status, and field export classifications.
  • Evidence export bundle. Artifact bytes and digest inventory, required roles, approval linkage, and issuance window.
  • Approval case. The export digest, the approved evidence-export subject, the declared approver quorum, the validity window, and a trusted approval signature.
  • Telemetry projection. Events bound to bundle artifacts and the required receipt-backed evidence.
  • Control evidence map. Recognized claims and their graph artifacts, with matching bytes and schemas.

The family takes independently pinned passport, approval, risk-comptroller, and receipt-kernel signer keys, and has no permissive default. An auditor reviewing your deployment pins each signer from a channel it trusts before it verifies the export:

Terminalbash
chio trust pin enterprise.receipt-kernel ./larkfield.card
chio trust pin enterprise.approval ./mara-okafor.pub --name mara
chio trust pin enterprise.risk-comptroller ./larkfield-risk.pub --name larkfield-risk
chio proof verify ./larkfield-export --require enterprise
Output
pinned     larkfield       enterprise.receipt-kernel     ed25519:4f1c…a2e9
pinned     mara            enterprise.approval           did:chio:z6Mkf3…Qp9
pinned     larkfield-risk  enterprise.risk-comptroller   ed25519:4f1c…a2e9
file       ~/.chio/trust.toml
VERIFIED   passport-larkfield-export  12 claims
required   enterprise: all covered
trust      ~/.chio/trust.toml

A role with no pin stops the run with CHIO-TRUST-ROLE-UNPINNED before any artifact is read. Proof Room runs the transaction verifier; Risk Comptroller Reports covers the signed risk artifact.

Matching a check to a conclusion

Ordinary verification establishes package consistency and the signatures under your pinned keys. Require tool inclusion proofs when checkpoint coverage matters, keep a directory digest when whole-package provenance matters, and read the tenant disclosure notice and the import's node before relying on either boundary.

Source files

  • crates/platform/chio-control-plane/src/evidence_export.rs and evidence_export/verification.rs: package writing and offline checks.
  • crates/platform/chio-store-sqlite/src/evidence_export.rs: selection, combined-log positions, and proof assembly.
  • crates/kernel/chio-kernel/src/evidence_export.rs: child scope and transparency claims.
  • crates/platform/chio-transaction-passport/src/minimal.rs (lines 200 to 255, the signed-root and subset checks) and crates/platform/chio-enterprise-export/src/lib.rs: scoped verification and enterprise inputs.

Next: reproduce a package and verify it

Evidence Export · Chio Docs