Skip to content

Commit ebb0580

Browse files
committed
🤖 Update Claude Hooks documentation - 2025-11-24
1 parent 86864a9 commit ebb0580

File tree

1 file changed

+50
-23
lines changed

1 file changed

+50
-23
lines changed

‎docs/external/claude-hooks-reference.md‎

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Ask AI
123123
```
124124

125125
- **matcher**: Pattern to match tool names, case-sensitive (only applicable for
126-
`PreToolUse` and `PostToolUse`)
126+
`PreToolUse`, `PermissionRequest`, and `PostToolUse`)
127127

128128
- Simple strings match exactly: `Write` matches only the Write tool
129129
- Supports regex: `Edit|Write` or `Notebook.*`
@@ -313,6 +313,7 @@ Prompt-based hooks work with any hook event, but are most useful for:
313313
- **SubagentStop**: Evaluate if a subagent has completed its task
314314
- **UserPromptSubmit**: Validate user prompts with LLM assistance
315315
- **PreToolUse**: Make context-aware permission decisions
316+
- **PermissionRequest**: Intelligently allow or deny permission dialogs
316317

317318
### [​](https://code.claude.com/docs/en/hooks\#example:-intelligent-stop-hook) Example: Intelligent Stop hook
318319

@@ -582,7 +583,8 @@ Ask AI
582583
"tool_input": {
583584
"file_path": "/path/to/file.txt",
584585
"content": "file content"
585-
}
586+
},
587+
"tool_use_id": "toolu_01ABC123..."
586588
}
587589
```
588590

@@ -609,7 +611,8 @@ Ask AI
609611
"tool_response": {
610612
"filePath": "/path/to/file.txt",
611613
"success": true
612-
}
614+
},
615+
"tool_use_id": "toolu_01ABC123..."
613616
}
614617
```
615618

@@ -723,21 +726,24 @@ Ask AI
723726

724727
## [​](https://code.claude.com/docs/en/hooks\#hook-output) Hook Output
725728

726-
There are two ways for hooks to return output back to Claude Code. The output
729+
There are two mutually-exclusive ways for hooks to return output back to Claude Code. The output
727730
communicates whether to block and any feedback that should be shown to Claude
728731
and the user.
729732

730733
### [​](https://code.claude.com/docs/en/hooks\#simple:-exit-code) Simple: Exit Code
731734

732735
Hooks communicate status through exit codes, stdout, and stderr:
733736

734-
- **Exit code 0**: Success. `stdout` is shown to the user in transcript mode
735-
(CTRL-R), except for `UserPromptSubmit` and `SessionStart`, where stdout is
736-
added to the context.
737-
- **Exit code 2**: Blocking error. `stderr` is fed back to Claude to process
738-
automatically. See per-hook-event behavior below.
739-
- **Other exit codes**: Non-blocking error. `stderr` is shown to the user and
740-
execution continues.
737+
- **Exit code 0**: Success. `stdout` is shown to the user in verbose mode
738+
(ctrl+o), except for `UserPromptSubmit` and `SessionStart`, where stdout is
739+
added to the context. JSON output in `stdout` is parsed for structured control
740+
(see [Advanced: JSON Output](https://code.claude.com/docs/en/hooks#advanced-json-output)).
741+
- **Exit code 2**: Blocking error. Only `stderr` is used as the error message
742+
and fed back to Claude. The format is `[command]: {stderr}`. JSON in `stdout`
743+
is **not** processed for exit code 2. See per-hook-event behavior below.
744+
- **Other exit codes**: Non-blocking error. `stderr` is shown to the user in verbose mode (ctrl+o) with
745+
format `Failed with non-blocking status code: {stderr}`. If `stderr` is empty,
746+
it shows `No stderr output`. Execution continues.
741747

742748
Reminder: Claude Code does not see stdout if the exit code is 0, except for
743749
the `UserPromptSubmit` hook where stdout is injected as context.
@@ -747,6 +753,7 @@ the `UserPromptSubmit` hook where stdout is injected as context.
747753
| Hook Event | Behavior |
748754
| --- | --- |
749755
| `PreToolUse` | Blocks the tool call, shows stderr to Claude |
756+
| `PermissionRequest` | Denies the permission, shows stderr to Claude |
750757
| `PostToolUse` | Shows stderr to Claude (tool already ran) |
751758
| `Notification` | N/A, shows stderr to user only |
752759
| `UserPromptSubmit` | Blocks prompt processing, erases prompt, shows stderr to user only |
@@ -758,7 +765,11 @@ the `UserPromptSubmit` hook where stdout is injected as context.
758765

759766
### [​](https://code.claude.com/docs/en/hooks\#advanced:-json-output) Advanced: JSON Output
760767

761-
Hooks can return structured JSON in `stdout` for more sophisticated control:
768+
Hooks can return structured JSON in `stdout` for more sophisticated control.
769+
770+
JSON output is only processed when the hook exits with code 0. If your hook
771+
exits with code 2 (blocking error), `stderr` text is used directly—any JSON in `stdout`
772+
is ignored. For other non-zero exit codes, only `stderr` is shown to the user in verbose mode (ctrl+o).
762773

763774
#### [​](https://code.claude.com/docs/en/hooks\#common-json-fields) Common JSON Fields
764775

@@ -881,13 +892,21 @@ Ask AI
881892

882893
#### [​](https://code.claude.com/docs/en/hooks\#userpromptsubmit-decision-control) `UserPromptSubmit` Decision Control
883894

884-
`UserPromptSubmit` hooks can control whether a user prompt is processed.
895+
`UserPromptSubmit` hooks can control whether a user prompt is processed and add context.**Adding context (exit code 0):**
896+
There are two ways to add context to the conversation:
885897

886-
- `"block"` prevents the prompt from being processed. The submitted prompt is
887-
erased from context. `"reason"` is shown to the user but not added to context.
888-
- `undefined` allows the prompt to proceed normally. `"reason"` is ignored.
889-
- `"hookSpecificOutput.additionalContext"` adds the string to the context if not
890-
blocked.
898+
1. **Plain text stdout** (simpler): Any non-JSON text written to stdout is added
899+
as context. This is the easiest way to inject information.
900+
2. **JSON with `additionalContext`** (structured): Use the JSON format below for
901+
more control. The `additionalContext` field is added as context.
902+
903+
Both methods work with exit code 0. Plain stdout is shown as hook output in
904+
the transcript; `additionalContext` is added more discretely.**Blocking prompts:**
905+
906+
- `"decision": "block"` prevents the prompt from being processed. The submitted
907+
prompt is erased from context. `"reason"` is shown to the user but not added
908+
to context.
909+
- `"decision": undefined` (or omitted) allows the prompt to proceed normally.
891910

892911
Copy
893912

@@ -904,6 +923,10 @@ Ask AI
904923
}
905924
```
906925

926+
The JSON format is not required for simple use cases. To add context, you can
927+
just print plain text to stdout with exit code 0. Use JSON when you need to
928+
block prompts or want more structured control.
929+
907930
#### [​](https://code.claude.com/docs/en/hooks\#stop/subagentstop-decision-control) `Stop`/`SubagentStop` Decision Control
908931

909932
`Stop` and `SubagentStop` hooks can control whether Claude must continue.
@@ -1006,8 +1029,12 @@ if issues:
10061029

10071030
For `UserPromptSubmit` hooks, you can inject context using either method:
10081031

1009-
- Exit code 0 with stdout: Claude sees the context (special case for `UserPromptSubmit`)
1010-
- JSON output: Provides more control over the behavior
1032+
- **Plain text stdout** with exit code 0: Simplest approach—just print text
1033+
- **JSON output** with exit code 0: Use `"decision": "block"` to reject prompts,
1034+
or `additionalContext` for structured context injection
1035+
1036+
Remember: Exit code 2 only uses `stderr` for the error message. To block using
1037+
JSON (with a custom reason), use `"decision": "block"` with exit code 0.
10111038

10121039
Copy
10131040

@@ -1091,7 +1118,7 @@ if tool_name == "Read":
10911118
output = {
10921119
"decision": "approve",
10931120
"reason": "Documentation file auto-approved",
1094-
"suppressOutput": True # Don't show in transcript mode
1121+
"suppressOutput": True # Don't show in verbose mode
10951122
}
10961123
print(json.dumps(output))
10971124
sys.exit(0)
@@ -1209,7 +1236,7 @@ This prevents malicious hook modifications from affecting your current session.
12091236
- **Input**: JSON via stdin
12101237
- **Output**:
12111238

1212-
- PreToolUse/PostToolUse/Stop/SubagentStop: Progress shown in transcript (Ctrl-R)
1239+
- PreToolUse/PermissionRequest/PostToolUse/Stop/SubagentStop: Progress shown in verbose mode (ctrl+o)
12131240
- Notification/SessionEnd: Logged to debug only (`--debug`)
12141241
- UserPromptSubmit/SessionStart: stdout added as context for Claude
12151242

@@ -1262,7 +1289,7 @@ Ask AI
12621289
[DEBUG] Hook command completed with status 0: <Your stdout>
12631290
```
12641291

1265-
Progress messages appear in transcript mode (Ctrl-R) showing:
1292+
Progress messages appear in verbose mode (ctrl+o) showing:
12661293

12671294
- Which hook is running
12681295
- Command being executed

0 commit comments

Comments
 (0)