Evidence Exchange Walkthrough
Export receipts under a signed sharing policy, import them with their origin intact, and issue a partner grant from the imported capability.
On this page
Two operators can audit each other's agent work from signed records, with no access to each other's systems. The origin exports its kernel's receipts under a signed sharing policy; the partner imports them with the origin's signer key intact, then issues its own agents authority that names the imported grant as its parent.
Run the exchangeThe partner imports three signed receipts under the origin's policy
Download the federation guide project, produce the origin's evidence, then sign the sharing policy, export under it, and import on the partner's side. Both operators run on this machine, and every command starts in federation-guide/.
curl --fail --location https://www.chio.computer/examples/federation-guide.zip \
--output federation-guide.zip
unzip federation-guide.zip
cd federation-guide
cargo run --locked --bin evidence
EVIDENCE_SINCE=$(jq -r .since evidence-run/window.json)
EVIDENCE_UNTIL=$(jq -r .until evidence-run/window.json)
umask 077
openssl rand -hex 32 > sharing.seed
chio evidence federation-policy create \
--output sharing-policy.json --signing-seed-file sharing.seed \
--issuer operator-review --partner operator-audit --admin-all \
--since "$EVIDENCE_SINCE" --until "$EVIDENCE_UNTIL" \
--expires-at "$((EVIDENCE_UNTIL + 3600))" --require-proofs \
--purpose 'review the bounded local example run'
chio evidence export --receipt-db evidence-run/receipts.sqlite3 \
--federation-policy sharing-policy.json --output partner-package
chio evidence import --receipt-db partner-receipts.sqlite3 --input partner-packagetwo allowed calls; one out-of-scope denial; handler calls 2 three receipt signatures verified; checkpoint batch size 1 wrote evidence-run/receipts.sqlite3, window.json, and kernel-public-key.txt federation policy created output: sharing-policy.json issuer: operator-review partner: operator-audit signer_public_key: a79d14964c71eabaa06955b1a3709dc58ebc0e7e8d6f5b9e59194fea184a924e require_proofs: true federated evidence share imported share_id: share-6f9d2c1a916c3e3c6a575f14826be511af95c792e89e8d7e81d8350f5c1d4ed6 issuer: operator-review partner: operator-audit signer_public_key: a79d14964c71eabaa06955b1a3709dc58ebc0e7e8d6f5b9e59194fea184a924e tool_receipts: 3 capability_lineage: 1
You should see two allowed calls, one out-of-scope denial, and three verified receipt signatures from the origin, then the signed policy, then federated evidence share imported with tool_receipts: 3 and capability_lineage: 1. Keys, timestamps, and the share id change between runs.
Before you begin
Install Git, curl, unzip, Rust through rustup, a C or C++ build toolchain, jq, and OpenSSL, and install the CLI with curl -fsSL https://chio.computer/install.sh | sh. The project pins its Rust toolchain and a Cargo lockfile, and Cargo fetches the pinned public Chio crates, so the first build compiles the kernel and later programs reuse it. The evidence program refuses to overwrite evidence-run/; move it aside to repeat the run.
One package carries both the receipts and the lineage the partner builds on
The origin operator issues the sharing policy and the primary package. The reviewing operator checks the policy's scope, verifies the package, and applies its own weighting to what it imports.
The partner holds the origin’s receipts, still signed by the origin
The origin kernel signs a receipt for each of three calls: two allowed and one refused as out of scope. chio evidence export packages them under the signed sharing policy, and chio evidence import stores the share on the partner’s side with the issuer and signer key it arrived with. Share evidence with a partner.
Only the package crosses the boundary. Each kernel keeps its own keys, receipt store, and policy, and a third operator can mirror published artifacts that the reviewing operator reads without trusting the mirror.
The origin's kernel signs a receipt for every call, the refusal included
evidence.rs sends two allowed calls and one call to a tool outside the grant through a kernel with a SQLite receipt store and a checkpoint for every receipt, then writes the time window it used.
use chio_kernel::Verdict;
use federation_guide::*;
use serde_json::json;
use std::{path::Path, sync::atomic::Ordering};
#[tokio::main]
async fn main() -> Result<(), Error> {
let directory = Path::new("evidence-run");
let host = host(directory)?;
let since = now();
for id in ["review-a", "review-b"] {
let response = host
.kernel
.evaluate_tool_call(&request(&host.capability, id))
.await?;
assert_eq!(response.verdict, Verdict::Allow);
record(directory, id, &response)?;
}
let mut forbidden = request(&host.capability, "review-denied");
forbidden.tool_name = "delete".into();
let denied = host.kernel.evaluate_tool_call(&forbidden).await?;
assert_ne!(denied.verdict, Verdict::Allow);
record(directory, "denied", &denied)?;
assert_eq!(host.calls.load(Ordering::SeqCst), 2);
let until = now();
std::fs::write(
directory.join("window.json"),
serde_json::to_vec_pretty(
&json!({"since":since,"until":until,"boundary":"admin-all","capabilityId":host.capability.id,"expectedAllow":2,"expectedDeny":1}),
)?,
)?;
println!("two allowed calls; one out-of-scope denial; handler calls 2");
println!("three receipt signatures verified; checkpoint batch size 1");
println!("wrote evidence-run/receipts.sqlite3, window.json, and kernel-public-key.txt");
Ok(())
}The run's first lines are the evidence: three receipt signatures verified; checkpoint batch size 1. The program also saves window.json, whose since and until bound every later command, and kernel-public-key.txt, the key a partner verifies the receipts against.
Read more in Receipts.
An export leaves only through a declared read boundary
Without a boundary, chio evidence export refuses the export.
chio evidence export --receipt-db evidence-run/receipts.sqlite3 --output missing-boundaryerror[CHIO-KERNEL-RECEIPT-READ-CONTEXT-MISSING]: evidence export needs a read boundary help: pass --tenant <id> to export one tenant's receipts, or --admin-all to export every tenant as the operator code: urn:chio:error:kernel:receipt-read-context-missing docs: https://chio.computer/docs/reference/errors#error-kernel-receipt-read-context-missing
The sharing policy is the boundary a partner receives. It names the issuer operator-review and the partner operator-audit, reads every receipt inside the run's window, expires an hour after the window closes, requires inclusion proofs, and records its purpose.
The signing seed stays with the origin, written under umask 077. The policy's signer_public_key appears again in the partner's import, so the partner can tie the share to the policy that bounded it.
Every exported receipt arrives with its inclusion proof and its origin's signature
With --require-proofs, the export carries a checkpoint and an inclusion proof for each receipt, and chio evidence verify checks the package before it is shared.
EVIDENCE_SINCE=$(jq -r .since evidence-run/window.json)
EVIDENCE_UNTIL=$(jq -r .until evidence-run/window.json)
chio evidence export --receipt-db evidence-run/receipts.sqlite3 --admin-all \
--since "$EVIDENCE_SINCE" --until "$EVIDENCE_UNTIL" \
--require-proofs --output evidence-package
chio evidence verify --input evidence-packageevidence package verified tool_receipts: 3 child_receipts: 0 checkpoints: 3 checkpoint_publications: 3 checkpoint_witnesses: 2 checkpoint_consistency_proofs: 2 checkpoint_equivocations: 0 capability_lineage: 1 inclusion_proofs: 3 uncheckpointed_receipts: 0 authorized_receipts: 2 trace_observations: 0 advisory_evaluations: 0 verified_files: 12 child_receipt_scope: FullQueryWindow transparency_preview_logs: 1 publication_state: transparency_preview
You should see inclusion_proofs: 3 beside tool_receipts: 3 and uncheckpointed_receipts: 0. On the partner's side, the import in the run stores the share under its own share_id and keeps issuer: operator-review and the origin's signer key. The imported receipts stay attributed to the origin, and the partner's own receipt history is unchanged.
Read more in Share evidence with a partner.
The partner issues downstream authority from the imported parent
chio trust federated-issue --upstream-capability-id makes an imported capability the parent of one the partner issues under its own delegation anchor. The record below is the child's entry in a lineage export.
$ jq 'del(.signed_capability)' \
evidence-export-package/capability-lineage.ndjson{
"capability_id": "cap-ioa-web3-provider",
"subject_key": "bff663535a5cf58658cc38595d20dc4501f6dfc076ddf07e20571d413a3ceb5a",
"issuer_key": "a090e1a43efcd3a3bd5ea5b015e6014d20e33e0e2d480194802720e4d38f108b",
"issued_at": 1776995579,
"expires_at": 1776996779,
"grants_json": "{\"grants\":[{\"constraints\":[],\"operations\":[\"invoke\"],\"server_id\":\"provider-review\",\"tool_name\":\"inspect_service_order\"},{\"constraints\":[],\"operations\":[\"invoke\"],\"server_id\":\"provider-review\",\"tool_name\":\"evaluate_provider_reputation\"},{\"constraints\":[],\"operations\":[\"invoke\"],\"server_id\":\"provider-review\",\"tool_name\":\"issue_review_attestation\"}],\"prompt_grants\":[],\"resource_grants\":[]}",
"delegation_depth": 1,
"parent_capability_id": "cap-019dbd30-b376-7b92-ba54-d00aec973369"
}parent_capability_id names the imported grant and delegation_depth counts the hop, so the chain back to the origin stays visible. federated-issue verifies a challenge-bound passport presentation before it issues, and the qualification test for this path builds a four-entry lineage with the imported upstream parent intact.
Read more in Cross-operator delegation.
A changed byte stops the package at verification
Copy the package, append one newline to receipts.ndjson, and verify the copy.
cp -R evidence-package altered-package
printf '\n' >> altered-package/receipts.ndjson
chio evidence verify --input altered-packageerror[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
You should see evidence package file hash mismatch for receipts.ndjson and exit 1. The file hashes fail before any signature is checked, so a partner who verifies each package before importing it never imports altered records.
Keep a refused package as it arrived, compare its signer, scope, and lineage with what you expected, and ask the origin for a fresh export. Changing local trust until the check passes changes the relationship being verified.
Revoking the imported parent stops the child and keeps its history
Revoke the upstream capability in the partner's revocation store.
$ chio --revocation-db ./revocations.sqlite3 \
trust revoke --capability-id cap-019dbd30-b376-7b92-ba54-d00aec973369capability_id: cap-019dbd30-b376-7b92-ba54-d00aec973369 revoked: true newly_revoked: true backend: ./revocations.sqlite3
You should see revoked: true. Revoking the parent stops further use of the child, and the receipts the child already produced keep their lineage. In a deployment each operator runs its own kernel and stores, adds the other's partner card to pin its kernel key, and exchanges packages over HTTPS with mTLS or signed bodies.