chio.yaml Configuration
Find a chio.yaml field, its default, and the validation rule the loader applies before the kernel starts.
On this page
chio.yaml configures the process that hosts the kernel: its signing key, the upstream adapters, the protocol edges that expose them, receipt storage, logging, telemetry, and guard loading. Policy lives in a separate HushSpec document. The policy decides what a request may do; chio.yaml decides which identity, transports, and stores the process uses.
The file below is a complete configuration for the pricing service: one MCP edge over an OpenAPI adapter for its quote, discount, and refund operations, with two WASM guards. Secrets come from the environment through interpolation.
A complete file
kernel:
signing_key: "${CHIO_SIGNING_KEY}"
receipt_store: "sqlite:///var/lib/chio/receipts.db"
log_level: "${CHIO_KERNEL_LOG_LEVEL:-info}"
adapters:
- id: pricing
protocol: openapi
upstream: "https://${PRICING_HOST}"
spec: ./openapi.yaml
auth:
type: bearer
header: Authorization
edges:
- id: pricing-mcp
protocol: mcp
expose_from: pricing
receipts:
store: "sqlite:///var/lib/chio/receipts.db"
checkpoint_interval: 200
retention_days: 365
logging:
level: "${CHIO_LOG_LEVEL:-info}"
format: json
telemetry:
enabled: true
endpoint: "http://${OTEL_HOST:-localhost}:4317"
service_name: chio-pricing-edge
include_parameters: false
batch_size: 100
guards:
required:
- forbidden-path
- secret-leak
- patch-integrity
allow_advisory_promotion: false
wasm_guards:
- name: tool-denylist
path: /etc/chio/guards/tool-denylist/tool_denylist_guard.wasm
fuel_limit: 5000000
priority: 100
- name: customer-pii-scanner
path: /etc/chio/guards/customer-pii-scanner/pii_guard.wasm
fuel_limit: 20000000
priority: 200
advisory: falseEach node receives this file as a local file. Policy Rollout covers how the same bytes reach every node and how to detect two nodes that hold different bytes.
Try signing_key, checkpoint_interval, expose_from, or interpolation.
Top-level sections
The top-level object is ChioConfig. Only kernel and adapters are required.
| Field | Type | Required | Holds |
|---|---|---|---|
kernel | object | Yes | Signing key, receipt store, kernel log level. |
adapters | array | Yes (min 1) | Upstream API connections. |
edges | array | No | Protocol edges (mcp, a2a) that expose adapters. |
receipts | object | No | Receipt store, retention, and checkpoint cadence. |
logging | object | No | Log level and output format. |
telemetry | object | No | OpenTelemetry span export. |
guards | object | No | Globally required guard names and advisory promotion. |
wasm_guards | array | No | WASM guard modules loaded at runtime. |
kernel
The required section. It identifies the runtime to the rest of the system through its Ed25519 signing key.
signing_key
A hex-encoded Ed25519 key, or the literal "generate" for development. The empty string is rejected. "generate" creates an ephemeral keypair at startup, so receipts it signs are unverifiable after a restart; a deployment that must survive a restart uses a persistent hex key.
Example"${CHIO_SIGNING_KEY}"
receipt_store
The receipt store URI the kernel writes to directly.
Example"sqlite:///var/lib/chio/receipts.db"
log_level
The kernel subsystem's log level. The top-level logging.level covers the rest of the runtime.
Example"${CHIO_KERNEL_LOG_LEVEL:-info}"
deadlines
Hot-path wall-clock budgets. An absent table keeps the kernel defaults. The fields are listed under kernel.deadlines.
kernel.deadlines
The file sets the scalar budgets; the per-guard and per-server override maps are set programmatically. Every field is optional. Each value present replaces the matching kernel default, and each omitted field keeps it. The section applies deny_unknown_fields.
| Field | Type | Budget for |
|---|---|---|
guard_ | u64 (optional) | The full guard pipeline. |
dispatch_ | u64 (optional) | Dispatch to the tool server. |
receipt_ | u64 (optional) | Appending one receipt. |
receipt_ | u64 (optional) | The receipt writer's poll interval. |
receipt_ | u64 (optional) | Time before the receipt writer counts as stalled. |
adapters[]
Each adapter connects the kernel to one upstream API. At least one adapter is required.
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | Unique within the file. Referenced by edges. |
protocol | string | Yes | Adapter type: openapi, grpc, graphql, and others. |
upstream | string | Yes | URL of the upstream API. |
spec | string | No | Path to a spec file; for openapi, the OpenAPI YAML or JSON. |
auth | object | No | Upstream authentication. |
adapters[].auth
auth:
type: bearer # one of: bearer, api_key, cookie, mtls, none
header: Authorization # required for bearer and api_keytypeis one ofbearer,api_key,cookie,mtls,none.bearerandapi_keyrequireheader.cookie,mtls, andnonemay omitheader.
edges[]
Each edge exposes one adapter through a protocol endpoint.
| Field | Type | Notes |
|---|---|---|
id | string | Unique within the file. |
protocol | string | Edge protocol: mcp, a2a, acp, and others. |
expose_from | string | The id of a declared adapter this edge surfaces. |
receipts
| Field | Type | Default | Notes |
|---|---|---|---|
store | string | "sqlite:///var/ | Receipt store URI. |
checkpoint_ | u64 | 100 | Receipts between Merkle checkpoints. 0 disables checkpoints. |
retention_days | u64 | 90 | Days to retain receipts before expiry. |
logging
| Field | Type | Default | Allowed values |
|---|---|---|---|
level | string | "info" | trace, debug, info, warn, error |
format | string | "json" | json, text |
telemetry
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | bool | false | Master switch for OpenTelemetry export. |
endpoint | string | "" | Collector URL, such as http://localhost:4317. |
service_name | string | "chio-acp-proxy" | Service identifier reported to the collector. |
include_ | bool | false | Copies receipt parameters into span attributes; off keeps sensitive arguments out of spans. |
batch_size | usize | 0 | Span batch size. 0 exports each span immediately. |
guards
Pipeline-wide guard settings. Per-guard rules such as forbidden paths, tool access, and egress belong in a HushSpec policy; the runtime order is on Default Pipelines.
| Field | Type | Default | Notes |
|---|---|---|---|
allow_ | bool | false | true lets an overlay promote advisory verdicts to blocking. |
required | string[] | [] | Guard names that must pass on every request, on every route. |
Those two fields are the base runtime schema. Guard crates read their own tuning blocks under guards: internal_network.extra_blocked_hosts, agent_velocity.max_requests_per_agent, data_flow, behavioral_sequence, response_sanitization.min_level and action, and the advisory settings for anomaly, data transfer, and promotion rules. Each guard's page documents its block, for example Network Guards for internal_network and Filesystem Guards for the path guards.
External provider guards (Bedrock, Azure, Vertex, Safe Browsing, VirusTotal, Snyk) are configured on the control plane's external-guard policy schema: the cloud_guardrails and threat_intel fields on GuardPolicyConfig. The control plane compiles them into pipelines with build_guard_pipeline and build_post_invocation_pipeline, re-exported from chio_control_plane::policy. Inside a HushSpec document, threat-intel detection sits at extensions.detection.threat_intel and compiles to the EmbeddingAnomalyGuard. External Guards documents that schema.
wasm_guards[]
Each entry declares one WASM guard module for the pipeline. The loader reads the module's guard-manifest.yaml from the directory that holds the path file. Custom WASM Guards covers the manifest format, signing, and host imports.
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | required | Appears in receipts and logs. |
path | string | required | Filesystem path to the .wasm module. |
fuel_limit | u64 | 10000000 | Maximum fuel units per invocation. |
priority | u32 | 1000 | Evaluation order: lower values run first; ties break on advisory. |
advisory | bool | false | true records a failure without blocking. |
Environment variable interpolation
Interpolation runs on the raw YAML before parsing, so every string-typed field can take a variable. Two patterns are recognized.
${VAR} # required: error if VAR is unset
${VAR:-default} # optional: use VAR if set, otherwise the default literalVariable names match [A-Za-z_][A-Za-z0-9_]*. When several required variables are unset, the loader names all of them in one error. The sequence ${} with no variable name stays literal text.
kernel:
signing_key: "${CHIO_SIGNING_KEY}"
log_level: "${CHIO_LOG_LEVEL:-info}"
adapters:
- id: pricing
protocol: openapi
upstream: "http://${PRICING_HOST:-127.0.0.1}:${PRICING_PORT:-9440}"
auth:
type: bearer
header: AuthorizationValidation rules
Validation runs after interpolation and deserialization. Every failure collects into one ConfigError::Validation, so one run reports all of them.
- Unknown keys. Every section applies
deny_unknown_fields, so a typo such asrecieiptsfails at parse time, before validation. - At least one adapter. An empty adapter list is rejected.
- Unique adapter ids. Duplicates are rejected by string comparison, and so are empty ids.
- Unique edge ids. The same rule, including empty ids.
- Reference integrity. Every
edge.expose_frommatches an adapteriddeclared in the same file. - Auth completeness.
typetakes an enumerated value;bearerandapi_keyrequire aheader. - Signing key present.
kernel.signing_keyis a non-empty string. - Logging values.
levelandformattake values from their fixed sets.
Loading from Rust
Programs that embed the kernel load the file through the chio-config crate.
use chio_config::{load_from_file, load_from_str, ChioConfig};
// From a file path:
let config: ChioConfig = load_from_file(Path::new("/etc/chio/chio.yaml"))?;
// From a string (e.g., loaded over the network):
let config: ChioConfig = load_from_str(yaml_text)?;Both functions interpolate, parse with deny_unknown_fields, and validate before returning. Failures arrive as ConfigError with the variants Io, Interpolation, Parse, and Validation. A CI check for the runtime schema is a small Rust test that calls load_from_file and asserts Ok.
chio start runs the sidecar with zero-config defaults and takes no --config flag. Subcommands and embedded runtimes that read chio.yaml opt in through their own flags or programmatic APIs.
CLI checks
A policy is a separate file from chio.yaml, and the CLI evaluates it with its own commands.
# Spawn an agent under a HushSpec policy.
$ chio run --policy ./policy.yaml -- python agent.py --issue 416
# Evaluate a single tool call against a policy without spawning anything.
$ chio check --policy ./policy.yaml \
--tool read_file \
--params '{"path": "/secrets/.env"}' \
--server workspace
# Scaffold a new project with a sample chio.yaml and policy.
$ chio init pricingchio doctor runs six ordered health probes. The sixth parses chio.yaml, checks the two top-level marker keys version and policy, and reports errors with line and column anchors. chio doctor --fix scaffolds a minimal file with exactly those keys: version: 1 and policy: ./policy.yaml. The marker schema is its own contract; the kernel, adapters, and edges schema above is validated by chio_config::load_from_file.