Configuration
Hooks are configured in JSON files at two levels:
Both files are merged additively. Identical handlers (same event, matcher, and command) are deduplicated.
Config format
hooks wrapper is optional — you can place event keys at the root.
Each event key maps to an array of rule objects. A rule has:
matcher— which tool or trigger to match (see Matchers)hooks— an array of handler objects, each with:type— always"command"command— the shell command to runtimeout— per-handler timeout in seconds (default 60)
Matchers
Matchers follow Claude Code semantics:Events
Execution protocol
Each matching handler runs through the shell withcwd set to the project path. A JSON payload is passed on stdin containing:
session_id— the current session IDcwd— the project pathhook_event_name— the event name
tool_name, tool_input, tool_response, prompt, trigger, agent_type, and goal.
The following environment variables are set:
Exit codes
Timeouts are also treated as non-blocking failures.
Decision output
On exit code0, stdout may contain a JSON object:
- Block a tool call (PreToolUse):
{"decision": "block", "reason": "..."} - Deny with reason (PreToolUse):
{"hookSpecificOutput": {"permissionDecision": "deny", "permissionDecisionReason": "..."}} - Append feedback (PostToolUse):
{"additionalContext": "..."}
Scope
Hooks apply across all agent contexts:- Main agent tool calls
- Sub-agent tool calls (with
agent_typein the payload) - GUI tool calls
- ACP tool calls
UserPromptSubmit only gates user-typed prompts — goal continuations and internal session messages are not intercepted.
Hook engine failures never propagate into the agent loop.
Plugins can also contribute hooks. They are approved explicitly at install time and merge alongside your global and project hooks.