Intercept and control agent behavior with hooks changedagent-sdk/hooks
Nearest release: v2.1.273, published 5 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 15 Sep 2026 23:29 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 28 Sep 2026 23:37 UTC.
Upstream edited
Recorded here
Lines+44added
Lines−44removed
From line
140
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits13to this page, all time
The whole hunk
from line 140, old and new numbered
/
from line 140
140140
141141The SDK provides hooks for different stages of agent execution. Some hooks are available in both SDKs, while others are TypeScript-only.
142142
143| Hook Event | Python SDK | TypeScript SDK | What triggers it | Example use case |
144| ------------------------------------------------------ | ---------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
145| `PreToolUse` | Yes | Yes | Tool call request (can block or modify) | Block dangerous shell commands |
146| `PostToolUse` | Yes | Yes | Tool execution result | Log all file changes to audit trail |
147| `PostToolUseFailure` | Yes | Yes | Tool execution failure | Handle or log tool errors |
148| `PostToolBatch` | No | Yes | A full batch of tool calls resolves, once per batch before the next model call | Inject conventions once for the whole batch |
149| `UserPromptSubmit` | Yes | Yes | User prompt submission | Inject additional context into prompts |
150| [`UserPromptExpansion`](/docs/en/hooks#userpromptexpansion) | No | Yes | A user-typed command, or an MCP prompt, expands into a prompt before it reaches Claude. Doesn't fire when Claude invokes a skill itself | Block a command from direct invocation or add context when a skill is typed |
151| `MessageDisplay` | No | Yes | An assistant message with text completes, once per message with the full message text | Redact or reformat the displayed text without changing the transcript |
152| `Stop` | Yes | Yes | Agent execution stop | Save session state before exit |
153| `StopFailure` | No | Yes | The turn ends with an API error instead of a normal stop | Log failures or send alerts |
154| `SubagentStart` | Yes | Yes | Subagent initialization | Track parallel task spawning |
155| `SubagentStop` | Yes | Yes | Subagent completion | Aggregate results from parallel tasks |
156| `PreCompact` | Yes | Yes | Conversation compaction request | Archive full transcript before summarizing |
157| `PostCompact` | No | Yes | Conversation compaction completes | Log the generated summary |
158| [`PreModelSwitch`](/docs/en/hooks#premodelswitch) | No | Yes | A requested model switch, before it happens (can block) | Block switching to a specific model |
159| [`PostModelSwitch`](/docs/en/hooks#postmodelswitch) | No | Yes | The session's model changes, including an automatic fallback | Give Claude model-specific guidance for the new model |
160| `PermissionRequest` | Yes | Yes | A tool call needs a permission decision | Custom permission handling |
161| `PermissionDenied` | No | Yes | Auto mode denies a tool call, including denials without a classifier verdict | Log denials, or tell the model it may retry; Claude Code ignores `retry: true` for no-verdict denials. See [PermissionDenied](/docs/en/hooks#permissiondenied) |
162| `SessionStart` | No | Yes | Session initialization | Initialize logging and telemetry |
163| `SessionEnd` | No | Yes | Session termination | Clean up temporary resources |
164| `Notification` | Yes | Yes | Agent status messages | Send agent status updates to Slack or PagerDuty |
165| `Setup` | No | Yes | Session setup/maintenance | Run initialization tasks |
166| `TeammateIdle` | No | Yes | Teammate becomes idle | Reassign work or notify |
167| `TaskCreated` | No | Yes | A task is created via the `TaskCreate` tool | Enforce task naming conventions |
168| [`TaskCompleted`](/docs/en/hooks#taskcompleted) | No | Yes | A task is marked completed | Require passing tests before a task closes |
169| `Elicitation` | No | Yes | An MCP server requests user input mid-task | Respond to MCP input requests programmatically |
170| `ElicitationResult` | No | Yes | A user responds to an MCP elicitation | Modify or block the response before it returns to the server |
171| `ConfigChange` | No | Yes | Configuration file changes | Reload settings dynamically |
172| `InstructionsLoaded` | No | Yes | A `CLAUDE.md` or rules file is loaded into context | Audit which instruction files load |
173| `WorktreeCreate` | No | Yes | Git worktree created | Track isolated workspaces |
174| `WorktreeRemove` | No | Yes | Git worktree removed | Clean up workspace resources |
175| `CwdChanged` | No | Yes | The working directory changes during a session | Reload environment variables per directory |
176| `FileChanged` | No | Yes | A watched file is modified, created, or deleted | Reload configuration when project files change |
177| `DirectoryAdded` | No | Yes | A working directory is added during a session | Install dependencies for a repository added mid-session |
143| Hook Event | Python SDK | TypeScript SDK | What triggers it | Example use case |
144| - | - | - | - | - |
145| `PreToolUse` | Yes | Yes | Tool call request (can block or modify) | Block dangerous shell commands |
146| `PostToolUse` | Yes | Yes | Tool execution result | Log all file changes to audit trail |
147| `PostToolUseFailure` | Yes | Yes | Tool execution failure | Handle or log tool errors |
148| `PostToolBatch` | No | Yes | A full batch of tool calls resolves, once per batch before the next model call | Inject conventions once for the whole batch |
149| `UserPromptSubmit` | Yes | Yes | User prompt submission | Inject additional context into prompts |
150| [`UserPromptExpansion`](/docs/en/hooks#userpromptexpansion) | No | Yes | A user-typed command, or an MCP prompt, expands into a prompt before it reaches Claude. Doesn't fire when Claude invokes a skill itself | Block a command from direct invocation or add context when a skill is typed |
151| `MessageDisplay` | No | Yes | An assistant message with text completes, once per message with the full message text | Redact or reformat the displayed text without changing the transcript |
152| `Stop` | Yes | Yes | Agent execution stop | Save session state before exit |
153| `StopFailure` | No | Yes | The turn ends with an API error instead of a normal stop | Log failures or send alerts |
154| `SubagentStart` | Yes | Yes | Subagent initialization | Track parallel task spawning |
155| `SubagentStop` | Yes | Yes | Subagent completion | Aggregate results from parallel tasks |
156| `PreCompact` | Yes | Yes | Conversation compaction request | Archive full transcript before summarizing |
157| `PostCompact` | No | Yes | Conversation compaction completes | Log the generated summary |
158| [`PreModelSwitch`](/docs/en/hooks#premodelswitch) | No | Yes | A requested model switch, before it happens (can block) | Block switching to a specific model |
159| [`PostModelSwitch`](/docs/en/hooks#postmodelswitch) | No | Yes | The session's model changes, including an automatic fallback | Give Claude model-specific guidance for the new model |
160| `PermissionRequest` | Yes | Yes | A tool call needs a permission decision | Custom permission handling |
161| `PermissionDenied` | No | Yes | Auto mode denies a tool call, including denials without a classifier verdict | Log denials, or tell the model it may retry; Claude Code ignores `retry: true` for no-verdict denials. See [PermissionDenied](/docs/en/hooks#permissiondenied) |
162| `SessionStart` | No | Yes | Session initialization | Initialize logging and telemetry |
163| `SessionEnd` | No | Yes | Session termination | Clean up temporary resources |
164| `Notification` | Yes | Yes | Agent status messages | Send agent status updates to Slack or PagerDuty |
165| `Setup` | No | Yes | Session setup/maintenance | Run initialization tasks |
166| `TeammateIdle` | No | Yes | Teammate becomes idle | Reassign work or notify |
167| `TaskCreated` | No | Yes | A task is created via the `TaskCreate` tool | Enforce task naming conventions |
168| [`TaskCompleted`](/docs/en/hooks#taskcompleted) | No | Yes | A task is marked completed | Require passing tests before a task closes |
169| `Elicitation` | No | Yes | An MCP server requests user input mid-task | Respond to MCP input requests programmatically |
170| `ElicitationResult` | No | Yes | A user responds to an MCP elicitation | Modify or block the response before it returns to the server |
171| `ConfigChange` | No | Yes | Configuration file changes | Reload settings dynamically |
172| `InstructionsLoaded` | No | Yes | A `CLAUDE.md` or rules file is loaded into context | Audit which instruction files load |
173| `WorktreeCreate` | No | Yes | Git worktree created | Track isolated workspaces |
174| `WorktreeRemove` | No | Yes | Git worktree removed | Clean up workspace resources |
175| `CwdChanged` | No | Yes | The working directory changes during a session | Reload environment variables per directory |
176| `FileChanged` | No | Yes | A watched file is modified, created, or deleted | Reload configuration when project files change |
177| `DirectoryAdded` | No | Yes | A working directory is added during a session | Install dependencies for a repository added mid-session |
178178
179179## Configure hooks
180180
from line 217
217217
218218SDK matchers follow the same rules as [matchers in settings files](/docs/en/hooks#matcher-patterns). That section documents the exact-string and regular-expression evaluation paths, their version requirements, and the matcher values for each event type.
219219
220| Option | Type | Default | Description |
221| --------- | ---------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
222| `matcher` | `string` | `undefined` | Pattern matched against the event's filter field, following the [rules for matchers in settings files](/docs/en/hooks#matcher-patterns). For tool hooks, this is the tool name. Built-in tools include `Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`, `Agent`, and others (see [Tool Input Types](/docs/en/agent-sdk/typescript#tool-input-types) for the full list). MCP tools use the pattern `mcp__<server>__<action>`, where `<server>` is the key you use in the `mcpServers` configuration. |
223| `hooks` | `HookCallback[]` | - | Required. Array of callback functions to execute when the pattern matches |
224| `timeout` | `number` | `undefined` | Timeout in seconds. When omitted, Claude Code applies the [event's default timeout](#hook-timeout). Your SDK callbacks follow the `command` hook defaults |
220| Option | Type | Default | Description |
221| - | - | - | - |
222| `matcher` | `string` | `undefined` | Pattern matched against the event's filter field, following the [rules for matchers in settings files](/docs/en/hooks#matcher-patterns). For tool hooks, this is the tool name. Built-in tools include `Bash`, `Read`, `Write`, `Edit`, `Glob`, `Grep`, `WebFetch`, `Agent`, and others (see [Tool Input Types](/docs/en/agent-sdk/typescript#tool-input-types) for the full list). MCP tools use the pattern `mcp__<server>__<action>`, where `<server>` is the key you use in the `mcpServers` configuration. |
223| `hooks` | `HookCallback[]` | - | Required. Array of callback functions to execute when the pattern matches |
224| `timeout` | `number` | `undefined` | Timeout in seconds. When omitted, Claude Code applies the [event's default timeout](#hook-timeout). Your SDK callbacks follow the `command` hook defaults |
225225
226226Use the `matcher` pattern to target specific tools whenever possible. A matcher with `'Bash'` only runs for Bash commands, while omitting the pattern runs your callbacks for every occurrence of the event. Omit it on purpose to log every tool call your session makes.
227227
from line 274
274274 ```
275275</CodeGroup>
276276
277| Field | Type | Description |
278| -------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
279| `async` | `true` | Signals async mode. The agent proceeds without waiting. In Python, use `async_` to avoid the reserved keyword. |
280| `asyncTimeout` | `number` | Optional timeout in milliseconds for the background operation |
277| Field | Type | Description |
278| - | - | - |
279| `async` | `true` | Signals async mode. The agent proceeds without waiting. In Python, use `async_` to avoid the reserved keyword. |
280| `asyncTimeout` | `number` | Optional timeout in milliseconds for the background operation |
281281
282282<Note>
283283 Async outputs can't block, modify, or inject context into the operation since the agent has already moved on. Use them only for side effects like logging, metrics, or notifications.
No line in this hunk matches that.