LearnSystem Architecture
Portable Kernel
This page compares the shared kernel core and its server, mobile, and browser adapters, including their supported runtime services.
Shared receipt encoding
One Core, Three Targets
The core is chio-kernel-core: a no_std + alloc Rust crate with no async runtime, no HTTP client, and no database. Its direct dependencies are chio-core-types (pulled with default-features = false so the portable build stays no_std) and serialization (serde, serde_json). The cryptography (ed25519-dalek, sha2) comes in transitively through chio-core-types, not as a direct dependency. The core provides capability verification, scope matching, DPoP binding, guard evaluation, receipt canonicalization and signing, and Merkle checkpoint construction.
Three adapter crates package the core for different deployment shapes:
chio-kernel· the production sidecar. Adds tokio, an HTTP server, a SQLite-backed receipt store, a price oracle, and a guard plugin interface. This is what you run in Kubernetes.chio-kernel-mobile· UniFFI wrapper that exposes the core to Swift and Kotlin through a JSON-in, JSON-out FFI. Ships as an.xcframeworkfor iOS and a.soplus Kotlin module for Android.chio-kernel-browser· wasm-bindgen wrapper that compiles the core to WebAssembly for direct use from JavaScript and TypeScript. Ships as an npm package with typed bindings.
Feature Parity
The adapters call the shared core for capability evaluation and receipt operations. They supply platform-specific services.
| Feature | Sidecar | Mobile | Browser |
|---|---|---|---|
| Capability verification | Yes | Yes | Yes |
| Scope matching and DPoP binding | Yes | Yes | Yes |
| Signed receipts (Ed25519) | Yes | Yes | Yes |
| Guard pipeline (sync) | Yes | Yes | Yes |
| Portable passport verification | Yes | Yes | Roadmap |
| Merkle checkpoint construction | Yes | Yes | Yes |
| Custom guards at runtime | Yes (dyn Guard) | Compile-time only | Compile-time only |
| Async runtime | Yes (tokio) | No | No |
| Persistent receipt store | SQLite | Ring buffer + platform drain | Ring buffer + platform drain |
| HTTP fetch (price oracle, siem) | Yes | Host supplies | Host supplies |
| Entropy source | OS getrandom | SecRandom / /dev/urandom | Web Crypto |
| Clock source | SystemTime | CFAbsoluteTime / SystemClock | Injectable (default Date.now) |
Native (Sidecar)
This is the default deployment: run chio-kernel as a sidecar next to your agent, your Prefect worker, your Temporal activity worker, or your Next.js server. It holds the policy, signs receipts, persists them to SQLite or whatever durable store you plug in, and exposes an HTTP interface for callers. The Installation and Quick Start guides are written against this shape.
Mobile (iOS and Android)
The mobile binding is a thin FFI over the core, generated with UniFFI and JSON-in, JSON-out throughout. It exposes eleven functions. The evaluation and signing surface is evaluate, sign_receipt, and sign_receipt_relaying_trusted_body; verification functions are verify_capability, verify_capability_with_context, verify_passport, and verify_mobile_receipt. On top of that sit four hardware-attestation entry points: Apple App Attest via attest_app_attest and verify_app_attest_evidence, and Android Play Integrity via attest_play_integrity and verify_play_integrity_evidence. UniFFI maps each to an idiomatic Swift and Kotlin name (for example sign_receipt becomes signReceipt). iOS consumers link an .xcframework; Android consumers link a shared library and a generated Kotlin module.
The mobile crate depends directly on chio-custody-hw, Chio's hardware-custody crate, so the kernel and platform key custody live in the same binary. The attestation calls can therefore bind a device signing key to the Secure Enclave or Android hardware keystore.
Swift
import chio_kernel_mobile
// Evaluate a tool call locally - no network, no server round trip.
let request: [String: Any] = [
"capability": cachedCapabilityJson,
"trusted_issuers": [issuerHex],
"request": [
"request_id": UUID().uuidString,
"tool_name": "read_medical_record",
"server_id": "clinical-srv",
"agent_id": agentPubHex,
"arguments": ["patient_id": patientId],
],
"now_secs": 0, // 0 = use the on-device clock
]
let verdictJson = try evaluate(
requestJson: JSONSerialization.string(from: request)
)
// On allow, sign a receipt and queue it for later upload.
if verdict.verdict == "allow" {
let receiptJson = try signReceipt(
bodyJson: canonicalReceiptBody,
signingSeedHex: deviceSigningSeedHex
)
receiptQueue.enqueue(receiptJson)
}Kotlin
import uniffi.chio_kernel_mobile.*
val verdictJson = evaluate(
requestJson = buildString {
append("""{"capability": """)
append(cachedCapabilityJson)
append(""", "trusted_issuers": [""")
append(""$issuerHex"")
append("""], "request": {"request_id": "$requestId", """)
append(""""tool_name": "read_medical_record", """)
append(""""server_id": "clinical-srv", """)
append(""""agent_id": "$agentPubHex", """)
append(""""arguments": $argsJson}, "now_secs": 0}""")
}
)
val receipt = signReceipt(
bodyJson = canonicalReceiptBody,
signingSeedHex = deviceSigningSeedHex
)Offline operation
Browser (WebAssembly)
The browser binding compiles the core to WebAssembly and exposes seven typed JavaScript exports: evaluate, sign_receipt, sign_receipt_relaying_trusted_body, verify_capability, verify_capability_with_context, verify_receipt, and mint_signing_seed_hex. Passport verification is not yet ported to the browser target; the feature parity table marks it as planned. Entropy comes from the Web Crypto API; the clock comes from Date.now (with an optional override for deterministic tests). This page does not provide a dated measurement method or current browser performance baseline.
Install
npm install chio-kernel-browserUse
import init, {
evaluate,
sign_receipt,
verify_capability,
mint_signing_seed_hex,
} from "chio-kernel-browser";
// Load the wasm module once at app start.
await init();
const verdictJson = evaluate(JSON.stringify({
request: {
request_id: crypto.randomUUID(),
tool_name: "read_medical_record",
server_id: "clinical-srv",
agent_id: agentPubHex,
arguments: { patient_id: patientId },
},
capability: cachedCapability,
trusted_issuers_hex: [issuerHex],
// clock_override_unix_secs: 1_717_200_000, // optional, for tests
}));
const verdict = JSON.parse(verdictJson) as EvaluationVerdict;
if (verdict.verdict !== "allow") {
throw new PermissionError(verdict.reason);
}
const seedHex = mint_signing_seed_hex();
const receiptJson = sign_receipt(
JSON.stringify(receiptBody),
seedHex,
);Integration in Next.js
The module loads in both Node and Edge runtimes. A common approach is a server-side helper shared by routes that need it:
// lib/chio-gate.ts
import init, { evaluate } from "chio-kernel-browser";
let ready: Promise<unknown> | null = null;
function ensure() {
return (ready ??= init());
}
export async function gate(request: EvaluateRequest) {
await ensure();
const verdict = JSON.parse(evaluate(JSON.stringify(request)));
if (verdict.verdict !== "allow") {
throw Object.assign(new Error(verdict.reason), { code: "chio_deny" });
}
return verdict;
}Adapter Design Decisions
- JSON at the FFI boundary. The mobile and browser bindings use JSON instead of projecting the full Chio type graph into UDL or TypeScript. The FFI exposes a fixed set of JSON entry points and keeps the type graph versionable. This is the tradeoff gRPC and protobuf make against native struct marshaling.
- Fail-closed entropy. If a platform's RNG cannot produce high-quality randomness at signing time, the kernel refuses with a
weak_entropyerror instead of signing predictable bytes. The caller receives an error instead of a weaker signature. - Ring-buffer receipts, platform drains. The core buffers emitted receipts in memory. Platform adapters call
drain_receiptson a schedule they choose and persist to available storage (Keychain-backed SQLite on iOS, Room on Android, IndexedDB in the browser). The core stays deterministic and ignorant of storage. - No custom guards at runtime on mobile or browser. Guards are compiled into the adapter library at build time. Runtime guard registration requires a plugin loader that mobile and WASM cannot practically support. Most mobile and browser deployments use the built-in guards; custom guards can run on the server-side sidecar for more complex policies.
- Shared receipt format. Mobile and browser adapters use the core's canonicalization rules and signature scheme. They do not define separate receipt formats.
Status and Roadmap
| Crate | Status | Distribution |
|---|---|---|
chio-kernel-core | Shipped · CI-gated for no_std and wasm32 | Internal crate, not separately versioned |
chio-kernel (sidecar) | Shipped | Container image, Homebrew, release binaries |
chio-kernel-mobile | Alpha · iOS device and simulator builds, plus Android builds on the configured NDK, have CI coverage | .xcframework and .aar produced; CocoaPods and Maven Central not yet published |
chio-kernel-browser | Alpha · headless Chrome qualification has CI coverage; this page reports no dated size or latency measurement | wasm-pack output ready; not yet published to npm |
Alpha contract
Next Steps
- Autonomous Commerce · the commerce model supported by the portable kernel
- Architecture · how the kernel fits into the broader Chio deployment topology
- Capabilities · the token format the portable kernel verifies on every call
- Receipts · the canonical form the kernel signs on each target
- Trust Model · what it means for a verdict to be identical across server, mobile, and browser