Default Pipelines
See which guards each default builder installs, in what order, and which controls your host registers itself.
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.
π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.
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:
chio policy explain hushspec-policies/team-policy.yamlpolicy 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 callSeven 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.
forbidden-path denies the request; the pipeline stops and the request is not dispatched.
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));
}
}
}
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.
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.
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
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
Search for a runtime name, a struct, or a requirement such as SessionJournal.
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.
| # | Guard | Runtime name | What it checks |
|---|---|---|---|
1 | Forbidden | forbidden-path | Matches declared filesystem paths against forbidden patterns. A denial stops the remaining pipeline. Filesystem |
2 | Shell | shell-command | Matches forbidden shell-command patterns against the command extracted from the request arguments. Shell & Code |
3 | Egress | egress- | Allows outbound requests only to listed domains. Host patterns take wildcards; the default action is block. Network |
4 | Path | 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 | Patch | patch-integrity | Checks patches against maximum additions, maximum deletions, forbidden content patterns, and the addition- |
/// 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.
| Guard | Crate, per the spec | Implementation | Defined in | Default control-plane profile |
|---|---|---|---|---|
Internal | chio-guards | Full | chio-guards | Installed by default runtime profile |
Agent | chio-guards | Full | chio-guards | Installed by default runtime profile |
DataFlowGuard | chio-guards | Full | chio-guards | Operator-wired (requires `SessionJournal`) |
Behavioral | chio-guards | Full | chio-guards | Operator-wired (requires `SessionJournal`) |
Response | chio-guards | Full | chio-guards | Installed by default runtime profile through `SanitizerHook` |
Post | chio-guards | Full | chio-kernel | Installed by default runtime profile |
Advisory | chio-guards | Full | chio-guards | Installed by default runtime profile (session-journal advisory guards remain operator-wired) |
Anomaly | chio-guards | Full | chio-guards | Operator-wired (requires `SessionJournal`) |
Data | chio-guards | Full | chio-guards | Operator-wired (requires `SessionJournal`) |
Portable | chio-guards | Full | No type of this name | Operator-wired (filesystem- |
WasmGuard | chio- | Full | chio- | Operator-wired |
Wasm | chio- | Full | chio- | Operator-wired |
SessionJournal | chio- | Full | chio- | 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;QueryResultGuardis a post-invocation hook over returned rows. Data Layer.AnomalyAdvisoryGuard,DataTransferAdvisoryGuard. The runtime profile installs an emptyAdvisoryPipeline; 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
.arcguardcomponents at start-up; the kernel ships with no WASM guards built in. WASM Guards.