Follow Discord
Sweep 06 Nov 2026 · 01:32Z Build v2.1.319 537 read Stable v2.1.311 Latest v2.1.318 Next v2.1.319 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Hooks reference changedhooks

Nearest release: v2.1.319, published 3 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 6 Nov 2026 04:20 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 6 Nov 2026 04:37 UTC.

Upstream edited
Recorded here
Lines+25added
Lines−7removed
From line 66 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits129to this page, all time

#### Match Monitor commands #### PreCompact output

The whole hunk

from line 66, old and new numbered
/
lines

This page is larger than the 256 KiB this site keeps, so one side of the diff below stops where the stored text does.

from line 66
6666 
6767> [tab] macOS/Linux
6868>
69> The `matcher` narrows to Bash tool calls and the `if` condition narrows further to Bash subcommands matching `rm *`, so `block-rm.sh` only spawns when both filters match:
69> The `matcher` narrows to Bash tool calls and [Monitor commands](#match-monitor-commands), and the `if` condition narrows further to Bash subcommands matching `rm *`, so `block-rm.sh` only spawns when both filters match:
7070>
7171> ```json theme={null}
7272> {
from line 112
112112 
113113> [tab] Windows (PowerShell)
114114>
115> The matcher `Bash|PowerShell` covers the [PowerShell tool](#powershell) as well as Bash. A single `if` rule matches only one tool's calls, so each tool gets its own handler: the first narrows to Bash subcommands matching `rm *`, the second to PowerShell commands matching `Remove-Item *`. Both run the same script through `powershell.exe`:
115> The matcher `Bash|PowerShell` covers the [PowerShell tool](#powershell) as well as Bash. A single `if` rule names one tool, so each tool gets its own handler: the first narrows to Bash subcommands matching `rm *`, the second to PowerShell commands matching `Remove-Item *`. Both run the same script through `powershell.exe`:
116116>
117117> ```json theme={null}
118118> {
from line 221
221221Hooks are defined in JSON settings files. The configuration has three levels of nesting:
222222 
2232231. Choose a [hook event](#hook-events) to respond to, like `PreToolUse` or `Stop`
2242. Add a [matcher group](#matcher-patterns) to filter when it fires, like "only for the Bash tool"
2242. Add a [matcher group](#matcher-patterns) to filter when it fires, like "for the Bash tool"
2252253. Define one or more [hook handlers](#hook-handler-fields) to run when matched
226226 
227227See [How a hook resolves](#how-a-hook-resolves) above for a complete walkthrough with an annotated example.
from line 273
273273| Matcher value | Evaluated as | Example |
274274| :- | :- | :- |
275275| `"*"`, `""`, or omitted | Match all | fires on every occurrence of the event |
276| Only letters, digits, `_`, `-`, spaces, `,`, and `\|` | Exact string, or list of exact strings separated by `\|` or `,` with optional surrounding whitespace | `Bash` matches only the Bash tool; `Edit\|Write` and `Edit, Write` each match either tool exactly; `code-reviewer` matches only that agent type |
276| Only letters, digits, `_`, `-`, spaces, `,`, and `\|` | Exact string, or list of exact strings separated by `\|` or `,` with optional surrounding whitespace | `Bash` matches the Bash tool, and on `PreToolUse` and `PermissionRequest` also [Monitor commands](#match-monitor-commands); `Edit\|Write` and `Edit, Write` each match either tool exactly; `code-reviewer` matches only that agent type |
277277| Contains any other character | JavaScript regular expression, unanchored | `^Notebook` matches any tool whose name starts with `Notebook`; `mcp__memory__.*` matches every tool from the `memory` server |
278278 
279279A matcher on the regular-expression path is tested with JavaScript's `RegExp.prototype.test`, which succeeds on a match anywhere in the value. `Edit.*` matches both `Edit` and `NotebookEdit`; wrap the pattern in `^` and `$`, as in `^Edit$`, when you need a whole-string match.
from line 381
381381}
382382```
383383 
384#### Match Monitor commands
385 
386A [`PreToolUse`](#pretooluse) or [`PermissionRequest`](#permissionrequest) hook with a `Bash` matcher also runs on shell commands Claude starts with the [Monitor tool](https://code.claude.com/docs/en/tools-reference.md#monitor-tool), but its `allow` and [`updatedInput`](#pretooluse-decision-control) have no effect on them. Requires Claude Code v2.1.314 or later. Matchers such as `Bash|PowerShell`, `^Bash$`, and `Bash.*` are `Bash` matchers too. A hook with a `Bash` matcher doesn't run for a [WebSocket watch](https://code.claude.com/docs/en/tools-reference.md#websocket-source), and a `PostToolUse` hook with one doesn't run for Monitor.
387 
388A hook that runs for a Monitor command can deny it or have Claude Code ask you about it. To allow or rewrite the command, switch from a `Bash` matcher to one that includes Monitor:
389 
390* **Matcher that includes Monitor**: with a matcher such as `Bash|Monitor` or `.*`, or with no matcher, the hook gets the Monitor call's own input, and `allow` and `updatedInput` apply. In [`if`](#common-fields), name Monitor, as in `Monitor(tail *)`, which matches by [the rules `Bash(tail *)` follows](#bash-if-matching). If its `if` names Bash, the hook still gets the Monitor call's input, but `allow` and `updatedInput` have no effect
391* **`Bash` matcher**: the hook gets a Bash call. In `if`, name Bash, as in `Bash(tail *)`. The hook doesn't run if its `if` names Monitor
392 
384393### Hook handler fields
385394 
386395Each object in the inner `hooks` array is a hook handler: the shell command, HTTP endpoint, MCP tool, LLM prompt, or agent that runs when the matcher matches. There are five types:
from line 816
807816* **Two or more lines that each parse as JSON on their own, the first starting with `{` and the last ending with `}`**: plain text when no line is a JSON output object that sets a field. When one line is, the output is a parse failure, so print that object with nothing else on stdout.
808817* **Anything else that starts with `{` and ends with `}` but isn't valid JSON**: a parse failure.
809818 
810For most events, Claude Code writes stdout to the debug log and doesn't show it in the transcript. The exceptions are `UserPromptSubmit`, `UserPromptExpansion`, `SessionStart`, and `PostModelSwitch`, where Claude Code adds plain-text stdout as context that Claude can see and act on. On those events, Claude Code doesn't add stdout it failed to parse.
819For most events, Claude Code writes stdout to the debug log and doesn't show it in the transcript. On these events, your stdout reaches Claude or the compaction summary:
811820 
821* **`UserPromptSubmit`, `UserPromptExpansion`, `SessionStart`, and `PostModelSwitch`**: Claude Code adds plain-text stdout as context that Claude can see and act on. It doesn't add stdout it failed to parse.
822* **`PreCompact`**: your stdout becomes [instructions for the compaction summary](#precompact-output)
823 
812824Claude never sees stderr from a hook that exits 0. To read it yourself on events such as `PreToolUse`, enable [debug logging](#debug-hooks). To surface a warning to Claude from a `PostToolUse` or `PostToolUseFailure` hook, exit 2 instead so [Claude sees the stderr](#exit-code-2-behavior-per-event) even though the tool already ran.
813825 
814826#### Exit code 2
from line 1058
10461058A hook's `additionalContext`, `systemMessage`, and `initialUserMessage` strings, and its plain stdout, are capped at 10,000 characters:
10471059 
10481060* **Scope**: Claude Code measures each string on its own, even when several hooks run for the same event. For JSON output, each field is measured separately; plain stdout is measured whole.
1049* **Over the limit**: Claude Code saves the output to a file in the session directory and replaces it with the file path and a preview of up to the first 2,000 characters. A large valid Bash result is handled the same way, described under [Output limits](https://code.claude.com/docs/en/tools-reference.md#output-limits). Unlike that Bash ceiling, this cap has no setting or environment variable to raise it.
1061* **Over the limit**: except for [PreCompact stdout](#precompact-output), Claude Code saves the output to a file in the session directory. It replaces the output with the file path and a preview of up to the first 2,000 characters. A large valid Bash result is handled the same way, described under [Output limits](https://code.claude.com/docs/en/tools-reference.md#output-limits). Unlike that Bash ceiling, this cap has no setting or environment variable to raise it.
10501062* **Reading the file**: Claude Code doesn't ask Claude to read the file, so keep anything Claude must always see within the cap.
10511063 
10521064The JSON object supports three kinds of fields:
from line 1962
19501962 
19511963#### PreToolUse decision control
19521964 
1953`PreToolUse` hooks can control whether a tool call proceeds. Unlike other hooks that use a top-level `decision` field, PreToolUse returns its decision inside a `hookSpecificOutput` object. This gives it richer control: four outcomes (allow, deny, ask, or defer) plus the ability to modify tool input before execution.
1965`PreToolUse` hooks can control whether a tool call proceeds. Unlike other hooks that use a top-level `decision` field, PreToolUse returns its decision inside a `hookSpecificOutput` object. This gives it richer control: four outcomes (allow, deny, ask, or defer) plus the ability to modify tool input before execution. To allow or rewrite a Monitor command, see [Match Monitor commands](#match-monitor-commands).
19541966 
19551967| Field | Description |
19561968| :- | :- |
from line 2156
21442156| `message` | For `"deny"` only: tells Claude why the permission was denied |
21452157| `interrupt` | For `"deny"` only: if `true`, stops Claude |
21462158 
2159To allow or rewrite a Monitor command, see [Match Monitor commands](#match-monitor-commands).
2160 
21472161A hook that exits 2 without a `decision` object leaves the permission flow unchanged, and its stderr is discarded. To grant or deny the request, return the `decision` object.
21482162 
21492163```json theme={null}
from line 3337
33233337}
33243338```
33253339 
3340#### PreCompact output
3341 
3342When a PreCompact hook exits 0 and doesn't block, Claude Code uses its stdout as instructions for the compaction summary. Keep that stdout under 10,000 characters per hook. Claude Code cuts longer output at the cap and appends a marker.
3343 
33263344### PostCompact
33273345 
33283346Runs after Claude Code completes a compact operation. Use this event to react to the new compacted state, for example to log the generated summary or update external state. Claude Code discards a PostCompact hook's `systemMessage` and `continue` fields.
from line 3758
37403758> ]
37413759> }
37423760> }
3743> ```
3744>
3745> Save this script to `.claude/hooks/answer-project-key.sh` in your project and make it executable with `chmod +x`:
3746>
3747> ```bash theme={null}
3748> #!/bin/bash
3749> input=$(cat)
3750> fields=$(jq -c '.requested_schema.properties // {} | keys' <<<"$input")
3751>
3752> if [ "$fields" = '["project_key"]' ]; then
3753> jq -n '{hookSpecificOutput: {hookEventName: "Elicitation", action: "accept", content: {project_key: "DOCS"}}}'
3754> fi
3755> ```
3756 
3757> [tab] Windows (PowerShell)
3758>
3759> Register a command hook that runs the script through PowerShell, with the server name as the matcher:
3760>
3761> ```json theme={null}
3762> {
3763> "hooks": {
3764> "Elicitation": [
3765> {
3766> "matcher": "issue-tracker",
3767> "hooks": [
3768> {
3769> "type": "command",
3770> "command": "powershell.exe",
3771> "args": [
3772> "-NoProfile",
3773> "-ExecutionPolicy",
3774> "Bypass",
3775> "-File",
3776> "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.ps1"
3777> ]
3778> }
3779> ]
3780> }
3781> ]
3782> }
3783> }
3784> ```
3785>
3786> Save this script to `.claude/hooks/answer-project-key.ps1` in your project:
3787>
3788> ```powershell theme={null}
3789> $request = [Console]::In.ReadToEnd() | ConvertFrom-Json
3790> $fields = @($request.requested_schema.properties.PSObject.Properties.Name)
3791>
3792> if ($fields.Count -eq 1 -and $fields[0] -eq 'project_key') {
3793> @{
3794> hookSpecificOutput = @{
3795> hookEventName = "Elicitation"
3796> action = "accept"
3797> content = @{ project_key = "DOCS" }
3798> }
3799> } | ConvertTo-Json -Depth 3
3800> }
3801> ```
3802 
3803To confirm the hook works, start Claude Code with `claude --debug` and give Claude a task that makes the server ask for the project key. No dialog appears, and the [debug log](#debug-hooks) has a line that ends with `Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}`.
3804 
3805### ElicitationResult
3806 
3807Runs after a user responds to an MCP elicitation. Hooks can observe, modify, or block the response before it is sent back to the MCP server.
3808 
3809When an [Elicitation](#elicitation) hook answers a request, Claude Code sends that answer to the server without running ElicitationResu
Feedback