HushSpec Policy Format
HushSpec is the YAML schema that describes what a Chio agent is allowed to do. The compiler in chio-policy reads a HushSpec document, resolves any extends chain, merges rule blocks according to the chosen strategy, and produces a guard pipeline plus capability grants. This page is the field-level reference. For a beginner walkthrough see Write a Policy; for inheritance patterns see Inherit & Merge Policies.
Compiler tests are the executable spec
crates/chio-cli/src/policy.rs and the type definitions in crates/chio-policy/src/models.rs. Where this page and the source disagree, trust the source.Document Version
Every HushSpec document begins with a version line:
hushspec: "0.1.0"The current version is "0.1.0" (constant HUSHSPEC_VERSION). This is the only supported value listed in HUSHSPEC_SUPPORTED_VERSIONS. A document with a different version is not auto-detected as HushSpec by is_hushspec_format, but the parser still accepts the field as a string so older corpora load.
Top-Level Fields
The root object uses deny_unknown_fields: any key not listed below is a parse-time error.
| Field | Type | Required | Description |
|---|---|---|---|
hushspec | string | Yes | Schema version. Always "0.1.0". |
name | string | No | Human-readable identifier carried into receipts. |
description | string | No | Free-form prose explaining intent. |
extends | string | No | Reference to a base policy (built-in or filesystem path). |
merge_strategy | enum | No | How the document folds into its parent. Default deep_merge. |
rules | object | No | Per-guard configuration. The core of the policy. |
extensions | object | No | Domain-specific add-ons: posture, origins, detection, reputation, runtime assurance, chio. |
metadata | object | No | Governance fields: author, classification, lifecycle. |
extends
extends takes a single reference string. The resolver in chio-policy::resolve loads the base, recurses on its own extends chain, and merges the children back over each parent. The composite loader supports two reference forms:
| Reference | Loader | Example |
|---|---|---|
| Built-in ruleset | Embedded YAML | chio:default, chio:strict, chio:permissive, chio:ai-agent, chio:cicd, chio:remote-desktop |
| Filesystem path | Reads from disk relative to the source policy | ../base/team.yaml, /etc/chio/policies/base.yaml |
Built-in references accept either the bare name or a chio: / hushspec: prefix. The catalogue lives in BUILTIN_RULESETS and ships default, strict, permissive, ai-agent, cicd, remote-desktop, and the reserved panic ruleset.
HTTP references are not supported
http:// and https:// references withResolveError::Http. Bring remote bases onto the filesystem first (e.g., as a build artifact) and reference the local path.Circular Detection
The resolver tracks every loaded canonical source on a stack. If a descendant resolves back to a source already in the stack, it returns ResolveError::Cycle with the full chain (joined with -> ). Cycles cannot compile.
merge_strategy
The merge strategy controls how the child policy combines with the resolved parent. Values are rendered in snake_case:
| Strategy | Behavior |
|---|---|
deep_merge (default) | Recursively merges nested rule and extension blocks. Lists concatenate; scalars in the child win. |
merge | Top-level shallow merge: child blocks fully replace any same-named parent block but other top-level blocks are preserved. |
replace | Child wholly replaces the parent. The extends chain is still loaded for source provenance, but no fields carry forward. |
The default is deep_merge: most policies want to inherit a baseline forbidden-paths list and add to it, not redeclare every entry.
rules
The rules object holds per-guard configuration. The struct uses deny_unknown_fields; unknown rule names are rejected. Every documented sub-block is optional. Omitted blocks compile to disabled guards (the default pipeline still applies a minimal safe baseline if extends: chio:default is in scope).
| Block | Compiles to |
|---|---|
forbidden_paths | ForbiddenPathGuard |
path_allowlist | PathAllowlistGuard |
egress | EgressAllowlistGuard |
secret_patterns | SecretLeakGuard |
patch_integrity | PatchIntegrityGuard |
shell_commands | ShellCommandGuard |
tool_access | McpToolGuard + capability grants |
computer_use | ComputerUseGuard |
remote_desktop_channels | RemoteDesktopChannelsGuard |
input_injection | InputInjectionGuard |
browser_automation | BrowserAutomationGuard |
code_execution | CodeExecutionGuard |
velocity | VelocityGuard (+ AgentVelocityGuard) |
human_in_loop | Constraint::RequireApprovalAbove on grants |
tool_access (Detail)
rules:
tool_access:
enabled: true # bool, default true
default: block # "allow" or "block", default "allow"
allow: [read_file] # tools explicitly permitted
block: [delete_file] # tools explicitly denied (overrides allow)
require_confirmation: # tools that require human approval
- write_file
max_args_size: 4096 # optional cap on serialized argument size
require_runtime_assurance_tier: hardware_isolated # optional
prefer_runtime_assurance_tier: hardware_isolated # optional
require_workload_identity: # optional
scheme: spiffe
trust_domain: example.org
path_prefixes: ["/agents/"]
credential_kinds: [x509]For details on every other rule (default values, list semantics, examples), the field-by-field tables in Write a Policy are the operator-facing reference. The Rust struct definitions below are the schema:
pub struct ForbiddenPathsRule {
pub enabled: bool, // default true
pub patterns: Vec<String>, // glob patterns to deny
pub exceptions: Vec<String>, // exempt specific paths
}
pub struct PathAllowlistRule {
pub enabled: bool, // default false
pub read: Vec<String>,
pub write: Vec<String>,
pub patch: Vec<String>,
}
pub struct EgressRule {
pub enabled: bool, // default true
pub allow: Vec<String>,
pub block: Vec<String>,
pub default: DefaultAction, // default Block
}
pub struct PatchIntegrityRule {
pub enabled: bool, // default true
pub max_additions: usize, // default 1000
pub max_deletions: usize, // default 500
pub forbidden_patterns: Vec<String>,
pub require_balance: bool, // default false
pub max_imbalance_ratio: f64, // default 10.0
}
pub struct VelocityRule {
pub enabled: bool, // default true
pub max_invocations_per_window: Option<u32>,
pub max_spend_per_window: Option<u64>, // minor units
pub max_requests_per_agent: Option<u32>,
pub max_requests_per_session: Option<u32>,
pub window_secs: u64, // default 60
pub burst_factor: f64, // default 1.0
}Conditional Activation
Some rule blocks accept conditions that gate evaluation on runtime context. The shared Condition type from chio_policy::conditions carries:
- A tool-name match (exact or glob), evaluated against
RuntimeContext::tool_name. - An agent-id match, evaluated against
RuntimeContext::agent_id. - A
TimeWindowConditionmatched against the request timestamp.
Conditions are evaluated by evaluate_condition(condition, context) and combine via the standard policy AND semantics: every condition on a rule must hold for the rule to apply.
extensions
Extensions hold optional, domain-specific configuration. The shape is fixed: unknown sub-blocks are rejected by deny_unknown_fields.
| Extension | Purpose |
|---|---|
posture | Stateful posture machine: initial state, state-specific capabilities/budgets, transitions on triggers. |
origins | Per-origin profiles with their own tool_access and egress overrides; default behavior is deny or minimal_profile. |
detection | Prompt-injection, jailbreak, and threat-intel detectors (regex and similarity-based). |
reputation | Reputation tiers, scoring weights, promotion/demotion triggers and metrics requirements. |
runtime_assurance | Tier requirements and verifier rules sourced from chio_core::appraisal. |
chio | Chio-specific overlay: market hours, signing, k8s namespaces, rollback, n-of-m approver sets. |
Each extension has its own merge function in chio-policy::merge so deep-merge respects the structure (e.g., posture states keyed by name, origin profiles keyed by id).
metadata
metadata carries governance fields. None are enforced by the runtime; they exist for audit pipelines and deployment review.
| Field | Type | Notes |
|---|---|---|
author | string | Free-form. |
approved_by | string | Free-form. |
approval_date | string | RFC 3339 recommended. |
classification | enum | public | internal | confidential | restricted |
change_ticket | string | Reference to your change-management system. |
lifecycle_state | enum | draft | review | approved | deployed | deprecated | archived |
policy_version | int | Internal version counter (separate from hushspec). |
effective_date | string | When the policy starts applying. |
expiry_date | string | When the policy expires. |
Compile Model
Compilation runs in three stages:
- Parse.
HushSpec::parsereads the YAML, applies pre-checks against malformed scalars, and deserializes withdeny_unknown_fields. - Resolve and merge.
resolve_with_loaderwalks theextendschain, detecting cycles, then folds children over parents permerge_strategy. - Compile.
compile_policyturns the resolvedHushSpecinto aCompiledPolicy: a guard pipeline plus initial capability grants. The CLI'sbuild_pipeline_from_external_guard_policyextends this with cloud guardrail and threat-intel adapters from the policy.
The compiled output drives the kernel's evaluation pipeline. See Guard Platform Architecture for the runtime flow.
Validation Rules
The following are enforced by the parser, resolver, or compiler. They are exercised in the test suites at crates/chio-policy/src/models.rs and crates/chio-cli/src/policy.rs.
- Unknown fields are rejected.
deny_unknown_fieldsapplies toHushSpec,Rules, every rule struct, and every extension. Typos likeforbidden_path(singular) instead offorbidden_pathsare parse-time errors. - YAML must be a mapping. A document that begins with a plain scalar, a sequence, or a URL fails before libyml runs. This is a defense against accidentally-pasted text.
- Quoted scalar overflow is rejected. Long whitespace runs inside quoted scalars (over
MAX_QUOTED_SCALAR_WHITESPACE_RUN) fail before reaching libyml so the underlying parser is not forced through an exponential path. - Cycles in
extendsare rejected. The resolver returnsResolveError::Cyclewith the chain. - HTTP references are rejected. The composite loader returns
ResolveError::Httpforhttp://andhttps://references. - Regex patterns are validated.
shell_commands.forbidden_patterns,patch_integrity.forbidden_patterns, andsecret_patterns.patterns[].patterngo throughchio_policy::regex_safetyand reject pathological patterns. - Default actions are enums.
tool_access.defaultandegress.defaultaccept onlyalloworblock. Other strings fail to deserialize. - Compiler-side checks. The CLI's policy compiler rejects duplicate guard IDs in the combined pipeline, missing required fields on external-guard providers, and broken cross-references between origins and posture states.
Worked Example
A team policy that extends the built-in chio:default ruleset, tightens forbidden paths, locks down tools to a project allowlist, adds a velocity cap, and records governance metadata.
hushspec: "0.1.0"
name: team-data-pipeline
description: Read-only data extraction agent with strict path and tool gates.
extends: "chio:default"
merge_strategy: deep_merge
rules:
tool_access:
enabled: true
default: block
allow:
- read_file
- list_directory
- search_files
- run_query
block:
- execute_command
require_confirmation:
- export_to_csv
max_args_size: 8192
forbidden_paths:
enabled: true
patterns:
- "**/.env*"
- "**/secrets/**"
- "**/.aws/credentials"
- "**/id_rsa*"
exceptions:
- "/var/lib/agent/.env.testing"
path_allowlist:
enabled: true
read:
- "/var/lib/agent/data/**"
- "/var/lib/agent/config/*.yaml"
write: []
patch: []
egress:
enabled: true
default: block
allow:
- "warehouse.internal"
- "*.metrics.example.com"
secret_patterns:
enabled: true
patterns:
- name: aws_access_key
pattern: "AKIA[0-9A-Z]{16}"
severity: critical
- name: bearer_token
pattern: "Bearer\\s+[A-Za-z0-9._~+/-]+=*"
severity: error
velocity:
enabled: true
max_invocations_per_window: 200
window_secs: 60
burst_factor: 1.5
human_in_loop:
enabled: true
require_confirmation:
- "export_*"
timeout_seconds: 300
on_timeout: deny
extensions:
chio:
market_hours:
tz: "America/New_York"
open: "09:30"
close: "16:00"
days: [Mon, Tue, Wed, Thu, Fri]
metadata:
author: "platform-security"
approved_by: "secops-lead"
classification: confidential
lifecycle_state: deployed
policy_version: 7
effective_date: "2026-04-01"Next Steps
- Write a Policy · field-by-field tables for every rule with worked examples
- Inherit & Merge Policies · base policies, overlay patterns, and multi-environment inheritance
- chio.yaml Configuration · the runtime config that loads a compiled policy and registers guards
- External Guards · the
guards.cloud_guardrailsandguards.threat_intelsub-blocks layered on top of HushSpec rules