hooks.md +235 −6
43 * Supports regex: `Edit|Write` or `Notebook.*`43 * Supports regex: `Edit|Write` or `Notebook.*`
44 * Use `*` to match all tools. You can also use empty string (`""`) or leave44 * Use `*` to match all tools. You can also use empty string (`""`) or leave
45 `matcher` blank.45 `matcher` blank.
4646* **hooks**: Array of commands to execute when the pattern matches* **hooks**: Array of hooks to execute when the pattern matches
4747 * `type`: Currently only `"command"` is supported * `type`: Hook execution type - `"command"` for bash commands or `"prompt"` for LLM-based evaluation
4848 * `command`: The bash command to execute (can use `$CLAUDE_PROJECT_DIR` * `command`: (For `type: "command"`) The bash command to execute (can use `$CLAUDE_PROJECT_DIR` environment variable)
4949 environment variable) * `prompt`: (For `type: "prompt"`) The prompt to send to the LLM for evaluation
5050 * `timeout`: (Optional) How long a command should run, in seconds, before * `timeout`: (Optional) How long a hook should run, in seconds, before canceling that specific hook
51 canceling that specific command.
52 51
53For events like `UserPromptSubmit`, `Notification`, `Stop`, and `SubagentStop`52For events like `UserPromptSubmit`, `Notification`, `Stop`, and `SubagentStop`
54that don't use matchers, you can omit the matcher field:53that don't use matchers, you can omit the matcher field:
143 142
144See the [plugin components reference](/en/docs/claude-code/plugins-reference#hooks) for details on creating plugin hooks.143See the [plugin components reference](/en/docs/claude-code/plugins-reference#hooks) for details on creating plugin hooks.
145 144
145## Prompt-Based Hooks
146
147In addition to bash command hooks (`type: "command"`), Claude Code supports prompt-based hooks (`type: "prompt"`) that use an LLM to evaluate whether to allow or block an action. Prompt-based hooks are currently only supported for `Stop` and `SubagentStop` hooks, where they enable intelligent, context-aware decisions.
148
149### How prompt-based hooks work
150
151Instead of executing a bash command, prompt-based hooks:
152
1531. Send the hook input and your prompt to a fast LLM (Haiku)
1542. The LLM responds with structured JSON containing a decision
1553. Claude Code processes the decision automatically
156
157### Configuration
158
159```json theme={null}
160{
161 "hooks": {
162 "Stop": [
163 {
164 "hooks": [
165 {
166 "type": "prompt",
167 "prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
168 }
169 ]
170 }
171 ]
172 }
173}
174```
175
176**Fields:**
177
178* `type`: Must be `"prompt"`
179* `prompt`: The prompt text to send to the LLM
180 * Use `$ARGUMENTS` as a placeholder for the hook input JSON
181 * If `$ARGUMENTS` is not present, input JSON is appended to the prompt
182* `timeout`: (Optional) Timeout in seconds (default: 30 seconds)
183
184### Response schema
185
186The LLM must respond with JSON containing:
187
188```json theme={null}
189{
190 "decision": "approve" | "block",
191 "reason": "Explanation for the decision",
192 "continue": false, // Optional: stops Claude entirely
193 "stopReason": "Message shown to user", // Optional: custom stop message
194 "systemMessage": "Warning or context" // Optional: shown to user
195}
196```
197
198**Response fields:**
199
200* `decision`: `"approve"` allows the action, `"block"` prevents it
201* `reason`: Explanation shown to Claude when decision is `"block"`
202* `continue`: (Optional) If `false`, stops Claude's execution entirely
203* `stopReason`: (Optional) Message shown when `continue` is false
204* `systemMessage`: (Optional) Additional message shown to the user
205
206### Supported hook events
207
208Prompt-based hooks work with any hook event, but are most useful for:
209
210* **Stop**: Intelligently decide if Claude should continue working
211* **SubagentStop**: Evaluate if a subagent has completed its task
212* **UserPromptSubmit**: Validate user prompts with LLM assistance
213* **PreToolUse**: Make context-aware permission decisions
214
215### Example: Intelligent Stop hook
216
217```json theme={null}
218{
219 "hooks": {
220 "Stop": [
221 {
222 "hooks": [
223 {
224 "type": "prompt",
225 "prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"decision\": \"approve\" or \"block\", \"reason\": \"your explanation\"}",
226 "timeout": 30
227 }
228 ]
229 }
230 ]
231 }
232}
233```
234
235### Example: SubagentStop with custom logic
236
237```json theme={null}
238{
239 "hooks": {
240 "SubagentStop": [
241 {
242 "hooks": [
243 {
244 "type": "prompt",
245 "prompt": "Evaluate if this subagent should stop. Input: $ARGUMENTS\n\nCheck if:\n- The subagent completed its assigned task\n- Any errors occurred that need fixing\n- Additional context gathering is needed\n\nReturn: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
246 }
247 ]
248 }
249 ]
250 }
251}
252```
253
254### Comparison with bash command hooks
255
256| Feature | Bash Command Hooks | Prompt-Based Hooks |
257| --------------------- | ----------------------- | ------------------------------ |
258| **Execution** | Runs bash script | Queries LLM |
259| **Decision logic** | You implement in code | LLM evaluates context |
260| **Setup complexity** | Requires script file | Just configure prompt |
261| **Context awareness** | Limited to script logic | Natural language understanding |
262| **Performance** | Fast (local execution) | Slower (API call) |
263| **Use case** | Deterministic rules | Context-aware decisions |
264
265### Best practices
266
267* **Be specific in prompts**: Clearly state what you want the LLM to evaluate
268* **Include decision criteria**: List the factors the LLM should consider
269* **Test your prompts**: Verify the LLM makes correct decisions for your use cases
270* **Set appropriate timeouts**: Default is 30 seconds, adjust if needed
271* **Use for complex decisions**: Bash hooks are better for simple, deterministic rules
272
273See the [plugin components reference](/en/docs/claude-code/plugins-reference#hooks) for details on creating plugin hooks.
274
146## Hook Events275## Hook Events
147 276
148### PreToolUse277### PreToolUse
166 295
167Recognizes the same matcher values as PreToolUse.296Recognizes the same matcher values as PreToolUse.
168 297
298### PostCustomToolCall
299
300Runs after an MCP tool completes but **before** `PostToolUse` hooks execute. This hook allows you to modify the tool's output before it's processed further or shown to the model.
301
302**Key characteristics:**
303
304* **Only runs for MCP tools** (tools starting with `mcp__`)
305* Executes after the tool completes but before `PostToolUse` hooks
306* Can modify tool output using the `updatedOutput` field
307* Original tool response is replaced with modified output
308
309**Common use cases:**
310
311* Adding metadata to MCP tool responses
312* Filtering sensitive information from tool outputs
313* Transforming response formats
314* Logging MCP tool usage with enriched data
315
316**Important**: If multiple hooks provide `updatedOutput` for the same tool call, they may conflict. Hook execution order is non-deterministic when hooks run in parallel. Only configure one hook per tool to modify output.
317
318**Matchers:**
319Recognizes the same matcher values as PreToolUse, but will only execute for MCP tools (`mcp__*`).
320
169### Notification321### Notification
170 322
171Runs when Claude Code sends notifications. Notifications are sent when:323Runs when Claude Code sends notifications. Notifications are sent when:
330}482}
331```483```
332 484
485### PostCustomToolCall Input
486
487The exact schema for `tool_input` and `tool_response` depends on the MCP tool.
488
489```json theme={null}
490{
491 "session_id": "abc123",
492 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
493 "cwd": "/Users/...",
494 "permission_mode": "default",
495 "hook_event_name": "PostCustomToolCall",
496 "tool_name": "mcp__github__create_issue",
497 "tool_input": {
498 "title": "Bug report",
499 "body": "Description of the issue"
500 },
501 "tool_response": {
502 "issue_number": 42,
503 "url": "https://github.com/org/repo/issues/42"
504 }
505}
506```
507
333### Notification Input508### Notification Input
334 509
335```json theme={null}510```json theme={null}
538}713}
539```714```
540 715
716#### `PostCustomToolCall` Output Control
717
718`PostCustomToolCall` hooks can modify MCP tool outputs before they're processed further.
719
720* `"hookSpecificOutput.updatedOutput"` replaces the original tool response
721* The modified output is shown to Claude instead of the original response
722* This runs **before** `PostToolUse` hooks, so they see the modified output
723
724```json theme={null}
725{
726 "hookSpecificOutput": {
727 "hookEventName": "PostCustomToolCall",
728 "updatedOutput": {
729 "issue_number": 42,
730 "url": "https://github.com/org/repo/issues/42",
731 "hook_processed": true,
732 "processed_at": "2025-01-01T00:00:00Z"
733 }
734 }
735}
736```
737
738**Example: Adding metadata to MCP tool responses**
739
740```bash theme={null}
741#!/bin/bash
742# Read JSON input from stdin
743INPUT=$(cat)
744
745# Extract tool information
746TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
747TOOL_RESPONSE=$(echo "$INPUT" | jq -r '.tool_response')
748
749# Only process MCP tools
750if [[ "$TOOL_NAME" != mcp__* ]]; then
751 exit 0
752fi
753
754# Add metadata to the response
755UPDATED_OUTPUT=$(echo "$TOOL_RESPONSE" | jq '. + {"hook_processed": true, "processed_at": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}')
756
757# Output the modified response
758jq -n --argjson output "$UPDATED_OUTPUT" '{
759 "hookSpecificOutput": {
760 "hookEventName": "PostCustomToolCall",
761 "updatedOutput": $output
762 }
763}'
764```
765
766<Warning>
767 If multiple hooks provide `updatedOutput` for the same tool call, conflicts may occur since hooks run in parallel. Only configure one hook per tool to modify output.
768</Warning>
769
541#### `UserPromptSubmit` Decision Control770#### `UserPromptSubmit` Decision Control
542 771
543`UserPromptSubmit` hooks can control whether a user prompt is processed.772`UserPromptSubmit` hooks can control whether a user prompt is processed.