Chio/Docs
LOGIN · JOIN

ReferenceSDKs

Rust SDK

Run agents on a computer from Rust, then build on the crates beneath it: evidence verification, custom guards, and the decision core.

The chio crate carries the Computer API from the Quickstart. Beneath it sit focused crates for local evidence verification, guard extensions, host adapters, and the portable decision core. Choose the boundary your application needs.

You need toCrate or interfaceWhere it runs
Run agents on a computer
Your application, talking to your kernel; grants, runs, receipts, and apply.
Buy checked work from a partner
Your application, talking to your owner work service; selection, agreement, submit, and the work view.
Verify receipts, capabilities, or manifests
Local pure functions; no kernel process or network connection.
Write a custom policy guard
Inside a WASM guard component loaded by the kernel.
Embed HTTP evaluation in a Rust service
Application process; host supplies identity, durable state, and execution integration.
Embed the portable decision core
Native, mobile, or WASM host with explicit adapters.
Cross a C ABI or verify evaluation bundles
Foreign-language integration or offline evidence tooling.

Install

bash
cargo add chio

The crate builds on Rust 1.94 or newer, edition 2021. Each crate below publishes to crates.io under its own name.

Computer

Computer is the API the Quickstart uses. A computer is a versioned environment where authority, resources, and work live. You open one, fork it, grant an agent part of the fork, run work, read the signed receipts, and apply the changes you keep. Your kernel enforces every grant and signs every decision.

Calls that reach the kernel are async and return chio::Result. Methods with options return builders that implement IntoFuture, so .await sends the call and chained methods set options first. grant and reissue are synchronous. Event streams implement futures::Stream; chio::stream::StreamExt brings next() into scope. #[chio::main] starts the runtime, so a binary needs no other dependency.

This program is Quickstart part 1 in one file. It runs inside the computer that chio new quickstart creates.

src/main.rsrust
use chio::stream::StreamExt;
use chio::{Computer, Grant, USD};

#[chio::main]
async fn main() -> chio::Result<()> {
    let project = Computer::open("quickstart").await?;
    let fixer = project.agent("fixer").await?;
    let fork = project.fork().await?;
    let authority = fork.grant(
        Grant::to(&fixer)
            .resource("/workspace", ["read", "write"])
            .resource("/models/default", ["invoke"])
            .budget(USD(2))
            .expires_in("20m"),
    )?;

    let mut run = fixer.run("fix issue #412").on(&fork).authority(authority).start().await?;
    let mut events = run.events();
    while let Some(event) = events.next().await {
        println!("{}", event?.summary());
    }

    let refusal = project.history().receipts().outcome("deny").first().await?;
    println!("{}", refusal.describe());
    Ok(())
}
Output
00:00  admitted   fixer runs "fix issue #412" on fork 51c07ae
00:03  read       /workspace/src/pricing.py
00:05  read       /workspace/tests/test_pricing.py
00:09  refused    read /secrets/.env: outside the grant
00:12  invoke     /models/default, USD 0.21
00:41  write      /workspace/src/pricing.py
00:56  test       pytest -k issue_412: passed
spent  USD 0.48 of 2.00

receipt    rcpt-01a8…9c04
request    fixer read /secrets/.env
verdict    deny: outside the grant
grant      cap-01a8…31f2
policy     sha256 3c7b…8010
signed     your kernel 4f1c…a2e9, signature verifies

The examples below continue from it: project is the quickstart computer, fixer is its agent, and fork and authority are the fork and grant above. The service examples use the pricing service from Quickstart part 2, and the partner examples use the partner card, treaty, and reviews mailbox from part 3.

Computer::open

async fn Computer::open(name: &str) -> chio::Result<Computer>

Opens a computer your operator identity owns and returns its handle. The handle reads the computer's current revision; nothing is copied.

rust
use chio::Computer;

let project = Computer::open("quickstart").await?;
println!("{}", project.describe());
Output
computer   quickstart
owner      did:chio:z6Mkf3…Qp9 (you)
revision   main @ 7c2e1d0
resources  /workspace         git, 14 files
           /models/default    model route, metered in USD
           /secrets           3 files

Computer::connect

async fn Computer::connect(name: &str) -> chio::Result<Partner>

Resolves a paired partner by the name you gave its card, and authenticates its kernel before returning.

rust
let partner = Computer::connect("partner").await?;
println!("{}", partner.describe());
Output
partner    partner, did:chio:z6MkpA7…c2T
operator   Halden, halden.example
kernel     9b07…d31c, pinned from its card
transport  iroh, authenticated at handshake

Computer::partners

async fn Computer::partners() -> chio::Result<Vec<Partner>>

Lists every partner you have paired with, each with its pinned kernel key and the treaty in force.

rust
for partner in Computer::partners().await? {
    println!("{}", partner.summary());
}
Output
partner    did:chio:z6MkpA7…c2T   Halden   kernel 9b07…d31c   treaty trt-01aa…4c19

Computer::agent

async fn agent(&self, name: &str) -> chio::Result<Agent>

Returns the agent with this name, issuing it an identity from your kernel the first time. An agent holds no authority until you grant it some.

rust
let fixer = project.agent("fixer").await?;
println!("{}", fixer.describe());
Output
agent      fixer, did:chio:z6MkrT2…8wd
issued by  your kernel 4f1c…a2e9
grants     none

Computer::agents

fn agents(&self, role: &str) -> AgentsBuilder; .count(n).reads(&mailbox).start().await -> chio::Result<Vec<Agent>>

Starts several agents of one role, numbered from 1, optionally reading a shared mailbox.

rust
let reviewers = project.agents("review").count(2).reads(&reviews).start().await?;
for reviewer in &reviewers {
    println!("{}", reviewer.summary());
}
Output
reviewer-1   did:chio:z6MkvR1…3mc   reads reviews
reviewer-2   did:chio:z6MkvR2…9tf   reads reviews

Computer::fork

fn fork(&self) -> ForkBuilder; .boot(program).await -> chio::Result<Fork>

Branches the computer's managed state at its current revision. Work on the fork stays there until you apply it. A fork does not reset authority, history, or spending.

rust
let fork = project.fork().await?;
println!("{}", fork.describe());
Output
fork       51c07ae of quickstart, base main 7c2e1d0
writes     stay in the fork until you apply them

Fork::grant

fn grant(&self, grant: Grant) -> chio::Result<Authority>

Issues a capability token over part of the fork: resources and their rights, a budget charged at your door, and an expiry. Grant::to takes an agent, a partner, or a DID; .delegation(...) lets the holder delegate narrower grants onward, and .under(&treaty) issues a grant within a treaty. Issuance completes durably before the call returns.

rust
let authority = fork.grant(
    Grant::to(&fixer)
        .resource("/workspace", ["read", "write"])
        .resource("/models/default", ["invoke"])
        .budget(USD(2))
        .expires_in("20m"),
)?;
println!("{}", authority.describe());
Output
grant      cap-01a8…31f2, signed by your kernel
to         fixer, did:chio:z6MkrT2…8wd
on         quickstart, fork 51c07ae
allows     /workspace         read, write
           /models/default    invoke
budget     USD 2.00, charged at your door
expires    in 20 minutes

Authority::reissue

fn reissue(&self, on: &Fork) -> chio::Result<Authority>; fn reissue_with(&self, on: &Fork, edit: impl FnOnce(Grant) -> Grant) -> chio::Result<Authority>

Issues a grant on another fork with the same terms. reissue_with edits the terms first, to change the resources, budget, or lifetime. Your kernel signs the new grant; the original is unchanged.

rust
let next = project.fork().await?;
let again = authority.reissue(&next)?;
println!("{}", again.describe());
Output
grant      cap-01a8…5b3e, signed by your kernel
to         fixer, did:chio:z6MkrT2…8wd
on         quickstart, fork 7d2e914
allows     /workspace         read, write
           /models/default    invoke
budget     USD 2.00, charged at your door
expires    in 20 minutes

Authority::delegate

fn delegate(&self, grant: Grant) -> chio::Result<Authority>

Issues a child grant from this one to another agent. The child can drop resources, rights, money, and time, never add them, and its budget is held from the parent's. The parent must carry a delegation allowance. A child that asks for more raises chio::Error::Attenuation, and nothing is issued.

rust
// authority was granted with .delegation(Delegation::depth(1).fanout(2))
let tester = project.agent("tester").await?;
let child = authority.delegate(
    Grant::to(&tester)
        .resource("/workspace", ["read"])
        .budget(Money::cents(50))
        .expires_in("10m"),
)?;
println!("{}", child.describe());
Output
grant      cap-01d2…6c13, delegated by fixer from cap-01d2…2a90
to         tester, did:chio:z6MkvH5…3qe
allows     /workspace         read
budget     USD 0.50, held from the fixer's USD 2.00
expires    in 10 minutes
chain      you, fixer, tester

Authority::revoke

async fn revoke(&self) -> chio::Result<()>

Revokes the grant and every grant delegated from it. The kernel checks each ancestor at admission, so a run under any of them is refused from its next call.

rust
authority.revoke().await?;
Output
revoked    cap-01d2…2a90, by you
cascade    cap-01d2…6c13 (tester), refused from its next call

Authority::token

fn token(&self) -> &CapabilityToken

The signed capability token behind the grant, in its wire form. The Computer and the Kernel reads one field by field.

rust
println!("{}", serde_json::to_string_pretty(authority.token())?);
Output
{
  "id": "cap-01a8…31f2",
  "issuer": "4f1c…a2e9",
  "subject": "b81e…40c7",
  "scope": { "grants": [ 3 tool grants with path_prefix constraints ] },
  "issued_at": 1791763200,
  "expires_at": 1791764400,
  "signature": "a3f9…0d52"
}

Agent::run

fn run(&self, task: &str) -> RunBuilder; .on(&fork).authority(authority).start().await -> chio::Result<Run>

Sends a task to an agent under a grant. Every operation the agent attempts reaches your kernel before it reaches a resource.

rust
let mut run = fixer.run("fix issue #412").on(&fork).authority(authority).start().await?;
println!("{}", run.describe());
Output
run        run-01a8…e7c0
agent      fixer, on fork 51c07ae
authority  cap-01a8…31f2

Run::events

fn events(&mut self) -> EventStream; .include(&agents); impl Stream<Item = chio::Result<RunEvent>>

Streams the run's events in order: admissions, reads, writes, model calls, tests, and refusals. A refusal is an event with a receipt, not an exception, and the run continues.

rust
let mut events = run.events();
while let Some(event) = events.next().await {
    println!("{}", event?.summary());
}
Output
00:00  admitted   fixer runs "fix issue #412" on fork 51c07ae
00:03  read       /workspace/src/pricing.py
00:05  read       /workspace/tests/test_pricing.py
00:09  refused    read /secrets/.env: outside the grant
00:12  invoke     /models/default, USD 0.21
00:41  write      /workspace/src/pricing.py
00:56  test       pytest -k issue_412: passed
spent  USD 0.48 of 2.00

Partner::exec

fn exec(&self, task: &str) -> ExecBuilder; .on(&fork).authority(a).report_to(&mailbox).start().await -> chio::Result<Run>

Sends a task to a partner's agents under a grant issued within a treaty. The partner's kernel admits the work and runs it in its own process tree. run.join_tree() waits for every agent the partner delegated to.

rust
let exec = partner.exec("fix issue #414").on(&fork).authority(authority);
let mut run = exec.report_to(&reviews).start().await?;
let mut events = run.events();
while let Some(event) = events.next().await {
    println!("{}", event?.summary());
}
run.join_tree().await?;
Output
00:00  them  admitted   "fix issue #414" under trt-01aa…4c19
00:01  them  delegate   coordinator to fixer-1, fixer-2, tester, each narrower
00:31  them  refused    fixer-2 read /secrets/.env: outside the grant, at your door
01:47  them  sealed     fork c4e81b7 at 5b93d10
spent  USD 3.12 of 5.00 across 4 of their agents

Fork::diff

async fn diff(&self) -> chio::Result<Diff>

Returns the changes the fork holds against its base, as a unified diff.

rust
println!("{}", fork.diff().await?);
Output
src/pricing.py
@@ def discount(price, percent):
+    if not 0 <= percent <= 100:
+        raise ValueError("percent must be between 0 and 100")
     return price * (1 - percent / 100)

Computer::apply

fn apply(&self, changes: ChangeSet) -> ApplyBuilder; .treaty(&treaty).await -> chio::Result<Applied>

Publishes the fork's exact changes if main still matches the fork's base, and returns the signed merge. Under a treaty, both kernels co-sign it.

rust
let merged = project.apply(fork.changes()).await?;
println!("{}", merged.describe());
Output
applied    fork 51c07ae onto quickstart main
revision   main 8d4b2e7, base 7c2e1d0
receipt    rcpt-01a8…d51e, signed by your kernel

History::receipts

fn receipts(&self) -> ReceiptQuery; .outcome(o).agent(name).rule(name).service(name).since(d); .first().await, .all().await, or .export(dir)

Reads signed receipts from the computer's history, filtered by outcome, agent, rule, service, or time. Every filter combines with the others.

rust
let refusal = project.history().receipts().outcome("deny").first().await?;
println!("{}", refusal.describe());
Output
receipt    rcpt-01a8…9c04
request    fixer read /secrets/.env
verdict    deny: outside the grant
grant      cap-01a8…31f2
policy     sha256 3c7b…8010
signed     your kernel 4f1c…a2e9, signature verifies

Receipt

impl Receipt { fn id(&self) -> &str; fn request(&self) -> &str; fn summary(&self) -> String; fn raw(&self) -> &str; fn describe(&self) -> String }

One signed decision. summary is one line for listings, describe is the full card, and raw is the canonical JSON your kernel signed.

rust
println!("{}", refusal.raw());
Output
{"action":{"parameter_hash":"5e0d…71c2","parameters":{"path":"/secrets/.env"}},"capability_id":"cap-01a8…31f2","decision":{"reason":"not in capability scope","verdict":"deny"},"evidence":[],"id":"rcpt-01a8…9c04","kernel_key":"4f1c…a2e9","policy_hash":"3c7b…8010","receipt_kind":"mediated_decision","signature":"9d2e…07b4","tool_name":"read","tool_server":"quickstart"}

History::export

fn export(&self, dir: impl AsRef<Path>) -> chio::Result<Evidence>; ReceiptQuery::export(self, dir) -> chio::Result<Evidence>

Writes the computer's history, or one agent's part of it, to a directory as an evidence package. Verification checks every signature against pinned kernel keys, offline.

rust
let evidence = project.history().export("audit/")?;
println!("{}", evidence.verify()?);
Output
receipts   9 signed decisions from your kernel
refusals   1: fixer read /secrets/.env
spend      USD 0.48 of 2.00
verified   offline, against your kernel key 4f1c…a2e9

Evidence::verify_ledger

fn verify(&self) -> chio::Result<Verification>; fn verify_ledger(&self) -> chio::Result<Verification>

Checks every signature in an exported evidence package against your pinned kernel key, offline. verify_ledger also rebuilds both money ledgers from the signed records: each budget hold must close as committed, released, or retained with nothing outstanding, and each escrowed deposit must satisfy paid + refunded + locked + free = deposited. A hold whose outcome is unknown stays retained until it is resolved. Money Conservation states both identities.

rust
let evidence = project.history().export("audit/")?;
println!("{}", evidence.verify_ledger()?);
Output
receipts   9 signed decisions from your kernel
holds      3 on cap-01a8…31f2, each with one terminal disposition or a retained outcome
budget     reserved 2.40 = committed 0.21 + released 1.39 + retained 0.80 + outstanding 0.00
retained   rcpt-01a8…c311: outcome unknown, hold kept until resolved
funding    1 deposit: paid 200 + refunded 60 + locked 0 + free 40 = deposited 300
verified   offline, against your kernel key 4f1c…a2e9

Spend::stream

fn spend(&self) -> Spend; fn stream(&self) -> SpendStream; .capability(id).cursor(c) implements Stream<Item = chio::Result<SpendEvent>>

Streams spend events from your kernel's signed receipts, optionally for one capability lineage. Each event copies one receipt's financial metadata, bound to it by digest, and carries its sequence number. Pass an earlier cursor to resume: the cursor is opaque and binds your tenant, the filter, the last sequence scanned, and the store generation, and a stale cursor yields a typed gap rather than skipping ahead. Comptroller Console covers webhooks and burn rate.

rust
let mut events = project.spend().stream().capability("cap-01d2…6c13");
while let Some(event) = events.next().await {
    println!("{}", event?.summary());
}
Output
seq 4308  15:46  triage-418  models  USD 0.02   remaining USD 10.04 of USD 20.00
seq 4309  15:46  triage-419  models  USD 0.02   remaining USD 10.02 of USD 20.00
seq 4310  15:47  triage-417  models  USD 0.02   remaining USD 10.00 of USD 20.00
cursor    9c1d…77ae, complete through seq 4310, checkpoint 43

Policy::add

async fn add(&self, rule: Rule) -> chio::Result<RuleRef>; Rule::new(name).deny_write(glob) or .egress_allow(hosts)

Adds a named rule to the computer's policy: a path match to allow or deny, or an egress allow list for network connections. Policy narrows every grant on the computer, and no grant widens policy.

rust
let rule = Rule::new("tests-are-evidence").deny_write("/workspace/tests/**");
let added = project.policy().add(rule).await?;
println!("{}", added.describe());
Output
rule       tests-are-evidence
denies     write /workspace/tests/**
policy     sha256 9a41…e6f2, narrows every grant on quickstart

Policy::describe

async fn describe(&self) -> chio::Result<String>

Describes the policy in force: its hash and the one it replaced, your rules, and the defaults every computer starts with.

rust
println!("{}", project.policy().describe().await?);
Output
policy     sha256 9e42…c5d1, was 3c7b…8010
rules      tests-are-evidence   deny write /workspace/tests/**
base       forbidden paths      **/.env, **/.env.*, **/.ssh/** and 27 more
compiled   HushSpec 0.1.0, evaluated at admission

Policy::hash

async fn hash(&self) -> chio::Result<PolicyHash>

Returns the hash every receipt records as policy_hash. A process you build yourself passes it to the kernel so its receipts name the same policy.

rust
println!("{}", project.policy().hash().await?);
Output
sha256:9e42…c5d1

Computer::node_key and the project stores

async fn node_key(&self, name: &str) -> chio::Result<NodeKey>; History::receipt_store(&self) -> ReceiptStore; fn revocation_store(&self) -> RevocationStore

Attach a process you build yourself to the project's kernel state: a serving key your kernel certifies, the receipt store history reads, and the revocation store every grant is checked against. Connect an Application builds an axum service this way.

rust
let node_key = project.node_key("pricing-http").await?;
let receipts = project.history().receipt_store();
let revocations = project.revocation_store();
let layer = chio_tower::ChioLayer::builder(node_key, project.policy().hash().await?)
    .receipt_store(receipts)
    .revocation_store(revocations)
    .build()?;

Computer::service

fn service(&self, name: &str) -> ServiceBuilder; .tool(name, target).create().await -> chio::Result<Service>

Exposes project functions as named tools and publishes them over MCP and HTTP. Every caller presents a grant from your kernel.

rust
let pricing = project
    .service("pricing")
    .tool("quote", "src/pricing.py:quote")
    .tool("refund", "src/pricing.py:refund")
    .create()
    .await?;
let endpoint = pricing.publish(["mcp", "http"]).await?;
println!("{}", endpoint.describe());
Output
service    pricing, from quickstart @ main 2f60a91
tools      quote · refund
mcp        https://127.0.0.1:9440/pricing/mcp
http       https://127.0.0.1:9440/pricing/v1, OpenAPI at /openapi.json
admits     callers that hold a grant from your kernel

Service::grant

fn grant(&self, grant: ServiceGrant) -> chio::Result<Authority>

Grants a caller named tools on the service, with a call rate, a budget spent at each tool's price, and an expiry.

rust
let access = pricing.grant(
    ServiceGrant::to("did:chio:z6MkbY4…e1R")
        .tool("quote")
        .limit(100, "1h")
        .budget(USD(2))
        .expires_in("24h"),
)?;
println!("{}", access.describe());
Output
grant      cap-01ab…77d1, signed by your kernel
to         did:chio:z6MkbY4…e1R
allows     pricing.quote
limits     100 calls per hour
budget     USD 2.00, USD 0.01 per call
expires    in 24 hours

Service::require

async fn require(&self, approval: Approval) -> chio::Result<RuleRef>

Pauses each matching call until the approver signs for that exact request.

rust
let rule = pricing.require(Approval::by_you().when("quote.percent > 50")).await?;
println!("{}", rule.describe());
Output
rule       quote.percent > 50 waits for did:chio:z6Mkf3…Qp9 (you)
binds      one signature to one request

Service::settle

async fn settle(&self, terms: Settle) -> chio::Result<SettlementTerms>; Settle::tool(name).rail(r).chain(c).token(t).payee(p)

Declares how a tool's calls are paid: the rail, the chain, the token, and where the payee comes from. The terms go inside the governed intent, so an approval required by require covers the chain, payee, amount, and token along with the request. Approval-Bound Payments walks the flow.

rust
use chio::Settle;

let terms = pricing
    .settle(Settle::tool("refund").rail("eip3009").chain("eip155:8453").token("USDC").payee("refund.wallet"))
    .await?;
println!("{}", terms.describe());
Output
settles    refund over eip3009 on eip155:8453 in USDC, payee from refund.wallet
binding    chain, payee, amount, token contract, dispatch, capability, expiry

Service::price

fn price(&self, tool: &str, amount: Money) -> PriceBuilder; .economy(urn).split([Payee]).await -> chio::Result<ToolPricing>; Payee::to(beneficiary).bps(n).vest(cliff, end).cosigner(did)

Sets a tool's price per call, the economy it settles in, and the payee split, one Payee per beneficiary. Your kernel writes the terms into the tool manifest as ToolPricing and signs the manifest again. A split must sum to exactly 10,000 basis points; each share may carry a vesting window and the cosigners who must sign it. Revenue Splits covers vesting and settlement.

rust
use chio::Payee;

let partner = Payee::to("did:chio:z6MkpA7…c2T")
    .bps(3333)
    .vest("2026-11-01", "2027-01-30")
    .cosigner("did:chio:z6Mkf3…Qp9");
let priced = pricing
    .price("quote", USD("0.01"))
    .economy("urn:chio:economy:pricing")
    .split([
        Payee::to("did:chio:z6Mkf3…Qp9").bps(5000),
        partner,
        Payee::to("urn:chio:economy:pricing:reserve").bps(1667),
    ])
    .await?;
println!("{}", priced.describe());
Output
price      pricing.quote USD 0.01 per call, economy urn:chio:economy:pricing
split      5000  did:chio:z6Mkf3…Qp9
           3333  did:chio:z6MkpA7…c2T, vests 2026-11-01 to 2027-01-30, cosigned by you
           1667  urn:chio:economy:pricing:reserve
manifest   re-signed, payee_split sums to 10000 bps

Service::events

fn events(&self) -> impl Stream<Item = chio::Result<CallEvent>>

Streams calls to the service as your kernel decides them.

rust
let mut calls = pricing.events();
while let Some(call) = calls.next().await {
    println!("{}", call?.summary());
}
Output
00:00  z6MkbY4  quote   sku-118 at 10%        allow     USD 0.01
00:04  z6MkbY4  refund  order-77              refused   not in the grant
00:05  z6MkQx8  quote   sku-118 at 10%        refused   no grant from your kernel
00:09  z6MkbY4  quote   sku-301 at 80%        pending   approval required
00:41  z6MkbY4  quote   sku-301 at 80%        allow     USD 0.01

Service::usage

fn usage(&self) -> UsageQuery; .since(d).await -> chio::Result<Usage>

Summarizes each caller's calls, refusals, approvals, and spend, computed from that caller's signed receipts.

rust
println!("{}", pricing.usage().since("1h").await?);
Output
caller             calls   refused   approvals   spent
z6MkbY4…e1R        100     2         1           USD 1.00
z6MkQx8…7Ha        0       1         0           USD 0.00

Computer::treaty

async fn treaty(&self, terms: Treaty) -> chio::Result<TreatyRef>

Agrees terms with a partner: the actions you cooperate on and what each requires. Both kernels sign, and each computes the intersection of the two governance ladders, so the stricter requirement wins.

rust
let treaty = project
    .treaty(
        Treaty::with(&partner)
            .actions(["workspace.read", "workspace.write", "model.invoke", "merge"])
            .expires_in("7d"),
    )
    .await?;
println!("{}", treaty.describe());
Output
treaty           trt-01aa…4c19, signed by both kernels
participants     you · partner (did:chio:z6MkpA7…c2T)
action           you       them      admitted as
workspace.read   allow     allow     either kernel admits under its own policy
workspace.write  allow     allow     either kernel admits under its own policy
model.invoke     allow     allow     charged at your door
merge            co-sign   co-sign   both kernels sign
expires          in 7 days

TreatyRef::revoke

async fn revoke(&self) -> chio::Result<()>

Ends the treaty and every grant issued under it, including grants the partner's agents delegated to each other. The revocation reaches the partner's kernel over iroh, and its next call is refused.

rust
treaty.revoke().await?;
let mut events = run2.events();
while let Some(event) = events.next().await {
    println!("{}", event?.summary());
}
Output
00:00  them  admitted   "add banker's rounding as an option" under trt-01aa…4c19
00:04  you   revoked    trt-01aa…4c19, revocation root sent over iroh
00:05  them  refused    fixer-1 write /workspace/src/pricing.py: treaty revoked
00:05  them  stopped    their work closed, no effects after revocation

Computer::mailbox

fn mailbox(&self, name: &str) -> MailboxBuilder; .partner(&p).treaty(&t).open().await -> chio::Result<Mailbox>

Opens a mailbox shared with a partner under a treaty. Each message is sent and claimed under its sender's or reader's own grant.

rust
let reviews = project.mailbox("reviews").partner(&partner).treaty(&treaty).open().await?;
println!("{}", reviews.describe());
Output
mailbox    reviews, under trt-01aa…4c19
senders    partner's agents, each under its own grant
readers    your agents that hold a reads grant

first_passing

async fn first_passing(runs: impl IntoIterator<Item = Run>, check: &str) -> chio::Result<Run>

Waits on several runs and returns the first whose sealed fork passes the check. The other runs are cancelled, and their receipts stay in history.

rust
use chio::first_passing;

let ours = fixer.run("fix issue #414").on(&fork_a).authority(grant_a).start().await?;
let theirs = partner.exec("fix issue #414").on(&fork_b).authority(grant_b).start().await?;
let winner = first_passing([ours, theirs], "pytest").await?;
println!("{}", winner.describe());
project.apply(winner.changes()).await?;
Output
winner     run-01ab…0c7d, partner on fork c4e81b7
check      pytest: 14 passed
others     cancelled, receipts kept in history

Program composition

impl BitAnd for Program (parallel); impl BitOr for Program (sequence)

Composes boot programs, the pinned descriptors your project exports. & runs programs at once and | runs them in sequence; Rust binds & tighter, so the expression below needs no parentheses. Operators build immutable syntax and run nothing. A fork started with a boot program runs it under the fork's grant.

rust
use programs::{patch, reproduce, survey, verify};

let fork = project.fork().boot(reproduce() & survey() | patch() | verify()).await?;
println!("{}", fork.describe());
Output
boot       (reproduce & survey) | patch | verify
fork       a3d90f1 of quickstart, base main 2f60a91

USD

fn USD(dollars: u64) -> Money; Money::cents(cents: u64) -> Money

Constructs an exact dollar amount for budgets and prices. Money stores integer cents, so arithmetic is exact.

rust
use chio::{Money, USD};

println!("{}", USD(2));
println!("{}", Money::cents(1) * 100);
Output
USD 2.00
USD 1.00

Error::ApplyConflict

chio::Error::ApplyConflict { base: Revision, current: Revision }

Apply refuses to publish when main moved after the fork was taken. Nothing changes; fork again from the new main and reapply.

rust
match project.apply(fork.changes()).await {
    Err(conflict @ chio::Error::ApplyConflict { .. }) => println!("{conflict}"),
    result => {
        result?;
    }
}
Output
main moved from 7c2e1d0 to 9e03a4b; fork 51c07ae was not applied

How the Computer reaches the kernel

Each grant is a chio.capability.v1 token signed by your kernel. Each operation in a run is a mediated call, and each event carries the id of a chio.receipt.v1 receipt in the store that history reads. Policy rules compile into the HushSpec policy every grant on the computer is checked against. The Computer and the Kernel maps each Computer object onto its kernel mechanism. The low-level clients below speak to the same kernel and the same records without the Computer layer.

Work

WorkClient buys checked work from another company through your owner work service. You select a partner's offer, prepare the agreement both sides sign, submit the funded commitment, and read the work view until the verifier's decision settles the claim. Your owner service holds every key; the client sends chio.work.v1 documents and never constructs authority. Verifiable Work explains the model.

The client ships in chio-runtime behind its work feature, under chio_runtime::work. Calls that reach the owner service are async and return chio_runtime::work::Result; the document builders and describe are synchronous. WorkClient is generic over its WorkTransport, and open picks the authenticated local socket. Documents are typed values with private fields and checked constructors; builders produce the same bytes as the wire documents. The client never retries a side effect and never generates a replacement command id.

bash
cargo add chio-runtime --features work

The examples follow Run Verifiable Work: work is the client on ./work, your partner sells an authentication inventory of the pricing service's OpenAPI document for USD 28.00, and the examples run inside an async main.

WorkClient::open

async fn WorkClient::open(state: impl AsRef<Path>) -> Result<WorkClient>

Connects to the owner work service serving this state directory, over its authenticated local socket. chio work serve must be running; opening dispatches nothing.

rust
use chio_runtime::work::WorkClient;

let work = WorkClient::open("./work").await?;

work.select

async fn work.select(offer: Signed<WorkOffer>, program_id: &str, command_id: &str) -> Result<WorkSelection>

Selects the exact offer you pass: your owner service signs the selection, the partner's kernel seals a dispatch permit for one slot, and the result's commitment() is a draft WorkCommitmentV1 with no funding attached.

rust
use chio_runtime::work::{Signed, WorkOffer};

let offer = Signed::<WorkOffer>::from_file("partner-offer.json")?;
let draft = work.select(offer, "pricing-openapi-auth", "auth-select-1").await?;
draft.commitment().write_file("auth-draft.json")?;
println!("{}", draft.describe());
Output
offer        openapi-explicit-auth-v1 from did:chio:z6MkpA7…c2T, USD 28.00
selection    signed by did:chio:z6Mkf3…Qp9 at revision 2
permit       sealed by kernel 9b07…d31c for slot auth-inventory
draft        WorkCommitmentV1 written to auth-draft.json, no funding yet

WorkPreparationV1::agreement

fn WorkPreparationV1::agreement(program_id: &str, command_id: &str, commitment: WorkCommitmentV1) -> WorkPreparationV1; fn funding_profile(self, id: &str) -> Self; fn terms(self, reference: &str) -> Self

Builds the Agreement proposal of a chio.work.preparation.v1 document: the draft commitment, the funding profile the rail is configured under, and the terms file both parties sign.

rust
use chio_runtime::work::WorkPreparationV1;

let proposal =
    WorkPreparationV1::agreement("pricing-openapi-auth", "auth-agree-1", draft.commitment())
        .funding_profile("work-claim-escrow")
        .terms("terms/openapi-auth.json");

work.prepare

async fn work.prepare(proposal: WorkPreparationV1) -> Result<WorkPreparedV1>

Prepares one owner artifact from a chio.work.preparation.v1 document. The proposal is one of Delegate, Offer, Select, Extend, Join, or Agreement, and the outcome is Prepared, Pending, or Refused. An agreement binds the terms both parties sign and moves no money; chio work fund locks the allocation and attaches its WorkFundingRefV1 to the commitment.

rust
let prepared = work.prepare(proposal).await?;
println!("{}", prepared.describe());
Output
preparation  auth-agree-1  Prepared
agreement    7e1d…c04a  SHA-256 of the RFC 8785 body
buyer        did:chio:z6Mkf3…Qp9  signed
provider     did:chio:z6MkpA7…c2T  signed through kernel.halden.example/cosign
verifier     verify.corbel.example  pinned 0x9f62…3ad5
checker      openapi-explicit-auth-v1  c7a1…02be
amount       USD 28.00 to 0x7d0c…12f4
deadlines    submitBy 2026-10-14T18:00Z  challengeUntil 2026-10-15T18:00Z
             resolveBy 2026-10-16T18:00Z  refundAfter 2026-10-17T18:00Z

WorkCommitmentV1::from_file

fn WorkCommitmentV1::from_file(path: impl AsRef<Path>) -> Result<WorkCommitmentV1>; fn write_file(&self, path: impl AsRef<Path>) -> Result<()>

Reads or writes a commitment as its JSON document. Reading decodes through the checked conversions, so a duplicate key, an unknown field, or an out-of-range number is refused; Signed::<WorkOffer>::from_file reads an offer the same way.

rust
use chio_runtime::work::WorkCommitmentV1;

let commitment = WorkCommitmentV1::from_file("auth-commitment.json")?;

WorkCommandV1::submit

fn WorkCommandV1::submit(program_id: &str, command_id: &str, commitment: WorkCommitmentV1) -> WorkCommandV1

Builds a chio.work.command.v1 document whose action is Submit with the funded commitment.

rust
use chio_runtime::work::WorkCommandV1;

let command = WorkCommandV1::submit("pricing-openapi-auth", "auth-submit-1", commitment);

work.submit

async fn work.submit(command: WorkCommandV1) -> Result<WorkCommandResultV1>

Submits one chio.work.command.v1 document under its caller-supplied command id. The action is one of Delegate, Select, Seal, Extend, Submit, Reconcile, or Cancel. The outcome is Applied with a revision, Pending with the owner's operation reference, or Refused. Applied reports that the command was processed, not that the work succeeded. The same command id with the same body returns the original outcome; a different body is refused before dispatch.

rust
let submitted = work.submit(command).await?;
println!("{}", submitted.describe());
Output
command     auth-submit-1  Applied at revision 4
admitted    by kernel 9b07…d31c under its own policy

WorkCommandResultV1::handle

fn handle(&self) -> Result<WorkHandleV1>

The handle an applied Submit returns: program, slot, allocation hash, receiver kernel, and original request id. It is a reference, not a bearer permit. On a Pending or Refused outcome it returns WorkError; query the original command id instead.

rust
println!("{}", serde_json::to_string_pretty(&submitted.handle()?)?);
Output
{
  "program_id": "pricing-openapi-auth",
  "slot_id": "auth-inventory",
  "allocation_hash": "a51e…07c3",
  "receiver_kernel_id": "9b07…d31c",
  "request_id": "req-01c4…7a90"
}

work.inspect

async fn work.inspect(handle: WorkHandleV1) -> Result<WorkViewV1>

Reads the work view for a handle. It is a query, so it mutates nothing and dispatches no checker.

rust
println!("{}", work.inspect(submitted.handle()?).await?.describe());
Output
handle      pricing-openapi-auth/auth-inventory, request req-01c4…7a90
execution   Available      returned, rcpt-01c4…7a92 signed by kernel 9b07…d31c
acceptance  Pending        verify.corbel.example, recordable after 2026-10-15T18:00Z
results     Available      output 6f0e…b31a, 3 operations
recovery    NotApplicable
settlement  Pending        Submitted, commitment 0x2a90…f1e3
delivery    Available      co-signed by kernels 4f1c…a2e9 and 9b07…d31c

work.query

async fn work.query(query: WorkQueryV1) -> Result<WorkQueryResultV1>

Reads by reference: Work by handle, Command or Preparation by original id, and Catalog or Profile for the entries owners provisioned for you. An original-id query answers before you hold a handle, so it resolves a lost response.

rust
use chio_runtime::work::WorkQueryV1;

let found = work.query(WorkQueryV1::command("auth-submit-1")).await?;
println!("{}", found.describe());
Output
query       Command auth-submit-1
command     auth-submit-1  Applied at revision 4
handle      pricing-openapi-auth/auth-inventory, request req-01c4…7a90

work.collect

async fn work.collect(handle: WorkHandleV1) -> Result<WorkViewV1>

Reconciles finished work: it records the settlement and evidence the owning authorities already hold and returns the view. It never dispatches the work again and never returns protected result bytes; read those through the recovery release operation.

rust
let view = work.collect(submitted.handle()?).await?;
println!("{}", view.describe());
Output
handle      pricing-openapi-auth/auth-inventory, request req-01c4…7a90
execution   Available      returned, rcpt-01c4…7a92 signed by kernel 9b07…d31c
acceptance  Available      Accepted, predicate match, checker c7a1…02be
results     Available      output 6f0e…b31a, 3 operations
recovery    NotApplicable
settlement  Available      Paid USD 28.00, allocation 0x8c1f…40d2
delivery    Available      co-signed by kernels 4f1c…a2e9 and 9b07…d31c

WorkCommitmentV1

fn handle(&self) -> &WorkHandleV1; fn permit(&self) -> &Signed<DispatchPermit>; fn profile_ref(&self) -> &WorkProfileRefV1; fn funding(&self) -> Option<&WorkFundingRefV1>

Links the handle, the sealed permit, the agreed profile, the custody reference for the exact invocation, and the graph. funding() names the rail, the agreement digest, and the reserve; the receiver checks the allocation on the rail before it admits the work.

rust
let commitment = WorkCommitmentV1::from_file("auth-commitment.json")?;
println!("{}", serde_json::to_string_pretty(&commitment.funding())?);
Output
{
  "rail": "work-claim-escrow",
  "agreement_digest": "7e1d…c04a",
  "reserve_ref": "0x8c1f…40d2"
}

WorkViewV1

fn execution(&self) -> &Observation; fn acceptance(&self) -> &Observation; fn results(&self) -> &Observation; fn recovery(&self) -> &Observation; fn settlement(&self) -> &Observation; fn delivery(&self) -> &Observation; fn describe(&self) -> String

Six independent observations. Each is NotApplicable, Pending with the owner's reference, Available with its source, revision, time, and value, or Unavailable with a code. Each authority revises its own observation, so acceptance and settlement can move separately from execution.

rust
println!("{}", serde_json::to_string_pretty(view.acceptance())?);
Output
{
  "Available": {
    "source": "verify.corbel.example",
    "revision": 1,
    "observed_at": "2026-10-15T18:04Z",
    "value": { "decision": "Accepted", "predicate": "match", "checker": "c7a1…02be" }
  }
}

WorkError

pub struct WorkError; fn code(&self) -> &str; fn command_ref(&self) -> Option<&CommandRef>

A stable code and the original command reference. After a timeout, query that reference; the outcome the owner recorded is the answer.

rust
match work.submit(command).await {
    Ok(submitted) => println!("{}", submitted.describe()),
    Err(_) => {
        let found = work.query(WorkQueryV1::command("auth-submit-1")).await?;
        println!("{}", found.describe());
    }
}
Output
query       Command auth-submit-1
command     auth-submit-1  Applied at revision 4
handle      pricing-openapi-auth/auth-inventory, request req-01c4…7a90

Low-level crates

The Computer API is built on crates you can use directly: verification helpers for evidence you receive, the guard SDK for policy extensions the kernel loads, and chio-tower for evaluation inside your own HTTP service.

Verify evidence without running a kernel

chio-binding-helpers exposes the same canonicalization and verification contract used across Chio’s language bindings. For a receipt, supply the signed JSON and an independently trusted kernel key:

rust
// Inside a function returning chio_binding_helpers::Result<_>:
let verification = chio_binding_helpers::verify_receipt_json_with_trusted_signer_hex(
    receipt_json,
    &[trusted_kernel_key_hex],
)?;

verification.ok checks integrity and signer trust. verification.authorized additionally requires an authorizing mediated decision. A valid denial receipt should verify successfully while remaining unauthorized. The complete example below handles both.

A standalone verifier

An auditor checks the receipts you export without running a kernel. Create a crate named receipt-check, add the helpers, and place the verification program in src/main.rs.

bash
cargo new receipt-check && cd receipt-check
cargo add chio-binding-helpers

Supply the exported receipt.json and your kernel key in trusted-kernel-key.hex, then run:

bash
cargo run

Success prints the recorded decision and whether authorization is established. Invalid integrity or an untrusted signer returns an error. The program opens no sockets.

Crate layout

The low-level SDK crates, each published under its own name, with the source path it is built from.

CratePathRole
chio-binding-helpers
crates/sdk/chio-binding-helpers
Canonical JSON, SHA-256, Ed25519, and receipt, capability, and manifest verification. The contract every language binding implements.
chio-bindings-ffi
crates/sdk/chio-bindings-ffi
A C ABI over chio-binding-helpers. UTF-8 strings and byte buffers in, UTF-8 buffers out, explicit Rust-side deallocation, no session state across the boundary.
chio-cpp-kernel-ffi
crates/sdk/chio-cpp-kernel-ffi
A C ABI over chio-core-types and chio-kernel-core for the C++ offline kernel package, in the mobile adapter's JSON-in, JSON-out shape.
chio-eval-receipt
crates/sdk/chio-eval-receipt
Reference verifier and exporter for chio.eval-report.bundle.v1 receipt bundles, plus a chio-eval-receipt binary.
chio-guard-sdk
crates/sdk/chio-guard-sdk
Guest-side SDK for WASM guards targeting the chio:guard@0.2.0 WIT world: types, host bindings, ABI glue, and the guest allocator.
chio-guard-sdk-macros
crates/sdk/chio-guard-sdk-macros
The chio_guard proc-macro attribute that wraps a guard author's evaluate function.

Three crates outside that group appear on this page. crates/core/chio-core holds the kernel types (ChioReceipt, CapabilityToken, ChioScope) and validate_delegation_chain, which the invariants wrap. crates/platform/chio-manifest holds the signed tool manifest types. crates/protocol/chio-tower governs an HTTP service in process.

chio-binding-helpers

The crate exposes seven modules and re-exports their public names at the root (src/lib.rs:22-40). It implements RFC 8785 canonical JSON, SHA-256, Ed25519 sign and verify, receipt parsing and verification, capability parsing and verification including delegation-chain walking through chio-core, and signed manifest parsing and verification. Session runtime, transport, authentication, and callback orchestration stay in the language-native SDKs (src/lib.rs:1-12).

ModuleRe-exported at the root
canonical
canonicalize_json_str (canonical.rs:6).
hashing
sha256_hex_bytes (hashing.rs:2) and sha256_hex_utf8 (:7).
signing
public_key_hex_matches at line 23, is_valid_public_key_hex at 28, is_valid_signature_hex at 33, sign_utf8_message_ed25519 at 37, verify_utf8_message_ed25519 at 46, sign_json_str_ed25519 at 56, verify_json_str_signature_ed25519 at 70, plus Utf8MessageSignature and CanonicalJsonSignature.
receipt
parse_receipt_json at line 71, receipt_body_canonical_json at 75, verify_receipt at 79, verify_receipt_with_trusted_signers at 83, verify_receipt_with_trusted_signer_hex at 120, verify_receipt_json at 128, verify_receipt_json_with_trusted_signer_hex at 133, plus ReceiptDecisionKind and ReceiptVerification.
capability
parse_capability_json at line 25, capability_body_canonical_json at 29, verify_capability at 33, verify_capability_json at 57, plus CapabilityTimeStatus and CapabilityVerification.
manifest
parse_signed_manifest_json at line 15, signed_manifest_body_canonical_json at 19, verify_signed_manifest at 23, verify_signed_manifest_json at 39, plus ManifestVerification.
error
Error, ErrorCode, and the Result alias.

Receipt verification

ReceiptVerification (receipt.rs:56-68) carries signature_valid, parameter_hash_valid, receipt_id_valid, decision, receipt_kind, boundary_class, trust_level, result, authorized, signer_key_hex, signer_trusted, and ok. signer_trusted is true only when the caller supplies a signer list that contains the receipt's kernel_key, and both authorized and ok conjoin it (receipt.rs:95-117). verify_receipt passes an empty list (receipt.rs:80), so it reports the three validity booleans and leaves authorized false. Pass keys through the trusted-signer forms to get an authorization answer.

src/main.rsrust
use chio_binding_helpers::verify_receipt_json_with_trusted_signer_hex;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let json = std::fs::read_to_string("receipt.json")?;
    // Supplied independently by your trusted operator configuration.
    let trusted_key = std::fs::read_to_string("trusted-kernel-key.hex")?;
    let verification =
        verify_receipt_json_with_trusted_signer_hex(&json, &[trusted_key.trim()])?;

    if !verification.ok {
        return Err("receipt integrity or signer trust check failed".into());
    }
    println!("Recorded decision: {:?}", verification.decision);
    println!("Authorization established: {}", verification.authorized);
    Ok(())
}

Never copy the receipt’s own kernel_key into the trusted signer list. The display field result describes recorded semantics; it can say Authorized even when verification fails. Branch on the verification booleans and match the receipt to the expected request.

FieldMeaning
signature_valid, parameter_hash_valid, receipt_id_valid
The signed record and its content-addressed fields pass their integrity checks.
signer_trusted
The signer is in the independently supplied allow-list.
ok
All three integrity checks and signer trust pass. A denial can satisfy this.
authorized
The verified, trusted record also establishes an allow decision at the mediated prevention boundary.

Capability verification

verify_capability takes the parsed token, a u64 Unix timestamp, and an Option<u32> maximum delegation depth (capability.rs:33-37). The returned CapabilityVerification carries signature_valid, delegation_chain_shape_valid, time_valid, and time_status, whose variants are Valid, NotYetValid, and Expired (capability.rs:11-15, with the struct at :18-23).

rust
use chio_binding_helpers::{parse_capability_json, verify_capability, Result};

fn inspect_capability(json: &str, now: u64) -> Result<bool> {
    let capability = parse_capability_json(json)?;
    let status = verify_capability(&capability, now, Some(8))?;
    println!("Time status: {:?}", status.time_status);
    Ok(status.signature_valid
        && status.delegation_chain_shape_valid
        && status.time_valid)
}

This is an offline structural check. It does not establish issuer trust, current revocation, request scope, proof of possession, or complete delegation attenuation. The compatibility chain checker verifies signatures, adjacent identities, timestamps, and depth; it does not enforce parent_scope_hash binding. Use the kernel’s request-validation path for an authorization decision.

Manifest verification

ManifestVerification (manifest.rs:8-13) carries structure_valid, signature_valid, embedded_public_key_valid, and embedded_public_key_matches_signer.

rust
use chio_binding_helpers::{
    parse_signed_manifest_json,
    verify_signed_manifest,
};

let manifest = parse_signed_manifest_json(&json)?;
let result = verify_signed_manifest(&manifest)?;
assert!(result.structure_valid);
assert!(result.signature_valid);
assert!(result.embedded_public_key_valid);
assert!(result.embedded_public_key_matches_signer);

These booleans validate the manifest and its embedded signing relationship. Your application still chooses which manifest signer to trust.

Ed25519 and canonical JSON

sign_json_str_ed25519 canonicalizes the input and returns a CanonicalJsonSignature whose fields are canonical_json, public_key_hex, and signature_hex (signing.rs:12-16). verify_json_str_signature_ed25519 takes the input, then the public key, then the signature.

rust
use chio_binding_helpers::{
    canonicalize_json_str,
    sha256_hex_bytes,
    sha256_hex_utf8,
    sign_json_str_ed25519,
    verify_json_str_signature_ed25519,
    sign_utf8_message_ed25519,
    verify_utf8_message_ed25519,
};

let canonical = canonicalize_json_str(r#"{"b":2,"a":1}"#)?;
assert_eq!(canonical, r#"{"a":1,"b":2}"#);

let digest = sha256_hex_utf8("hello world");

let sig = sign_json_str_ed25519(&canonical, &seed_hex)?;
let ok = verify_json_str_signature_ed25519(&canonical, &sig.public_key_hex, &sig.signature_hex)?;
assert!(ok);

chio-guard-sdk

crates/sdk/chio-guard-sdk is the guest-side SDK for writing WASM guards against the chio:guard@0.2.0 WIT world. It compiles to wasm32-unknown-unknown for production guards, and on native targets it compiles with no-op fallbacks for the host imports so cargo test runs without a WASM runtime (src/lib.rs:18-20).

ModuleWhat it holds
types
GuardRequest, GuardVerdict, and GuestDenyResponse, with serde annotations matching the host ABI, plus the constants VERDICT_ALLOW and VERDICT_DENY.
host
Wrappers for the host imports chio.log, chio.get_config, chio.get_time_unix_secs, and chio:guard/host.fetch-blob, exported as log, log_level, get_config, get_time, and fetch_blob, plus the PolicyContext bundle-handle wrapper.
glue
read_request deserializes from linear memory, encode_verdict produces the ABI return code, and the crate exports chio_deny_reason for structured deny reasons.
alloc
The chio_alloc and chio_free exports the host runtime probes for allocation in guest linear memory.

The four module declarations sit at src/lib.rs:38-41 and the root re-exports at :44-46. chio_guard_sdk::prelude (:52-55) re-exports the glue functions, the host bindings, and the types other than GuestDenyResponse.

rust
use chio_guard_sdk::prelude::*;

fn evaluate(req: GuardRequest) -> GuardVerdict {
    if req.tool_name == "dangerous_tool" {
        GuardVerdict::deny("tool is blocked by policy")
    } else {
        GuardVerdict::allow()
    }
}

crates/sdk/chio-guard-sdk-macros is a proc-macro crate whose one export is the chio_guard attribute (src/lib.rs:159-160), which wires an author's evaluate function to the exports above. sdks/rust/chio-guard-sdk-compat is a compatibility package that re-exports the same API under the library name chio_guard_sdk (sdks/README.md:18). It declares an empty [workspace] table, so it stands outside the root workspace and builds through --manifest-path.

The C ABI crates

Two crates carry a C ABI. Both declare crate-type = ["staticlib", "cdylib", "rlib"] so a C or C++ consumer links either form.

  • chio-bindings-ffi exports the invariants over a C boundary: UTF-8 strings and byte buffers in, UTF-8 buffers out, Rust-side deallocation, and no async or session state crossing the boundary (src/lib.rs:1-5). It declares CHIO_FFI_ABI_VERSION and the CHIO_FFI_STATUS_* constants at src/lib.rs:14-20. The Bindings API page lists its exported symbols.
  • chio-cpp-kernel-ffi binds chio-core-types and chio-kernel-core for the C++ offline kernel package. It mirrors the mobile adapter's JSON-in, JSON-out shape over a plain C ABI, so no UniFFI or Rust concept appears in a public C++ header (src/lib.rs:1-5).

chio-eval-receipt

crates/sdk/chio-eval-receipt verifies eval-report receipt bundles end to end: it validates the bundle envelope, recomputes the corpus SHA-256, and checks the detached memo signatures attached to each receipt, failing closed on any mismatch (src/lib.rs:3-7). It also exports scenario runs into the bundle format, and it ships a chio-eval-receipt binary at src/bin/cli.rs.

The two entry points are verify_bundle with verify_fixture_bundle, which parse a bundle JSON document into a VerifiedBundle, and export_scenario_run, which builds a Bundle from scenario inputs (src/lib.rs:9-11). The crate pins the schema it verifies as constants: BUNDLE_SCHEMA_ID is chio.eval-report.bundle.v1 and BUNDLE_SCHEMA_PATH is spec/eval/receipt-format.v1.json (src/lib.rs:34 and :37). It carries #![forbid(unsafe_code)] at src/lib.rs:13.

Embed evaluation in an HTTP service

chio-tower brings Chio evaluation into a Rust service process. It wraps compatible Tower HTTP services. With durable stores configured, it records authorization evidence before invoking the inner handler, then records the resulting HTTP receipt. This supports policy-aware service boundaries without a network hop to a sidecar.

Supply the host’s durable stores

The durable integration uses an evaluator with receipt and revocation stores, qualified admission and outcome stores, and their mutation fence. The following is the assembly shape once those stores have been provisioned:

rust
use chio_tower::{ChioEvaluator, ChioLayer};

let evaluator = ChioEvaluator::builder(keypair, policy_hash)
    .receipt_store(receipt_store)
    .revocation_store(revocation_store)
    .durable_admission_stores(admission_store, outcome_store, mutation_fence)
    .build()?;
let layer = ChioLayer::from_evaluator(evaluator);

The evaluator integration tests show store provisioning and the authority-lock directory. ChioLayer::builder does not expose the qualified admission-store method; use from_evaluator for that setup. ChioLayer::new starts without durable stores and fails closed; new_ephemeral is an explicit local scaffold.

Check the service contract

Integration concernCurrent contract
Request and response bodies
Request bodies implement Body + From<Bytes>; response bodies implement Default + From<Bytes>, with Send and static lifetimes. The default buffered-body limit is 8 MiB.
Async runtime
Use a multi-thread Tokio runtime for the synchronous bridge into async kernel dispatch, as exercised by the HTTP integration tests.
Axum error handling
Adapt the layer’s boxed errors to Axum’s Infallible service contract. The source includes an explicit adapter in its Axum integration test.
Identity
The default header extractor marks identities unverified. Extracting a bearer token, API key, or cookie is not authenticating it.
Policy
The current evaluator selects SessionAllow for safe methods and DenyByDefault otherwise. The policy_hash parameter records context; it does not load policy rules.
Handler effects
Evidence recording around a handler does not make its external effects transactional. The host still owns execution and recovery.

For remote MCP sessions or receipt-query pagination, use the TypeScript, Python, or Go client surfaces where supported, or the documented protocol endpoints. chio-binding-helpers itself opens no sockets.

Error model

chio_binding_helpers::Error (error.rs:37-46) is a thiserror enum with three variants: Core, Json, and Manifest. Each is produced only by #[from] conversion from the underlying crate's error, so there is no Error::new constructor: parse and verify helpers propagate with ?. Call .code() (error.rs:50) to map an Error onto an ErrorCode, the serde snake-case enum at error.rs:5-34 that the other bindings share.

rust
use chio_binding_helpers::{parse_capability_json, verify_capability};

fn inspect(json: &str, now: u64) {
    let result = parse_capability_json(json)
        .and_then(|cap| verify_capability(&cap, now, Some(8)));
    match result {
        Err(error) => eprintln!("Verification could not complete: {:?}", error.code()),
        Ok(status) => {
            println!("Signature: {}", status.signature_valid);
            println!("Chain shape: {}", status.delegation_chain_shape_valid);
            println!("Time: {:?}", status.time_status);
        }
    }
}

An expired token normally returns a verification result with time_valid = false. A broken chain can return delegation_chain_shape_valid = false. Handle these result fields as well as Err.

Source

The public SDK crates define the verification helpers, C ABIs, guard SDK, and evaluation-receipt tooling. The crate table renders checked workspace manifests. The compatibility shim is sdks/rust/chio-guard-sdk-compat; HTTP integration lives in crates/protocol/chio-tower.

The chio crate is the Computer API; the installer's chio binary is the CLI built from chio-cli. Below the Computer layer, import the crate for the boundary you need: chio-binding-helpers for local invariants, chio-core and chio-core-types for shared types, and chio-kernel-core for the portable decision core.

Conformance

The Rust crates are the reference the other languages are checked against. One JSON corpus of vectors covers canonical JSON, hashing, signing, receipts, capabilities, and manifests, and chio-binding-helpers round-trips every vector through its public API. The installed CLI runs the same corpus against each peer language:

bash
chio conformance run --peer all