Policy Engine
Define YAML rules that gate merges based on behavioral signals. Policies are version-controlled alongside your code.
Policy file structure
spooled-policy.yml
name: "My Policy" enabled: true block_merges: true rules: - name: "Block new tools" description: "Prevent unauthorized tool additions" severity: high fail_if: new_side_effects: true - name: "Warn on latency" severity: medium warn_if: latency_spike: threshold_percent: 50.0
Top-level fields
| Field | Type | Default | Description |
|---|---|---|---|
| name | string | "" | Policy name |
| enabled | boolean | true | Enable/disable the entire policy |
| block_merges | boolean | false | Exit code 1 when violations exist |
| rules | list | [] | Array of rule objects |
| profiles | dict | None | Per-agent policy overrides |
Rule structure
Each rule has a fail_if block (violations that block), a warn_if block (warnings only), or both.
| Field | Type | Description |
|---|---|---|
| name | string | Rule identifier |
| description | string | Human-readable description |
| severity | "high" | "medium" | "low" | Default: "medium" |
| fail_if | dict | Conditions that cause rule to fail |
| warn_if | dict | Conditions that cause rule to warn |
Supported conditions
Signal-based conditions
fail_if: new_side_effects: true latency_spike: threshold_percent: 50.0 retry_explosion: threshold: 5 error_increase: threshold: 1 new_tools: true tool_usage_change: threshold_percent: 50.0 token_usage_spike: threshold_percent: 50.0 component_latency_drift: threshold_percent: 100.0 tool_overuse: threshold_percent: 50.0 retrieval_regression: threshold: 0.2
Content-blind conditions (Pro)
fail_if: output_schema_drift: fail_on_removed: true fail_on_added: false
Behavioral conditions
fail_if: # Block when behavioral fingerprint doesn't match on_variant: true # Or with minimum similarity threshold on_variant: min_similarity: 0.75 # Require specific tools to be present required_tools: tools: ["check_pii", "detect_hallucination"] message: "Compliance guardrails must be present"
Per-agent profiles
Override policy rules for specific agents:
spooled-policy.yml
profiles: default: block_merges: true rules: - name: "Standard checks" fail_if: new_side_effects: true payment_agent: block_merges: true rules: - name: "Strict: low latency tolerance" fail_if: latency_spike: threshold_percent: 25.0 new_side_effects: true
When agent_id matches a profile key, that profile is used. Otherwise, the default profile applies. If no profiles section exists, top-level rules apply to all agents.
CLI commands
spooled policy init # Create default policy file spooled policy validate # Check policy YAML syntax spooled policy show # Display current configuration
Policy templates
Three built-in templates:
| Template | Description |
|---|---|
| strict | Block on any behavioral change, variant, or new tool |
| moderate | Block on high-severity signals, warn on medium |
| permissive | Warn only, never block |
Evaluation flow
When spooled ci run or spooled ci compare is called with a policy:
Trace → Fingerprint → Compare to baseline → Status → Detect signals → Evaluate policy rules → Result: { passed, violations, warnings, should_block }
The policy engine returns:
| Field | Description |
|---|---|
| passed | true if no violations |
| should_block | block_merges AND violations exist |
| violations | List of fail_if violations from all rules |
| warnings | List of warn_if warnings from all rules |
| violation_count | Total violations |
| warning_count | Total warnings |