Chio/Docs
LOGIN · JOIN

Default Pipelines

See which guards each default builder installs, in what order, and which controls your host registers itself.

Concept chio@5f63e6e

On this page

A host that embeds the kernel starts from a ready set of guards, installed by one builder call. Registration decides which checks run and which refusal can stop evaluation.

Two builders in chio-guards supply those sets, and they install different controls. GuardPipeline::default_pipeline() registers seven input guards in a fixed order. default_runtime_guard_profile() installs checks before dispatch and a sanitizer after it. GuardPipeline::new() starts empty.

Each builder installs its own set of controls

Neither named default contains the other. The library default covers paths, shell commands, egress, tool names, secrets, and patches; the runtime profile covers internal networks, agent velocity, and output sanitization.

Default guard setsChoose a builder.
before dispatchafter dispatchbefore dispatchafter dispatch

π1library defaultπ2runtime profileπ0empty pipeline

Each builder installs its own set

default_pipeline() installs seven input guards. default_runtime_guard_profile() installs three input controls and one output hook. GuardPipeline::new() installs nothing. No control appears in both named sets. Guard catalog.

The controls each chio-guards builder installs, by runtime name, against the side of dispatch where each runs. A compiled HushSpec policy and operator-wired guards are left out.

The library default leaves output hooks to the host: it registers the composed pipeline and configures each control. The runtime profile returns input guards and an output pipeline, and the host installs both, then adds its policy-specific controls. An empty pipeline from GuardPipeline::new() or Default holds whatever guards the host adds.

A compiled HushSpec policy can produce yet another set. A guard’s catalog entry describes the control; the host’s registration path installs it, so read that path to know what runs. For a policy file, chio policy explain prints the set and order it compiles to. The HushSpec example team policy compiles to eight guards, with velocity second and internal-network beside egress-allowlist, a set neither builder produces:

Terminal · beside hushspec-policiesbash
chio policy explain hushspec-policies/team-policy.yaml
Output
policy     hushspec-policies/team-policy.yaml  extends hushspec-policies/builtin-default.yaml
grants     read_file on server *       max_args_size 8192
           list_directory on server *  max_args_size 8192
           search_files on server *    max_args_size 8192
           sql on server *             max_args_size 8192
           export_to_csv on server *   max_args_size 8192, approval required
guards     1 forbidden-path
           2 velocity
           3 egress-allowlist
           4 internal-network
           5 mcp-tool
           6 secret-leak
           7 patch-integrity
           8 path-allowlist
output     1 hook
approvals  export_to_csv on every call

Seven guards run in a fixed order, and order decides which refusal you see

The library default registers its seven guards in one sequence and evaluates them in that sequence. The first denial ends evaluation, and an error counts as a denial.

The guard pipeline as a conjunction of guard resultsr =read_file README.mdread_file ~/.ssh/id_rsahttp_get evil.examplegj(r)j = 0forbidden-path0j = 1shell-commandj = 2egress-allowlistj = 3path-allowlistj = 4mcp-toolj = 5secret-leakj = 6patch-integrity∧no dispatch
v(r)=⋀j=06 gj(r)v(r) = \displaystyle\htmlClass{role-seal}{\bigwedge_{j=0}^{6}}\, \htmlClass{role-call}{g_j}(r)
v(r)=0∧⋯=0\phantom{v(r)}= \htmlClass{role-deny}{0} \wedge \cdots = \htmlClass{role-deny}{0}
gj(r)={1Allow0Deny or error\htmlClass{role-call}{g_j}(r) = \begin{cases} 1 & \text{Allow} \\ \htmlClass{role-deny}{0} & \text{Deny or error} \end{cases}
first gj = 0 at j = 0; later guards do not run
The guard pipeline as a conjunction of guard resultsr =read_file README.mdread_file ~/.ssh/id_rsahttp_get evil.examplegj(r)forbidden-path0shell-commandegress-allowlistpath-allowlistmcp-toolsecret-leakpatch-integrity∧v = 0no dispatchfirst gj = 0 at j = 0; later guards do not run

forbidden-path denies the request; the pipeline stops and the request is not dispatched.

v(r)=⋀j=06 gj(r)=0∧⋯=0gj(r)={1Allow0Deny or error\begin{aligned} v(r) &= \htmlClass{role-seal}{\bigwedge_{j=0}^{6}}\, \htmlClass{role-call}{g_j}(r) \\ &= \htmlClass{role-deny}{0} \wedge \cdots = \htmlClass{role-deny}{0} \\[4pt] \htmlClass{role-call}{g_j}(r) &= \begin{cases} 1 & \text{Allow} \\ \htmlClass{role-deny}{0} & \text{Deny or error} \end{cases} \end{aligned}
In Rust · pipeline.rs:6620 lines
for guard in &self.guards {
    match guard.evaluate(ctx) {
        Ok(decision) => {
            evidence.extend(decision.evidence);
            match decision.verdict {
                Verdict::Allow => continue,
                // … PendingApproval
                Verdict::Deny => {
                    // … record the denial
                    return Ok(GuardDecision::deny(evidence));
                }
            }
        }
        Err(e) => {
            // Fail closed: guard errors are treated as denials.
            // … record the error
            return Ok(GuardDecision::deny(evidence));
        }
    }
}
The seven guards of the default pipeline, in registration order, with illustrative requests. A request reaches the pipeline only after its capability check passes. A guard error counts as a denial.Guards

Each guard answers to a runtime name, such as forbidden-path. A denial reason, a metric label, and a GuardEvidence row all carry that name. For independent, total, stateless checks over the same immutable input, conjunction gives the same allow or deny result in any order; short-circuiting still changes which refusal and evidence you see. Stateful guards, timeouts, and failures need a stronger analysis.

A rate check can consume a token before a later guard denies, so reordering that pipeline changes future admission as well as this call’s evidence and cost. The builder registers a fixed sequence and never measures request cost or reorders checks. Choose another order from your workload and your guards’ semantics, then test it.

Read more in Pipelines & Composition, which owns the combination rules.

The runtime profile checks both sides of dispatch

default_runtime_guard_profile() returns a RuntimeGuardProfile that the standard runtime installs: three controls before dispatch and a post-invocation pipeline after it.

crates/guards/chio-guards/src/lib.rsrust
pub fn default_runtime_guard_profile() -> RuntimeGuardProfile {
    let mut post_invocation_pipeline = PostInvocationPipeline::new();
    post_invocation_pipeline.add(Box::new(SanitizerHook::new()));

    RuntimeGuardProfile {
        pre_invocation_guards: vec![
            Box::new(InternalNetworkGuard::new()),
            Box::new(AgentVelocityGuard::new(AgentVelocityConfig::default())),
            Box::new(AdvisoryPipeline::new(PromotionPolicy::new())),
        ],
        post_invocation_pipeline,
    }
}

Three controls an operator might expect to wire by hand arrive with it. InternalNetworkGuard (internal-network, on Network) prevents server-side request forgery. AgentVelocityGuard (agent-velocity, on Rate Limit) limits an agent’s rate across capabilities. ResponseSanitizationGuard runs through the post-invocation SanitizerHook, named output-sanitizer (Sanitization).

The AdvisoryPipeline (advisory-pipeline) is installed empty. The session-journal advisory guards that populate it, and any promotion rules, stay operator-wired; Advisory Signals covers PromotionPolicy.

Opt-in guards wait for the configuration they read

The full chio-guards catalog ships more than the two defaults install, and the rest stay operator-wired even with the runtime profile enabled. Each depends on something only the deployment can supply.

  • Thresholds and tuning. Jailbreak and prompt-injection detection carry inference cost and false-positive risk that vary by deployment.
  • History. Behavioral profiles read a receipt feed, and session-aware guards read a session journal that not every edge maintains.
  • Connections and credentials. External adapters and data-layer guards reach a provider or a data store.
  • The tool interface itself. Computer-use, code-execution, content-review, and memory-governance guards apply only where that interface exists.

Each guard’s requirement is listed under Opt-in guards in the installation reference.

A host extends or trims the default by registering guards itself

Start from the default and append controls that should run after its checks. Choose their order from dependency, state, and failure semantics as well as measured cost.

Extend the default · embedded kernelrust
use chio_guards::{
    GuardPipeline, AgentVelocityGuard, AgentVelocityConfig,
    DataFlowGuard, DataFlowConfig,
};
let mut pipeline = GuardPipeline::default_pipeline();

// AgentVelocityGuard keeps its own in-memory rate buckets.
pipeline.add(Box::new(AgentVelocityGuard::new(
    AgentVelocityConfig::default(),
)));
// DataFlowGuard is session-aware and needs a journal handle.
pipeline.add(Box::new(DataFlowGuard::new(
    journal.clone(),
    DataFlowConfig::default(),
)));

// Custom guards last: refuse a refund above USD 50.00 (amounts in cents).
pipeline.add(Box::new(RefundCeilingGuard::new(5_000)));

kernel.add_guard(Box::new(pipeline));

The response side registers separately: add a PostInvocationPipeline on the kernel, as Sanitization shows. To trim instead, build the pipeline by hand; the kernel accepts a manually registered pipeline. Omit a default guard only when another control closes its interface, such as a network sandbox, an immutable filesystem, or the absence of a shell tool.

Build a pipeline without the shell and egress guards
Trim the default · embedded kernelrust
use chio_guards::{
    GuardPipeline, ForbiddenPathGuard, PathAllowlistGuard,
    McpToolGuard, SecretLeakGuard, PatchIntegrityGuard,
};

// A pipeline without ShellCommandGuard or EgressAllowlistGuard,
// for a deployment that has no shell or network surface to begin with.
let mut pipeline = GuardPipeline::new();
pipeline.add(Box::new(ForbiddenPathGuard::new()));
pipeline.add(Box::new(PathAllowlistGuard::new()));
pipeline.add(Box::new(McpToolGuard::new()));
pipeline.add(Box::new(SecretLeakGuard::new()));
pipeline.add(Box::new(PatchIntegrityGuard::new()));

kernel.add_guard(Box::new(pipeline));

Read more in Custom Guards, which covers authoring the guards you append.

Guard installation reference

Registration order

The 7 guards GuardPipeline::default_pipeline() registers, from the source inventory. Post-invocation hooks, advisory guards, and operator-wired guards are outside it, and Default::default() is empty.

#GuardRuntime nameWhat it checks
1
ForbiddenPathGuard
forbidden-path
Matches declared filesystem paths against forbidden patterns. A denial stops the remaining pipeline. Filesystem
2
ShellCommandGuard
shell-command
Matches forbidden shell-command patterns against the command extracted from the request arguments. Shell & Code
3
EgressAllowlistGuard
egress-allowlist
Allows outbound requests only to listed domains. Host patterns take wildcards; the default action is block. Network
4
PathAllowlistGuard
path-allowlist
Allowlist for filesystem read, write, and patch operations. Disabled by default; an enabled empty list denies access. Session roots are checked independently. Filesystem
5
McpToolGuard
mcp-tool
Name lists and a maximum argument size for the generic McpTool action. Specialized actions go to their domain guards. Tool Access
6
SecretLeakGuard
secret-leak
Scans FileWrite content and Patch diffs for configured secret patterns, subject to skip-path rules. Filesystem
7
PatchIntegrityGuard
patch-integrity
Checks patches against maximum additions, maximum deletions, forbidden content patterns, and the addition-to-deletion balance. Shell & Code
crates/guards/chio-guards/src/pipeline.rs39-49rust
/// Create a default pipeline with all implemented guards using their
/// default configurations.
pub fn default_pipeline() -> Self {
    let mut pipeline = Self::new();
    pipeline.add(Box::new(crate::ForbiddenPathGuard::new()));
    pipeline.add(Box::new(crate::ShellCommandGuard::new()));
    pipeline.add(Box::new(crate::EgressAllowlistGuard::new()));
    pipeline.add(Box::new(crate::PathAllowlistGuard::new()));
    pipeline.add(Box::new(crate::McpToolGuard::new()));
    pipeline.add(Box::new(crate::SecretLeakGuard::new()));
    pipeline.add(Box::new(crate::PatchIntegrityGuard::new()));
    pipeline
}

Runtime installation contracts

spec/GUARDS.md lists the controls the runtime profile installs and the controls the host registers. The source inventory resolves each type to its defining crate. PostInvocationPipeline is listed under chio-guards and defined in crates/kernel/chio-kernel/src/post_invocation.rs, where the post-invocation phase lives.

GuardCrate, per the specImplementationDefined inDefault control-plane profile
InternalNetworkGuard
chio-guards
Full
chio-guards
Installed by default runtime profile
AgentVelocityGuard
chio-guards
Full
chio-guards
Installed by default runtime profile
DataFlowGuard
chio-guards
Full
chio-guards
Operator-wired (requires `SessionJournal`)
BehavioralSequenceGuard
chio-guards
Full
chio-guards
Operator-wired (requires `SessionJournal`)
ResponseSanitizationGuard
chio-guards
Full
chio-guards
Installed by default runtime profile through `SanitizerHook`
PostInvocationPipeline
chio-guards
Full
chio-kernel
Installed by default runtime profile
AdvisoryPipeline
chio-guards
Full
chio-guards
Installed by default runtime profile (session-journal advisory guards remain operator-wired)
AnomalyAdvisoryGuard
chio-guards
Full
chio-guards
Operator-wired (requires `SessionJournal`)
DataTransferAdvisoryGuard
chio-guards
Full
chio-guards
Operator-wired (requires `SessionJournal`)
PortableFilesystemRootsGuard
chio-guards
Full
No type of this name
Operator-wired (filesystem-scoped)
WasmGuard
chio-wasm-guards
Full
chio-wasm-guards
Operator-wired
WasmGuardRuntime
chio-wasm-guards
Full
chio-wasm-guards
Operator-wired
SessionJournal
chio-http-session
Full
chio-http-session
Operator-wired

Opt-in guards

The guards neither default installs, with what each needs before it is useful.

  • JailbreakGuard (heuristic, statistical, and ML layers). ML inference cost and false-positive risk vary by deployment; review its thresholds before enabling it. Jailbreak Detection.
  • PromptInjectionGuard. Pattern detection on incoming text, noisy until you tune its signal set. Jailbreak Detection.
  • BehavioralProfileGuard. Reads receipt feed history, so it needs a configured feed source and baseline windows before it has anything to compare against.
  • DataFlowGuard, BehavioralSequenceGuard. Session-aware: each reads a configured session journal, which not every edge maintains. Session-aware Guards.
  • VelocityGuard. A per-window, per-grant invocation cap. Pick a window and a limit that match your workload. Rate Limit.
  • External adapters (Bedrock, Azure, Vertex, Safe Browsing, VirusTotal, Snyk). Each adds a network dependency, credentials, and latency; enable them per External Guards and External Adapters.
  • chio-data-guards (SqlQueryGuard, VectorDbGuard, WarehouseCostGuard, QueryResultGuard). A separate crate that neither default references. It reads a configured data-store connection and a table and column allowlist policy; QueryResultGuard is a post-invocation hook over returned rows. Data Layer.
  • AnomalyAdvisoryGuard, DataTransferAdvisoryGuard. The runtime profile installs an empty AdvisoryPipeline; these session-journal advisory guards and any promotion rules are operator-wired. Advisory Signals.
  • Computer-use guards (computer_use, browser_automation, remote_desktop, input_injection, embedding_anomaly). Relevant to deployments that mediate computer use, and off elsewhere. Computer Use.
  • code_execution, content_review, memory_governance. Domain-specific; operators wire each where the corresponding tool interface exists. Shell & Code and Memory.
  • WASM custom guards. Loaded from operator-authored .arcguard components at start-up; the kernel ships with no WASM guards built in. WASM Guards.

Next: implement a guard of your own