Chio/Docs

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

The most authoritative description of HushSpec is the test suite in 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:

yaml
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.

FieldTypeRequiredDescription
hushspecstringYesSchema version. Always "0.1.0".
namestringNoHuman-readable identifier carried into receipts.
descriptionstringNoFree-form prose explaining intent.
extendsstringNoReference to a base policy (built-in or filesystem path).
merge_strategyenumNoHow the document folds into its parent. Default deep_merge.
rulesobjectNoPer-guard configuration. The core of the policy.
extensionsobjectNoDomain-specific add-ons: posture, origins, detection, reputation, runtime assurance, chio.
metadataobjectNoGovernance 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:

ReferenceLoaderExample
Built-in rulesetEmbedded YAMLchio:default, chio:strict, chio:permissive, chio:ai-agent, chio:cicd, chio:remote-desktop
Filesystem pathReads 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

The composite loader explicitly rejects 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:

StrategyBehavior
deep_merge (default)Recursively merges nested rule and extension blocks. Lists concatenate; scalars in the child win.
mergeTop-level shallow merge: child blocks fully replace any same-named parent block but other top-level blocks are preserved.
replaceChild 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).

BlockCompiles to
forbidden_pathsForbiddenPathGuard
path_allowlistPathAllowlistGuard
egressEgressAllowlistGuard
secret_patternsSecretLeakGuard
patch_integrityPatchIntegrityGuard
shell_commandsShellCommandGuard
tool_accessMcpToolGuard + capability grants
computer_useComputerUseGuard
remote_desktop_channelsRemoteDesktopChannelsGuard
input_injectionInputInjectionGuard
browser_automationBrowserAutomationGuard
code_executionCodeExecutionGuard
velocityVelocityGuard (+ AgentVelocityGuard)
human_in_loopConstraint::RequireApprovalAbove on grants

tool_access (Detail)

yaml
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:

crates/chio-policy/src/models.rs
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 TimeWindowCondition matched 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.

ExtensionPurpose
postureStateful posture machine: initial state, state-specific capabilities/budgets, transitions on triggers.
originsPer-origin profiles with their own tool_access and egress overrides; default behavior is deny or minimal_profile.
detectionPrompt-injection, jailbreak, and threat-intel detectors (regex and similarity-based).
reputationReputation tiers, scoring weights, promotion/demotion triggers and metrics requirements.
runtime_assuranceTier requirements and verifier rules sourced from chio_core::appraisal.
chioChio-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.

FieldTypeNotes
authorstringFree-form.
approved_bystringFree-form.
approval_datestringRFC 3339 recommended.
classificationenumpublic | internal | confidential | restricted
change_ticketstringReference to your change-management system.
lifecycle_stateenumdraft | review | approved | deployed | deprecated | archived
policy_versionintInternal version counter (separate from hushspec).
effective_datestringWhen the policy starts applying.
expiry_datestringWhen the policy expires.

Compile Model

Compilation runs in three stages:

  1. Parse. HushSpec::parse reads the YAML, applies pre-checks against malformed scalars, and deserializes with deny_unknown_fields.
  2. Resolve and merge. resolve_with_loader walks the extends chain, detecting cycles, then folds children over parents per merge_strategy.
  3. Compile. compile_policy turns the resolved HushSpec into a CompiledPolicy: a guard pipeline plus initial capability grants. The CLI's build_pipeline_from_external_guard_policy extends 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_fields applies to HushSpec, Rules, every rule struct, and every extension. Typos like forbidden_path (singular) instead of forbidden_paths are 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 extends are rejected. The resolver returns ResolveError::Cycle with the chain.
  • HTTP references are rejected. The composite loader returns ResolveError::Http for http:// and https:// references.
  • Regex patterns are validated. shell_commands.forbidden_patterns,patch_integrity.forbidden_patterns, and secret_patterns.patterns[].pattern go through chio_policy::regex_safety and reject pathological patterns.
  • Default actions are enums. tool_access.default and egress.default accept only allow or block. 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.

team-policy.yaml
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

HushSpec Policy Format · Chio Docs