LearnSystem Architecture
The State a Verdict Depends On
The evaluation core reads no store and no clock of its own, so every input a verdict turns on arrived as an argument.
Overview
chio-kernel-core is the pure-compute part of capability evaluation. Its own architecture notes state the boundary: the crate performs no I/O and holds no state beyond what a caller explicitly supplies. It is built no_std + alloc, so the same verdict-producing code runs in a browser, in a mobile app, behind a C++ FFI host, and inside the hosted sidecar without modification.
That has a consequence worth stating in full. If the function that produces the verdict cannot read a database, cannot open a socket, and cannot ask the operating system what time it is, then everything the verdict depends on arrived as an argument. The list of arguments is therefore the complete list of state a verdict can turn on, and the code that fetched each one runs before the call rather than inside it.
Model
A pure function with no memory
The evaluation entry point takes an EvaluateInput and returns an EvaluationVerdict. Every field of the input is a borrow the caller owns.
pub struct EvaluateInput<'a> {
/// Tool call request being evaluated.
pub request: &'a PortableToolCallRequest,
/// The capability token authorising this call.
pub capability: &'a CapabilityToken,
/// Trusted issuer public keys (typically CA + kernel + authority).
pub trusted_issuers: &'a [PublicKey],
/// Clock used for time-bound enforcement.
pub clock: &'a dyn Clock,
/// Guard pipeline. Evaluated in order, fail-closed on deny or error.
pub guards: &'a [&'a dyn Guard],
/// Optional filesystem roots from the owning session, passed through to
/// guards that enforce root-based resource protection.
pub session_filesystem_roots: Option<&'a [String]>,
}Three more values arrive alongside it on the full path. evaluate_with_full_floor takes a CapabilityCryptoFloor, a CapabilityNegotiation for the peer, a &dyn TrustRootResolver, and a mutable &mut dyn BudgetRegistry. The registry is the only argument the function writes to, and it writes to it last.
The clock and the entropy source are traits
Time and randomness are the two things a pure function cannot compute and cannot do without. Both enter as traits, and both doc comments name the rule directly.
//! Abstract clock for capability time-bound enforcement.
//!
//! The kernel core never calls `std::time::SystemTime::now()`. All time
//! enters the pure evaluation surface through a `&dyn Clock` so that
//! browser, WASM, and embedded adapters can inject `Date.now()`,
//! `instant::now()`, or a fuzzed/mock clock for deterministic testing.
/// Abstract monotonic wall-clock exposing Unix seconds.
///
/// Implementations MUST return a value consistent with the signed
/// `issued_at` / `expires_at` fields on capabilities. The verdict path is
/// fail-closed against clock errors: if `now_unix_secs` returns a value in
/// the past of `issued_at` or past `expires_at`, the capability is rejected.
pub trait Clock {
/// Current Unix timestamp in seconds.
fn now_unix_secs(&self) -> u64;
}rng.rs mirrors it. The core never calls OsRng directly; browser adapters route to crypto.getRandomValues() through the getrandom crate's js feature, WASI adapters route to the host random API, and mobile adapters use SecRandomCopyBytes or /dev/urandom. Determinism and Replay covers what a caller owes those two traits.
How it works
Who fetches, and when
chio-kernel is the hosted layer that does the reading. Its architecture notes draw the stores it depends on as consumer-supplied traits, hanging off the stages that use them rather than off the evaluation core. Four groups appear, and each one is a trait a deployment implements.
crates/kernel/chio-kernel/ARCHITECTURE.md:14-63at fe56570Read that as an answer to the question of provenance. A verdict that turns on revocation turned on a RevocationStore read the hosted layer performed during capability validation. A verdict that turns on remaining budget turned on a BudgetStore read at budget admission. Neither read happens inside the pure function, and neither can happen twice with different answers inside one evaluation.
The reads behind one verdict, in order
evaluate_with_full_floor, the path production kernels use, runs six steps in a fixed order.
- Capability base verification: issuer trust, signature under the configured crypto floor, and the time window. Reads
trusted_issuersand the clock. - Delegation chain shape, when the token carries one: per-link signatures and the final delegatee against the token subject. An attenuated token additionally binds
attenuation_proof.parent_scope_hashto the trust root through theTrustRootResolver, gated by the negotiatedDELEGATION_CHAIN_BINDINGfeature. - Subject binding:
request.agent_idmust equal the verified capability subject. - Portable scope match:
scope::resolve_matching_grantspicks the most specific grant covering the server and tool pair. A constraint the portable matcher cannot evaluate fails closed withConstraintError. - Guard pipeline: every
&dyn Guardruns in order, and aDeny,PendingApproval, orErrfrom any guard fails the whole evaluation. - Sibling-budget admission, last. Only after steps one through five pass does
admit_delegated_budgetmutate the caller's realBudgetRegistry.
Why admission runs last
The verdict that comes back is three-valued in the hosted kernel and two-valued in the core: the core emits only Allow and Deny, and PendingApproval is produced by the layer that can hold a request open.
pub enum Verdict {
/// The action is allowed.
Allow,
/// The action is denied.
Deny,
/// The action is suspended pending a human decision. Look up the
/// associated `ApprovalRequest` via the HITL API.
PendingApproval,
}Guarantees and limits
Status: shipped. chio-kernel-core is a no_std crate with #![deny(unsafe_code)] at its root, and formal/proof-manifest.toml names evaluate.rs, capability_verify.rs, scope.rs, normalized.rs, and receipts.rs as the modules the bounded verified core covers.
- No module in the core reaches out. The crate's stated invariant is that no module reaches into
std, wall-clock globals, the filesystem, the network, async runtimes, stores, or policy engines. Hosted-only code such asrevocation_viewand the fuzz harnesses is feature-gated. - An unknown input denies. Unknown budget parents, unsupported scope constraints, missing chain-binding trust roots, and a clock value outside
[issued_at, expires_at)all deny. There is no path where the core proceeds on a value it could not interpret. - Freshness is the caller's problem. The core decides against the snapshot it was handed. A revocation that lands after the hosted layer read
RevocationStoreis not visible to that evaluation, which is why revocation propagation is a store property rather than a verdict property. See Revocation Store. - The core cannot hold a request open.
PendingApprovalnever flows out ofchio-kernel-core, because suspending a call requires state that outlives the function. That branch belongs to the hosted layer and the approval store. - Purity is not the proof. The bounded verified core covers the five modules the proof manifest names. Payment authorization, governed-transaction policy, DPoP nonce replay, and tool dispatch live in
chio-kerneland are outside that boundary. See Formal Assurance.
Next steps
- Portable Kernel · the platforms the same core runs on unchanged
- Core & Shell · the split between the pure core and the layer that reads
- Node State on Disk · the stores behind the consumer-supplied traits
- Determinism and Replay · what the clock and the entropy source owe the kernel
- The Mediated Call · the full sequence the six evaluation steps sit inside