-
Notifications
You must be signed in to change notification settings - Fork 0
Guard Example
A minimal reference guard. Demonstrates the canonical shape of a guard hook that votes on a tool call by inspecting its arguments. Reference only — normative shape and rules live in Hooks (contract).
A guard hook is the last line of defense before a tool body runs. This example denies any Bash tool invocation whose command argument contains rm -rf. It is the kind of per-call, argument-sensitive policy the Hooks § Orthogonality with State Machines section calls out as guard territory — coarse allowedTools at the SM level cannot express this, because the SM cannot peek inside command strings.
| Field | Value |
|---|---|
| Kind |
Hook. |
subKind |
guard. |
| Attachment |
TOOL_CALL/pre. |
| Firing |
sync (guards are always sync — see Firing mode). |
| Validation severity |
Critical by default — a guard on TOOL_CALL/pre is critical per Hooks § Validation severity. A load failure fails the session, because silently dropping the guard would weaken security posture. |
| State slot | None needed. Guards should be stateless and deterministic. |
flowchart LR
Call[TOOL_CALL/pre fires] --> Check{tool is Bash<br/>and command<br/>matches rm -rf?}
Check -->|yes| Deny["return deny<br/>reason: dangerous-delete"]
Check -->|no| Approve[return approve]
Deny --> Audit["emit audit record:<br/>GuardDeny"]
Approve --> Next[next guard / body]
On deny:
- The turn-stage body does not run.
- Post-slot transforms and observers do not run.
-
TOOL_CALL/preobservers still fire so the deny is visible in the event stream. - The guard writes a
GuardDenyaudit record throughhost.audit— see Hooks § Security notes. Audit on deny is non-optional. - Core translates the deny into a typed tool-result the LLM can see on the next turn. See Guard-Deny-Reproposal flow.
| Field | Meaning | Default |
|---|---|---|
enabled |
Whether the hook participates. |
true. |
severity |
critical or optional. Cannot demote below critical per the conditional-severity rule. |
critical. |
patterns[] |
Regex or substring patterns the command is matched against. |
[] (no-op if empty). |
The guard reads its own config through the validated config object delivered during init; it does not read env or files directly.
- You need to block a tool call based on arguments, not on identity. Coarse "block the whole Bash tool" belongs in
allowedTools, not here. - The decision is cheap and pure — no network calls, no filesystem reads per invocation. Guards are on the hot path.
- The decision can be audited with useful context. A deny a user cannot understand is worse than no deny at all.
Do not use a guard for:
- Mutating arguments — that is a
transform. - Recording every tool call for analytics — that is an
observer. - Asking the user "are you sure?" — that is the Security Mode gate or an interactive tool, not a guard. Guards cannot drive the Interaction Protocol.
- Execution Model
- Message Loop
- Concurrency and Cancellation
- Error Model
- Event and Command Ordering
- Event Bus
- Command Model
- Interaction Protocol
- Hook Taxonomy
- Host API
- Extension Lifecycle
- Env Provider
- Prompt Registry
- Resource Registry
- Session Lifecycle
- Session Manifest
- Persistence and Recovery
- Stage Executions
- Subagent Sessions
- Contract Pattern
- Versioning and Compatibility
- Deprecation Policy
- Capability Negotiation
- Dependency Resolution
- Validation Pipeline
- Cardinality and Activation
- Extension State
- Conformance and Testing
- Providers
- Provider Params
- Tools
- Hooks
- UI
- Loggers
- State Machines
- SM Stage Lifecycle
- Stage Definitions
- Commands
- Session Store
- Context Providers
- Settings Shape
- Trust Model
- Project Trust
- Extension Isolation
- Extension Integrity
- LLM Context Isolation
- Secrets Hygiene
- Security Modes
- Tool Approvals
- MCP Trust
- Sandboxing
- Configuration Scopes
- Project Root
- Extension Discovery
- Extension Installation
- Extension Reloading
- Headless and Interactor
- Determinism and Ordering
- Launch Arguments
- Network Policy
- Platform Integration
Tools
UI
Session Stores
Loggers
Providers
Hooks
Context Providers
Commands
- First Run
- Default Chat
- Tool Call Cycle
- Hook Interception
- Guard Deny Reproposal
- State Machine Workflow
- SM Stage Retry
- Hot Model Switch
- Capability Mismatch Switch
- Session Resume
- Session Resume Drift
- Approval and Auth
- Interaction Timeout
- Headless Run
- Parallel Tool Approvals
- Subagent Delegation
- Scope Layering
- Project First-Run Trust
- Reload Mid-Turn
- Compaction Warning
- MCP Remote Tool Call
- MCP Prompt Consume
- MCP Resource Bind
- MCP Reconnect