PlatformConfiguration & Custody
Node
chio.yaml Configuration
A field reference for chio.yaml: runtime signing keys, upstream APIs, protocol endpoints, and guard modules.
Root Structure
The top-level object is ChioConfig with these sections:
| Field | Type | Required | Description |
|---|---|---|---|
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. |
This file reaches a node as a local file and nothing else; Policy Rollout documents why there is no distribution service and how to detect two nodes that ended up with different bytes.
kernel
The required section. It identifies the runtime to the rest of the system through its Ed25519 signing key.
| Field | Type | Default | Notes |
|---|---|---|---|
signing_key | string | required | Hex-encoded Ed25519 key, or the literal "generate" for dev mode. Empty values are rejected. |
receipt_store | string | "sqlite:///var/chio/receipts.db" | Receipt store URI used by the kernel directly. |
log_level | string | "info" | Kernel-subsystem log level. The top-level logging.level covers the rest of the runtime. |
deadlines | object | kernel defaults | Hot-path wall-clock budgets. Optional; an absent table falls back to kernel defaults. See below. |
signing_key: generate is not for production
"generate" creates an ephemeral keypair at startup. Receipts signed by an ephemeral key are unverifiable after restart. Use a persistent hex-encoded key in any deployment that has to survive a restart.kernel.deadlines
An optional sub-section exposing the runtime hot-path wall-clock budgets. Only the scalar budgets are set from the file; the per-guard and per-server override maps are wired programmatically. Every field is optional, so an absent kernel.deadlines table is valid. Each Some value replaces the matching kernel default, and each omitted field keeps it. The section applies deny_unknown_fields.
| Field | Type | Notes |
|---|---|---|
guard_pipeline_budget_ms | u64 (optional) | Wall-clock budget for the full guard pipeline. |
dispatch_budget_ms | u64 (optional) | Budget for dispatch to the tool server. |
receipt_append_budget_ms | u64 (optional) | Budget for appending a receipt. |
receipt_writer_poll_ms | u64 (optional) | Receipt-writer poll interval. |
receipt_writer_stall_ms | u64 (optional) | Threshold before the receipt writer is treated 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, etc. |
upstream | string | Yes | URL of the upstream API. |
spec | string | No | Path to a spec file (for openapi, the OpenAPI YAML/JSON). |
auth | object | No | Upstream authentication. |
auth
auth:
type: bearer # one of: bearer, api_key, cookie, mtls, none
header: Authorization # required for bearer and api_keyValidation:
typemust be one ofbearer,api_key,cookie,mtls,none.- When
typeisbearerorapi_key, theheaderfield is required. cookie,mtls, andnonemay omitheader.
edges[]
Each edge exposes an adapter through a protocol endpoint.
| Field | Type | Notes |
|---|---|---|
id | string | Unique within the file. |
protocol | string | Edge protocol: mcp, a2a, acp, etc. |
expose_from | string | Adapter id that this edge surfaces. Must reference a declared adapter. |
receipts
| Field | Type | Default | Notes |
|---|---|---|---|
store | string | "sqlite:///var/chio/receipts.db" | Receipt store URI. |
checkpoint_interval | u64 | 100 | Receipts between Merkle checkpoints. 0 disables. |
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 OTel export. |
endpoint | string | "" | OTel collector URL (e.g., http://localhost:4317). |
service_name | string | "chio-acp-proxy" | Service identifier reported to the collector. |
include_parameters | bool | false | Include receipt parameters in span attributes. Off by default to avoid leaking sensitive data. |
batch_size | usize | 0 | Span batch size. 0 exports each span immediately. |
guards
Globally applied guard configuration. Per-guard configuration (forbidden paths, tool access, egress) belongs in a HushSpec policy; this section sets pipeline-wide knobs.
| Field | Type | Default | Notes |
|---|---|---|---|
allow_advisory_promotion | bool | false | When true, advisory-only verdicts can be promoted to deterministic blocking via overlay. |
required | string[] | [] | Guard names that must pass on every request, regardless of route. |
For details on which guards are configurable through HushSpec, see HushSpec Policy Format. For the runtime pipeline, see Default Pipeline.
Additional guard configuration
guards: per-guard blocks such as internal_network.extra_blocked_hosts, agent_velocity.max_requests_per_agent, data_flow, behavioral_sequence, response_sanitization.min_level/action, and the advisory knobs (anomaly, data-transfer, promotion rules). These configure individual guards. Each guard's reference page documents its own block. See, for example, Network Guards for internal_network and Filesystem Guards for the path guards.wasm_guards[]
Each entry declares a WASM guard module for the pipeline. A module travels with its manifest: guard-manifest.yaml is read from the directory holding the path file.
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | required | Surfaces in receipts and logs. |
path | string | required | Filesystem path to the .wasm module. |
fuel_limit | u64 | 10000000 | Max fuel units per invocation. |
priority | u32 | 1000 | Sort key for the guard list, ascending, with ties broken on advisory. The field is parsed and validated. No load path consumes it, so the ordering does not reach evaluation. See Custom WASM Guards. |
advisory | bool | false | When true, a failure is recorded but not blocking. |
See Custom WASM Guards for the manifest format, signing, and host imports.
Environment Variable Interpolation
Interpolation runs on the raw YAML before parsing, so every string-typed field is eligible. Two patterns are supported:
${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_]*. If multiple required variables are unset, the loader reports them all in a single error so you can fix everything in one pass. The sequence ${} with no variable name is left as literal text.
kernel:
signing_key: "${CHIO_SIGNING_KEY}"
log_level: "${CHIO_LOG_LEVEL:-info}"
adapters:
- id: petstore
protocol: openapi
upstream: "http://${API_HOST}:${API_PORT:-8080}/api"
auth:
type: bearer
header: AuthorizationValidation
Validation runs after interpolation and YAML deserialization. All errors collect into a single ConfigError::Validation so the operator can fix everything at once.
- deny_unknown_fields. Every section rejects unknown keys at parse time. Typos like
recieiptsfail before validation runs. - At least one adapter. An empty adapter list is rejected.
- Unique adapter IDs. Duplicates are rejected by string comparison. Empty IDs are also rejected.
- Unique edge IDs. Same rule. Empty edge IDs are rejected.
- Reference integrity. Every
edge.expose_frommust match an adapteriddeclared in the same file. - Auth completeness.
typevalues are enumerated;bearerandapi_keyrequire aheader. - Non-empty signing key.
kernel.signing_keymust not be the empty string. - Logging enums.
levelandformatare checked against their fixed value sets.
Loading from Code
Programmatic callers use the loader entry points in chio-config:
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 helpers run interpolation, parse with deny_unknown_fields, and run the validation pass before returning. Errors are surfaced as ConfigError with Io, Interpolation, Parse, and Validation variants.
chio start and chio.yaml
chio start starts the sidecar with zero-config defaults and takes no --config flag. Subcommands and embedded runtimes that consume chio.yaml opt in through their own flags or programmatic APIs. The CLI also ships a chio doctor probe that parses chio.yaml and checks a minimal marker schema: the top-level version and policy keys, not the adapter/edge runtime schema on this page (see below). For the full runtime schema, call chio_config::load_from_file from a small Rust binary or a test harness.CLI Policy Checks
A policy is a separate file from chio.yaml, and the chio CLI evaluates it through its own commands:
# Spawn an agent under a HushSpec policy.
$ chio run --policy ./policy.yaml -- agent --task my-task
# Evaluate a single tool call against a policy without spawning anything.
$ chio check --policy ./policy.yaml \
--tool read_file \
--params '{"path": "/etc/passwd"}' \
--server '*'
# Scaffold a new project with a sample chio.yaml and policy.
$ chio init my-deploymentchio.yaml itself is checked by chio doctor, which runs six ordered health probes; the sixth parses chio.yaml and checks for two top-level marker keys, version and policy, reporting errors with line and column anchors. chio doctor --fix scaffolds a minimal file containing exactly those keys (version: 1, policy: ./policy.yaml).
The doctor probe validates a different, minimal schema
version/policy marker schema is a separate contract from the kernel/adapters/edges runtime schema this page documents. A well-formed adapter/edge chio.yaml carries neither version nor policy and does not satisfy the probe. For full validation of the runtime schema in CI, write a small Rust test that calls load_from_file and asserts Ok, or shell out from a build script.Worked Example
A complete chio.yaml for a small deployment: one MCP edge over an OpenAPI adapter, one external guard reachable via the policy compiler, and one custom WASM guard. Secrets are interpolated from the environment.
kernel:
signing_key: "${CHIO_SIGNING_KEY}"
receipt_store: "sqlite:///var/lib/chio/receipts.db"
log_level: "${CHIO_KERNEL_LOG_LEVEL:-info}"
adapters:
- id: petstore
protocol: openapi
upstream: "https://${PETSTORE_HOST}/v1"
spec: ./specs/petstore.openapi.yaml
auth:
type: bearer
header: Authorization
edges:
- id: petstore-mcp
protocol: mcp
expose_from: petstore
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-petstore-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: org-pii-scanner
path: /etc/chio/guards/pii-scanner/pii_guard.wasm
fuel_limit: 20000000
priority: 200
advisory: falseExternal provider guards (Bedrock, Azure, Vertex, Safe Browsing, VirusTotal, Snyk) use a distinct policy schema. They are not configured through chio.yaml or a guards: block inside a HushSpec document. Their cloud-guardrail and threat-intel configuration lives on the control-plane external-guard policy schema (the cloud_guardrails and threat_intel fields on GuardPolicyConfig), which the control plane compiles into a pipeline via build_guard_pipeline and build_post_invocation_pipeline (re-exported from chio_control_plane::policy). Within a HushSpec document, threat-intel-driven detection is instead configured at extensions.detection.threat_intel (compiling to the EmbeddingAnomalyGuard). See External Guards for that schema.
Next Steps
- HushSpec Policy Format · the policy file that pairs with
chio.yaml - Custom WASM Guards · author the modules referenced from
wasm_guards - External Guards · cloud content-safety and threat-intel integration
- Wrap an MCP Server · a deployment that uses adapters and protocol endpoints