Hooks allow you to execute custom commands at specific points during agent lifecycle and tool execution. This enables security validation, logging, formatting, context gathering, and other custom behaviors.
Hooks are defined in the agent configuration file. See the Agent Configuration Reference for the complete syntax and examples.
Hooks receive hook event in JSON format via STDIN:
{ "hook_event_name": "agentSpawn", "cwd": "/current/working/directory", "session_id": "abc123-def456-789" }
For tool-related hooks, additional fields are included:
session_id: The current session UUID (available in all hook events)tool_name: Name of the tool being executedtool_input: Tool-specific parameters (see individual tool documentation)tool_response: Tool execution results (PostToolUse only)Use the matcher field to specify which tools the hook applies to. You can use either canonical tool names or their aliases.
"fs_write" or "write" - Match write tool"fs_read" or "read" - Match read tool"execute_bash" or "shell" - Match shell command execution"use_aws" or "aws" - Match AWS CLI tool"@git" - All tools from git MCP server"@git/status" - Specific tool from git MCP server"*" - All tools (built-in and MCP)"@builtin" - All built-in tools onlyFor complete tool reference format, see Agent Configuration Reference.
Runs when agent is activated. No tool context provided.
Hook Event
{ "hook_event_name": "agentSpawn", "cwd": "/current/working/directory", "session_id": "abc123-def456-789" }
Exit Code Behavior:
Runs when user submits a prompt. Output is added to conversation context.
Hook Event
{ "hook_event_name": "userPromptSubmit", "cwd": "/current/working/directory", "session_id": "abc123-def456-789", "prompt": "user's input prompt" }
Exit Code Behavior:
Runs before tool execution. Can validate and block tool usage.
Hook Event
{ "hook_event_name": "preToolUse", "cwd": "/current/working/directory", "session_id": "abc123-def456-789", "tool_name": "read", "tool_input": { "operations": [ { "mode": "Line", "path": "/current/working/directory/docs/hooks.md" } ] } }
Exit Code Behavior:
Runs after tool execution with access to tool results.
Hook Event
{ "hook_event_name": "postToolUse", "cwd": "/current/working/directory", "session_id": "abc123-def456-789", "tool_name": "read", "tool_input": { "operations": [ { "mode": "Line", "path": "/current/working/directory/docs/hooks.md" } ] }, "tool_response": { "success": true, "result": ["# Hooks\n\nHooks allow you to execute..."] } }
Exit Code Behavior:
Runs when the assistant finishes responding to the user (at the end of each turn). This is useful for running post-processing tasks like code compilation, testing, formatting, or cleanup after the assistant's response.
Hook Event
{ "hook_event_name": "stop", "cwd": "/current/working/directory", "session_id": "conversation-uuid", "assistant_response": "The assistant's last response text..." }
session_id: The current conversation/session identifier.assistant_response: The text content of the assistant's last response. Use this to inspect what the agent said without needing to parse a transcript.Exit Code Behavior:
Block Decision: A stop hook can prevent the agent from stopping by returning JSON on STDOUT:
{"decision": "block", "reason": "You haven't run the tests yet."}
When a stop hook returns decision: "block", the reason is sent as a new user message to the LLM, continuing the conversation. This enables a feedback loop where a script can evaluate the agent's work and nudge it to keep going — for example, checking if tests pass, verifying lint rules, or confirming that required files were updated before allowing the agent to stop.
If no block decision is returned (no output, non-JSON output, or JSON without "decision": "block"), the agent stops normally. This is fully backward compatible.
Note: Stop hooks do not use matchers since they don't relate to specific tools.
For MCP tools, the tool name includes the full namespaced format including the MCP Server name:
Hook Event
{ "hook_event_name": "preToolUse", "cwd": "/current/working/directory", "session_id": "abc123-def456-789", "tool_name": "@postgres/query", "tool_input": { "sql": "SELECT * FROM orders LIMIT 10;" } }
Default timeout is 30 seconds (30,000ms). Configure with timeout_ms field.
Successful hook results are cached based on cache_ttl_seconds:
0: No caching (default)> 0: Cache successful results for specified seconds
Hooks