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/JCMefyZyaJwkJgv-/images/hooks-lifecycle.svg?fit=max&auto=format&n=JCMefyZyaJwkJgv-&q=85&s=f004f3fc7324fa2a4630e8d6559cf6dd" alt="Hook lifecycle diagram showing the sequence of hooks from SessionStart through the agentic loop (PreToolUse, PermissionRequest, PostToolUse, SubagentStart/Stop, TaskCompleted) to Stop or StopFailure, TeammateIdle, PreCompact, PostCompact, and SessionEnd, with Elicitation and ElicitationResult nested inside MCP tool execution and WorktreeCreate, WorktreeRemove, Notification, ConfigChange, InstructionsLoaded, CwdChanged, and FileChanged as standalone async events" width="520" height="1100" data-path="images/hooks-lifecycle.svg" />21 <img src="https://mintcdn.com/claude-code/1wr0LPds6lVWZkQB/images/hooks-lifecycle.svg?fit=max&auto=format&n=1wr0LPds6lVWZkQB&q=85&s=53a826e7bb64c6bff5f867506c0530ad" alt="Hook lifecycle diagram showing the sequence of hooks from SessionStart through the agentic loop (PreToolUse, PermissionRequest, PostToolUse, SubagentStart/Stop, TaskCreated, TaskCompleted) to Stop or StopFailure, TeammateIdle, PreCompact, PostCompact, and SessionEnd, with Elicitation and ElicitationResult nested inside MCP tool execution and WorktreeCreate, WorktreeRemove, Notification, ConfigChange, InstructionsLoaded, CwdChanged, and FileChanged as standalone async events" width="520" height="1155" data-path="images/hooks-lifecycle.svg" />
22 </Frame>22 </Frame>
23</div>23</div>
24 24
35| `Notification` | When Claude Code sends a notification |35| `Notification` | When Claude Code sends a notification |
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| `TaskCreated` | When a task is being created via `TaskCreate` |
39| `TaskCompleted` | When a task is being marked as completed |
38| `Stop` | When Claude finishes responding |40| `Stop` | When Claude finishes responding |
39| `StopFailure` | When the turn ends due to an API error. Output and exit code are ignored |41| `StopFailure` | When the turn ends due to an API error. Output and exit code are ignored |
40| `TeammateIdle` | When an [agent team](/en/agent-teams) teammate is about to go idle |42| `TeammateIdle` | When an [agent team](/en/agent-teams) teammate is about to go idle |
41| `TaskCompleted` | When a task is being marked as completed |
42| `InstructionsLoaded` | When a CLAUDE.md or `.claude/rules/*.md` file is loaded into context. Fires at session start and when files are lazily loaded during a session |43| `InstructionsLoaded` | When a CLAUDE.md or `.claude/rules/*.md` file is loaded into context. Fires at session start and when files are lazily loaded during a session |
43| `ConfigChange` | When a configuration file changes during a session |44| `ConfigChange` | When a configuration file changes during a session |
44| `CwdChanged` | When the working directory changes, for example when Claude executes a `cd` command. Useful for reactive environment management with tools like direnv |45| `CwdChanged` | When the working directory changes, for example when Claude executes a `cd` command. Useful for reactive environment management with tools like direnv |
169The `matcher` field is a regex string that filters when hooks fire. Use `"*"`, `""`, or omit `matcher` entirely to match all occurrences. Each event type matches on a different field:170The `matcher` field is a regex string that filters when hooks fire. Use `"*"`, `""`, or omit `matcher` entirely to match all occurrences. Each event type matches on a different field:
170 171
171| Event | What the matcher filters | Example matcher values |172| Event | What the matcher filters | Example matcher values |
172| :---------------------------------------------------------------------------------------------- | :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------ |173| :------------------------------------------------------------------------------------------------------------- | :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------ |
173| `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest` | tool name | `Bash`, `Edit\|Write`, `mcp__.*` |174| `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest` | tool name | `Bash`, `Edit\|Write`, `mcp__.*` |
174| `SessionStart` | how the session started | `startup`, `resume`, `clear`, `compact` |175| `SessionStart` | how the session started | `startup`, `resume`, `clear`, `compact` |
175| `SessionEnd` | why the session ended | `clear`, `resume`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` |176| `SessionEnd` | why the session ended | `clear`, `resume`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` |
184| `InstructionsLoaded` | load reason | `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact` |185| `InstructionsLoaded` | load reason | `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact` |
185| `Elicitation` | MCP server name | your configured MCP server names |186| `Elicitation` | MCP server name | your configured MCP server names |
186| `ElicitationResult` | MCP server name | same values as `Elicitation` |187| `ElicitationResult` | MCP server name | same values as `Elicitation` |
187| `UserPromptSubmit`, `Stop`, `TeammateIdle`, `TaskCompleted`, `WorktreeCreate`, `WorktreeRemove` | no matcher support | always fires on every occurrence |188| `UserPromptSubmit`, `Stop`, `TeammateIdle`, `TaskCreated`, `TaskCompleted`, `WorktreeCreate`, `WorktreeRemove` | no matcher support | always fires on every occurrence |
188 189
189The 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.190The 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.
190 191
208}209}
209```210```
210 211
211`UserPromptSubmit`, `Stop`, `TeammateIdle`, `TaskCompleted`, `WorktreeCreate`, `WorktreeRemove`, and `CwdChanged` don't support matchers and always fire on every occurrence. If you add a `matcher` field to these events, it is silently ignored.212`UserPromptSubmit`, `Stop`, `TeammateIdle`, `TaskCreated`, `TaskCompleted`, `WorktreeCreate`, `WorktreeRemove`, and `CwdChanged` don't support matchers and always fire on every occurrence. If you add a `matcher` field to these events, it is silently ignored.
212 213
213#### Match MCP tools214#### Match MCP tools
214 215
279In addition to the [common fields](#common-fields), command hooks accept these fields:280In addition to the [common fields](#common-fields), command hooks accept these fields:
280 281
281| Field | Required | Description |282| Field | Required | Description |
282| :-------- | :------- | :------------------------------------------------------------------------------------------------------------------ |283| :-------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
283| `command` | yes | Shell command to execute |284| `command` | yes | Shell command to execute |
284| `async` | no | If `true`, runs in the background without blocking. See [Run hooks in the background](#run-hooks-in-the-background) |285| `async` | no | If `true`, runs in the background without blocking. See [Run hooks in the background](#run-hooks-in-the-background) |
286| `shell` | no | Shell to use for this hook. Accepts `"bash"` (default) or `"powershell"`. Setting `"powershell"` runs the command via PowerShell on Windows. Does not require `CLAUDE_CODE_USE_POWERSHELL_TOOL` since hooks spawn PowerShell directly |
285 287
286#### HTTP hook fields288#### HTTP hook fields
287 289
521| `Stop` | Yes | Prevents Claude from stopping, continues the conversation |523| `Stop` | Yes | Prevents Claude from stopping, continues the conversation |
522| `SubagentStop` | Yes | Prevents the subagent from stopping |524| `SubagentStop` | Yes | Prevents the subagent from stopping |
523| `TeammateIdle` | Yes | Prevents the teammate from going idle (teammate continues working) |525| `TeammateIdle` | Yes | Prevents the teammate from going idle (teammate continues working) |
526| `TaskCreated` | Yes | Prevents the task from being created |
524| `TaskCompleted` | Yes | Prevents the task from being marked as completed |527| `TaskCompleted` | Yes | Prevents the task from being marked as completed |
525| `ConfigChange` | Yes | Blocks the configuration change from taking effect (except `policy_settings`) |528| `ConfigChange` | Yes | Blocks the configuration change from taking effect (except `policy_settings`) |
526| `StopFailure` | No | Output and exit code are ignored |529| `StopFailure` | No | Output and exit code are ignored |
588| Events | Decision pattern | Key fields |591| Events | Decision pattern | Key fields |
589| :-------------------------------------------------------------------------------------------------------------------------- | :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |592| :-------------------------------------------------------------------------------------------------------------------------- | :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
590| UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop, ConfigChange | Top-level `decision` | `decision: "block"`, `reason` |593| UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop, ConfigChange | Top-level `decision` | `decision: "block"`, `reason` |
591| TeammateIdle, TaskCompleted | Exit code or `continue: false` | Exit code 2 blocks the action with stderr feedback. JSON `{"continue": false, "stopReason": "..."}` also stops the teammate entirely, matching `Stop` hook behavior |594| TeammateIdle, TaskCreated, TaskCompleted | Exit code or `continue: false` | Exit code 2 blocks the action with stderr feedback. JSON `{"continue": false, "stopReason": "..."}` also stops the teammate entirely, matching `Stop` hook behavior |
592| PreToolUse | `hookSpecificOutput` | `permissionDecision` (allow/deny/ask), `permissionDecisionReason` |595| PreToolUse | `hookSpecificOutput` | `permissionDecision` (allow/deny/ask), `permissionDecisionReason` |
593| PermissionRequest | `hookSpecificOutput` | `decision.behavior` (allow/deny) |596| PermissionRequest | `hookSpecificOutput` | `decision.behavior` (allow/deny) |
594| WorktreeCreate | stdout path | Hook prints absolute path to created worktree. Non-zero exit fails creation |597| WorktreeCreate | path return | Command hook prints path on stdout; HTTP hook returns `hookSpecificOutput.worktreePath`. Hook failure or missing path fails creation |
595| Elicitation | `hookSpecificOutput` | `action` (accept/decline/cancel), `content` (form field values for accept) |598| Elicitation | `hookSpecificOutput` | `action` (accept/decline/cancel), `content` (form field values for accept) |
596| ElicitationResult | `hookSpecificOutput` | `action` (accept/decline/cancel), `content` (form field values override) |599| ElicitationResult | `hookSpecificOutput` | `action` (accept/decline/cancel), `content` (form field values override) |
597| WorktreeRemove, Notification, SessionEnd, PreCompact, PostCompact, InstructionsLoaded, StopFailure, CwdChanged, FileChanged | None | No decision control. Used for side effects like logging or cleanup |600| WorktreeRemove, Notification, SessionEnd, PreCompact, PostCompact, InstructionsLoaded, StopFailure, CwdChanged, FileChanged | None | No decision control. Used for side effects like logging or cleanup |
1264 1267
1265SubagentStop hooks use the same decision control format as [Stop hooks](#stop-decision-control).1268SubagentStop hooks use the same decision control format as [Stop hooks](#stop-decision-control).
1266 1269
1270### TaskCreated
1271
1272Runs when a task is being created via the `TaskCreate` tool. Use this to enforce naming conventions, require task descriptions, or prevent certain tasks from being created.
1273
1274When a `TaskCreated` hook exits with code 2, the task is not created and the stderr message is fed back to the model as feedback. To stop the teammate entirely instead of re-running it, return JSON with `{"continue": false, "stopReason": "..."}`. TaskCreated hooks do not support matchers and fire on every occurrence.
1275
1276#### TaskCreated input
1277
1278In addition to the [common input fields](#common-input-fields), TaskCreated hooks receive `task_id`, `task_subject`, and optionally `task_description`, `teammate_name`, and `team_name`.
1279
1280```json theme={null}
1281{
1282 "session_id": "abc123",
1283 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
1284 "cwd": "/Users/...",
1285 "permission_mode": "default",
1286 "hook_event_name": "TaskCreated",
1287 "task_id": "task-001",
1288 "task_subject": "Implement user authentication",
1289 "task_description": "Add login and signup endpoints",
1290 "teammate_name": "implementer",
1291 "team_name": "my-project"
1292}
1293```
1294
1295| Field | Description |
1296| :----------------- | :---------------------------------------------------- |
1297| `task_id` | Identifier of the task being created |
1298| `task_subject` | Title of the task |
1299| `task_description` | Detailed description of the task. May be absent |
1300| `teammate_name` | Name of the teammate creating the task. May be absent |
1301| `team_name` | Name of the team. May be absent |
1302
1303#### TaskCreated decision control
1304
1305TaskCreated hooks support two ways to control task creation:
1306
1307* **Exit code 2**: the task is not created and the stderr message is fed back to the model as feedback.
1308* **JSON `{"continue": false, "stopReason": "..."}`**: stops the teammate entirely, matching `Stop` hook behavior. The `stopReason` is shown to the user.
1309
1310This example blocks tasks whose subjects don't follow the required format:
1311
1312```bash theme={null}
1313#!/bin/bash
1314INPUT=$(cat)
1315TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
1316
1317if [[ ! "$TASK_SUBJECT" =~ ^\[TICKET-[0-9]+\] ]]; then
1318 echo "Task subject must start with a ticket number, e.g. '[TICKET-123] Add feature'" >&2
1319 exit 2
1320fi
1321
1322exit 0
1323```
1324
1325### TaskCompleted
1326
1327Runs 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.
1328
1329When 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. To stop the teammate entirely instead of re-running it, return JSON with `{"continue": false, "stopReason": "..."}`. TaskCompleted hooks do not support matchers and fire on every occurrence.
1330
1331#### TaskCompleted input
1332
1333In 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`.
1334
1335```json theme={null}
1336{
1337 "session_id": "abc123",
1338 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
1339 "cwd": "/Users/...",
1340 "permission_mode": "default",
1341 "hook_event_name": "TaskCompleted",
1342 "task_id": "task-001",
1343 "task_subject": "Implement user authentication",
1344 "task_description": "Add login and signup endpoints",
1345 "teammate_name": "implementer",
1346 "team_name": "my-project"
1347}
1348```
1349
1350| Field | Description |
1351| :----------------- | :------------------------------------------------------ |
1352| `task_id` | Identifier of the task being completed |
1353| `task_subject` | Title of the task |
1354| `task_description` | Detailed description of the task. May be absent |
1355| `teammate_name` | Name of the teammate completing the task. May be absent |
1356| `team_name` | Name of the team. May be absent |
1357
1358#### TaskCompleted decision control
1359
1360TaskCompleted hooks support two ways to control task completion:
1361
1362* **Exit code 2**: the task is not marked as completed and the stderr message is fed back to the model as feedback.
1363* **JSON `{"continue": false, "stopReason": "..."}`**: stops the teammate entirely, matching `Stop` hook behavior. The `stopReason` is shown to the user.
1364
1365This example runs tests and blocks task completion if they fail:
1366
1367```bash theme={null}
1368#!/bin/bash
1369INPUT=$(cat)
1370TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
1371
1372# Run the test suite
1373if ! npm test 2>&1; then
1374 echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
1375 exit 2
1376fi
1377
1378exit 0
1379```
1380
1267### Stop1381### Stop
1268 1382
1269Runs when the main Claude Code agent has finished responding. Does not run if1383Runs when the main Claude Code agent has finished responding. Does not run if
1377exit 01491exit 0
1378```1492```
1379 1493
1380### TaskCompleted
1381
1382Runs 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.
1383
1384When 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. To stop the teammate entirely instead of re-running it, return JSON with `{"continue": false, "stopReason": "..."}`. TaskCompleted hooks do not support matchers and fire on every occurrence.
1385
1386#### TaskCompleted input
1387
1388In 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`.
1389
1390```json theme={null}
1391{
1392 "session_id": "abc123",
1393 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
1394 "cwd": "/Users/...",
1395 "permission_mode": "default",
1396 "hook_event_name": "TaskCompleted",
1397 "task_id": "task-001",
1398 "task_subject": "Implement user authentication",
1399 "task_description": "Add login and signup endpoints",
1400 "teammate_name": "implementer",
1401 "team_name": "my-project"
1402}
1403```
1404
1405| Field | Description |
1406| :----------------- | :------------------------------------------------------ |
1407| `task_id` | Identifier of the task being completed |
1408| `task_subject` | Title of the task |
1409| `task_description` | Detailed description of the task. May be absent |
1410| `teammate_name` | Name of the teammate completing the task. May be absent |
1411| `team_name` | Name of the team. May be absent |
1412
1413#### TaskCompleted decision control
1414
1415TaskCompleted hooks support two ways to control task completion:
1416
1417* **Exit code 2**: the task is not marked as completed and the stderr message is fed back to the model as feedback.
1418* **JSON `{"continue": false, "stopReason": "..."}`**: stops the teammate entirely, matching `Stop` hook behavior. The `stopReason` is shown to the user.
1419
1420This example runs tests and blocks task completion if they fail:
1421
1422```bash theme={null}
1423#!/bin/bash
1424INPUT=$(cat)
1425TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
1426
1427# Run the test suite
1428if ! npm test 2>&1; then
1429 echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
1430 exit 2
1431fi
1432
1433exit 0
1434```
1435
1436### ConfigChange1494### ConfigChange
1437 1495
1438Runs when a configuration file changes during a session. Use this to audit settings changes, enforce security policies, or block unauthorized modifications to configuration files.1496Runs when a configuration file changes during a session. Use this to audit settings changes, enforce security policies, or block unauthorized modifications to configuration files.
1574 1632
1575When you run `claude --worktree` or a [subagent uses `isolation: "worktree"`](/en/sub-agents#choose-the-subagent-scope), Claude Code creates an isolated working copy using `git worktree`. If you configure a WorktreeCreate hook, it replaces the default git behavior, letting you use a different version control system like SVN, Perforce, or Mercurial.1633When you run `claude --worktree` or a [subagent uses `isolation: "worktree"`](/en/sub-agents#choose-the-subagent-scope), Claude Code creates an isolated working copy using `git worktree`. If you configure a WorktreeCreate hook, it replaces the default git behavior, letting you use a different version control system like SVN, Perforce, or Mercurial.
1576 1634
1577The hook must print the absolute path to the created worktree directory on stdout. Claude Code uses this path as the working directory for the isolated session.1635The hook must return the absolute path to the created worktree directory. Claude Code uses this path as the working directory for the isolated session. Command hooks print it on stdout; HTTP hooks return it via `hookSpecificOutput.worktreePath`.
1578 1636
1579This example creates an SVN working copy and prints the path for Claude Code to use. Replace the repository URL with your own:1637This example creates an SVN working copy and prints the path for Claude Code to use. Replace the repository URL with your own:
1580 1638
1613 1671
1614#### WorktreeCreate output1672#### WorktreeCreate output
1615 1673
1616The hook must print the absolute path to the created worktree directory on stdout. If the hook fails or produces no output, worktree creation fails with an error.1674WorktreeCreate hooks do not use the standard allow/block decision model. Instead, the hook's success or failure determines the outcome. The hook must return the absolute path to the created worktree directory:
1617 1675
1618WorktreeCreate hooks do not use the standard allow/block decision model. Instead, the hook's success or failure determines the outcome. Only `type: "command"` hooks are supported.1676* **Command hooks** (`type: "command"`): print the path on stdout.
1677* **HTTP hooks** (`type: "http"`): return `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }` in the response body.
1678
1679If the hook fails or produces no path, worktree creation fails with an error.
1619 1680
1620### WorktreeRemove1681### WorktreeRemove
1621 1682
1622The cleanup counterpart to [WorktreeCreate](#worktreecreate). This hook fires when a worktree is being removed, either when you exit a `--worktree` session and choose to remove it, or when a subagent with `isolation: "worktree"` finishes. For git-based worktrees, Claude handles cleanup automatically with `git worktree remove`. If you configured a WorktreeCreate hook for a non-git version control system, pair it with a WorktreeRemove hook to handle cleanup. Without one, the worktree directory is left on disk.1683The cleanup counterpart to [WorktreeCreate](#worktreecreate). This hook fires when a worktree is being removed, either when you exit a `--worktree` session and choose to remove it, or when a subagent with `isolation: "worktree"` finishes. For git-based worktrees, Claude handles cleanup automatically with `git worktree remove`. If you configured a WorktreeCreate hook for a non-git version control system, pair it with a WorktreeRemove hook to handle cleanup. Without one, the worktree directory is left on disk.
1623 1684
1624Claude Code passes the path that WorktreeCreate printed on stdout as `worktree_path` in the hook input. This example reads that path and removes the directory:1685Claude Code passes the path returned by WorktreeCreate as `worktree_path` in the hook input. This example reads that path and removes the directory:
1625 1686
1626```json theme={null}1687```json theme={null}
1627{1688{
1654}1715}
1655```1716```
1656 1717
1657WorktreeRemove hooks have no decision control. They cannot block worktree removal but can perform cleanup tasks like removing version control state or archiving changes. Hook failures are logged in debug mode only. Only `type: "command"` hooks are supported.1718WorktreeRemove hooks have no decision control. They cannot block worktree removal but can perform cleanup tasks like removing version control state or archiving changes. Hook failures are logged in debug mode only.
1658 1719
1659### PreCompact1720### PreCompact
1660 1721
1877* `Stop`1938* `Stop`
1878* `SubagentStop`1939* `SubagentStop`
1879* `TaskCompleted`1940* `TaskCompleted`
1941* `TaskCreated`
1880* `UserPromptSubmit`1942* `UserPromptSubmit`
1881 1943
1882Events that only support `type: "command"` hooks:1944Events that support `command` and `http` hooks but not `prompt` or `agent`:
1883 1945
1884* `ConfigChange`1946* `ConfigChange`
1885* `CwdChanged`1947* `CwdChanged`
1891* `PostCompact`1953* `PostCompact`
1892* `PreCompact`1954* `PreCompact`
1893* `SessionEnd`1955* `SessionEnd`
1894* `SessionStart`
1895* `StopFailure`1956* `StopFailure`
1896* `SubagentStart`1957* `SubagentStart`
1897* `TeammateIdle`1958* `TeammateIdle`
1898* `WorktreeCreate`1959* `WorktreeCreate`
1899* `WorktreeRemove`1960* `WorktreeRemove`
1900 1961
1962`SessionStart` supports only `command` hooks.
1963
1901### How prompt-based hooks work1964### How prompt-based hooks work
1902 1965
1903Instead of executing a Bash command, prompt-based hooks:1966Instead of executing a Bash command, prompt-based hooks:
2141* **Use absolute paths**: specify full paths for scripts, using `"$CLAUDE_PROJECT_DIR"` for the project root2204* **Use absolute paths**: specify full paths for scripts, using `"$CLAUDE_PROJECT_DIR"` for the project root
2142* **Skip sensitive files**: avoid `.env`, `.git/`, keys, etc.2205* **Skip sensitive files**: avoid `.env`, `.git/`, keys, etc.
2143 2206
2207## Windows PowerShell tool
2208
2209On Windows, you can run individual hooks in PowerShell by setting `"shell": "powershell"` on a command hook. Hooks spawn PowerShell directly, so this works regardless of whether `CLAUDE_CODE_USE_POWERSHELL_TOOL` is set. Claude Code auto-detects `pwsh.exe` (PowerShell 7+) with a fallback to `powershell.exe` (5.1).
2210
2211```json theme={null}
2212{
2213 "hooks": {
2214 "PostToolUse": [
2215 {
2216 "matcher": "Write",
2217 "hooks": [
2218 {
2219 "type": "command",
2220 "shell": "powershell",
2221 "command": "Write-Host 'File written'"
2222 }
2223 ]
2224 }
2225 ]
2226 }
2227}
2228```
2229
2144## Debug hooks2230## Debug hooks
2145 2231
2146Run `claude --debug` to see hook execution details, including which hooks matched, their exit codes, and output. Toggle verbose mode with `Ctrl+O` to see hook progress in the transcript.2232Run `claude --debug` to see hook execution details, including which hooks matched, their exit codes, and output. Toggle verbose mode with `Ctrl+O` to see hook progress in the transcript.