Hooks reference changedhooks
Nearest release: v2.1.238, published 10 hours before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+39added
Lines−7removed
From line
1,927
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits112to this page, all time
#### Annotate a result for the auto mode classifier
The whole hunk
from line 1927, old and new numbered
/
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 1927
19271927
19281928`PostToolUse` hooks can provide feedback to Claude after tool execution. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:
19291929
1930| Field | Description |
1931| :--------------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
1932| `decision` | `"block"` adds the `reason` next to the tool result. Claude still sees the original output; to replace it, use `updatedToolOutput` |
1933| `reason` | Explanation shown to Claude when `decision` is `"block"` |
1934| `additionalContext` | String added to Claude's context alongside the tool result. See [Add context for Claude](#add-context-for-claude) |
1935| `updatedToolOutput` | Replaces the tool's output with the provided value before it is sent to Claude. The value must match the tool's output shape |
1936| `updatedMCPToolOutput` | Replaces the output for [MCP tools](#match-mcp-tools) only. Prefer `updatedToolOutput`, which works for all tools |
1930| Field | Description |
1931| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1932| `decision` | `"block"` adds the `reason` next to the tool result. Claude still sees the original output; to replace it, use `updatedToolOutput` |
1933| `reason` | Explanation shown to Claude when `decision` is `"block"` |
1934| `additionalContext` | String added to Claude's context alongside the tool result. See [Add context for Claude](#add-context-for-claude) |
1935| `classifierContext` | Short note about this call's result for the [auto mode](/docs/en/permission-modes#eliminate-prompts-with-auto-mode) classifier rather than for Claude. See [Annotate a result for the auto mode classifier](#annotate-a-result-for-the-auto-mode-classifier). Requires Claude Code v2.1.236 or later |
1936| `updatedToolOutput` | Replaces the tool's output with the provided value before it is sent to Claude. The value must match the tool's output shape |
1937| `updatedMCPToolOutput` | Replaces the output for [MCP tools](#match-mcp-tools) only. Prefer `updatedToolOutput`, which works for all tools |
19371938
19381939The example below replaces the output of a `Bash` call. The replacement value matches the `Bash` tool's output shape:
19391940
from line 1959
19581959 The replacement value must match the tool's output shape. Built-in tools return structured objects rather than plain strings. For example, `Bash` returns an object with `stdout`, `stderr`, `interrupted`, and `isImage` fields. For built-in tools, a value that doesn't match the tool's output schema is ignored and the original output is used. MCP tool output is passed through without schema validation. Stripping error details that Claude needs can cause it to proceed on a false assumption.
19591960</Warning>
19601961
1962#### Annotate a result for the auto mode classifier
1963
1964Return `classifierContext` to send a short note about the tool call's result to the [auto mode](/docs/en/permission-modes#eliminate-prompts-with-auto-mode) classifier rather than to Claude. The classifier [never receives tool results themselves](/docs/en/permission-modes#how-the-classifier-evaluates-actions), so this field is the supported way to tell it something about what a call returned before it reviews later actions. The field requires Claude Code v2.1.236 or later.
1965
1966The example below tells the classifier where a query's output came from:
1967
1968```json theme={null}
1969{
1970 "hookSpecificOutput": {
1971 "hookEventName": "PostToolUse",
1972 "classifierContext": "This query ran against the staging database, not production."
1973 }
1974}
1975```
1976
1977How much weight the classifier gives the note depends on where you configured the hook:
1978
1979* **Hooks configured in Claude Code**: for hooks from settings files, plugins, skills, and agent frontmatter, the classifier treats the note as unverified, application-provided context. The note never establishes user intent, and if it claims you approved or requested something, the classifier checks that claim against your own messages in the conversation
1980* **In-process Agent SDK callbacks**: when an application embedding Claude Code registers the hook as a [TypeScript SDK callback](/docs/en/agent-sdk/hooks) and returns the note during the live session, the classifier may weigh a user statement relayed in the note as user intent. Such a statement can satisfy a consent requirement the classifier would accept from a message you send, but it never lifts a block that your own message couldn't lift either. After a session resumes, Claude Code treats restored notes as unverified context. When hooks from both groups annotate the same call, the classifier treats the combined note as unverified
1981
1982Claude Code applies these limits when delivering the note:
1983
1984* **Length**: Claude Code caps the notes for one tool call at 2,000 characters and truncates the rest. The cap is shared across every hook that responds to that call
1985* **Synchronous responses only**: Claude Code ignores the field in the response of a hook that [runs in the background](#run-hooks-in-the-background), because that response arrives after Claude Code records the tool result
1986* **Calls that the classifier doesn't record**: the classifier's transcript omits read-only lookups such as file reads and searches. Claude Code discards a note attached to one of those calls
1987* **Interaction with rewrites**: when the note describes output you're replacing with `updatedToolOutput`, return both fields in the same hook response. Claude Code drops the note if that rewrite is rejected or another hook's rewrite replaces it. Claude Code delivers a note you return without a rewrite even when another hook rewrites the output
1988
1989<Warning>
1990 The classifier reads content you place in `classifierContext` as information from the application hosting the session, so don't copy untrusted tool output or third-party text into it. Keep the note to a short assertion about this one call, such as a fact about its origin or a user statement about it; don't use the field to deliver unrelated messages or a stream of events.
1991</Warning>
1992
19611993### PostToolUseFailure
19621994
19631995Runs when a tool that started executing fails: the tool threw an error, or an MCP tool returned an error result. Use this to log failures, send alerts, or provide corrective feedback to Claude.
from line 3181
31493181* `PostCompact`
31503182* `PreCompact`
31513183* `SessionEnd`
3152* `StopFailure`
3153* `SubagentStart`
3154* `WorktreeCreate`
3155* `WorktreeRemove`
3156
3157`SessionStart` and `Setup` support `command` and `mcp_tool` hooks. They don't support `http`, `prompt`, or `agent` hooks.
3158
3159### How prompt-based hooks work
3160
3161Instead of executing a Bash command, prompt-based hooks:
3162
31631. Send the hook input and your prompt to a Claude model, Haiku by default
31642. The LLM responds with structured JSON containing a decision
31653. Claude Code processes the decision automatically
3166
3167### Prompt hook configuration
3168
3169Set `type` to `"prompt"` and provide a `prompt` string instead of a `command`. Use the `$ARGUMENTS` placeholder to inject the hook's JSON input data into your prompt text.
3170
3171This `Stop` hook asks the LLM to evaluate whether all tasks are complete before allowing Claude to finish:
3172
3173```json theme={null}
3174{
3175 "hooks": {
3176 "Stop": [
3177 {
3178 "hooks": [
3179 {
3180 "type": "prompt",
3181 "prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
3182 }
3183 ]
3184 }
3185 ]
3186 }
3187}
3188```
3189
3190| Field | Required | Description |
3191| :---------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3192| `type` | yes | Must be `"prompt"` |
3193| `prompt` | yes | The prompt text to send to the LLM. Use `$ARGUMENTS` as a placeholder for the hook input JSON. If `$ARGUMENTS` is not present, input JSON is appended to the prompt |
3194| `model` | no | Model to use for evaluation. Defaults to a fast model |
3195| `timeout` | no | Timeout in seconds. Default: 30 |
3196| `continueOnBlock` | no | On the events it applies to, `true` feeds an `ok: false` reason back to Claude and continues instead of ending the turn. Default: `false`. See [Response schema](#response-schema) for per-event behavior |
3197
3198### Response schema
3199
3200The LLM must respond with JSON containing:
3201
3202```json theme={null}
3203{
3204 "ok": true | false,
3205 "reason": "Explanation for the decision",
3206 "impossible": true | false
3207}
3208```
3209
3210| Field | Description |
3211| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3212| `ok` | `true` to allow. For `false`, see the per-event behavior below |
3213| `reason` | Required when `ok` is `false` |
3214| `impossible` | Optional. The model returns it with `ok: false` when it judges the condition can never be satisfied. On `Stop` and `SubagentStop`, Claude Code then lets the turn end instead of feeding the reason back. Agent hooks and other events ignore it |
3215
3216What happens on `ok: false` depends on the event:
3217
3218* `Stop` and `SubagentStop`: the reason is fed back to Claude as its next instruction and the turn continues, unless the response also sets `impossible: true`, in which case Claude Code allows the stop and the turn ends
3219* `PreToolUse`: the tool call is denied; by default the turn ends and the deny reason appears in the chat as a warning line. Set `continueOnBlock: true` to instead return the reason to Claude as the tool error so it can adjus
3184* `StopFailure
No line in this hunk matches that.