18 18
19<div style={{maxWidth: "500px", margin: "0 auto"}}>19<div style={{maxWidth: "500px", margin: "0 auto"}}>
20 <Frame>20 <Frame>
21 <img src="https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=5c25fedbc3db6f8882af50c3cc478c32" alt="Hook lifecycle diagram showing the sequence of hooks from SessionStart through the agentic loop to SessionEnd" data-og-width="8876" width="8876" data-og-height="12492" height="12492" data-path="images/hooks-lifecycle.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=280&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=62406fcd5d4a189cc8842ee1bd946b84 280w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=560&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=fa3049022a6973c5f974e0f95b28169d 560w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=840&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=bd2890897db61a03160b93d4f972ff8e 840w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=1100&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=7ae8e098340479347135e39df4a13454 1100w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=1650&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=848a8606aab22c2ccaa16b6a18431e32 1650w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=2500&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=f3a9ef7feb61fa8fe362005aa185efbc 2500w" />21 <img src="https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=7a351ea1cc3d5da7a2176bf51196bc1a" alt="Hook lifecycle diagram showing the sequence of hooks from SessionStart through the agentic loop to SessionEnd" data-og-width="520" width="520" data-og-height="960" height="960" data-path="images/hooks-lifecycle.svg" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?w=280&fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=8f32c67d025f0a318d5ed10a4f8ff2e6 280w, https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?w=560&fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=896fc424e39ff8d590720331a77e3d80 560w, https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?w=840&fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=a1c1c9739cde965e1eade843cee567c5 840w, https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?w=1100&fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=5bb083988de020e7d568e8dd8f1422fc 1100w, https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?w=1650&fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=343e9883c1e3172f08096c352aa46f12 1650w, https://mintcdn.com/claude-code/tpQvD9DKENFo4zX_/images/hooks-lifecycle.svg?w=2500&fit=max&auto=format&n=tpQvD9DKENFo4zX_&q=85&s=4de37b29de0f6df8b0c3e937a76c3bc6 2500w" />
22 </Frame>22 </Frame>
23</div>23</div>
24 24
25The table below summarizes when each event fires. The [Hook events](#hook-events) section documents the full input schema and decision control options for each one.25The table below summarizes when each event fires. The [Hook events](#hook-events) section documents the full input schema and decision control options for each one.
26 26
27| Event | When it fires |27| Event | When it fires |
28| :------------------- | :--------------------------------------------------- |28| :------------------- | :----------------------------------------------------------------- |
29| `SessionStart` | When a session begins or resumes |29| `SessionStart` | When a session begins or resumes |
30| `UserPromptSubmit` | When you submit a prompt, before Claude processes it |30| `UserPromptSubmit` | When you submit a prompt, before Claude processes it |
31| `PreToolUse` | Before a tool call executes. Can block it |31| `PreToolUse` | Before a tool call executes. Can block it |
36| `SubagentStart` | When a subagent is spawned |36| `SubagentStart` | When a subagent is spawned |
37| `SubagentStop` | When a subagent finishes |37| `SubagentStop` | When a subagent finishes |
38| `Stop` | When Claude finishes responding |38| `Stop` | When Claude finishes responding |
39| `TeammateIdle` | When an [agent team](/en/agent-teams) teammate is about to go idle |
40| `TaskCompleted` | When a task is being marked as completed |
39| `PreCompact` | Before context compaction |41| `PreCompact` | Before context compaction |
40| `SessionEnd` | When a session terminates |42| `SessionEnd` | When a session terminates |
41 43
165| `SubagentStart` | agent type | `Bash`, `Explore`, `Plan`, or custom agent names |167| `SubagentStart` | agent type | `Bash`, `Explore`, `Plan`, or custom agent names |
166| `PreCompact` | what triggered compaction | `manual`, `auto` |168| `PreCompact` | what triggered compaction | `manual`, `auto` |
167| `SubagentStop` | agent type | same values as `SubagentStart` |169| `SubagentStop` | agent type | same values as `SubagentStart` |
168| `UserPromptSubmit`, `Stop` | no matcher support | always fires on every occurrence |170| `UserPromptSubmit`, `Stop`, `TeammateIdle`, `TaskCompleted` | no matcher support | always fires on every occurrence |
169 171
170The matcher is a regex, so `Edit|Write` matches either tool and `Notebook.*` matches any tool starting with Notebook. The matcher runs against a field from the [JSON input](#hook-input-and-output) that Claude Code sends to your hook on stdin. For tool events, that field is `tool_name`. Each [hook event](#hook-events) section lists the full set of matcher values and the input schema for that event.172The matcher is a regex, so `Edit|Write` matches either tool and `Notebook.*` matches any tool starting with Notebook. The matcher runs against a field from the [JSON input](#hook-input-and-output) that Claude Code sends to your hook on stdin. For tool events, that field is `tool_name`. Each [hook event](#hook-events) section lists the full set of matcher values and the input schema for that event.
171 173
441Exit code 2 is the way a hook signals "stop, don't do this." The effect depends on the event, because some events represent actions that can be blocked (like a tool call that hasn't happened yet) and others represent things that already happened or can't be prevented.443Exit code 2 is the way a hook signals "stop, don't do this." The effect depends on the event, because some events represent actions that can be blocked (like a tool call that hasn't happened yet) and others represent things that already happened or can't be prevented.
442 444
443| Hook event | Can block? | What happens on exit 2 |445| Hook event | Can block? | What happens on exit 2 |
444| :------------------- | :--------- | :-------------------------------------------------------- |446| :------------------- | :--------- | :----------------------------------------------------------------- |
445| `PreToolUse` | Yes | Blocks the tool call |447| `PreToolUse` | Yes | Blocks the tool call |
446| `PermissionRequest` | Yes | Denies the permission |448| `PermissionRequest` | Yes | Denies the permission |
447| `UserPromptSubmit` | Yes | Blocks prompt processing and erases the prompt |449| `UserPromptSubmit` | Yes | Blocks prompt processing and erases the prompt |
448| `Stop` | Yes | Prevents Claude from stopping, continues the conversation |450| `Stop` | Yes | Prevents Claude from stopping, continues the conversation |
449| `SubagentStop` | Yes | Prevents the subagent from stopping |451| `SubagentStop` | Yes | Prevents the subagent from stopping |
452| `TeammateIdle` | Yes | Prevents the teammate from going idle (teammate continues working) |
453| `TaskCompleted` | Yes | Prevents the task from being marked as completed |
450| `PostToolUse` | No | Shows stderr to Claude (tool already ran) |454| `PostToolUse` | No | Shows stderr to Claude (tool already ran) |
451| `PostToolUseFailure` | No | Shows stderr to Claude (tool already failed) |455| `PostToolUseFailure` | No | Shows stderr to Claude (tool already failed) |
452| `Notification` | No | Shows stderr to user only |456| `Notification` | No | Shows stderr to user only |
491| Events | Decision pattern | Key fields |495| Events | Decision pattern | Key fields |
492| :-------------------------------------------------------------------- | :------------------- | :---------------------------------------------------------------- |496| :-------------------------------------------------------------------- | :------------------- | :---------------------------------------------------------------- |
493| UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop | Top-level `decision` | `decision: "block"`, `reason` |497| UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop | Top-level `decision` | `decision: "block"`, `reason` |
498| TeammateIdle, TaskCompleted | Exit code only | Exit code 2 blocks the action, stderr is fed back as feedback |
494| PreToolUse | `hookSpecificOutput` | `permissionDecision` (allow/deny/ask), `permissionDecisionReason` |499| PreToolUse | `hookSpecificOutput` | `permissionDecision` (allow/deny/ask), `permissionDecisionReason` |
495| PermissionRequest | `hookSpecificOutput` | `decision.behavior` (allow/deny) |500| PermissionRequest | `hookSpecificOutput` | `decision.behavior` (allow/deny) |
496 501
498 503
499<Tabs>504<Tabs>
500 <Tab title="Top-level decision">505 <Tab title="Top-level decision">
501 Used by `UserPromptSubmit`, `PostToolUse`, `PostToolUseFailure`, `Stop`, and `SubagentStop`. The only value is `"block"` — to allow the action to proceed, omit `decision` from your JSON, or exit 0 without any JSON at all:506 Used by `UserPromptSubmit`, `PostToolUse`, `PostToolUseFailure`, `Stop`, and `SubagentStop`. The only value is `"block"`. To allow the action to proceed, omit `decision` from your JSON, or exit 0 without any JSON at all:
502 507
503 ```json theme={null}508 ```json theme={null}
504 {509 {
1134}1139}
1135```1140```
1136 1141
1142### TeammateIdle
1143
1144Runs when an [agent team](/en/agent-teams) teammate is about to go idle after finishing its turn. Use this to enforce quality gates before a teammate stops working, such as requiring passing lint checks or verifying that output files exist.
1145
1146When a `TeammateIdle` hook exits with code 2, the teammate receives the stderr message as feedback and continues working instead of going idle. TeammateIdle hooks do not support matchers and fire on every occurrence.
1147
1148#### TeammateIdle input
1149
1150In addition to the [common input fields](#common-input-fields), TeammateIdle hooks receive `teammate_name` and `team_name`.
1151
1152```json theme={null}
1153{
1154 "session_id": "abc123",
1155 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
1156 "cwd": "/Users/...",
1157 "permission_mode": "default",
1158 "hook_event_name": "TeammateIdle",
1159 "teammate_name": "researcher",
1160 "team_name": "my-project"
1161}
1162```
1163
1164| Field | Description |
1165| :-------------- | :-------------------------------------------- |
1166| `teammate_name` | Name of the teammate that is about to go idle |
1167| `team_name` | Name of the team |
1168
1169#### TeammateIdle decision control
1170
1171TeammateIdle hooks use exit codes only, not JSON decision control. This example checks that a build artifact exists before allowing a teammate to go idle:
1172
1173```bash theme={null}
1174#!/bin/bash
1175
1176if [ ! -f "./dist/output.js" ]; then
1177 echo "Build artifact missing. Run the build before stopping." >&2
1178 exit 2
1179fi
1180
1181exit 0
1182```
1183
1184### TaskCompleted
1185
1186Runs when a task is being marked as completed. This fires in two situations: when any agent explicitly marks a task as completed through the TaskUpdate tool, or when an [agent team](/en/agent-teams) teammate finishes its turn with in-progress tasks. Use this to enforce completion criteria like passing tests or lint checks before a task can close.
1187
1188When a `TaskCompleted` hook exits with code 2, the task is not marked as completed and the stderr message is fed back to the model as feedback. TaskCompleted hooks do not support matchers and fire on every occurrence.
1189
1190#### TaskCompleted input
1191
1192In addition to the [common input fields](#common-input-fields), TaskCompleted hooks receive `task_id`, `task_subject`, and optionally `task_description`, `teammate_name`, and `team_name`.
1193
1194```json theme={null}
1195{
1196 "session_id": "abc123",
1197 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
1198 "cwd": "/Users/...",
1199 "permission_mode": "default",
1200 "hook_event_name": "TaskCompleted",
1201 "task_id": "task-001",
1202 "task_subject": "Implement user authentication",
1203 "task_description": "Add login and signup endpoints",
1204 "teammate_name": "implementer",
1205 "team_name": "my-project"
1206}
1207```
1208
1209| Field | Description |
1210| :----------------- | :------------------------------------------------------ |
1211| `task_id` | Identifier of the task being completed |
1212| `task_subject` | Title of the task |
1213| `task_description` | Detailed description of the task. May be absent |
1214| `teammate_name` | Name of the teammate completing the task. May be absent |
1215| `team_name` | Name of the team. May be absent |
1216
1217#### TaskCompleted decision control
1218
1219TaskCompleted hooks use exit codes only, not JSON decision control. This example runs tests and blocks task completion if they fail:
1220
1221```bash theme={null}
1222#!/bin/bash
1223INPUT=$(cat)
1224TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
1225
1226# Run the test suite
1227if ! npm test 2>&1; then
1228 echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
1229 exit 2
1230fi
1231
1232exit 0
1233```
1234
1137### PreCompact1235### PreCompact
1138 1236
1139Runs before Claude Code is about to run a compact operation.1237Runs before Claude Code is about to run a compact operation.
1195 1293
1196## Prompt-based hooks1294## Prompt-based hooks
1197 1295
1198In 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 work with the following events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, `UserPromptSubmit`, `Stop`, and `SubagentStop`.1296In 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 work with the following events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, `UserPromptSubmit`, `Stop`, `SubagentStop`, and `TaskCompleted`. `TeammateIdle` does not support prompt-based or agent-based hooks.
1199 1297
1200### How prompt-based hooks work1298### How prompt-based hooks work
1201 1299