Configure Hooks (Allow / Deny / Approval)
Hooks are pattern-matched rules that intercept tool calls before they execute. Use them to:
- Block tools under certain conditions ("EMCON active -- no map emissions")
- Allow tools that would otherwise require approval
- Force approval on tools that would otherwise auto-run
Where hooks live
In custos.yaml:
hooks:
rules:
- event: PreToolUse
toolPattern: "place_*"
action: deny
reason: "EMCON active — no map emissions"
- event: PreToolUse
toolPattern: "speak_alert"
action: allow
- event: PreToolUse
toolPattern: "detect_*"
action: require_approval
Rule fields
| Field | Required | Description |
|---|---|---|
event |
yes | When to evaluate. Supported: PreToolUse, PostToolUse, PostToolUseFailure |
toolPattern |
yes | Glob pattern matched against the tool name. * matches anything. |
action |
yes | One of: allow, deny, require_approval |
reason |
no | Human-readable string shown to the operator on deny and logged to audit |
whenTier |
no | List of tier names. Rule only fires when the chat provider serving the current turn is in this set. Null/empty matches every tier. |
Rule semantics
Rules are evaluated in order. The first match wins. If no rule matches, the tool is evaluated against its @impact level alone (the default approval gate).
allow-- tool runs immediately, bypassing the impact-level gatedeny-- tool does NOT run; the agent sees a denied result with your reasonrequire_approval-- the approval dialog opens regardless of impact level
If two rules match, only the first one fires. Order your rules carefully.
Recipes
Deny everything that mutates state
hooks:
rules:
- event: PreToolUse
toolPattern: "place_*"
action: deny
reason: "Read-only mode"
- event: PreToolUse
toolPattern: "send_*"
action: deny
reason: "Read-only mode"
- event: PreToolUse
toolPattern: "delete_*"
action: deny
reason: "Read-only mode"
- event: PreToolUse
toolPattern: "create_*"
action: deny
reason: "Read-only mode"
Allow alerts without approval, require approval for everything else
hooks:
rules:
- event: PreToolUse
toolPattern: "play_tone"
action: allow
- event: PreToolUse
toolPattern: "speak_alert"
action: allow
- event: PreToolUse
toolPattern: "send_notification"
action: allow
- event: PreToolUse
toolPattern: "*"
action: require_approval
The catch-all toolPattern: "*" at the end forces approval on anything not whitelisted above.
EMCON (radio silence) lockdown
hooks:
rules:
- event: PreToolUse
toolPattern: "send_cot"
action: deny
reason: "EMCON in effect"
- event: PreToolUse
toolPattern: "send_chat"
action: deny
reason: "EMCON in effect"
- event: PreToolUse
toolPattern: "place_marker"
action: deny
reason: "EMCON in effect — markers broadcast as CoT"
Approval-gate the dangerous tools only
hooks:
rules:
- event: PreToolUse
toolPattern: "delete_*"
action: require_approval
- event: PreToolUse
toolPattern: "send_package"
action: require_approval
- event: PreToolUse
toolPattern: "activate_beacon"
action: require_approval
Require approval when reasoning is on the cloud or at the command post
whenTier lets a rule care about which provider is producing the tool call. Useful when you want tighter gates on comms actions when reasoning happens off-handheld, but want the local model to run the same tools without extra friction:
hooks:
rules:
- event: PreToolUse
toolPattern: "send_*"
whenTier: ["cloud", "command-post"]
action: require_approval
reason: "Comms tools require approval when reasoning at remote tiers"
This rule only fires when the active chat provider's tier is cloud or command-post. If a handheld-tier on-device model issues the same tool call, the rule is skipped and the default @impact gate applies.
What the operator sees on a deny
The agent reports the denial in plain language ("I cannot place a marker right now: EMCON in effect"). The denial is also recorded in the Audit panel.
What the operator sees on require_approval
An approval dialog opens with:
- The tool name
- The arguments the agent wants to pass
- The impact level
- An approve / deny / modify choice
The dialog blocks the agent until the operator chooses. If the operator picks "modify," they can edit the tool arguments inline before approving -- useful for sanity-checking coordinates.
Hot-reload
Saving custos.yaml reloads the config. New rules take effect on the next tool call. No restart needed.
Limits
- First-match wins. Put specific rules above generic ones.
- PreToolUse fires before the impact gate. Use it for the override-the-gate use case.
- PostToolUse and PostToolUseFailure fire after -- useful for logging or auditing, but you cannot undo a tool call.
- Glob patterns are simple.
*matches anything. No?or character classes.