Hooks
Hooks are handlers executed automatically in response to agent lifecycle events. With hooks you can:
- Format code after edits
- Block dangerous operations before execution
- Send notifications when the agent finishes
- Perform automatic recovery on failures
- Audit all tool calls
Configure hooks
Hooks are defined in settings.json or settings.local.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|FileWrite",
"hooks": [
{
"type": "command",
"command": "prettier --write {{file}}"
}
]
}
]
}
}Use /update-config to configure hooks with automatic 7-step verification.
Available events
| Event | When it fires |
|---|---|
PermissionRequest |
Before asking the user for permission to use a tool |
PreToolUse |
Immediately before executing any tool |
PostToolUse |
Immediately after the tool returns (success or failure) |
PreCompact |
Before compacting the conversation context |
PostCompact |
After compaction is complete |
Stop |
When the agent finishes the response |
Notification |
When the agent needs to notify the user |
SessionStart |
At the start of a new session |
UserPromptSubmit |
When the user submits a prompt |
Hook types
`command` — shell script
Executes a shell command. The hook receives a JSON via stdin and can return a JSON via stdout to influence agent behavior.
{
"type": "command",
"command": "bash /home/user/.verboo/hooks/lint-on-edit.sh"
}Input format (stdin):
{
"event": "PostToolUse",
"tool_name": "Edit",
"tool_input": { "file_path": "/src/main.ts", "..." },
"tool_result": { "..." }
}Output format (stdout) — optional:
{
"continue": true,
"decision": "approve",
"reason": "File formatted successfully"
}`prompt` — LLM evaluation
Uses a language model to evaluate whether the operation should continue:
{
"type": "prompt",
"prompt": "Is the following command safe to run? Answer only 'allow' or 'deny'.\n\nCommand: {{command}}"
}`http` — POST to URL
Makes an HTTP POST to an external URL:
{
"type": "http",
"url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${SLACK_TOKEN}"
},
"body": {
"text": "Agent finished: {{TASK_SUBJECT}}"
}
}Environment variables are expanded with ${VAR}. Context template variables are expanded with {{VAR}}.
`agent` — agentic verification
Invokes a sub-agent to verify the operation:
{
"type": "agent",
"prompt": "Check if the edit in {{file_path}} doesn't introduce security vulnerabilities."
}Hook fields
| Field | Type | Description |
|---|---|---|
type |
string | command, prompt, http, agent |
command |
string | Shell command (command only) |
url |
string | Endpoint URL (http only) |
prompt |
string | Model prompt (prompt, agent only) |
headers |
object | HTTP headers (http only) |
body |
object | Request body (http only) |
timeout |
number | Timeout in ms (default: 10000) |
statusMessage |
string | Message shown while the hook runs |
once |
bool | Runs only once per session |
async |
bool | Runs in background without blocking the agent |
asyncRewake |
bool | Rewakes the agent when the async hook finishes |
if |
string | Execution condition (permission rule syntax) |
Hook matchers
The matcher field is a pattern that filters which tool the hook fires for:
{
"matcher": "Bash|Edit|Write",
"hooks": [...]
}Supported patterns:
- Exact name:
"Edit" - Alternation:
"Edit|Write|FileWrite" - Wildcard:
"*"(all tools) - Negation with
if:"if": "not tool_name:Bash"
Hook output (decision)
command type hooks can return a JSON to control the agent:
{
"continue": false,
"decision": "block",
"reason": "Operation blocked: destination outside authorized directory",
"stopReason": "Security policy violated"
}| Field | Values | Description |
|---|---|---|
continue |
true/false |
If false, aborts the operation |
decision |
approve, deny, block |
Explicit decision |
reason |
string | Explanation shown to the user |
stopReason |
string | Stop message (when continue: false) |
Practical examples
Format code after edit
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "prettier --write \"{{tool_input.file_path}}\" 2>/dev/null || true",
"async": true
}
]
}
]
}
}Block dangerous rm commands
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'echo $HOOK_INPUT | jq -r .tool_input.command | grep -qE \"rm -rf /\" && echo \\'{ \"continue\": false, \"reason\": \"rm -rf / blocked\" }\\' || echo \\'{ \"continue\": true }\\''",
}
]
}
]
}
}Slack notification on finish
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "https://hooks.slack.com/services/T.../B.../XXX",
"body": {
"text": "Verboo Code finished: {{TASK_SUBJECT}}"
}
}
]
}
]
}
}Bash command audit log
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$(date): $HOOK_INPUT\" >> ~/.verboo-audit.log",
"async": true
}
]
}
]
}
}Hook Chains
Hook Chains are automatic recovery rules triggered by tool or task outcomes.
Configuration
{
"hookChains": {
"version": 1,
"enabled": true,
"maxChainDepth": 2,
"defaultCooldownMs": 30000,
"rules": [
{
"id": "retry-on-bash-fail",
"enabled": true,
"trigger": {
"event": "PostToolUse",
"outcome": "failed"
},
"condition": {
"toolNames": ["Bash"],
"errorIncludes": "ECONNREFUSED"
},
"actions": [
{
"type": "spawn_fallback_agent",
"prompt": "The command failed with ECONNREFUSED. Check if the service is running and try again."
}
]
}
]
}
}Rule fields
| Field | Description |
|---|---|
id |
Unique rule identifier |
enabled |
Enables/disables the rule |
trigger.event |
Event that fires (e.g., PostToolUse, TaskCompleted) |
trigger.outcome |
success, failed, timeout, unknown |
condition.toolNames |
List of tools that activate the rule |
condition.errorIncludes |
Substring in the error |
cooldownMs |
Minimum ms between triggers (default: 30000) |
dedupWindowMs |
Deduplication window (default: 30000) |
maxDepth |
Maximum chain depth (default: 2, max: 10) |
actions |
Array of actions to execute |
Action types
| Type | Description |
|---|---|
spawn_fallback_agent |
Triggers a recovery agent |
notify_team |
Notifies the configured team |
warm_remote_capacity |
Pre-warms remote capacity |
Template variables in actions
| Variable | Value |
|---|---|
{{EVENT_NAME}} |
Event name |
{{OUTCOME}} |
Event outcome |
{{RULE_ID}} |
Rule ID |
{{TASK_SUBJECT}} |
Task subject |
{{ERROR}} |
Error message |
{{PAYLOAD_JSON}} |
Full event JSON |
Hook Chains are disabled by default. Enable gradually per environment after validating behavior.