10 有关包含示例的快速入门指南,请参阅[使用 hooks 自动化工作流](/docs/zh-CN/hooks-guide)。10 有关包含示例的快速入门指南,请参阅[使用 hooks 自动化工作流](/docs/zh-CN/hooks-guide)。
11</Tip>11</Tip>
12 12
13Hooks 是用户定义的 shell 命令、HTTP 端点或 LLM 提示,在 Claude Code 生命周期中的特定点自动执行。使用此参考查找事件架构、配置选项、JSON 输入/输出格式以及异步 hooks、HTTP hooks 和 MCP 工具 hooks 等高级功能。如果您是第一次设置 hooks,请改为从[指南](/docs/zh-CN/hooks-guide)开始。13Hooks 是用户定义的 shell 命令、HTTP 端点、MCP 工具调用、LLM 提示或子代理,在 Claude Code 生命周期中的特定点自动执行。Claude Code 在其运行的任何地方都会触发相同的 hook 事件:终端中的会话、IDE 扩展、[桌面应用](/docs/zh-CN/desktop-quickstart)和[云会话](/docs/zh-CN/claude-code-on-the-web)。使用此参考查找事件架构、配置选项、JSON 输入/输出格式以及异步 hooks、HTTP hooks 和 MCP 工具 hooks 等高级功能。
14 14
15<h2 id="hook-lifecycle">15<h2 id="hook-lifecycle">
16 Hook 生命周期16 Hook 生命周期
17</h2>17</h2>
18 18
19Hooks 在 Claude Code 会话期间的特定点触发。当事件触发且匹配器匹配时,Claude Code 会将关于该事件的 JSON 上下文传递给您的 hook 处理程序。对于命令 hooks,输入通过 stdin 到达。对于 HTTP hooks,它作为 POST 请求体到达。您的处理程序随后可以检查输入、采取行动并可选地返回决定。19Claude Code 在会话期间的特定点运行 hooks。当事件触发且匹配器匹配时,Claude Code 会将关于该事件的 JSON 上下文传递给您的 hook 处理程序。对于命令 hooks,输入通过 stdin 到达。对于 HTTP hooks,它作为 POST 请求体到达。您的处理程序随后可以检查输入、采取行动并可选地返回决定。
20 20
21事件分为三种频率:21事件分为三种频率:
22 22
23* 每个会话一次:`SessionStart` 和 `SessionEnd`23* 每个会话一次:`SessionStart` 和 `SessionEnd`
24* 每轮一次:`UserPromptSubmit`、`Stop` 和 `StopFailure`24* 每轮一次:`UserPromptSubmit`、`Stop` 和 `StopFailure`
25* 代理循环内的每个工具调用:`PreToolUse` 和 `PostToolUse`25* 代理循环内的每个工具调用:`PreToolUse` 和 `PostToolUse`,除了 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 调用,它们跳过两者
26 26
27<div style={{maxWidth: "500px", margin: "0 auto"}}>27<div style={{maxWidth: "500px", margin: "0 auto"}}>
28 <Frame>28 <Frame>
29 <img src="https://mintcdn.com/claude-code/x7pO8l4XcvAXCoVc/images/hooks-lifecycle.svg?fit=max&auto=format&n=x7pO8l4XcvAXCoVc&q=85&s=81b9256c1bbe8832553485f5d9e9c746" alt="Hook 生命周期图,显示可选的 Setup 流入 SessionStart,然后是每轮循环,包含 UserPromptSubmit、用于 slash commands 的 UserPromptExpansion、嵌套的代理循环(PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、PostToolBatch、SubagentStart/Stop、TaskCreated、TaskCompleted)和 Stop 或 StopFailure,然后是 TeammateIdle、PreCompact、PostCompact 和 SessionEnd,Elicitation 和 ElicitationResult 嵌套在 MCP 工具执行内,PermissionDenied 作为 PermissionRequest 的副分支用于自动模式拒绝,WorktreeCreate、WorktreeRemove、Notification、ConfigChange、InstructionsLoaded、CwdChanged 和 FileChanged 作为独立异步事件,MessageDisplay 作为仅显示事件,在助手消息文本流式传输时运行" width="520" height="1336" data-path="images/hooks-lifecycle.svg" />29 <img src="https://mintcdn.com/claude-code/x7pO8l4XcvAXCoVc/images/hooks-lifecycle.svg?fit=max&auto=format&n=x7pO8l4XcvAXCoVc&q=85&s=81b9256c1bbe8832553485f5d9e9c746" className="dark:hidden" alt="Hook 生命周期图,显示可选的 Setup 流入 SessionStart,然后是每轮循环,包含 UserPromptSubmit、用于 slash commands 的 UserPromptExpansion、嵌套的代理循环(PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、PostToolBatch、SubagentStart/Stop、TaskCreated、TaskCompleted)和 Stop 或 StopFailure,然后是 TeammateIdle、PreCompact、PostCompact 和 SessionEnd,Elicitation 和 ElicitationResult 嵌套在 MCP 工具执行内,PermissionDenied 作为 PermissionRequest 的副分支用于自动模式拒绝,WorktreeCreate、WorktreeRemove、Notification、ConfigChange、InstructionsLoaded、CwdChanged、FileChanged 和 DirectoryAdded 作为独立异步事件,PreModelSwitch 作为独立顺序事件,在请求的模型切换之前运行,PostModelSwitch 作为独立异步事件,在会话的模型更改后运行,MessageDisplay 作为仅显示事件,在助手消息文本流式传输时运行" width="520" height="1336" data-path="images/hooks-lifecycle.svg" />
30
31 <img src="https://mintcdn.com/claude-code/x7pO8l4XcvAXCoVc/images/hooks-lifecycle-dark.svg?fit=max&auto=format&n=x7pO8l4XcvAXCoVc&q=85&s=c9b3d88487335f58cce0b52e2f9e7531" className="hidden dark:block" alt="Hook 生命周期图,显示可选的 Setup 流入 SessionStart,然后是每轮循环,包含 UserPromptSubmit、用于 slash commands 的 UserPromptExpansion、嵌套的代理循环(PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、PostToolBatch、SubagentStart/Stop、TaskCreated、TaskCompleted)和 Stop 或 StopFailure,然后是 TeammateIdle、PreCompact、PostCompact 和 SessionEnd,Elicitation 和 ElicitationResult 嵌套在 MCP 工具执行内,PermissionDenied 作为 PermissionRequest 的副分支用于自动模式拒绝,WorktreeCreate、WorktreeRemove、Notification、ConfigChange、InstructionsLoaded、CwdChanged、FileChanged 和 DirectoryAdded 作为独立异步事件,PreModelSwitch 作为独立顺序事件,在请求的模型切换之前运行,PostModelSwitch 作为独立异步事件,在会话的模型更改后运行,MessageDisplay 作为仅显示事件,在助手消息文本流式传输时运行" width="520" height="1336" data-path="images/hooks-lifecycle-dark.svg" />
30 </Frame>32 </Frame>
31</div>33</div>
32 34
33下表总结了每个事件何时触发。[Hook 事件](#hook-events)部分记录了每个事件的完整输入架构和决定控制选项。35下表总结了每个事件何时触发。[Hook 事件](#hook-events)部分记录了每个事件的完整输入架构和决定控制选项。
34 36
35| Event | When it fires |37| 事件 | 触发时机 |
36| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |38| :-------------------- | :--------------------------------------------------------------------------------------------------------------------- |
37| `SessionStart` | When a session begins or resumes |39| `SessionStart` | 当会话开始或恢复时 |
38| `Setup` | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts |40| `Setup` | 当你使用 `--init-only` 启动 Claude Code,或在 `-p` 模式下使用 `--init` 或 `--maintenance` 时。用于 CI 或脚本中的一次性准备 |
39| `UserPromptSubmit` | When you submit a prompt, before Claude processes it |41| `UserPromptSubmit` | 当你提交提示词时,在 Claude 处理之前 |
40| `UserPromptExpansion` | When a user-typed command expands into a prompt, before it reaches Claude. Can block the expansion |42| `UserPromptExpansion` | 当用户输入的命令扩展为提示词时,在到达 Claude 之前。可以阻止扩展 |
41| `PreToolUse` | Before a tool call executes. Can block it |43| `PreToolUse` | 在工具调用执行之前。可以阻止它 |
42| `PermissionRequest` | When a tool call needs a permission decision |44| `PermissionRequest` | 当工具调用需要权限决策时 |
43| `PermissionDenied` | When auto mode denies a tool call, including denials without a classifier verdict. Use JSON `hookSpecificOutput.retry: true` to tell the model it may retry the denied tool call. Claude Code ignores `retry` when the classifier produced no verdict |45| `PermissionDenied` | 当自动模式拒绝工具调用时,包括没有分类器判决的拒绝。使用 JSON `hookSpecificOutput.retry: true` 来告诉模型它可以重试被拒绝的工具调用。Claude Code 在分类器未产生判决时忽略 `retry` |
44| `PostToolUse` | After a tool call succeeds |46| `PostToolUse` | 在工具调用成功后 |
45| `PostToolUseFailure` | After a tool call fails |47| `PostToolUseFailure` | 在工具调用失败后 |
46| `PostToolBatch` | After a full batch of parallel tool calls resolves, before the next model call |48| `PostToolBatch` | 在一整批并行工具调用解决后,在下一次模型调用之前 |
47| `Notification` | When Claude Code sends a notification |49| `Notification` | 当 Claude Code 发送通知时 |
48| `MessageDisplay` | While assistant message text is displayed |50| `MessageDisplay` | 当助手消息文本正在显示时 |
49| `SubagentStart` | When a subagent is spawned |51| `SubagentStart` | 当子代理被生成时 |
50| `SubagentStop` | When a subagent finishes |52| `SubagentStop` | 当子代理完成时 |
51| `TaskCreated` | When a task is being created via `TaskCreate` |53| `TaskCreated` | 当通过 `TaskCreate` 创建任务时 |
52| `TaskCompleted` | When a task is being marked as completed |54| `TaskCompleted` | 当任务被标记为已完成时 |
53| `Stop` | When Claude finishes responding |55| `Stop` | 当 Claude 完成响应时 |
54| `StopFailure` | When the turn ends due to an API error |56| `StopFailure` | 当轮次因 API 错误而结束时 |
55| `TeammateIdle` | When an [agent team](/docs/en/agent-teams) teammate is about to go idle |57| `TeammateIdle` | 当[代理团队](/docs/zh-CN/agent-teams)队友即将空闲时 |
56| `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 |58| `InstructionsLoaded` | 当 CLAUDE.md 或 `.claude/rules/*.md` 文件被加载到上下文中时。在会话开始时和文件在会话期间被延迟加载时触发 |
57| `ConfigChange` | When a configuration file changes during a session |59| `ConfigChange` | 当配置文件在会话期间更改时 |
58| `CwdChanged` | When the working directory changes, for example when Claude executes a `cd` command. Useful for reactive environment management with tools like direnv |60| `CwdChanged` | 当工作目录更改时,例如当 Claude 执行 `cd` 命令时。对于使用 direnv 等工具的反应式环境管理很有用 |
59| `DirectoryAdded` | When a working directory is added mid-session via `/add-dir` or the SDK `register_repo_root` control request |61| `DirectoryAdded` | 当工作目录在会话中期通过 `/add-dir` 或 SDK `register_repo_root` 控制请求添加时 |
60| `FileChanged` | When a watched file changes on disk. The `matcher` field specifies which filenames to watch |62| `FileChanged` | 当监视的文件在磁盘上更改时。`matcher` 字段指定要监视的文件名 |
61| `WorktreeCreate` | When a worktree is being created via `--worktree`, `isolation: "worktree"`, or for a background session. Replaces default git behavior |63| `WorktreeCreate` | 当通过 `--worktree`、`isolation: "worktree"` 创建工作树时,或用于后台会话。替换默认的 git 行为 |
62| `WorktreeRemove` | When a worktree is being removed at session exit, when a subagent finishes, or when you delete a background session |64| `WorktreeRemove` | 当在会话退出时、子代理完成时或删除后台会话时移除工作树 |
63| `PreCompact` | Before context compaction |65| `PreCompact` | 在上下文压缩之前 |
64| `PostCompact` | After context compaction completes |66| `PostCompact` | 在上下文压缩完成后 |
65| `PreModelSwitch` | Before Claude Code applies a model switch that you or a client requested. Can block the switch |67| `PreModelSwitch` | 在 Claude Code 应用你或客户端请求的模型切换之前。可以阻止切换 |
66| `PostModelSwitch` | After the session's model changes, including changes Claude Code makes on its own, such as restoring the model when you resume a session |68| `PostModelSwitch` | 在会话的模型更改后,包括 Claude Code 自己进行的更改,例如在你恢复会话时恢复模型 |
67| `Elicitation` | When an MCP server requests user input during a tool call |69| `Elicitation` | 当 MCP 服务器在工具调用期间请求用户输入时 |
68| `ElicitationResult` | After a user responds to an MCP elicitation, before the response is sent back to the server |70| `ElicitationResult` | 在用户响应 MCP 引出后,在响应发送回服务器之前 |
69| `SessionEnd` | When a session terminates |71| `SessionEnd` | 当会话终止时 |
70 72
71<h3 id="how-a-hook-resolves">73<h3 id="how-a-hook-resolves">
72 Hook 如何解析74 Hook 如何解析
73</h3>75</h3>
74 76
75要了解这些部分如何组合在一起,请考虑这个 `PreToolUse` hook,它阻止破坏性 shell 命令。`matcher` 缩小到 Bash 工具调用,`if` 条件进一步缩小到匹配 `rm *` 的 Bash 子命令,因此 `block-rm.sh` 仅在两个过滤器都匹配时生成:77要了解事件、匹配器和处理程序如何组合在一起,请考虑这个 `PreToolUse` hook,它阻止破坏性 shell 命令。
76 78
77```json theme={null}79<Tabs>
78{80 <Tab title="macOS/Linux">
81 `matcher` 缩小到 Bash 工具调用,`if` 条件进一步缩小到匹配 `rm *` 的 Bash 子命令,因此 `block-rm.sh` 仅在两个过滤器都匹配时生成:
82
83 ```json theme={null}
84 {
79 "hooks": {85 "hooks": {
80 "PreToolUse": [86 "PreToolUse": [
81 {87 {
91 }97 }
92 ]98 ]
93 }99 }
94}100 }
95```101 ```
96 102
97该脚本从 stdin 读取 JSON 输入,提取命令,如果包含 `rm -rf`,则返回 `permissionDecision` 为 `"deny"`:103 该脚本从 stdin 读取 JSON 输入,提取命令,如果包含 `rm -rf`,则返回 `permissionDecision` 为 `"deny"`。将其保存到项目中的 `.claude/hooks/block-rm.sh`,并使用 `chmod +x .claude/hooks/block-rm.sh` 使其可执行,以便 Claude Code 可以运行它:
98 104
99```bash theme={null}105 ```bash theme={null}
100#!/bin/bash106 #!/bin/bash
101# .claude/hooks/block-rm.sh107 # .claude/hooks/block-rm.sh
102COMMAND=$(jq -r '.tool_input.command')108 COMMAND=$(jq -r '.tool_input.command')
103 109
104if echo "$COMMAND" | grep -q 'rm -rf'; then110 if echo "$COMMAND" | grep -q 'rm -rf'; then
105 jq -n '{111 jq -n '{
106 hookSpecificOutput: {112 hookSpecificOutput: {
107 hookEventName: "PreToolUse",113 hookEventName: "PreToolUse",
109 permissionDecisionReason: "Destructive command blocked by hook"115 permissionDecisionReason: "Destructive command blocked by hook"
110 }116 }
111 }'117 }'
112else118 else
113 exit 0 # no decision; normal permission flow applies119 exit 0 # no decision; normal permission flow applies
114fi120 fi
115```121 ```
122
123 此脚本与本页面上解析 JSON 输入的其他 Bash 示例一样,使用 `jq`,因此在尝试它们之前,请安装 `jq` 并确保它在您的 `PATH` 上。
124 </Tab>
125
126 <Tab title="Windows (PowerShell)">
127 匹配器 `Bash|PowerShell` 涵盖 [PowerShell 工具](#powershell)以及 Bash。单个 `if` 规则仅匹配一个工具的调用,因此每个工具都有自己的处理程序:第一个缩小到匹配 `rm *` 的 Bash 子命令,第二个缩小到匹配 `Remove-Item *` 的 PowerShell 命令。两者都通过 `powershell.exe` 运行相同的脚本:
128
129 ```json theme={null}
130 {
131 "hooks": {
132 "PreToolUse": [
133 {
134 "matcher": "Bash|PowerShell",
135 "hooks": [
136 {
137 "type": "command",
138 "if": "Bash(rm *)",
139 "command": "powershell.exe",
140 "args": [
141 "-NoProfile",
142 "-ExecutionPolicy",
143 "Bypass",
144 "-File",
145 "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.ps1"
146 ]
147 },
148 {
149 "type": "command",
150 "if": "PowerShell(Remove-Item *)",
151 "command": "powershell.exe",
152 "args": [
153 "-NoProfile",
154 "-ExecutionPolicy",
155 "Bypass",
156 "-File",
157 "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.ps1"
158 ]
159 }
160 ]
161 }
162 ]
163 }
164 }
165 ```
166
167 `-NoProfile` 标志跳过加载您的 PowerShell 配置文件,以便 hook 快速启动,`-ExecutionPolicy Bypass` 让 PowerShell 运行本地脚本文件。
116 168
117现在假设 Claude Code 决定运行 `Bash "rm -rf /tmp/build"`。以下是发生的情况:169 该脚本从 stdin 读取 JSON 输入,提取命令,如果包含 `rm -rf` 或 `Remove-Item` 后跟 `-Recurse`,则返回 `permissionDecision` 为 `"deny"`。将其保存到项目中的 `.claude/hooks/block-rm.ps1`:
170
171 ```powershell theme={null}
172 # .claude/hooks/block-rm.ps1
173 $callInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
174 $command = $callInput.tool_input.command
175
176 if ($command -match 'rm -rf|Remove-Item.*-Recurse') {
177 @{
178 hookSpecificOutput = @{
179 hookEventName = "PreToolUse"
180 permissionDecision = "deny"
181 permissionDecisionReason = "Destructive command blocked by hook"
182 }
183 } | ConvertTo-Json
184 } else {
185 exit 0 # no decision; normal permission flow applies
186 }
187 ```
188 </Tab>
189</Tabs>
190
191现在假设 Claude Code 决定针对 macOS/Linux 配置运行 `Bash "rm -rf /tmp/build"`。以下是发生的情况:
118 192
119<Frame>193<Frame>
120 <img src="https://mintcdn.com/claude-code/ikqp3_70mqIahteV/images/hook-resolution.svg?fit=max&auto=format&n=ikqp3_70mqIahteV&q=85&s=be0bf3053550c26de5f54cd64674c197" alt="Hook 解析流程图:PreToolUse 触发,匹配器检查 Bash 匹配,然后 if 条件检查 Bash(rm *) 匹配。如果两者都匹配,hook 命令运行并返回 permissionDecision deny,因此工具调用被阻止,Claude Code 继续。如果任一检查未能匹配,hook 被跳过,工具调用被允许继续。" width="930" height="270" data-path="images/hook-resolution.svg" />194 <img src="https://mintcdn.com/claude-code/ikqp3_70mqIahteV/images/hook-resolution.svg?fit=max&auto=format&n=ikqp3_70mqIahteV&q=85&s=be0bf3053550c26de5f54cd64674c197" className="dark:hidden" alt="Hook 解析流程图:PreToolUse 触发,匹配器检查 Bash 匹配,然后 if 条件检查 Bash(rm *) 匹配。如果两者都匹配,hook 命令运行并返回 permissionDecision deny,因此工具调用被阻止,Claude Code 继续。如果任一检查未能匹配,hook 被跳过,工具调用被允许继续。" width="930" height="270" data-path="images/hook-resolution.svg" />
195
196 <img src="https://mintcdn.com/claude-code/_xqph1dUOslCOwsj/images/hook-resolution-dark.svg?fit=max&auto=format&n=_xqph1dUOslCOwsj&q=85&s=e80af91f8507cee6bd51ac3c2dd92f63" className="hidden dark:block" alt="Hook 解析流程图:PreToolUse 触发,匹配器检查 Bash 匹配,然后 if 条件检查 Bash(rm *) 匹配。如果两者都匹配,hook 命令运行并返回 permissionDecision deny,因此工具调用被阻止,Claude Code 继续。如果任一检查未能匹配,hook 被跳过,工具调用被允许继续。" width="930" height="270" data-path="images/hook-resolution-dark.svg" />
121</Frame>197</Frame>
122 198
123<Steps>199<Steps>
183您定义 hook 的位置决定了其范围:259您定义 hook 的位置决定了其范围:
184 260
185| 位置 | 范围 | 可共享 |261| 位置 | 范围 | 可共享 |
186| :---------------------------------------------------------- | :----- | :----------------------------- |262| :------------------------------------------ | :--------------------------------------------------------------------- | :---------------------------------- |
187| `~/.claude/settings.json` | 您的所有项目 | 否,本地于您的计算机 |263| `~/.claude/settings.json` | 您的所有项目 | 否,本地于您的计算机 |
188| `.claude/settings.json` | 单个项目 | 是,可以提交到仓库 |264| `.claude/settings.json` | 单个项目 | 是,可以提交到仓库 |
189| `.claude/settings.local.json` | 单个项目 | 否,gitignored 当 Claude Code 创建时 |265| `.claude/settings.local.json` | 单个项目 | 否,gitignored 当 Claude Code 保存设置到其中时 |
190| 托管策略设置 | 组织范围 | 是,管理员控制 |266| 托管策略设置 | 组织范围 | 是,管理员控制 |
191| [Plugin](/docs/zh-CN/plugins) `hooks/hooks.json` | 启用插件时 | 是,与插件捆绑 |267| [Plugin](/docs/zh-CN/plugins) `hooks/hooks.json` | 启用插件时 | 是,与插件捆绑 |
192| [Skill](/docs/zh-CN/skills) 或[代理](/docs/zh-CN/sub-agents) frontmatter | 组件活跃时 | 是,在组件文件中定义 |268| [Skill](/docs/zh-CN/skills) frontmatter | 调用 skill 后的会话其余部分。请参阅[Skills 和代理中的 Hooks](#hooks-in-skills-and-agents) | 是,在 skill 文件中定义 |
269| [Subagent](/docs/zh-CN/sub-agents) frontmatter | 该 subagent 运行时 | 是,在 subagent 文件中定义 |
270
271[Cloud sessions](/docs/zh-CN/claude-code-on-the-web)不读取您的本地 `~/.claude/settings.json`;那里的 hooks 来自仓库,意味着其 `.claude/settings.json` 在具有一个仓库的会话中以及它在任何会话中声明的插件,以及来自您组织的服务器管理的设置。在[自托管环境](/docs/zh-CN/self-hosted-environments-configuration#permissions-and-tool-approval)中,Claude Code 也运行操作员从运行程序主机的 `~/.claude/` 中播种的 hooks,并且当该文件在[Claude Code 应用的托管源](/docs/zh-CN/managed-settings#how-claude-code-combines-managed-sources)中时,它运行运行程序镜像的托管设置文件中的 hooks,默认情况下仅当服务器管理的设置和 MDM 交付的 Claude Code 策略都不提供托管层时。有关哪些文件到达云会话,请参阅[您的设置中携带的内容](/docs/zh-CN/cloud-environments#what-carries-over-from-your-setup)。
193 272
194有关设置文件解析的详细信息,请参阅[设置](/docs/zh-CN/settings)。企业管理员可以使用 `allowManagedHooksOnly` 来阻止用户、项目和插件 hooks。在托管设置 `enabledPlugins` 中强制启用的插件中的 Hooks 是豁免的,因此管理员可以通过组织市场分发经过审查的 hooks。请参阅[Hook 配置](/docs/zh-CN/settings#hook-configuration)。273有关设置文件解析的详细信息,请参阅[设置](/docs/zh-CN/settings)。
274
275来自设置文件、托管策略设置和插件的 Hooks 也在[subagents](/docs/zh-CN/sub-agents)内运行。当 subagent 调用工具时,工具事件(如 `PreToolUse` 和 `PostToolUse`)触发与主对话中配置的相同 hooks,输入携带 `agent_id` 和 `agent_type`[通用输入字段](#common-input-fields),用于标识 subagent。
276
277企业管理员可以使用 `allowManagedHooksOnly` 来限制哪些 hooks 运行:
278
279* 您的用户、项目、本地和插件 hooks 被阻止。托管设置 `enabledPlugins` 中强制启用的插件中的 Hooks 是豁免的
280* Claude Code 也将您的[`statusLine`](/docs/zh-CN/statusline)、[`fileSuggestion`](/docs/zh-CN/settings-reference#filesuggestion)和[`subagentStatusLine`](/docs/zh-CN/statusline#subagent-status-lines)设置缩小到托管设置
281* Claude Code 也禁用具有[`command` 源](/docs/zh-CN/plugin-marketplaces#command-sources)的插件,包括托管设置 `enabledPlugins` 中强制启用的插件,除非[`disableCommandPluginSources`](/docs/zh-CN/settings-reference#disablecommandpluginsources)明确设置为 `false`。`command` 源需要 Claude Code v2.1.229 或更高版本
282* Claude Code 也阻止市场[`headersHelper` 命令](/docs/zh-CN/plugin-marketplaces#authenticate-archive-downloads),除非[`disableCommandPluginSources`](/docs/zh-CN/settings-reference#disablecommandpluginsources)明确设置为 `false`,除了托管设置本身声明的市场
283
284请参阅[在 `allowManagedHooksOnly` 下运行的内容](/docs/zh-CN/settings-reference#what-runs-under-allowmanagedhooksonly)。
285
286Hook 条目在设置级别之间合并而不是相互替换:用户、项目和本地设置添加它们自己的 hooks 而不移除托管的,[`disableAllHooks`](#disable-or-remove-hooks)设置无法从托管设置外部禁用托管 hooks。
287
288[HTTP hook 允许列表](/docs/zh-CN/settings-reference#hook-and-skill-settings)适用于来自每个源的 hooks,包括托管策略设置:
289
290* `allowedHttpHookUrls`:在任何设置级别定义时,Claude Code 仅在其 URL 与合并的允许列表匹配时运行 HTTP hook 处理程序
291* `httpHookAllowedEnvVars`:定义时,Claude Code 仅将该列表上的环境变量插值到 hook 标头中
195 292
196<h3 id="matcher-patterns">293<h3 id="matcher-patterns">
197 匹配器模式294 匹配器模式
218每个事件类型在不同的字段上匹配:315每个事件类型在不同的字段上匹配:
219 316
220| 事件 | 匹配器过滤的内容 | 示例匹配器值 |317| 事件 | 匹配器过滤的内容 | 示例匹配器值 |
221| :---------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |318| :---------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
222| `PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest`、`PermissionDenied` | 工具名称 | `Bash`、`Edit\|Write`、`mcp__.*` |319| `PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest`、`PermissionDenied` | 工具名称 | `Bash`、`Edit\|Write`、`mcp__.*` |
223| `SessionStart` | 会话如何启动 | `startup`、`resume`、`clear`、`compact` |320| `SessionStart` | 会话如何启动 | `startup`、`resume`、`clear`、`compact`、`fork` |
224| `Setup` | 哪个 CLI 标志触发了设置 | `init`、`maintenance` |321| `Setup` | 哪个 CLI 标志触发了设置 | `init`、`maintenance` |
225| `SessionEnd` | 会话为何结束 | `clear`、`resume`、`logout`、`prompt_input_exit`、`bypass_permissions_disabled`、`other` |322| `SessionEnd` | 会话为何结束 | `clear`、`resume`、`logout`、`prompt_input_exit`、`other` |
226| `Notification` | 通知类型 | `permission_prompt`、`idle_prompt`、`auth_success`、`elicitation_dialog`、`elicitation_complete`、`elicitation_response`、`agent_needs_input`、`agent_completed` |323| `Notification` | 通知类型 | `permission_prompt`、`idle_prompt`、`auth_success`、`elicitation_dialog`、`elicitation_url_dialog`、`elicitation_complete`、`elicitation_response`、`agent_needs_input`、`agent_completed`、`quota_auto_resume_fired`、`quota_auto_resume_stale`、`quota_auto_resume_disabled` |
227| `SubagentStart` | 代理类型 | `general-purpose`、`Explore`、`Plan`、自定义代理名称或插件范围的名称如 `^my-plugin:reviewer$` |324| `SubagentStart` | 代理类型 | `general-purpose`、`Explore`、`Plan`、自定义代理名称或插件范围的名称如 `^my-plugin:reviewer$` |
228| `PreCompact`、`PostCompact` | 触发压缩的原因 | `manual`、`auto` |325| `PreCompact`、`PostCompact` | 触发压缩的原因 | `manual`、`auto` |
326| `PreModelSwitch`、`PostModelSwitch` | 会话切换到的模型的规范名称,如[PreModelSwitch](#premodelswitch)下所述 | `claude-opus-5`、`claude-opus-4-6\|claude-opus-5`、`.*opus.*` |
229| `SubagentStop` | 代理类型 | 与 `SubagentStart` 相同的值 |327| `SubagentStop` | 代理类型 | 与 `SubagentStart` 相同的值 |
230| `ConfigChange` | 配置源 | `user_settings`、`project_settings`、`local_settings`、`policy_settings`、`skills` |328| `ConfigChange` | 配置源 | `user_settings`、`project_settings`、`local_settings`、`policy_settings`、`skills` |
231| `CwdChanged` | 不支持匹配器 | 总是在每次目录更改时触发 |329| `CwdChanged` | 不支持匹配器 | 总是在每次出现时触发 |
330| `DirectoryAdded` | 目录如何被添加 | `slash_command`、`register_repo_root` |
232| `FileChanged` | 文字文件名以监视(请参阅 [FileChanged](#filechanged)) | `.envrc\|.env` |331| `FileChanged` | 文字文件名以监视(请参阅 [FileChanged](#filechanged)) | `.envrc\|.env` |
233| `StopFailure` | 错误类型 | `rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens`、`unknown` |332| `StopFailure` | 错误类型 | `rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`account_on_hold`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens`、`cloud_credential_error`、`unknown` |
234| `InstructionsLoaded` | 加载原因 | `session_start`、`nested_traversal`、`path_glob_match`、`include`、`compact` |333| `InstructionsLoaded` | 加载原因 | `session_start`、`nested_traversal`、`path_glob_match`、`include`、`compact` |
235| `UserPromptExpansion` | 命令名称 | 您的 skill 或命令名称 |334| `UserPromptExpansion` | 命令名称 | 您的 skill 或命令名称 |
236| `Elicitation` | MCP 服务器名称 | 您配置的 MCP 服务器名称 |335| `Elicitation` | MCP 服务器名称 | 您配置的 MCP 服务器名称 |
237| `ElicitationResult` | MCP 服务器名称 | 与 `Elicitation` 相同的值 |336| `ElicitationResult` | MCP 服务器名称 | 与 `Elicitation` 相同的值 |
238| `UserPromptSubmit`、`PostToolBatch`、`Stop`、`TeammateIdle`、`TaskCreated`、`TaskCompleted`、`WorktreeCreate`、`WorktreeRemove`、`MessageDisplay` | 不支持匹配器 | 总是在每次出现时触发 |337| `UserPromptSubmit`、`PostToolBatch`、`Stop`、`TeammateIdle`、`TaskCreated`、`TaskCompleted`、`WorktreeCreate`、`WorktreeRemove`、`MessageDisplay` | 不支持匹配器 | 总是在每次出现时触发 |
239 338
240匹配器针对 Claude Code 在 stdin 上发送给您的 hook 的[JSON 输入](#hook-input-and-output)中的字段运行。对于工具事件,该字段是 `tool_name`。每个[hook 事件](#hook-events)部分列出了完整的匹配器值集和该事件的输入架构。339在 `cloud_credential_error` 上匹配 `StopFailure` 需要 Claude Code v2.1.267 或更高版本,这是第一个在该值下报告凭证加载失败而不是 `server_error` 或 `unknown` 的版本。
340
341对于大多数事件,Claude Code 针对它在 stdin 上发送给您的 hook 的[JSON 输入](#hook-input-and-output)中的字段评估匹配器。对于工具事件,该字段是 `tool_name`。对于 `PreModelSwitch` 和 `PostModelSwitch`,Claude Code 针对它从 `to_model` 派生的规范名称评估匹配器,如[PreModelSwitch](#premodelswitch)下所述。每个[hook 事件](#hook-events)部分列出了完整的匹配器值集和该事件的输入架构。
241 342
242此示例仅在 Claude 写入或编辑文件时运行 linting 脚本:343此示例仅在 Claude 写入或编辑文件时运行 linting 脚本:
243 344
259}360}
260```361```
261 362
262`UserPromptSubmit`、`PostToolBatch`、`Stop`、`TeammateIdle`、`TaskCreated`、`TaskCompleted`、`WorktreeCreate`、`WorktreeRemove`、`MessageDisplay` 和 `CwdChanged` 不支持匹配器,总是在每次出现时触发。如果您向这些事件添加 `matcher` 字段,它会被静默忽略。363如果您向不支持匹配器的事件添加 `matcher` 字段,它会被静默忽略。
263 364
264对于工具事件,您可以通过在单个 hook 处理程序上设置[`if` 字段](#common-fields)来更狭隘地过滤。`if` 使用[权限规则语法](/docs/zh-CN/permissions)来匹配工具名称和参数,因此 `"Bash(git *)"` 仅在任何 Bash 输入的子命令与 `git *` 匹配时运行,`"Edit(*.ts)"` 仅对 TypeScript 文件运行。365对于工具事件,您可以通过在单个 hook 处理程序上设置[`if` 字段](#common-fields)来更狭隘地过滤。`if` 使用[权限规则语法](/docs/zh-CN/permissions)来匹配工具名称和参数,因此 `"Bash(git *)"` 仅在任何 Bash 输入的子命令与 `git *` 匹配时运行,`"Edit(*.ts)"` 仅对 TypeScript 文件运行。
265 366
323* **[命令 hooks](#command-hook-fields)**(`type: "command"`):运行 shell 命令。您的脚本在 stdin 上接收事件的[JSON 输入](#hook-input-and-output),并通过退出代码和 stdout 传回结果。424* **[命令 hooks](#command-hook-fields)**(`type: "command"`):运行 shell 命令。您的脚本在 stdin 上接收事件的[JSON 输入](#hook-input-and-output),并通过退出代码和 stdout 传回结果。
324* **[HTTP hooks](#http-hook-fields)**(`type: "http"`):将事件的 JSON 输入作为 HTTP POST 请求发送到 URL。端点通过使用与命令 hooks 相同的[JSON 输出格式](#json-output)的响应体传回结果。425* **[HTTP hooks](#http-hook-fields)**(`type: "http"`):将事件的 JSON 输入作为 HTTP POST 请求发送到 URL。端点通过使用与命令 hooks 相同的[JSON 输出格式](#json-output)的响应体传回结果。
325* **[MCP 工具 hooks](#mcp-tool-hook-fields)**(`type: "mcp_tool"`):在已连接的[MCP 服务器](/docs/zh-CN/mcp)上调用工具。工具的文本输出被视为命令 hook stdout。426* **[MCP 工具 hooks](#mcp-tool-hook-fields)**(`type: "mcp_tool"`):在已连接的[MCP 服务器](/docs/zh-CN/mcp)上调用工具。工具的文本输出被视为命令 hook stdout。
326* **[提示 hooks](#prompt-and-agent-hook-fields)**(`type: "prompt"`):向 Claude 模型发送提示以进行单轮评估。模型返回 yes/no 决定作为 JSON。请参阅[基于提示的 hooks](#prompt-based-hooks)。427* **[提示 hooks](#prompt-and-agent-hook-fields)**(`type: "prompt"`):向 Claude 模型发送提示以进行单轮评估。模型返回其决定作为 JSON。请参阅[基于提示的 hooks](#prompt-based-hooks)。
327* **[代理 hooks](#prompt-and-agent-hook-fields)**(`type: "agent"`):生成一个可以使用 Read、Grep 和 Glob 等工具来验证条件的 subagent,然后返回决定。代理 hooks 是实验性的,可能会改变。请参阅[基于代理的 hooks](#agent-based-hooks)。428* **[代理 hooks](#prompt-and-agent-hook-fields)**(`type: "agent"`):生成一个可以使用 Read、Grep 和 Glob 等工具来验证条件的 subagent,然后返回决定。代理 hooks 是实验性的,可能会改变。请参阅[基于代理的 hooks](#agent-based-hooks)。
328 429
329所有匹配的 hooks 并行运行,相同的处理程序会自动去重。命令 hooks 按命令字符串和 `args` 去重,HTTP hooks 按 URL 去重。430所有匹配的 hooks 并行运行。如果您在多个设置文件中定义相同的处理程序,它运行一次。插件或 skill 的相同处理程序副本保持分离。
330 431
331处理程序在当前目录中运行,使用 Claude Code 的环境。在远程 web 环境中,`$CLAUDE_CODE_REMOTE` 环境变量设置为 `"true"`,在本地 CLI 中未设置。从 v2.1.199 开始,[`$CLAUDE_CODE_BRIDGE_SESSION_ID`](/docs/zh-CN/env-vars)设置为[远程控制](/docs/zh-CN/remote-control)会话 ID,而本地会话具有活跃的远程控制连接。432处理程序在当前目录中运行,使用 Claude Code 的环境。如果当前目录不再存在,例如另一个 shell 在会话中途删除的 worktree 或临时目录,Claude Code 从以下第一个仍然存在的目录运行命令 hooks:会话启动的目录、项目根目录、您的主目录或系统临时目录。Claude Code 在[调试日志](#debug-hooks)中记录一条警告,命名回退目录。
433
434`$CLAUDE_CODE_REMOTE` 环境变量在远程 web 环境中为 `"true"`,在本地 CLI 中未设置。Claude Code v2.1.199 及更高版本在本地会话具有活跃的远程控制连接时将[`$CLAUDE_CODE_BRIDGE_SESSION_ID`](/docs/zh-CN/env-vars)设置为[远程控制](/docs/zh-CN/remote-control)会话 ID。
332 435
333<h4 id="common-fields">436<h4 id="common-fields">
334 通用字段437 通用字段
337这些字段适用于所有 hook 类型:440这些字段适用于所有 hook 类型:
338 441
339| 字段 | 必需 | 描述 |442| 字段 | 必需 | 描述 |
340| :-------------- | :- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |443| :-------------- | :- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
341| `type` | 是 | `"command"`、`"http"`、`"mcp_tool"`、`"prompt"` 或 `"agent"` |444| `type` | 是 | `"command"`、`"http"`、`"mcp_tool"`、`"prompt"` 或 `"agent"` |
342| `if` | 否 | 权限规则语法以过滤此 hook 何时运行,例如 `"Bash(git *)"` 或 `"Edit(*.ts)"`。hook 命令仅在工具调用与模式匹配时运行。请参阅下面的[Bash 匹配表](#bash-if-matching)了解 Bash 模式如何针对子命令、`$()`和反引号进行评估。仅在工具事件上评估:`PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest` 和 `PermissionDenied`。在其他事件上,设置了 `if` 的 hook 永远不会运行。使用与[权限规则](/docs/zh-CN/permissions)相同的语法 |445| `if` | 否 | 权限规则语法以过滤此 hook 何时运行,例如 `"Bash(git *)"` 或 `"Edit(*.ts)"`。hook 命令仅在工具调用与模式匹配时运行。请参阅下面的[Bash 匹配表](#bash-if-matching)了解 Bash 模式如何针对子命令、`$()` 和反引号进行评估。仅在工具事件上评估:`PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest` 和 `PermissionDenied`。在其他事件上,设置了 `if` 的 hook 永远不会运行。使用与[权限规则](/docs/zh-CN/permissions)相同的语法 |
343| `timeout` | 否 | 取消前的秒数。默认值:`command`、`http` 和 `mcp_tool` 为 600;`prompt` 为 30;`agent` 为 60。[`UserPromptSubmit`](#userpromptsubmit) 将 `command`、`http` 和 `mcp_tool` 的默认值降低到 30,[`MessageDisplay`](#messagedisplay) 将其降低到 10 |446| `timeout` | 否 | 取消前的秒数。Claude Code 不在您使用 [`async: true`](#run-hooks-in-the-background)运行的命令 hook 上强制执行它。默认值:`command`、`http` 和 `mcp_tool` 为 600;`prompt` 为 30;`agent` 为 60。Claude Code 在[`UserPromptSubmit`](#userpromptsubmit)、[`PreModelSwitch`](#premodelswitch)和[`PostModelSwitch`](#postmodelswitch)上将 `command`、`http` 和 `mcp_tool` 的默认值降低到 30,在[`MessageDisplay`](#messagedisplay)上降低到 10。[`SessionEnd`](#sessionend) hooks 共享 1.5 秒的预算;如果您的设置设置了更长的每个 hook `timeout`,Claude Code 会提高预算以匹配,最多 60 秒 |
344| `statusMessage` | 否 | hook 运行时显示的自定义加载程序消息 |447| `statusMessage` | 否 | hook 运行时显示的自定义加载程序消息 |
345| `once` | 否 | 如果为 `true`,每个会话仅运行一次,然后被移除。仅在[skill frontmatter](#hooks-in-skills-and-agents)中声明的 hooks 中受尊重;在设置文件和代理 frontmatter 中被忽略 |448| `once` | 否 | 如果为 `true`,Claude Code 在其第一次成功运行后移除 hook。失败、以退出代码 2 阻止或超时的运行会将 hook 保留在原位,因此它在下一个匹配事件上再次运行。仅在[skill frontmatter](#hooks-in-skills-and-agents)中声明的 hooks 中受尊重;在设置文件和代理 frontmatter 中被忽略 |
346 449
347`if` 字段恰好包含一个权限规则。没有 `&&`、`||` 或列表语法来组合规则;要应用多个条件,请为每个条件定义一个单独的 hook 处理程序。450`if` 字段恰好包含一个权限规则。没有 `&&`、`||` 或列表语法来组合规则;要应用多个条件,请为每个条件定义一个单独的 hook 处理程序。
348 451
452在文件工具的 `if` 条件中,单段目录模式如 `"Edit(src/**)"` 仅匹配工作目录中的 `src` 目录及其下的文件。要匹配任何深度的名为 `src` 的目录,请写 `"Edit(**/src/**)"`。在 v2.1.214 之前,`"Edit(src/**)"` 匹配工作目录下任何深度的名为 `src` 的目录。
453
349<span id="bash-if-matching" />对于 Bash 模式,您的 hook 命令是否运行取决于模式的形状和 Claude 调用的 Bash 命令。前导 `VAR=value` 赋值在匹配前被剥离。454<span id="bash-if-matching" />对于 Bash 模式,您的 hook 命令是否运行取决于模式的形状和 Claude 调用的 Bash 命令。前导 `VAR=value` 赋值在匹配前被剥离。
350 455
351| `if` 模式 | Bash 命令 | Hook 运行? | 原因 |456| `if` 模式 | Bash 命令 | Hook 运行? | 原因 |
352| :----------------- | :--------------------- | :------- | :-------------------------------------- |457| :----------------- | :-------------------------- | :------- | :----------------------------------------- |
353| `Bash(git *)` | `FOO=bar git push` | 是 | 前导赋值被剥离;`git push` 匹配 |458| `Bash(git *)` | `FOO=bar git push` | 是 | 前导赋值被剥离;`git push` 匹配 |
354| `Bash(git *)` | `npm test && git push` | 是 | 每个子命令都被检查;`git push` 匹配 |459| `Bash(git *)` | `npm test && git push` | 是 | 每个子命令都被检查;`git push` 匹配 |
355| `Bash(rm *)` | `echo $(rm -rf /)` | 是 | `$()` 和反引号内的命令被检查;`rm -rf /` 匹配 |460| `Bash(rm *)` | `echo $(rm -rf /)` | 是 | `$()` 和反引号内的命令被检查;`rm -rf /` 匹配 |
356| `Bash(rm *)` | `echo $(date)` | 否 | 没有子命令匹配 `rm *` |461| `Bash(rm *)` | `echo $(date)` | 否 | 没有子命令匹配 `rm *` |
462| `Bash(cat *)` | `echo before $(date) after` | 否 | 替换可以位于任何参数位置,因此检查完整命令和 `date`;都不匹配 `cat *` |
463| `Bash(git *)` | `$TOOL git push` | 是 | Claude Code 无法判断命令名称展开为什么,因此它运行 hook |
357| `Bash(git push *)` | `echo $(date)` | 是 | 指定超过命令名称的模式在 `$()`、反引号或 `$VAR` 上运行 hook |464| `Bash(git push *)` | `echo $(date)` | 是 | 指定超过命令名称的模式在 `$()`、反引号或 `$VAR` 上运行 hook |
358 465
359过滤器也会失败开放,当 Bash 命令无法解析时无论如何运行您的 hook。因为 `if` 过滤器是尽力而为的,使用[权限系统](/docs/zh-CN/permissions)而不是 hook 来强制执行硬允许或拒绝。466当 Claude Code 无法确定 Bash 输入运行哪些命令时,它无论如何都会运行您的 hook。因为 `if` 过滤器是尽力而为的,使用[权限系统](/docs/zh-CN/permissions)而不是 hook 来强制执行硬允许或拒绝。
360 467
361<h4 id="command-hook-fields">468<h4 id="command-hook-fields">
362 命令 hook 字段469 命令 hook 字段
369| `command` | 是 | 要执行的 shell 命令。与 `args` 一起,要直接生成的可执行文件。请参阅[Exec 形式和 shell 形式](#exec-form-and-shell-form) |476| `command` | 是 | 要执行的 shell 命令。与 `args` 一起,要直接生成的可执行文件。请参阅[Exec 形式和 shell 形式](#exec-form-and-shell-form) |
370| `args` | 否 | 参数列表。存在时,`command` 被解析为可执行文件并直接使用 `args` 作为参数向量生成,不涉及 shell。请参阅[Exec 形式和 shell 形式](#exec-form-and-shell-form) |477| `args` | 否 | 参数列表。存在时,`command` 被解析为可执行文件并直接使用 `args` 作为参数向量生成,不涉及 shell。请参阅[Exec 形式和 shell 形式](#exec-form-and-shell-form) |
371| `async` | 否 | 如果为 `true`,在后台运行而不阻止。请参阅[在后台运行 hooks](#run-hooks-in-the-background) |478| `async` | 否 | 如果为 `true`,在后台运行而不阻止。请参阅[在后台运行 hooks](#run-hooks-in-the-background) |
372| `asyncRewake` | 否 | 如果为 `true`,在后台运行并在退出代码 2 时唤醒 Claude。暗示 `async`。Hook 的 stderr,或 stdout(如果 stderr 为空),作为系统提醒显示给 Claude,以便它可以对长时间运行的后台失败做出反应 |479| `asyncRewake` | 否 | 如果为 `true`,在后台运行并在退出代码 2 时唤醒 Claude。hook 的 stderr,或 stdout(如果 stderr 为空),作为系统提醒显示给 Claude,以便它可以对长时间运行的后台失败做出反应 |
373| `shell` | 否 | 用于此 hook 的 shell。接受 `"bash"` 或 `"powershell"`。默认为 `"bash"`,或在未安装 Git Bash 时在 Windows 上默认为 `"powershell"`。设置 `"powershell"` 在 Windows 上通过 PowerShell 运行命令。不需要 `CLAUDE_CODE_USE_POWERSHELL_TOOL`,因为 hooks 直接生成 PowerShell。设置 `args` 时被忽略 |480| `shell` | 否 | 用于此 hook 的 shell。接受 `"bash"` 或 `"powershell"`。默认为 `"bash"`,或在未安装 Git Bash 时在 Windows 上默认为 `"powershell"`。设置 `"powershell"` 在 Windows 上通过 PowerShell 运行命令。不需要 `CLAUDE_CODE_USE_POWERSHELL_TOOL`,因为 hooks 直接生成 PowerShell。设置 `args` 时被忽略 |
374 481
375<a id="exec-form-and-shell-form" />482<a id="exec-form-and-shell-form" />
431 538
432Claude Code 使用 `Content-Type: application/json` 将 hook 的[JSON 输入](#hook-input-and-output)作为 POST 请求体发送。响应体使用与命令 hooks 相同的[JSON 输出格式](#json-output)。539Claude Code 使用 `Content-Type: application/json` 将 hook 的[JSON 输入](#hook-input-and-output)作为 POST 请求体发送。响应体使用与命令 hooks 相同的[JSON 输出格式](#json-output)。
433 540
434错误处理与命令 hooks 不同:非 2xx 响应、连接失败和超时都会产生非阻止错误,允许执行继续。要阻止工具调用或拒绝权限,返回 2xx 响应,其 JSON 体包含 `decision: "block"` 或 `hookSpecificOutput` 与 `permissionDecision: "deny"`。541错误处理与命令 hooks 不同;请参阅[HTTP 响应处理](#http-response-handling)。
435 542
436此示例将 `PreToolUse` 事件发送到本地验证服务,使用来自 `MY_TOKEN` 环境变量的令牌进行身份验证:543此示例将 `PreToolUse` 事件发送到本地验证服务,使用来自 `MY_TOKEN` 环境变量的令牌进行身份验证:
437 544
470| `tool` | 是 | 该服务器上要调用的工具的名称 |577| `tool` | 是 | 该服务器上要调用的工具的名称 |
471| `input` | 否 | 传递给工具的参数。字符串值支持从 hook 的[JSON 输入](#hook-input-and-output)进行 `${path}` 替换,例如 `"${tool_input.file_path}"` |578| `input` | 否 | 传递给工具的参数。字符串值支持从 hook 的[JSON 输入](#hook-input-and-output)进行 `${path}` 替换,例如 `"${tool_input.file_path}"` |
472 579
473工具的文本内容被视为命令 hook stdout:如果它解析为有效的[JSON 输出](#json-output),则作为决定进行处理,否则显示为纯文本。如果命名的服务器未连接,或工具返回 `isError: true`,hook 会产生非阻止错误,执行继续。580Claude Code 读取工具的文本内容的方式与读取命令 hook stdout 相同,遵循[退出代码 0 下的解析规则](#exit-code-0)。如果命名的服务器未连接,或工具返回 `isError: true`,hook 会产生非阻止错误,执行继续。
474
475MCP 工具 hooks 在 Claude Code 连接到您的 MCP 服务器后在每个 hook 事件上可用。`SessionStart` 和 `Setup` 通常在服务器完成连接之前触发,因此这些事件上的 hooks 应该期望在首次运行时出现"未连接"错误。
476 581
477此示例在每个 `Write` 或 `Edit` 后在 `my_server` MCP 服务器上调用 `security_scan` 工具,传递编辑文件的路径:582此示例在每个 `Write` 或 `Edit` 后在 `my_server` MCP 服务器上调用 `security_scan` 工具,传递编辑文件的路径:
478 583
496}601}
497```602```
498 603
604`mcp_tool` hook 仅在 Claude Code 使会话的 MCP 服务器对 hooks 可用后才能在每个 hook 事件上运行。`SessionStart` 和 `Setup` 可能在该点之前触发:
605
606* **在启动时**:`SessionStart` 在服务器可用之前触发,包括当您使用 `--continue` 或 `--resume` 启动时。Claude Code 跳过事件的 `mcp_tool` hooks 而不调用它们的工具,[调试日志](#debug-hooks)记录 `mcp_tool hooks are not available for the 'SessionStart' hook event (no MCP client context)`。
607* **稍后在运行的会话中**:在 `/clear` 或压缩后,`SessionStart` 再次触发,服务器已可用,其 `mcp_tool` hooks 运行。
608* **在 `Setup` 上**:`Setup` 总是在服务器可用之前触发,因此 Claude Code 每次都跳过其 `mcp_tool` hooks 并记录相同的消息,命名 `Setup`。
609
610例如,此配置从没有匹配器的 `SessionStart` hook 在 `my_server` MCP 服务器上调用 `load_context` 工具,因此它适用于每个 `SessionStart` 源:
611
612```json theme={null}
613{
614 "hooks": {
615 "SessionStart": [
616 {
617 "hooks": [
618 {
619 "type": "mcp_tool",
620 "server": "my_server",
621 "tool": "load_context"
622 }
623 ]
624 }
625 ]
626 }
627}
628```
629
630当您运行 `claude` 时,Claude Code 跳过此 hook,永远不调用 `load_context`,并将 `no MCP client context` 消息写入调试日志。在该同一会话中运行 `/clear`,hook 运行并调用 `load_context`。`type: "command"` hook 在 `SessionStart` 上运行,因此对会话从其第一个转向需要的任何东西使用一个。
631
499<h4 id="prompt-and-agent-hook-fields">632<h4 id="prompt-and-agent-hook-fields">
500 提示和代理 hook 字段633 提示和代理 hook 字段
501</h4>634</h4>
513 646
514使用这些占位符按项目或插件根目录引用 hook 脚本,无论 hook 运行时的工作目录如何:647使用这些占位符按项目或插件根目录引用 hook 脚本,无论 hook 运行时的工作目录如何:
515 648
516* `${CLAUDE_PROJECT_DIR}`:项目根目录。Claude Code 也在[stdio MCP 服务器](/docs/zh-CN/mcp#option-3-add-a-local-stdio-server)和插件 LSP 服务器的环境中设置此变量。649* `${CLAUDE_PROJECT_DIR}`:项目根目录,会话启动的位置。Claude Code 也在[stdio MCP 服务器](/docs/zh-CN/mcp#option-3-add-a-local-stdio-server)和插件 LSP 服务器的环境中设置此变量。
517* `${CLAUDE_PLUGIN_ROOT}`:插件的安装目录,用于与[插件](/docs/zh-CN/plugins)捆绑的脚本。在每次插件更新时更改。650* `${CLAUDE_PLUGIN_ROOT}`:插件的安装目录,用于与[插件](/docs/zh-CN/plugins)捆绑的脚本。请参阅[插件环境变量](/docs/zh-CN/plugins-reference#environment-variables)了解路径在更新中的行为。
518* `${CLAUDE_PLUGIN_DATA}`:插件的[持久数据目录](/docs/zh-CN/plugins-reference#persistent-data-directory),用于应该在插件更新后保留的依赖项和状态。651* `${CLAUDE_PLUGIN_DATA}`:插件的[持久数据目录](/docs/zh-CN/plugins-reference#persistent-data-directory),用于应该在插件更新后保留的依赖项和状态。
519 652
520对于任何引用路径占位符的 hook,优先使用[exec 形式](#exec-form-and-shell-form)。Exec 形式将每个 `args` 元素作为一个参数传递,不带 shell 标记化,因此包含空格或特殊字符的路径不需要引号。在 shell 形式中,用双引号包装每个占位符。653<Note>
654 **Worktrees 是不同的。** 如果 Claude 在会话期间进入[worktree](/docs/zh-CN/worktrees),Claude Code 保持 `${CLAUDE_PROJECT_DIR}` 在其原位,并以不同的方式将 worktree 路径传递给您的 hooks:
655
656 * **`${CLAUDE_PROJECT_DIR}` 保持不变**:它仍然指向会话启动的项目根目录,因此像 `${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.sh` 这样的命令仍然在主检出中运行脚本。
657 * **`cwd` 跟随 Claude**:hook 的[输入 JSON](#common-input-fields)中的 `cwd` 字段在 Claude 进入 worktree 后是 worktree 根目录,在 Claude 运行 `cd` 后是新目录。当 hook 需要知道 Claude 正在哪个目录中工作时读取它。
658</Note>
659
660对于任何引用路径占位符的 hook,优先使用[exec 形式](#exec-form-and-shell-form)。在 shell 形式中,用双引号包装每个占位符。
521 661
522<Tabs>662<Tabs>
523 <Tab title="项目脚本">663 <Tab title="项目脚本">
577 Skills 和代理中的 Hooks717 Skills 和代理中的 Hooks
578</h3>718</h3>
579 719
580除了设置文件和插件外,hooks 还可以使用 frontmatter 直接在[skills](/docs/zh-CN/skills)和[subagents](/docs/zh-CN/sub-agents)中定义。这些 hooks 的范围限于组件的生命周期,仅在该组件活跃时运行。720除了设置文件和插件外,hooks 还可以使用 frontmatter 直接在[skills](/docs/zh-CN/skills)和[subagents](/docs/zh-CN/sub-agents)中定义,使用与基于设置的 hooks 相同的配置格式。Claude Code 保持它们注册多长时间取决于组件:
581
582支持所有 hook 事件。对于 subagents,`Stop` hooks 会自动转换为 `SubagentStop`,因为这是 subagent 完成时触发的事件。
583 721
584Hooks 使用与基于设置的 hooks 相同的配置格式,但范围限于组件的生命周期,并在其完成时清理。722* **Subagent hooks**:Claude Code 仅在该 subagent 运行时运行它们,并在其完成时移除它们。Claude Code 在此处将 `Stop` hook 转换为 `SubagentStop`,这是 subagent 完成时触发的事件。
723* **Skill hooks**:Claude Code 在您或 Claude 调用 skill 时注册它们,并在会话的其余部分保持运行它们,在 skill 自己的转向之后的转向上也是如此。要让 Claude Code 在第一次成功运行后移除 hook,请在其上设置[`once: true`](#common-fields)。
585 724
586此 skill 定义了一个 `PreToolUse` hook,在每个 `Bash` 命令之前运行安全验证脚本:725此 skill 定义了一个 `PreToolUse` hook,在每个 `Bash` 命令之前运行安全验证脚本:
587 726
598---737---
599```738```
600 739
601代理在其 YAML frontmatter 中使用相同的格式。740Subagents 在其 YAML frontmatter 中使用相同的格式。
741
742项目 skill 中的 Frontmatter hooks 遵循与设置文件中的 hooks 相同的[工作区信任规则](#workspace-trust)。Claude Code 在您或 Claude 调用 skill 时注册它们,包括在您未信任的文件夹中的 `-p` 运行。
743
744项目 subagent 中的 Frontmatter hooks 仅在您接受 agent 文件来自的文件夹的[工作区信任对话](/docs/zh-CN/permissions#project-allow-rules-and-workspace-trust)后运行。`-p` 会话不计为接受它。[在您信任文件夹之前运行的内容](/docs/zh-CN/permissions#what-runs-before-you-trust-a-folder)将此与设置文件规则进行比较,subagents 页面列出[哪些范围是豁免的](/docs/zh-CN/sub-agents#hooks-in-subagent-frontmatter)。在 v2.1.218 之前,这些 hooks 可以从您未信任的文件夹运行。
602 745
603<h3 id="the-/hooks-menu">746<h3 id="the-/hooks-menu">
604 `/hooks` 菜单747 `/hooks` 菜单
608 751
609菜单显示所有五种 hook 类型:`command`、`prompt`、`agent`、`http` 和 `mcp_tool`。每个 hook 都标有 `[type]` 前缀和指示其定义位置的源:752菜单显示所有五种 hook 类型:`command`、`prompt`、`agent`、`http` 和 `mcp_tool`。每个 hook 都标有 `[type]` 前缀和指示其定义位置的源:
610 753
611* `User`:来自 `~/.claude/settings.json`754* `User Settings`:来自 `~/.claude/settings.json`
612* `Project`:来自 `.claude/settings.json`755* `Project Settings`:来自 `.claude/settings.json`
613* `Local`:来自 `.claude/settings.local.json`756* `Local Settings`:来自 `.claude/settings.local.json`
614* `Plugin`:来自插件的 `hooks/hooks.json`757* `Plugin Hooks`:来自插件的 `hooks/hooks.json`
615* `Session`:在当前会话中在内存中注册758* `Session Hooks`:在当前会话中在内存中注册
616* `Built-in`:由 Claude Code 内部注册
617 759
618选择 hook 会打开详细视图,显示其事件、匹配器、类型、源文件以及完整的命令、提示或 URL。菜单是只读的:要添加、修改或移除 hooks,请直接编辑设置 JSON 或要求 Claude 进行更改。760选择 hook 会打开详细视图,显示其事件、匹配器、类型、源文件以及完整的命令、提示或 URL。菜单是只读的:要添加、修改或移除 hooks,请直接编辑设置 JSON 或要求 Claude 进行更改。
619 761
623 765
624要移除 hook,请从设置 JSON 文件中删除其条目。766要移除 hook,请从设置 JSON 文件中删除其条目。
625 767
626要临时禁用所有 hooks 而不移除它们,请在设置文件中设置 `"disableAllHooks": true`。没有办法在保持 hook 在配置中的同时禁用单个 hook。768要临时禁用所有 hooks 而不移除它们,请在设置文件中设置 `"disableAllHooks": true`。Claude Code 读取[设置优先级](/docs/zh-CN/settings#settings-precedence)应用后留下的值,因此项目的 `.claude/settings.json` 中的 `"disableAllHooks": false` 覆盖您的用户设置中的 `true`。要关闭一次运行,无论项目的设置说什么,请传递 `--settings '{"disableAllHooks": true}'`,这优先于项目和本地设置。没有办法在保持 hook 在配置中的同时禁用单个 hook。
627 769
628`disableAllHooks` 设置遵守托管设置层次结构。如果管理员通过托管策略设置配置了 hooks,则在用户、项目或本地设置中设置的 `disableAllHooks` 无法禁用这些托管 hooks。仅在托管设置级别设置的 `disableAllHooks` 可以禁用托管 hooks。770`disableAllHooks` 设置遵守托管设置层次结构。如果管理员通过托管策略设置配置了 hooks,则在用户、项目或本地设置中设置的 `disableAllHooks` 无法禁用这些托管 hooks。仅在托管设置级别设置的 `disableAllHooks` 可以禁用托管 hooks。对于每个级别的完整范围,请参阅[`disableAllHooks`](/docs/zh-CN/settings-reference#disableallhooks)。
629 771
630对设置文件中 hooks 的直接编辑通常由文件监视程序自动拾取。772对设置文件中 hooks 的直接编辑通常由文件监视程序自动拾取。
631 773
633 Hook 输入和输出775 Hook 输入和输出
634</h2>776</h2>
635 777
636命令 hooks 通过 stdin 接收 JSON 数据,并通过退出代码、stdout 和 stderr 传回结果。HTTP hooks 接收相同的 JSON 作为 POST 请求体,并通过 HTTP 响应体传回结果。本部分涵盖所有事件通用的字段和行为。每个事件在[Hook 事件](#hook-events)下的部分包括其特定的输入架构和决定控制选项。778命令 hook 通过 stdin 接收 JSON 数据,并通过退出代码、stdout 和 stderr 传达结果。HTTP hook 接收与 POST 请求体相同的 JSON,并通过 HTTP 响应体传达结果。本节涵盖所有事件通用的字段和行为。[Hook 事件](#hook-events)下的每个事件部分包括其特定的输入架构和决策控制选项。
779
780在 macOS 和 Linux 上,命令 hook 在没有控制终端的自己的会话中运行。hook 进程和任何子进程无法打开 `/dev/tty` 或直接向 Claude Code 界面发送转义序列。Windows 没有 `/dev/tty`。
637 781
638从 v2.1.139 开始,在 macOS 和 Linux 上,命令 hooks 在没有控制终端的自己的会话中运行。hook 进程和任何子进程无法打开 `/dev/tty` 或直接向 Claude Code 界面发送转义序列。Windows 没有 `/dev/tty`。要在任何平台上向用户显示消息,请在 JSON 输出中返回[`systemMessage`](#json-output)。要触发桌面通知、设置窗口标题或响铃,请改为返回[`terminalSequence`](#emit-terminal-notifications)。782要在任何平台上向用户显示消息,请在 JSON 输出中返回 [`systemMessage`](#json-output)。某些事件会丢弃它或将其传递到其他地方,每个[事件部分](#hook-events)都会说明这一点。要触发桌面通知、设置窗口标题或响铃,请改为返回 [`terminalSequence`](#emit-terminal-notifications)。
639 783
640<h3 id="common-input-fields">784<h3 id="common-input-fields">
641 通用输入字段785 通用输入字段
642</h3>786</h3>
643 787
644Hook 事件接收这些字段作为 JSON,除了每个[hook 事件](#hook-events)部分中记录的事件特定字段。对于命令 hooks,此 JSON 通过 stdin 到达。对于 HTTP hooks,它作为 POST 请求体到达。788Hook 事件接收这些字段作为 JSON,除了每个 [hook 事件](#hook-events)部分中记录的事件特定字段。对于命令 hook,此 JSON 通过 stdin 到达。对于 HTTP hook,它作为 POST 请求体到达。
645 789
646| 字段 | 描述 |790| 字段 | 描述 |
647| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |791| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
648| `session_id` | 当前会话标识符 |792| `session_id` | 当前会话标识符 |
649| `prompt_id` | UUID 标识当前正在处理的用户提示。与 OpenTelemetry 事件上的[`prompt.id` 属性](/docs/zh-CN/monitoring-usage#event-correlation-attributes)匹配,因此您可以将 hook 输出与单个提示的遥测关联起来。在第一个用户输入之前不存在。需要 Claude Code v2.1.196 或更高版本 |793| `prompt_id` | 标识当前正在处理的用户提示的 UUID。与 [OpenTelemetry 事件上的 `prompt.id` 属性](/docs/zh-CN/monitoring-usage#event-correlation-attributes)匹配,因此您可以将 hook 输出与单个提示的遥测关联起来。在第一个用户输入之前不存在。需要 Claude Code v2.1.196 或更高版本 |
650| `transcript_path` | 对话 JSON 的路径。成绩单文件异步写入,可能滞后于内存中的对话,因此当 hook 触发时,它可能还不包括当前轮次的最新消息。需要当前轮次最后助手文本的 hooks 应该在[Stop](#stop) 和 [SubagentStop](#subagentstop) 上使用 `last_assistant_message`,而不是读取成绩单 |794| `transcript_path` | 对话 JSON 的路径。转录文件异步写入,可能滞后于内存中的对话,因此当 hook 触发时,它可能还不包括当前轮次的最新消息。需要当前轮次最终助手文本的 hook 应在 [Stop](#stop) 和 [SubagentStop](#subagentstop) 上使用 `last_assistant_message`,而不是读取转录 |
651| `cwd` | 调用 hook 时的当前工作目录 |795| `cwd` | 调用 hook 时的当前工作目录 |
652| `permission_mode` | 当前[权限模式](/docs/zh-CN/permissions#permission-modes):`"default"`、`"plan"`、`"acceptEdits"`、`"auto"`、`"dontAsk"` 或 `"bypassPermissions"`。标记为**手动**的模式作为 `"default"` 到达,永远不会作为 `"manual"` 到达,因此匹配 `"default"` 的脚本继续工作。并非所有事件都接收此字段。检查每个[hook 事件](#hook-events)部分中的 JSON 示例 |796| `scratchpad_dir` | 会话的 scratchpad 目录的路径,Claude 在其中保存临时工作文件。当会话没有 scratchpad 或 temp 目录不可用时不存在。需要 Claude Code v2.1.257 或更高版本 |
653| `effort` | 对象,其中 `level` 字段保存该轮次的活跃[努力级别](/docs/zh-CN/model-config#adjust-effort-level):`"low"`、`"medium"`、`"high"`、`"xhigh"` 或 `"max"`。如果请求的模型努力级别超过当前模型支持的级别,这是模型实际使用的降级级别。Ultracode 不是一个不同的级别,报告为 `"xhigh"`。该对象与[状态行](/docs/zh-CN/statusline#available-data) `effort` 字段匹配。存在于在工具使用上下文中触发的事件中,例如 `PreToolUse`、`PostToolUse`、`Stop` 和 `SubagentStop`,当当前模型支持努力参数时。该级别也可作为 `$CLAUDE_EFFORT` 环境变量提供给 hook 命令和 Bash 工具。 |797| `permission_mode` | 当前[权限模式](/docs/zh-CN/permissions#permission-modes):`"default"`、`"plan"`、`"acceptEdits"`、`"auto"`、`"dontAsk"` 或 `"bypassPermissions"`。标记为**手动**的模式作为 `"default"` 到达,从不作为 `"manual"`,因此匹配 `"default"` 的脚本继续工作。并非所有事件都接收此字段。检查每个 [hook 事件](#hook-events)部分中的 JSON 示例 |
654| `hook_event_name` | 触发的事件名称 |798| `effort` | 对象,其 `level` 字段保存 hook 运行时生效的[工作量级别](/docs/zh-CN/model-config#adjust-effort-level):`"low"`、`"medium"`、`"high"`、`"xhigh"` 或 `"max"`。如果您设置了活跃模型不支持的级别,`level` 会报告 Claude Code 运行的级别;[调整工作量级别](/docs/zh-CN/model-config#adjust-effort-level)说明它如何选择该级别。Ultracode 不是一个不同的级别,报告为 `"xhigh"`。该对象与[状态行](/docs/zh-CN/statusline#available-data) `effort` 字段匹配。对于在工具使用上下文中触发的事件(如 `PreToolUse`、`PostToolUse`、`Stop` 和 `SubagentStop`),当当前模型支持工作量参数时存在。该级别也可作为 `$CLAUDE_EFFORT` 环境变量供 hook 命令和 Bash 工具使用。 |
799| `hook_event_name` | 触发的事件的名称 |
655 800
656使用 `--agent` 运行或在 subagent 内部时,包括两个额外字段:801使用 `--agent` 运行或在 subagent 内部时,包括两个额外字段:
657 802
658| 字段 | 描述 |803| 字段 | 描述 |
659| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |804| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
660| `agent_id` | Subagent 的唯一标识符。仅当 hook 在 subagent 调用内触发时存在。使用此来区分 subagent hook 调用和主线程调用。 |805| `agent_id` | subagent 的唯一标识符。仅当 hook 在 subagent 调用内触发时存在。使用此来区分 subagent hook 调用和主线程调用。 |
661| `agent_type` | 代理名称(例如,`"Explore"` 或 `"security-reviewer"`)。当会话使用 `--agent` 或 hook 在 subagent 内触发时存在。对于 subagents,subagent 的类型优先于会话的 `--agent` 值。对于[自定义 subagents](/docs/zh-CN/sub-agents),这是代理 frontmatter 中的 `name` 字段,而不是文件名。对于由[插件](/docs/zh-CN/plugins)提供的 subagents,这是插件范围的标识符,例如 `my-plugin:reviewer`,而不是裸 frontmatter 名称。请参阅[SubagentStart](#subagentstart)了解如何针对插件范围的名称编写匹配器。 |806| `agent_type` | Agent 名称(例如,`"Explore"` 或 `"security-reviewer"`)。当会话使用 `--agent` 或 hook 在 subagent 内触发时存在。对于 subagent,subagent 的类型优先于会话的 `--agent` 值。请参阅 [SubagentStart](#subagentstart) 了解自定义和插件 subagent 报告的值以及如何针对插件范围的名称编写匹配器。 |
807
808只有 [`SessionStart`](#sessionstart) hook 可以接收 `model` 字段,Claude Code 并不总是包括它。[`PreModelSwitch`](#premodelswitch) 和 [`PostModelSwitch`](#postmodelswitch) hook 改为接收 `from_model` 和 `to_model`,因此使用 PostModelSwitch hook 来跟踪模型在会话期间的变化。
809
810没有 `$CLAUDE_MODEL` 环境变量。如果您在 shell 中设置了 hook,可以读取 `$ANTHROPIC_MODEL`,但该值在您使用 `/model` 在会话期间切换模型时不会改变。
662 811
663仅[`SessionStart`](#sessionstart) hooks 可以接收 `model` 字段,且不保证存在。没有 `$CLAUDE_MODEL` 环境变量。Hook 进程继承父环境,因此如果您在 shell 中设置了 `$ANTHROPIC_MODEL`,它可以读取该值,但当您在会话期间使用 `/model` 切换模型时,该值不会改变。一组变量不被继承:Claude Code [从它生成的每个子进程中删除 `OTEL_*` 导出器变量](/docs/zh-CN/monitoring-usage#administrator-configuration),包括 hooks。812hook 进程继承父环境,除了 Claude Code [从它生成的每个子进程中删除](/docs/zh-CN/monitoring-usage#administrator-configuration)的 `OTEL_*` 导出器变量,以及当 [`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB`](/docs/zh-CN/env-vars#variables) 设置为 `1` 时它剥离的变量。
664 813
665例如,Bash 命令的 `PreToolUse` hook 在 stdin 上接收:814例如,Bash 命令的 `PreToolUse` hook 在 stdin 上接收以下内容:
666 815
667```json theme={null}816```json theme={null}
668{817{
670 "prompt_id": "550e8400-e29b-41d4-a716-446655440000",819 "prompt_id": "550e8400-e29b-41d4-a716-446655440000",
671 "transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",820 "transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
672 "cwd": "/home/user/my-project",821 "cwd": "/home/user/my-project",
822 "scratchpad_dir": "/tmp/claude-1000/-home-user-my-project/abc123/scratchpad",
673 "permission_mode": "default",823 "permission_mode": "default",
674 "hook_event_name": "PreToolUse",824 "hook_event_name": "PreToolUse",
675 "tool_name": "Bash",825 "tool_name": "Bash",
676 "tool_input": {826 "tool_input": {
677 "command": "npm test"827 "command": "npm test",
678 }828 "description": "Run test suite",
829 "timeout": 120000,
830 "run_in_background": false
831 },
832 "tool_use_id": "toolu_01ABC123..."
679}833}
680```834```
681 835
682`tool_name` 和 `tool_input` 字段是事件特定的。每个[hook 事件](#hook-events)部分记录了该事件的额外字段。836`tool_name`、`tool_input` 和 `tool_use_id` 字段是事件特定的。每个 [hook 事件](#hook-events)部分记录该事件的额外字段。
683 837
684<h3 id="exit-code-output">838<h3 id="exit-code-output">
685 退出代码输出839 退出代码输出
686</h3>840</h3>
687 841
688您的 hook 命令的退出代码告诉 Claude Code 操作是否应该继续、被阻止或被忽略。842来自 hook 命令的退出代码告诉 Claude Code 该操作是否应继续、被阻止或被忽略。退出代码不单独起作用。Claude Code 从 stdout 读取[JSON 输出字段](#json-output),无论退出代码是什么,对于使用标准决策模型的事件,通过架构验证的解析对象与代码一起生效。退出 2 的阻止是 JSON 无法覆盖的唯一结果。
689 843
690**退出 0** 表示成功。Claude Code 解析 stdout 以获取[JSON 输出字段](#json-output)。JSON 输出仅在退出 0 时处理。对于大多数事件,stdout 被写入调试日志,但不显示在成绩单中。例外是 `UserPromptSubmit`、`UserPromptExpansion` 和 `SessionStart`,其中 stdout 作为 Claude 可以看到和作用的上下文添加。844两个表拥有每个事件的例外:[每个事件的退出代码 2 行为](#exit-code-2-behavior-per-event)说明退出代码对每个事件的作用,[决策控制](#decision-control)说明每个事件接受哪些决策字段。通用字段如 `systemMessage` 在大多数事件中工作,并在 [JSON 输出](#json-output)表中列出。
691 845
692**退出 2** 表示阻止错误。Claude Code 忽略 stdout 和其中的任何 JSON。相反,stderr 文本被反馈给 Claude 作为错误消息。效果取决于事件:`PreToolUse` 阻止工具调用,`UserPromptSubmit` 拒绝提示,等等。有关完整列表,请参阅[每个事件的退出代码 2 行为](#exit-code-2-behavior-per-event)。846<h4 id="exit-code-0">
847 退出代码 0
848</h4>
849
850退出 0 表示成功,是您打印 JSON 进行结构化控制时的预期退出代码。
851
852对于大多数事件,Claude Code 将 stdout 写入调试日志,不在转录中显示。例外是 `UserPromptSubmit`、`UserPromptExpansion`、`SessionStart` 和 `PostModelSwitch`,其中 Claude Code 添加纯文本 stdout 作为 Claude 可以看到和作用的上下文。
853
854Claude Code 是否将您的 stdout 读取为 [JSON 输出](#json-output)或纯文本取决于它如何开始和结束,忽略周围的空格:
693 855
694**任何其他退出代码** 是大多数 hook 事件的非阻止错误。成绩单显示 `<hook name> hook error` 通知,然后是 stderr 的第一行,因此您可以在不使用 `--debug` 的情况下识别原因。执行继续,完整的 stderr 被写入调试日志。856* **以 `{` 开始并以 `}` 结束**:Claude Code 将其解析为 JSON。当输出是两行或更多行,每行本身都解析为 JSON,且没有行是设置字段的 [JSON 输出](#json-output)对象时,Claude Code 将整个输出视为纯文本。当其中一行确实设置了字段时,整个输出是解析失败,如下所述。
857* **以 `{` 开始但不以 `}` 结束**:Claude Code 将其视为纯文本。
858* **以其他任何内容开始**:Claude Code 将其视为纯文本、JSON 数组或包含的引用 JSON 字符串。
695 859
696例如,一个 hook 命令脚本,阻止危险的 Bash 命令:860对于使用标准决策模型的事件,退出 0 且解析对象未通过架构验证是非阻止错误:操作继续,转录显示 `<hook name> hook error` 通知,带有验证消息。在任何退出代码(除 2 外)上都会发生相同情况,而[退出 2 仍然阻止](#exit-code-2)。
861
862对于使用标准决策模型的事件,当 Claude Code 尝试将您的 stdout 解析为 JSON 且无法解析时,它在除 2 外的每个退出代码上报告非阻止错误。转录显示 `<hook name> hook error` 通知,带有解析消息。在添加纯文本 stdout 作为上下文的事件上,Claude Code 不添加文本。在 v2.1.248 之前,Claude Code 将该 stdout 视为纯文本。
863
864来自退出 0 的 hook 的 Stderr 仅进入调试日志,从不进入转录,Claude 从不看到它。要自己读取它,请启用[调试日志](#debug-hooks)。要从 `PostToolUse` 或 `PostToolUseFailure` hook 向 Claude 显示警告,请改为退出 2,以便[Claude 看到 stderr](#exit-code-2-behavior-per-event),即使工具已经运行。
865
866<h4 id="exit-code-2">
867 退出代码 2
868</h4>
869
870退出 2 表示阻止错误。在[可以阻止的事件](#exit-code-2-behavior-per-event)上,退出 2 无论您是否打印 JSON 都会阻止:即使 JSON `permissionDecision` 为 `"allow"` 也无法覆盖它。Claude Code 仍然读取 stdout 上的任何有效 [JSON 输出](#json-output)。在 `Elicitation` 和 `ElicitationResult` 上,退出 2 hook 的 `hookSpecificOutput` 被忽略。
871
872阻止消息是您的 JSON 的阻止决策的原因(当它做出一个时),否则是您的 stderr 文本。阻止做什么因事件而异:`PreToolUse` 阻止工具调用,`UserPromptSubmit` 拒绝提示,等等。[每个事件的退出代码 2 行为](#exit-code-2-behavior-per-event)列出每个事件的效果,每个事件的部分说明消息去向。
873
874退出 2 的 hook 同时打印 JSON 且未通过 [JSON 输出](#json-output)架构验证仍然阻止:Claude Code 使用 stderr 作为阻止原因,并在调试日志中记录验证失败。在 v2.1.214 之前,Claude Code 将该组合视为非阻止错误,操作继续。
875
876此脚本通过退出 2 阻止 `rm` 命令,并将所有其他命令留给正常权限流:
697 877
698```bash theme={null}878```bash theme={null}
699#!/bin/bash879#!/bin/bash
700# 从 stdin 读取 JSON 输入,检查命令880# Reads JSON input from stdin, checks the command
701command=$(jq -r '.tool_input.command' < /dev/stdin)881input=$(cat)
882command=$(jq -r '.tool_input.command' <<<"$input")
702 883
703if [[ "$command" == rm* ]]; then884if [[ "$command" == rm* ]]; then
704 echo "Blocked: rm commands are not allowed" >&2885 echo "Blocked: rm commands are not allowed" >&2
705 exit 2 # 阻止错误:工具调用被阻止886 exit 2 # Blocking error: tool call is prevented
706fi887fi
707 888
708exit 0 # 无决定:正常权限流程适用889exit 0 # No decision: the normal permission flow applies
709```890```
710 891
892<h4 id="other-exit-codes">
893 其他退出代码
894</h4>
895
896任何其他退出代码对于大多数 hook 事件本身不会阻止。发生什么取决于您的 stdout:
897
898* 使用通过架构验证的解析对象,对于使用标准决策模型的事件,Claude Code 忽略退出代码,JSON 单独决定结果:
899 * 事件支持的每个字段都被接受,包括 `permissionDecision`、`additionalContext`、`updatedInput` 和 `systemMessage`,hook 不被报告为错误。
900 * [决策控制](#decision-control)列出每个事件的决策字段;通用字段如 `systemMessage` 遵循 [JSON 输出](#json-output)表。
901* 使用未通过架构验证的解析对象,对于使用标准决策模型的事件,它与[退出 0 上](#exit-code-0)相同的非阻止错误:操作继续,`<hook name> hook error` 通知带有验证消息。
902* 使用 Claude Code [尝试解析为 JSON](#exit-code-0)且无法解析的 stdout,Claude Code 报告与退出 0 上相同的非阻止错误,用于使用标准决策模型的事件。操作继续,通知带有解析消息。
903* 使用 Claude Code [视为纯文本](#exit-code-0)的 stdout,或使用空 stdout,对于大多数 hook 事件是非阻止错误:操作继续,转录显示 `<hook name> hook error` 通知,后跟 stderr 的第一行,前缀为 `Failed with non-blocking status code:`。要捕获完整 stderr,请启用[调试日志](#debug-hooks)。
904
905标准决策模型之外的事件在[每个事件表](#exit-code-2-behavior-per-event)中保持自己的行:`WorktreeCreate` 在任何非零退出时失败创建,无论您的 JSON 说什么,事件丢弃 hook 输出(如 `StopFailure`)在每个退出代码上忽略您的 JSON,除了副作用字段如 `terminalSequence`,它仍然触发。
906
907无法启动的 hook 落入相同的非阻止桶。当脚本路径不存在或不可执行时,shell 以代码(如 127)退出,您看到相同的通知,带有解释器的消息,例如 `Failed with non-blocking status code: /bin/sh: /path/to/hook.sh: No such file or directory`。对于大多数 hook 事件,操作继续。当您设置策略 hook 时,在其第一次运行时观察此通知:`settings.json` 中的拼写错误的路径使门无声地禁用。
908
711<Warning>909<Warning>
712 对于大多数 hook 事件,仅退出代码 2 阻止操作。Claude Code 将退出代码 1 视为非阻止错误并继续操作,尽管 1 是传统的 Unix 失败代码。如果您的 hook 旨在强制执行策略,请使用 `exit 2`。例外是 `WorktreeCreate`,其中任何非零退出代码都会中止 worktree 创建。910 对于大多数 hook 事件,退出代码 2 是唯一通过代码单独阻止的退出代码。没有 stdout 上的有效 JSON,Claude Code 将退出代码 1 视为非阻止错误并继续操作,即使 1 是传统的 Unix 失败代码。如果您的 hook 旨在强制执行策略,请使用 `exit 2`。worktree 事件不同:来自 `WorktreeCreate` 的任何非零退出代码中止 worktree 创建,来自 `WorktreeRemove` 的任何非零退出代码使 worktree 移除失败(如果目录仍然存在)。
713</Warning>911</Warning>
714 912
913<h4 id="timeouts">
914 超时
915</h4>
916
917除了您使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook,Claude Code 取消达到其 [`timeout`](#common-fields) 的 `command`、`http` 或 `mcp_tool` hook,丢弃 hook 的输出,因此在大多数事件上超时的 hook 不呈现决策。
918
919在 [`PreModelSwitch`](#premodelswitch) 上,在其超时处取消的 hook 阻止模型切换。在 `PreToolUse` 上,两个 hook 系列不同:
920
921* 超时的 `command`、`http` 或 `mcp_tool` hook 不阻止工具调用。调用通过正常[权限流](/docs/zh-CN/permissions)继续,因此不要指望停滞的 hook 充当门。
922* 超过其超时的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) [阻止工具调用](#pretooluse)。
923
715<h4 id="exit-code-2-behavior-per-event">924<h4 id="exit-code-2-behavior-per-event">
716 每个事件的退出代码 2 行为925 每个事件的退出代码 2 行为
717</h4>926</h4>
718 927
719退出代码 2 是 hook 发出"停止,不要这样做"的方式。效果取决于事件,因为某些事件代表可以被阻止的操作(如尚未发生的工具调用),而其他事件代表已经发生或无法防止的事情。928退出代码 2 是 hook 发出"停止,不要这样做"信号的方式。效果取决于事件,因为某些事件代表可以被阻止的操作(如尚未发生的工具调用),而其他事件代表已经发生或无法防止的事情。
720 929
721| Hook 事件 | 可以阻止? | 退出 2 时发生的情况 |930| Hook 事件 | 可以阻止? | 退出 2 时发生什么 |
722| :-------------------- | :---- | :------------------------------------------------------------------------- |931| :-------------------- | :---- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
723| `PreToolUse` | 是 | 阻止工具调用 |932| `PreToolUse` | 是 | 阻止工具调用 |
724| `PermissionRequest` | 是 | 拒绝权限 |933| `PermissionRequest` | 否 | 此事件不接受退出代码 2,权限流程保持不变。改为通过 [`decision` 对象](#permissionrequest-decision-control)拒绝 |
725| `UserPromptSubmit` | 是 | 阻止提示处理并从上下文中删除提示 |934| `UserPromptSubmit` | 是 | 阻止提示处理并删除提示 |
726| `UserPromptExpansion` | 是 | 阻止扩展 |935| `UserPromptExpansion` | 是 | 阻止扩展 |
727| `Stop` | 是 | 防止 Claude 停止,继续对话 |936| `Stop` | 是 | 防止 Claude 停止,继续对话 |
728| `SubagentStop` | 是 | 防止 subagent 停止 |937| `SubagentStop` | 是 | 防止 subagent 停止 |
729| `TeammateIdle` | 是 | 防止队友空闲(队友继续工作) |938| `TeammateIdle` | 是 | 防止队友空闲,因此它继续工作 |
730| `TaskCreated` | 是 | 回滚任务创建 |939| `TaskCreated` | 是 | 回滚任务创建 |
731| `TaskCompleted` | 是 | 防止任务被标记为已完成 |940| `TaskCompleted` | 是 | 防止任务被标记为已完成 |
732| `ConfigChange` | 是 | 阻止配置更改生效(除了 `policy_settings`) |941| `ConfigChange` | 是 | 阻止配置更改生效(除 `policy_settings` 外) |
733| `StopFailure` | 否 | 输出和退出代码被忽略 |942| `StopFailure` | 否 | 输出和退出代码被忽略,除 `terminalSequence` 外 |
734| `PostToolUse` | 否 | 向 Claude 显示 stderr(工具已运行) |943| `PostToolUse` | 否 | 向 Claude 显示 stderr;工具已经运行 |
735| `PostToolUseFailure` | 否 | 向 Claude 显示 stderr(工具已失败) |944| `PostToolUseFailure` | 否 | 向 Claude 显示 stderr;工具已经失败 |
736| `PostToolBatch` | 是 | 在下一个模型调用之前停止代理循环 |945| `PostToolBatch` | 是 | 在下一个模型调用之前停止代理循环 |
737| `PermissionDenied` | 否 | 退出代码和 stderr 被忽略(拒绝已发生)。使用 JSON `hookSpecificOutput.retry: true` 告诉模型它可能重试 |946| `PermissionDenied` | 否 | 退出代码和 stderr 被忽略,因为拒绝已经发生。使用 JSON `hookSpecificOutput.retry: true` 告诉模型它可能重试;Claude Code 对[无判决拒绝](#permissiondenied-decision-control)忽略 `retry: true` |
738| `Notification` | 否 | 仅向用户显示 stderr |947| `Notification` | 否 | 退出代码和 stderr 被忽略 |
739| `SubagentStart` | 否 | 仅向用户显示 stderr |948| `SubagentStart` | 否 | 仅向用户显示 stderr |
740| `SessionStart` | 否 | 仅向用户显示 stderr |949| `SessionStart` | 否 | 仅向用户显示 stderr |
741| `Setup` | 否 | 仅向用户显示 stderr |950| `Setup` | 否 | 退出代码和 stderr 被忽略 |
742| `SessionEnd` | 否 | 仅向用户显示 stderr |951| `SessionEnd` | 否 | 仅向用户显示 stderr |
743| `CwdChanged` | 否 | 仅向用户显示 stderr |952| `CwdChanged` | 否 | 仅向用户显示 stderr |
953| `DirectoryAdded` | 否 | Stderr 进入调试日志;目录已经添加 |
744| `FileChanged` | 否 | 仅向用户显示 stderr |954| `FileChanged` | 否 | 仅向用户显示 stderr |
745| `PreCompact` | 是 | 阻止压缩 |955| `PreCompact` | 是 | 阻止压缩 |
746| `PostCompact` | 否 | 仅向用户显示 stderr |956| `PostCompact` | 否 | 仅向用户显示 stderr |
747| `Elicitation` | 是 | 拒绝 elicitation |957| `PreModelSwitch` | 是 | 阻止模型切换并向用户显示 stderr |
748| `ElicitationResult` | 是 | 阻止响应(操作变为 decline) |958| `PostModelSwitch` | 否 | 仅向用户显示 stderr;模型已经切换 |
749| `WorktreeCreate` | 是 | 任何非零退出代码都会导致 worktree 创建失败 |959| `Elicitation` | 是 | 拒绝引出 |
750| `WorktreeRemove` | 否 | 失败仅在调试模式下记录 |960| `ElicitationResult` | 是 | 阻止响应(操作变为拒绝) |
961| `WorktreeCreate` | 是 | 任何非零退出代码导致 worktree 创建失败 |
962| `WorktreeRemove` | 是 | 任何非零退出代码导致 worktree 移除失败(如果目录仍然存在)。请参阅 [WorktreeRemove](#worktreeremove) 了解目录发生什么 |
751| `InstructionsLoaded` | 否 | 退出代码被忽略 |963| `InstructionsLoaded` | 否 | 退出代码被忽略 |
752| `MessageDisplay` | 否 | 显示原始文本 |964| `MessageDisplay` | 否 | 显示原始文本 |
753 965
754对于 `SessionStart`、`Setup` 和 `SubagentStart`,退出代码 2 stderr 在成绩单中呈现为 `<hook name> hook error` 通知,与[非阻止错误](#exit-code-output)的方式相同。Claude 看不到它,会话或 subagent 继续进行。对于 `SubagentStart`,通知出现在 subagent 自己的成绩单中,而不是在父对话中。966对于 `SessionStart`、`SubagentStart` 和 `PostModelSwitch`,Claude Code 在转录中呈现退出代码 2 stderr 作为 `<hook name> hook error` 通知,与呈现[非阻止错误](#exit-code-output)的方式相同。Claude 看不到它,会话或 subagent 继续。对于 `SubagentStart`,通知出现在 subagent 自己的转录中,而不是在父对话中。
755
756从 Claude Code v2.1.199 开始,`SessionStart`、`Setup` 和 `SubagentStart` 在成绩单中显示退出代码 2 stderr。早期版本仅将其写入调试日志。
757 967
758<h3 id="http-response-handling">968<h3 id="http-response-handling">
759 HTTP 响应处理969 HTTP 响应处理
760</h3>970</h3>
761 971
762HTTP hooks 使用 HTTP 状态代码和响应体而不是退出代码和 stdout:972HTTP hook 使用 HTTP 状态代码和响应体而不是退出代码和 stdout。下面的结果适用于大多数事件;在[每个事件表](#exit-code-2-behavior-per-event)中有自己的失败合约的事件(如 `WorktreeCreate`)将该合约应用于失败的 HTTP hook:
763 973
764* **2xx 带空体**:成功,等同于退出代码 0 且无输出974* **2xx 且空体**:成功,等同于退出代码 0 且无输出
765* **2xx 带纯文本体**:成功,文本作为上下文添加975* **2xx 且 JSON 对象体**:使用与命令 hook 相同的 [JSON 输出](#json-output)架构解析。未通过架构验证的体是非阻止错误
766* **2xx 带 JSON 体**:成功,使用与命令 hooks 相同的[JSON 输出](#json-output)架构解析976* **2xx 且任何其他体,如纯文本**:非阻止错误,处理方式与非 2xx 状态相同。Claude Code 不将文本添加到 Claude 的上下文
767* **非 2xx 状态**:非阻止错误,执行继续977* **非 2xx 状态**:非阻止错误,执行继续
768* **连接失败或超时**:非阻止错误,执行继续978* **连接失败**:非阻止错误,执行继续
979* **超时**:hook 被取消,如 [Timeouts](#timeouts) 下所述
769 980
770与命令 hooks 不同,HTTP hooks 无法仅通过状态代码发出阻止错误信号。要阻止工具调用或拒绝权限,返回 2xx 响应,其 JSON 体包含适当的决定字段。981与命令 hook 不同,HTTP hook 无法仅通过状态代码发出阻止错误信号。要阻止工具调用或拒绝权限,返回 2xx 响应,其 JSON 体包含适当的决策字段。
771 982
772<h3 id="json-output">983<h3 id="json-output">
773 JSON 输出984 JSON 输出
774</h3>985</h3>
775 986
776退出代码让您允许或阻止,但 JSON 输出提供更细粒度的控制。与其使用代码 2 退出来阻止,不如退出 0 并将 JSON 对象打印到 stdout。Claude Code 从该 JSON 读取特定字段以控制行为,包括[决定控制](#decision-control)以阻止、允许或升级给用户。987退出代码只让您阻止或保持沉默,但 JSON 输出给您更细粒度的控制。与其退出代码 2 来阻止,不如退出 0 并将 JSON 对象打印到 stdout。Claude Code 从该 JSON 读取特定字段来控制行为,包括[决策控制](#decision-control)来阻止、允许或升级给用户。
777 988
778<Note>989<Note>
779 您必须为每个 hook 选择一种方法,而不是两种:要么单独使用退出代码进行信号传递,要么退出 0 并打印 JSON 以进行结构化控制。Claude Code 仅在退出 0 时处理 JSON。如果您退出 2,任何 JSON 都会被忽略。990 每个 hook 选择一种方法:要么单独使用退出代码进行信号,要么退出 0 并打印 JSON 进行结构化控制。如果您混合它们,退出 2 保持其[阻止效果](#exit-code-2-behavior-per-event),Claude Code 仍然读取 JSON 字段,除了 [Exit code 2](#exit-code-2) 下注明的一个引出例外。
780</Note>991</Note>
781 992
782您的 hook 的 stdout 必须仅包含 JSON 对象。如果您的 shell 配置文件在启动时打印文本,它可能会干扰 JSON 解析。请参阅故障排除指南中的[JSON 验证失败](/docs/zh-CN/hooks-guide#json-validation-failed)。993您的 hook 的 stdout 必须仅包含 JSON 对象。如果您的 shell 配置文件在启动时打印文本,它可能会干扰 JSON 解析。请参阅故障排除指南中的 [Hook JSON 无效](/docs/zh-CN/hooks-guide#hook-json-has-no-effect)。
783 994
784Hook 输出字符串,包括 `additionalContext`、`systemMessage` 和纯 stdout,上限为 10,000 个字符。超过此限制的输出被保存到文件并替换为预览和文件路径,与大型工具结果的处理方式相同。995hook 的 `additionalContext`、`systemMessage` 和 `initialUserMessage` 字符串,以及其纯 stdout,限制为 10,000 个字符:
996
997* **范围**:Claude Code 单独测量每个字符串,即使多个 hook 为同一事件运行。对于 JSON 输出,每个字段单独测量;纯 stdout 整体测量。
998* **超过限制**:Claude Code 将输出保存到会话目录中的文件,并用文件路径和最多前 2,000 个字符的预览替换它。大型有效 Bash 结果的处理方式相同,在 [Output limits](/docs/zh-CN/tools-reference#output-limits) 下描述。与该 Bash 上限不同,此上限没有设置或环境变量来提高它。
999* **读取文件**:Claude Code 不要求 Claude 读取文件,因此将 Claude 必须始终看到的任何内容保持在上限内。
785 1000
786JSON 对象支持三种字段:1001JSON 对象支持三种字段:
787 1002
788* **通用字段**,如 `continue`,在所有事件中工作。这些列在下表中。1003* **通用字段**如 `continue` 在下表中列出。每个事件都接受它们,但某些事件丢弃它们或将 `systemMessage` 传递到转录以外的地方。每个事件的部分说明这一点。`terminalSequence` 也在这些事件上工作,除了 [Emit terminal notifications](#emit-terminal-notifications) 下列出的例外。
789* **顶级 `decision` 和 `reason`** 由某些事件用于阻止或提供反馈。1004* **顶级 `decision` 和 `reason`** 由某些事件用来阻止或提供反馈。
790* **`hookSpecificOutput`** 是一个嵌套对象,用于需要更丰富控制的事件。它需要一个设置为事件名称的 `hookEventName` 字段。1005* **`hookSpecificOutput`** 是需要更丰富控制的事件的嵌套对象。它需要一个 `hookEventName` 字段设置为事件名称。
791 1006
792| 字段 | 默认 | 描述 |1007| 字段 | 默认 | 描述 |
793| :----------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------- |1008| :----------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
794| `continue` | `true` | 如果为 `false`,Claude 在 hook 运行后完全停止处理。优先于任何事件特定的决定字段 |1009| `continue` | `true` | 如果 `false`,Claude 在 hook 运行后完全停止处理。优先于任何事件特定的决策字段 |
795| `stopReason` | 无 | 当 `continue` 为 `false` 时向用户显示的消息。不向 Claude 显示 |1010| `stopReason` | 无 | 当 `continue` 为 `false` 时向用户显示的消息。它保留在对话中,因此如果对话继续,Claude 会看到它 |
796| `suppressOutput` | `false` | 如果为 `true`,从成绩单中隐藏 hook 的 stdout。Stdout 仍然出现在调试日志中 |1011| `suppressOutput` | `false` | 无效果:Claude Code 接受字段但不作用。成功的 hook 的 stdout 从不在转录中显示,并在调试日志中记录 |
797| `systemMessage` | 无 | 向用户显示的警告消息 |1012| `systemMessage` | 无 | 向用户显示的警告消息。在 [Agent SDK](/docs/zh-CN/agent-sdk/overview) 和 [`--output-format stream-json`](/docs/zh-CN/headless) 输出中,它可以作为 [`SDKInformationalMessage`](/docs/zh-CN/agent-sdk/typescript#sdkinformationalmessage) 到达 |
798| `terminalSequence` | 无 | Claude Code 代表您发出的终端转义序列,例如桌面通知、窗口标题或响铃。限制为 OSC `0`/`1`/`2`/`9`/`99`/`777` 和 BEL。如果值包含允许列表之外的任何内容,该字段将被忽略。使用此而不是写入 `/dev/tty`,这对 hooks 不可用 |1013| `terminalSequence` | 无 | Claude Code 代表您发出的终端转义序列,如桌面通知、窗口标题或响铃。限制为 OSC `0`/`1`/`2`/`9`/`99`/`777` 和 BEL。如果值包含允许列表外的任何内容,字段被忽略。使用此而不是写入 `/dev/tty`,这对 hook 不可用 |
799 1014
800要无论事件类型如何都完全停止 Claude:1015要完全停止 Claude:
801 1016
802```json theme={null}1017```json theme={null}
803{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }1018{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }
804```1019```
805 1020
1021对于 `PreToolUse` 和 `PostToolUse` hook,停止适用,即使工具调用失败或在 Claude 仍在流式传输响应时完成。
1022
806<h4 id="emit-terminal-notifications">1023<h4 id="emit-terminal-notifications">
807 发出终端通知1024 发出终端通知
808</h4>1025</h4>
809 1026
810`terminalSequence` 字段需要 Claude Code v2.1.141 或更高版本。1027Hook 运行时没有控制终端,因此直接写入转义序列到 `/dev/tty` 失败。改为在 `terminalSequence` 字段中返回转义序列,Claude Code 通过其自己的终端写入路径代表您发出它。这是无竞争的,在 tmux 和 GNU screen 内工作,并在 Windows 上工作,其中没有 `/dev/tty`。
811
812Hooks 运行时没有控制终端,因此直接向 `/dev/tty` 写入转义序列会失败。相反,在 `terminalSequence` 字段中返回转义序列,Claude Code 通过其自己的终端写入路径为您发出它。这是无竞争的,在 tmux 和 GNU screen 内工作,并在 Windows 上工作,其中没有 `/dev/tty`。
813 1028
814该字段接受一个或多个允许列表转义序列的字符串:1029该字段接受一个或多个允许列表转义序列的字符串:
815 1030
819* OSC `777`:urxvt、Ghostty 和 Warp 通知1034* OSC `777`:urxvt、Ghostty 和 Warp 通知
820* 裸 BEL1035* 裸 BEL
821 1036
822序列可以用 BEL 或 ST 终止。允许列表之外的任何内容,包括 CSI 光标和颜色序列、OSC 调色板序列、OSC 8 超链接、OSC 52 剪贴板写入和 OSC 1337,都会被拒绝,该字段将被忽略。1037序列可以用 BEL 或 ST 终止。允许列表外的任何内容,包括 CSI 光标和颜色序列、OSC 调色板序列、OSC 8 超链接、OSC 52 剪贴板写入和 OSC 1337,被拒绝,字段被忽略。
1038
1039Claude Code 在处理您的 hook 输出时写入序列本身,因此字段在丢弃 `systemMessage` 和 `continue` 的事件上工作,如 `Notification` 和 `StopFailure`。它有两个限制:
1040
1041* Claude Code 仅在交互式会话中写入序列,仅当其界面在屏幕上时。在使用 `-p` 标志的非交互式模式和 Agent SDK 中,它忽略字段。
1042* `WorktreeCreate` 命令 hook 无法返回 JSON,因为 Claude Code 将其 stdout 读取为 worktree 路径。HTTP `WorktreeCreate` hook 返回 JSON 并可以包括字段。
823 1043
824下面的示例从 `Notification` hook 触发桌面通知。转义序列使用 `printf` 八进制转义构建,因此控制字节永远不会出现在 shell 命令行上,`jq -n --arg` 构建 JSON 输出,因此通知消息中的引号、反斜杠和换行符被正确转义:1044下面的示例从 `Notification` hook 触发桌面通知。转义序列用 `printf` 八进制转义构建,因此控制字节从不出现在 shell 命令行上,`jq -n --arg` 构建 JSON 输出,因此通知消息中的引号、反斜杠和换行符被正确转义:
825 1045
826```bash theme={null}1046```bash theme={null}
827#!/bin/bash1047#!/bin/bash
828# Notification hook:当 Claude Code 需要注意时 ping 桌面。1048# Notification hook: ping the desktop when Claude Code needs attention.
829input=$(cat)1049input=$(cat)
830title="Claude Code'1050title="Claude Code"
831body=$(jq -r '.message // 'Needs your attention"' <<<"$input")1051body=$(jq -r '.message // "Needs your attention"' <<<"$input")
832seq=$(printf '\033]777;notify;%s;%s\007' "$title" "$body")1052seq=$(printf '\033]777;notify;%s;%s\007' "$title" "$body")
833jq -nc --arg seq "$seq" '{terminalSequence: $seq}'1053jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
834```1054```
835 1055
836`{ "terminalSequence": "..." }` 形状从任何 shell 或语言都相同。在 Windows 上,在 PowerShell 或脚本中构建转义字符串并发出相同的 JSON 对象。1056`{ "terminalSequence": "..." }` 形状从任何 shell 或语言都相同。
837
838<Note>
839 `terminalSequence` 是之前直接向 `/dev/tty` 写入转义序列的 hooks 的受支持替代品。允许列表限制为无法移动光标或改变颜色的序列,因此 hook 永远无法破坏屏幕上的提示。
840</Note>
841 1057
842<h4 id="add-context-for-claude">1058<h4 id="add-context-for-claude">
843 为 Claude 添加上下文1059 为 Claude 添加上下文
844</h4>1060</h4>
845 1061
846`additionalContext` 字段将来自您的 hook 的字符串传递到 Claude 的上下文窗口中。Claude Code 将字符串包装在系统提醒中,并将其插入到 hook 触发的对话点。Claude 在下一个模型请求时读取提醒,但它不会在界面中显示为聊天消息。1062`additionalContext` 字段将字符串从您的 hook 传递到 Claude 的上下文窗口。Claude Code 将字符串包装在系统提醒中,并在 hook 触发的点将其插入对话。Claude 在下一个模型请求时读取提醒,但它不作为聊天消息出现在界面中。
847 1063
848在 `hookSpecificOutput` 中返回 `additionalContext` 以及事件名称:1064在 `hookSpecificOutput` 中返回 `additionalContext` 以及事件名称:
849 1065
858 1074
859提醒出现的位置取决于事件:1075提醒出现的位置取决于事件:
860 1076
861* [SessionStart](#sessionstart)、[Setup](#setup) 和 [SubagentStart](#subagentstart):在对话开始,在第一个提示之前1077* [SessionStart](#sessionstart) 和 [SubagentStart](#subagentstart):在对话开始,在第一个提示之前
862* [UserPromptSubmit](#userpromptsubmit) 和 [UserPromptExpansion](#userpromptexpansion):与提交的提示一起1078* [UserPromptSubmit](#userpromptsubmit) 和 [UserPromptExpansion](#userpromptexpansion):与提交的提示一起
863* [PreToolUse](#pretooluse)、[PostToolUse](#posttooluse)、[PostToolUseFailure](#posttoolusefailure) 和 [PostToolBatch](#posttoolbatch):在工具结果旁边1079* [PreToolUse](#pretooluse)、[PostToolUse](#posttooluse)、[PostToolUseFailure](#posttoolusefailure) 和 [PostToolBatch](#posttoolbatch):在工具结果旁边
864* [Stop](#stop) 和 [SubagentStop](#subagentstop):在轮次末尾。对话继续,以便 Claude 可以对反馈采取行动。请参阅[Stop 决定控制](#stop-decision-control)1080* [Stop](#stop) 和 [SubagentStop](#subagentstop):在轮次末尾。对话继续,因此 Claude 可以对反馈采取行动。请参阅 [Stop decision control](#stop-decision-control)
1081* [PostModelSwitch](#postmodelswitch):与切换后的下一个请求一起。请参阅 [PostModelSwitch decision control](#postmodelswitch-decision-control) 了解时间
1082
1083当多个 hook 为同一事件返回 `additionalContext` 时,Claude 接收所有值。
865 1084
866当多个 hooks 为同一事件返回 `additionalContext` 时,Claude 接收所有值。如果值超过 10,000 个字符,Claude Code 将完整文本写入会话目录中的文件,并将 Claude 传递文件路径以及简短预览。1085如果值超过 10,000 个字符,Claude Code 将文本写入会话目录中的文件,并改为传递 Claude 文件路径,带有最多前 2,000 个字符的预览。Claude 可以读取文件,但 Claude Code 不要求它。
867 1086
868使用 `additionalContext` 来获取 Claude 应该了解的有关您的环境当前状态或刚刚运行的操作的信息:1087使用 `additionalContext` 获取 Claude 应该知道的关于您的环境当前状态或刚刚运行的操作的信息:
869 1088
870* **环境状态**:当前分支、部署目标或活跃的功能标志1089* **环境状态**:当前分支、部署目标或活跃功能标志
871* **条件项目规则**:哪个测试命令适用于刚刚编辑的文件,哪些目录在此 worktree 中是只读的1090* **条件项目规则**:哪个测试命令适用于刚编辑的文件,哪些目录在此 worktree 中是只读的
872* **外部数据**:分配给您的开放问题、最近的 CI 结果、从内部服务获取的内容1091* **外部数据**:分配给您的开放问题、最近的 CI 结果、从内部服务获取的内容
873 1092
874对于永不改变的说明,更倾向于[CLAUDE.md](/docs/zh-CN/memory)。它加载时无需运行脚本,是静态项目约定的标准位置。1093对于从不改变的说明,更喜欢 [CLAUDE.md](/docs/zh-CN/memory)。它加载而不运行脚本,是静态项目约定的标准位置。
875 1094
876将文本写成事实陈述而不是命令式系统指令。措辞如"部署目标是生产"或"此 repo 使用 `bun test`"读作项目信息。框架为带外系统命令的文本可能会触发 Claude 的提示注入防御,这会导致 Claude 将文本呈现给您,而不是将其视为上下文。1095将文本写成事实陈述而不是命令式系统说明。措辞如"部署目标是生产"或"此 repo 使用 `bun test`"读作项目信息。框架为带外系统命令的文本可以触发 Claude 的提示注入防御,这导致 Claude 向您显示文本而不是将其视为上下文。
877 1096
878一旦注入,文本就会保存在会话成绩单中。对于 `PostToolUse` 或 `UserPromptSubmit` 等中期事件,使用 `--continue` 或 `--resume` 恢复会重放保存的文本,而不是为过去的轮次重新运行 hook,因此时间戳或提交 SHA 等值在恢复时变得陈旧。`SessionStart` hooks 在使用 `source` 设置为 `"resume"` 的 `--resume` 恢复时再次运行,因此它们可以刷新其上下文。1097Claude Code 在会话转录中保存注入的文本。对于 `PostToolUse` 或 `UserPromptSubmit` 等中期会话事件,当您使用 `--continue` 或 `--resume` 恢复时,Claude Code 重放保存的文本而不是为过去的轮次重新运行 hook,因此时间戳或提交 SHA 等值变得陈旧。`SessionStart` hook 在使用 `source` 设置为 `"resume"` 或 `"fork"`(如果您添加了 `--fork-session`)恢复时再次运行,因此它们可以刷新其上下文。
879 1098
880<h4 id="decision-control">1099<h4 id="decision-control">
881 决定控制1100 决策控制
882</h4>1101</h4>
883 1102
884并非每个事件都支持通过 JSON 阻止或控制行为。支持的事件各自使用不同的字段集来表达该决定。在编写 hook 之前,使用此表作为快速参考:1103并非每个事件都支持通过 JSON 阻止或控制行为。支持的事件各自使用不同的字段集来表达该决策。在编写 hook 之前,使用此表作为快速参考:
885 1104
886| 事件 | 决定模式 | 关键字段 |1105| 事件 | 决策模式 | 关键字段 |
887| :-------------------------------------------------------------------------------------------------------------------------- | :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1106| :-------------------------------------------------------------------------------------------------------------------------- | :---------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
888| UserPromptSubmit、UserPromptExpansion、PostToolUse、PostToolUseFailure、PostToolBatch、Stop、SubagentStop、ConfigChange、PreCompact | 顶级 `decision` | `decision: "block"`、`reason`。Stop 和 SubagentStop 也接受 `hookSpecificOutput.additionalContext` 用于[继续对话的非错误反馈](#stop-decision-control) |1107| UserPromptSubmit、UserPromptExpansion、PostToolUse、PostToolUseFailure、PostToolBatch、Stop、SubagentStop、ConfigChange、PreCompact | 顶级 `decision` | `decision: "block"`、`reason`。Stop 和 SubagentStop 也接受 `hookSpecificOutput.additionalContext` 用于[继续对话的非错误反馈](#stop-decision-control) |
889| TeammateIdle、TaskCreated、TaskCompleted | 退出代码或 `continue: false` | 退出代码 2 使用 stderr 反馈阻止操作。JSON `{"continue": false, "stopReason": "..."}` 也会完全停止队友,匹配 `Stop` hook 行为 |1108| TeammateIdle、TaskCompleted | 退出代码或 `continue: false` | 退出代码 2 用 stderr 反馈阻止操作。JSON `{"continue": false, "stopReason": "..."}` 也完全停止队友,匹配 `Stop` hook 行为;[TaskCompleted 在 `TaskUpdate` 工具触发事件时忽略它](#taskcompleted-decision-control) |
1109| TaskCreated | 退出代码或顶级 `decision` | 退出代码 2 或 `decision: "block"` [取消任务](#taskcreated-decision-control)并将消息返回给 Claude。`continue: false` 被忽略 |
890| PreToolUse | `hookSpecificOutput` | `permissionDecision`(allow/deny/ask/defer)、`permissionDecisionReason` |1110| PreToolUse | `hookSpecificOutput` | `permissionDecision`(allow/deny/ask/defer)、`permissionDecisionReason` |
1111| PreModelSwitch | `hookSpecificOutput` 或顶级 `decision` | `permissionDecision`(allow/deny/ask)、`permissionDecisionReason`。`decision: "block"` 也[取消切换](#premodelswitch-decision-control) |
891| PermissionRequest | `hookSpecificOutput` | `decision.behavior`(allow/deny) |1112| PermissionRequest | `hookSpecificOutput` | `decision.behavior`(allow/deny) |
892| PermissionDenied | `hookSpecificOutput` | `retry: true` 告诉模型它可能重试被拒绝的工具调用 |1113| PermissionDenied | `hookSpecificOutput` | `retry: true` 告诉模型它可能重试被拒绝的工具调用;Claude Code 对[无判决拒绝](#permissiondenied-decision-control)忽略它 |
893| WorktreeCreate | 路径返回 | 命令 hook 在 stdout 上打印路径;HTTP hook 通过 `hookSpecificOutput.worktreePath` 返回。Hook 失败或缺少路径会导致创建失败 |1114| WorktreeCreate | 路径返回 | 命令 hook 在 stdout 上打印路径;HTTP hook 返回 `hookSpecificOutput.worktreePath`。Hook 失败或缺少路径失败创建 |
894| Elicitation | `hookSpecificOutput` | `action`(accept/decline/cancel)、`content`(form 字段值用于 accept) |1115| WorktreeRemove | 退出代码 | 任何非零退出代码使移除失败(如果目录仍然存在)。JSON 输出被丢弃 |
895| ElicitationResult | `hookSpecificOutput` | `action`(accept/decline/cancel)、`content`(form 字段值覆盖) |1116| Elicitation | `hookSpecificOutput` | `action`(accept/decline/cancel)、`content`(接受的表单字段值) |
896| MessageDisplay | `hookSpecificOutput` | `displayContent` 替换屏幕上显示的文本。仅显示:成绩单和 Claude 看到的内容保持原始 |1117| ElicitationResult | `hookSpecificOutput` | `action`(accept/decline/cancel)、`content`(表单字段值覆盖) |
897| SessionStart、Setup、SubagentStart | 仅上下文 | `hookSpecificOutput.additionalContext` 为 Claude 添加上下文。SessionStart 也接受[`initialUserMessage`、`watchPaths`、`sessionTitle` 和 `reloadSkills`](#sessionstart-decision-control)。无阻止或决定控制 |1118| MessageDisplay | `hookSpecificOutput` | `displayContent` 替换屏幕上显示的文本。仅显示:转录和 Claude 看到的保持原始 |
898| WorktreeRemove、Notification、SessionEnd、PostCompact、InstructionsLoaded、StopFailure、CwdChanged、FileChanged | 无 | 无决定控制。用于日志记录或清理等副作用 |1119| SessionStart、SubagentStart、PostModelSwitch | 仅上下文 | `hookSpecificOutput.additionalContext` 为 Claude 添加上下文。SessionStart 也接受 [`initialUserMessage`、`watchPaths`、`sessionTitle` 和 `reloadSkills`](#sessionstart-decision-control)。无阻止或决策控制 |
899 1120| Setup、Notification、SessionEnd、PostCompact、InstructionsLoaded、StopFailure、CwdChanged、DirectoryAdded、FileChanged | 无 | 无决策控制。用于日志或清理等副作用 |
900一些事件也可以重写内容而不仅仅允许或阻止它:1121
901 1122少数事件也可以重写内容而不仅仅允许或阻止它:
902* `PreToolUse`:`updatedInput` 直接在 `hookSpecificOutput` 下替换工具的参数,然后它运行。请参阅[PreToolUse 决定控制](#pretooluse-decision-control)1123
903* `PermissionRequest`:`updatedInput` 在 `decision` 对象内。请参阅[PermissionRequest 决定控制](#permissionrequest-decision-control)1124* `PreToolUse`:`updatedInput` 直接在 `hookSpecificOutput` 下替换工具的参数,然后它运行。请参阅 [PreToolUse decision control](#pretooluse-decision-control)
904* `PostToolUse`:`updatedToolOutput` 替换工具的结果。请参阅[PostToolUse 决定控制](#posttooluse-decision-control)1125* `PermissionRequest`:`updatedInput` 在 `decision` 对象内。请参阅 [PermissionRequest decision control](#permissionrequest-decision-control)
905* `UserPromptSubmit`:无法替换提示;仅在其旁边注入 `additionalContext`1126* `PostToolUse`:`updatedToolOutput` 替换工具的结果。请参阅 [PostToolUse decision control](#posttooluse-decision-control)
1127* `UserPromptSubmit`:无法替换提示;它仅在其旁边注入 `additionalContext`
906 1128
907对于编辑或转换用例,在 `PreToolUse` 处拦截出站工具输入,在 `PostToolUse` 处拦截入站工具结果。1129对于编辑或转换用例,在 `PreToolUse` 处拦截出站工具输入,在 `PostToolUse` 处拦截入站工具结果。
908 1130
909以下是每种模式的实际示例:1131以下是每种模式的实际示例:
910 1132
911<Tabs>1133<Tabs>
912 <Tab title="顶级决定">1134 <Tab title="顶级 decision">
913 由 `UserPromptSubmit`、`UserPromptExpansion`、`PostToolUse`、`PostToolUseFailure`、`PostToolBatch`、`Stop`、`SubagentStop`、`ConfigChange` 和 `PreCompact` 使用。唯一的值是 `"block"`。要允许操作继续,从您的 JSON 中省略 `decision`,或退出 0 而不带任何 JSON:1135 `decision` 的唯一值是 `"block"`。要允许操作继续,从您的 JSON 中省略 `decision`,或退出 0 而不带任何 JSON:
914 1136
915 ```json theme={null}1137 ```json theme={null}
916 {1138 {
921 </Tab>1143 </Tab>
922 1144
923 <Tab title="PreToolUse">1145 <Tab title="PreToolUse">
924 使用 `hookSpecificOutput` 以获得更丰富的控制:允许、拒绝或升级给用户。您还可以在运行前修改工具输入或为 Claude 注入额外上下文。有关完整的选项集,请参阅[PreToolUse 决定控制](#pretooluse-decision-control)。1146 使用 `hookSpecificOutput` 进行更丰富的控制:允许、拒绝或升级给用户。您也可以在运行前修改工具输入或为 Claude 注入额外上下文。请参阅 [PreToolUse decision control](#pretooluse-decision-control) 了解完整的选项集。
925 1147
926 ```json theme={null}1148 ```json theme={null}
927 {1149 {
935 </Tab>1157 </Tab>
936 1158
937 <Tab title="PermissionRequest">1159 <Tab title="PermissionRequest">
938 使用 `hookSpecificOutput` 代表用户允许或拒绝权限请求。允许时,您还可以修改工具的输入或应用权限规则,以便用户不会再次被提示。有关完整的选项集,请参阅[PermissionRequest 决定控制](#permissionrequest-decision-control)。1160 使用 `hookSpecificOutput` 代表用户允许或拒绝权限请求。允许时,您也可以修改工具的输入或应用权限规则,以便用户不会再次被提示。请参阅 [PermissionRequest decision control](#permissionrequest-decision-control) 了解完整的选项集。
939 1161
940 ```json theme={null}1162 ```json theme={null}
941 {1163 {
953 </Tab>1175 </Tab>
954</Tabs>1176</Tabs>
955 1177
956有关扩展示例,包括 Bash 命令验证、提示过滤和自动批准脚本,请参阅指南中的[您可以自动化的内容](/docs/zh-CN/hooks-guide#what-you-can-automate)以及[Bash 命令验证器参考实现](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)。1178有关扩展示例,包括 Bash 命令验证、提示过滤和自动批准脚本,请参阅指南中的 [What you can automate](/docs/zh-CN/hooks-guide#what-you-can-automate) 和 [Bash command validator reference implementation](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)。
957 1179
958<h2 id="hook-events">1180<h2 id="hook-events">
959 Hook 事件1181 Hook 事件
960</h2>1182</h2>
961 1183
962每个事件对应于 Claude Code 生命周期中 hooks 可以运行的一个点。下面的部分按照生命周期排序:从会话设置通过代理循环到会话结束。每个部分描述事件何时触发、它支持的匹配器、它接收的 JSON 输入以及如何通过输出控制行为。1184每个事件对应于 Claude Code 生命周期中的一个点,hooks 可以在该点运行。下面的部分按照生命周期顺序排列:从会话设置到 agentic 循环再到会话结束。每个部分描述事件何时触发、它支持的匹配器、它接收的 JSON 输入,以及如何通过输出控制行为。
963 1185
964<h3 id="sessionstart">1186<h3 id="sessionstart">
965 SessionStart1187 SessionStart
966</h3>1188</h3>
967 1189
968在 Claude Code 启动新会话或恢复现有会话时运行。用于加载开发上下文,如现有问题或代码库的最近更改,或设置环境变量。对于不需要脚本的静态上下文,请改用[CLAUDE.md](/docs/zh-CN/memory)。1190在 Claude Code 启动新会话或恢复现有会话时运行。对于加载开发上下文(如现有问题或代码库的最近更改)或设置环境变量很有用。对于不需要脚本的静态上下文,请改用 [CLAUDE.md](/docs/zh-CN/memory)。
969 1191
970SessionStart 在每个会话上运行,因此保持这些 hooks 快速。仅支持 `type: "command"` 和 `type: "mcp_tool"` hooks。1192SessionStart 在每个会话上运行,因此请保持这些 hooks 快速。仅支持 `type: "command"` 和 `type: "mcp_tool"` hooks。有关 `mcp_tool` hooks 何时运行,请参阅 [MCP tool hook 字段](#mcp-tool-hook-fields)。
971 1193
972匹配器值对应于会话的启动方式:1194匹配器值对应于会话的启动方式:
973 1195
974| 匹配器 | 何时触发 |1196| 匹配器 | 何时触发 |
975| :-------- | :---------------------------------- |1197| :-------- | :------------------------------------------------------------------------------- |
976| `startup` | 新会话 |1198| `startup` | 新会话 |
977| `resume` | `--resume`、`--continue` 或 `/resume` |1199| `resume` | `--resume`、`--continue` 或 `/resume` |
978| `clear` | `/clear` |1200| `clear` | `/clear` |
979| `compact` | 自动或手动压缩 |1201| `compact` | 自动或手动压缩 |
1202| `fork` | 从现有会话分叉的新会话:`--fork-session` 与 `--resume` 或 `--continue`、`/fork` 后台副本或 `/branch` |
1203
1204在 v2.1.214 之前,分叉的会话报告源为 `"resume"`。
1205
1206当您启动交互式会话、使用 `--continue` 或 `--resume` 在启动时恢复对话、或运行 `/clear` 时,SessionStart hooks 在后台运行。您可以立即输入,恢复的对话出现时无需等待 hooks。Claude 的第一个响应仍然等待 hooks 完成,因此它们的上下文到达 Claude。
1207
1208当您在会话内使用 `/resume` 切换对话时,切换等待 hooks 完成。如果您在后台 hooks 仍在运行时运行 `/clear` 或切换到另一个对话,它们返回的任何内容都不适用于会话。
1209
1210在启动时也适用相同的等待,包括恢复的会话:您在 SessionStart hooks 仍在运行时发送的提示不会到达 Claude,直到它们完成。
1211
1212在任一等待期间,按 `Esc` 将提示返回到输入中而不发送它。hooks 继续运行。
980 1213
981<h4 id="sessionstart-input">1214<h4 id="sessionstart-input">
982 SessionStart 输入1215 SessionStart 输入
983</h4>1216</h4>
984 1217
985除了[通用输入字段](#common-input-fields)外,SessionStart hooks 还接收 `source` 和可选的 `model`、`agent_type` 和 `session_title`:1218除了 [常见输入字段](#common-input-fields) 外,SessionStart hooks 还接收 `source` 和可选的 `model`、`agent_type` 和 `session_title`:
986 1219
987| 字段 | 描述 |1220| 字段 | 描述 |
988| :-------------- | :---------------------------------------------------------------------------------------------------- |1221| :-------------- | :------------------------------------------------------------------------------------------------------ |
989| `source` | 会话如何启动:新会话为 `"startup"`,恢复会话为 `"resume"`,`/clear` 后为 `"clear"`,压缩后为 `"compact"` |1222| `source` | 会话如何启动:新会话为 `"startup"`、恢复的会话为 `"resume"`、`/clear` 后为 `"clear"`、压缩后为 `"compact"`、或从现有会话分叉的新会话为 `"fork"` |
990| `model` | 活跃模型标识符。它可以被省略,例如在 `/clear` 后或当会话通过对话恢复恢复时,因此在读取字段前检查它 |1223| `model` | 活跃的模型标识符。例如在 `/clear` 后或通过对话恢复恢复会话时可能被省略,因此在读取前检查该字段 |
991| `agent_type` | 代理名称,当您使用 `claude --agent <name>` 启动 Claude Code 时存在 |1224| `agent_type` | agent 名称,当您使用 `claude --agent <name>` 启动 Claude Code 时出现 |
992| `session_title` | 当前会话标题(如果已设置),例如通过 `--name` 或 `/rename`。发出 `sessionTitle` 的 hook 可以先检查 `session_title` 以避免覆盖用户显式设置的标题 |1225| `session_title` | 当前会话标题(如果已设置),例如通过 `--name` 或 `/rename`。发出 `sessionTitle` 的 hook 可以先检查 `session_title` 以避免覆盖用户明确设置的标题 |
1226
1227当 `source` 为 `"resume"` 或 `"fork"` 且成绩单包含至少一个来自 Claude 的响应时,SessionStart hooks 也会接收下面的四个字段。您的 hook 可以使用它们来报告在第一个请求之前恢复陈旧对话的成本,例如在 [`systemMessage`](#json-output) 中。这些字段需要 Claude Code v2.1.251 或更高版本。
1228
1229| 字段 | 描述 |
1230| :---------------------------- | :--------------------------------------------------------------------------------------------- |
1231| `seconds_since_last_response` | 自恢复成绩单中最后一个响应以来的挂钟秒数 |
1232| `context_tokens` | 恢复会话的第一个请求作为其提示重新发送的令牌 |
1233| `prompt_cache_likely_expired` | 当最后一个响应早于会话的 [prompt cache 生命周期](/docs/zh-CN/prompt-caching#cache-lifetime) 或更晚的压缩替换了缓存的对话时为 `true` |
1234| `estimated_cache_write_usd` | 将 `context_tokens` 写入会话模型的 prompt cache 的估计成本(美元),不包括响应 |
1235
1236此示例显示了在最后一个响应后 90 分钟恢复的会话的输入:
993 1237
994```json theme={null}1238```json theme={null}
995{1239{
997 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",1241 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
998 "cwd": "/Users/...",1242 "cwd": "/Users/...",
999 "hook_event_name": "SessionStart",1243 "hook_event_name": "SessionStart",
1000 "source": "startup",1244 "source": "resume",
1001 "model": "claude-sonnet-5"1245 "model": "claude-opus-5",
1246 "seconds_since_last_response": 5400,
1247 "context_tokens": 182340,
1248 "prompt_cache_likely_expired": true,
1249 "estimated_cache_write_usd": 1.1396
1002}1250}
1003```1251```
1004 1252
1005<h4 id="sessionstart-decision-control">1253<h4 id="sessionstart-decision-control">
1006 SessionStart 决定控制1254 SessionStart 决策控制
1007</h4>1255</h4>
1008 1256
1009您的 hook 脚本打印到 stdout 的任何文本都作为 Claude 的上下文添加。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您还可以返回这些事件特定字段:1257Claude Code 将它 [视为纯文本](#exit-code-0) 的 stdout 添加到 Claude 的上下文中。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您还可以返回这些事件特定的字段:
1010 1258
1011| 字段 | 描述 |1259| 字段 | 描述 |
1012| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |1260| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
1013| `additionalContext` | 添加到 Claude 上下文开始处的字符串,在第一个提示之前。请参阅[为 Claude 添加上下文](#add-context-for-claude)了解文本如何传递、放入什么内容以及恢复的会话如何处理过去的值 |1261| `additionalContext` | 在对话开始时添加到 Claude 上下文的字符串,在第一个提示之前。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1014| `initialUserMessage` | 用作会话第一个用户消息的字符串。适用于[非交互模式](/docs/zh-CN/headless)(`-p`),其中即使未提供提示,它也成为第一个轮次。如果提供了提示,它作为下一个轮次跟随。与 `additionalContext` 不同,后者附加到现有轮次,这创建轮次 |1262| `initialUserMessage` | 用作会话第一个用户消息的字符串。适用于 [非交互模式](/docs/zh-CN/headless),带有 `-p` 标志,即使未提供提示,它也成为第一个回合。如果提供了提示,它作为下一个回合跟随。与 `additionalContext` 不同,后者附加到现有回合,这会创建回合 |
1015| `sessionTitle` | 设置会话标题,与 `/rename` 的效果相同。使用此根据启动文件夹、git 分支或 worktree 名称自动命名会话。仅在 `source` 为 `"startup"` 或 `"resume"` 时适用;在 `"clear"` 和 `"compact"` 上被忽略 |1263| `sessionTitle` | 设置会话标题,与 `/rename` 效果相同。用于从启动文件夹、git 分支或 worktree 名称自动命名会话。当 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时适用;在 `"clear"` 和 `"compact"` 上被忽略 |
1016| `watchPaths` | 绝对路径数组,用于在此会话期间监视[FileChanged](#filechanged)事件 |1264| `watchPaths` | 绝对路径数组,用于在此会话期间监视 [FileChanged](#filechanged) 事件 |
1017| `reloadSkills` | 布尔值。当为 `true` 时,Claude Code 在 SessionStart hooks 完成后重新扫描[skill](/docs/zh-CN/skills)和命令目录,因此 hook 安装的 skills 在同一会话中可用,从第一个提示开始 |1265| `reloadSkills` | 布尔值。当为 `true` 时,Claude Code 在 SessionStart hooks 完成后重新扫描 [skill](/docs/zh-CN/skills) 和命令目录,因此 hook 安装的 skills 在同一会话中可用,从第一个提示开始 |
1018 1266
1019```json theme={null}1267```json theme={null}
1020{1268{
1026}1274}
1027```1275```
1028 1276
1029由于纯 stdout 已经为此事件到达 Claude,仅加载上下文的 hook 可以直接打印到 stdout 而无需构建 JSON。当您需要将上下文与其他字段(如 `suppressOutput` 或 `sessionTitle`)结合时,使用 JSON 形式。1277由于纯 stdout 已经为此事件到达 Claude,仅加载上下文的 hook 可以直接打印到 stdout 而无需构建 JSON。当您需要将上下文与其他字段(如 `sessionTitle`)结合时,使用 JSON 形式。
1030 1278
1031当 SessionStart hook 安装或更新 skills 时使用 `reloadSkills`。Skill 发现通常在 SessionStart hooks 完成之前运行,因此 hook 写入 `~/.claude/skills/` 或 `.claude/skills/` 的文件否则只会在下一个会话中出现。此示例同步共享 skills 仓库并请求重新扫描:1279当 SessionStart hook 安装或更新 skills 时使用 `reloadSkills`。Skill 发现通常在 SessionStart hooks 完成之前运行,因此 hook 写入 `~/.claude/skills/` 或 `.claude/skills/` 的文件否则只会在下一个会话中出现。此示例同步共享 skills 存储库并请求重新扫描:
1032 1280
1033```bash theme={null}1281```bash theme={null}
1034#!/bin/bash1282#!/bin/bash
1039echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'1287echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'
1040```1288```
1041 1289
1290存储库 URL 是占位符;将其替换为您自己的 skills 存储库。使用占位符,克隆失败并打印 `fatal:` 消息到 stderr。来自以 0 退出的 SessionStart hook 的 Stderr 仅供参考,因此 `reloadSkills` 请求仍然适用。
1291
1042<h4 id="persist-environment-variables">1292<h4 id="persist-environment-variables">
1043 持久化环境变量1293 持久化环境变量
1044</h4>1294</h4>
1045 1295
1046SessionStart hooks 可以访问 `CLAUDE_ENV_FILE` 环境变量,该变量提供一个文件路径,您可以在其中为后续 Bash 命令持久化环境变量。1296SessionStart hooks 可以访问 `CLAUDE_ENV_FILE` 环境变量,它提供一个文件路径,您可以在其中为后续 Bash 命令持久化环境变量。
1047 1297
1048要设置单个环境变量,请将 `export` 语句写入 `CLAUDE_ENV_FILE`。使用追加(`>>`)来保留由其他 hooks 设置的变量:1298要设置单个环境变量,请将 `export` 语句写入 `CLAUDE_ENV_FILE`。使用追加 (`>>`) 来保留由其他 hooks 设置的变量:
1049 1299
1050```bash theme={null}1300```bash theme={null}
1051#!/bin/bash1301#!/bin/bash
1066 1316
1067ENV_BEFORE=$(export -p | sort)1317ENV_BEFORE=$(export -p | sort)
1068 1318
1069# 运行修改环境的设置命令1319# Run your setup commands that modify the environment
1070source ~/.nvm/nvm.sh1320source ~/.nvm/nvm.sh
1071nvm use 201321nvm use 20
1072 1322
1078exit 01328exit 0
1079```1329```
1080 1330
1081写入此文件的任何变量都将在会话期间 Claude Code 执行的所有后续 Bash 命令中可用。
1082
1083<Note>1331<Note>
1084 `CLAUDE_ENV_FILE` 可用于 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hooks。其他 hook 类型无法访问此变量。1332 `CLAUDE_ENV_FILE` 可用于 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hooks。其他 hook 类型无法访问此变量。
1085</Note>1333</Note>
1088 Setup1336 Setup
1089</h3>1337</h3>
1090 1338
1091仅当您使用 `--init-only` 启动 Claude Code,或在[非交互模式](/docs/zh-CN/headless)中使用 `-p` 标志与 `--init` 或 `--maintenance` 结合时触发。它不在正常启动时触发。使用它进行一次性依赖安装或您从 CI 或脚本显式触发的计划清理,与正常会话启动分开。对于每个会话的初始化,请改用[SessionStart](#sessionstart)。1339仅当您使用 `--init-only` 启动 Claude Code,或在 [非交互模式](/docs/zh-CN/headless) 中使用 `--init` 或 `--maintenance` 与 `-p` 标志时触发。它不会在正常启动时触发。用于一次性依赖安装或您从 CI 或脚本显式触发的计划清理,与正常会话启动分开。对于每个会话的初始化,请改用 [SessionStart](#sessionstart)。
1092 1340
1093匹配器值对应于触发 hook 的 CLI 标志:1341匹配器值对应于触发 hook 的 CLI 标志:
1094 1342
1097| `init` | `claude --init-only` 或 `claude -p --init` |1345| `init` | `claude --init-only` 或 `claude -p --init` |
1098| `maintenance` | `claude -p --maintenance` |1346| `maintenance` | `claude -p --maintenance` |
1099 1347
1100`--init-only` 运行 Setup hooks 和 SessionStart hooks(带 `startup` 匹配器),然后退出而不启动对话。`--init` 和 `--maintenance` 仅在与 `-p` 结合时触发 Setup hooks;在交互式会话中,这两个标志目前不触发 Setup hooks。1348当您运行 `claude --init-only` 时,Claude Code 运行 Setup hooks 和带有 `startup` 匹配器的 `SessionStart` hooks,然后退出而不启动对话。
1349
1350当您使用 `-p` 启动或继续对话时,您还需要提供提示,作为参数或通过 stdin 管道传输。当 `SessionStart` hook 提供 [`initialUserMessage`](#sessionstart-decision-control) 或当您使用 [延迟工具调用](#defer-a-tool-call-for-later) 恢复会话时,您可以跳过提示。
1351
1352成功时,`--init-only` 不向终端打印任何内容。要确认 hooks 运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,并检查日志中的 Setup 和 SessionStart hook 条目。
1101 1353
1102因为 Setup 不在每次启动时触发,需要安装依赖的插件不能仅依赖 Setup。实际的模式是在首次使用时检查依赖,如果缺失则安装,例如测试 `${CLAUDE_PLUGIN_DATA}/node_modules` 的 hook 或 skill,如果不存在则运行 `npm install`。请参阅[持久数据目录](/docs/zh-CN/plugins-reference#persistent-data-directory)了解在何处存储已安装的依赖。1354由于 Setup 不会在每次启动时触发,需要安装依赖的插件不能仅依赖 Setup。实际的模式是在首次使用时检查依赖,如果缺失则安装,例如测试 `${CLAUDE_PLUGIN_DATA}/node_modules` 的 hook 或 skill,如果不存在则运行 `npm install`。有关存储已安装依赖的位置,请参阅 [持久数据目录](/docs/zh-CN/plugins-reference#persistent-data-directory)。如果您通过市场分发插件,您可能不需要此模式:Claude Code [在缓存插件时自动安装符合条件的 Node.js 包依赖](/docs/zh-CN/plugins-reference#node-js-package-dependencies)。
1103 1355
1104<h4 id="setup-input">1356<h4 id="setup-input">
1105 Setup 输入1357 Setup 输入
1106</h4>1358</h4>
1107 1359
1108除了[通用输入字段](#common-input-fields)外,Setup hooks 还接收一个 `trigger` 字段,设置为 `"init"` 或 `"maintenance"`:1360除了 [常见输入字段](#common-input-fields) 外,Setup hooks 接收设置为 `"init"` 或 `"maintenance"` 的 `trigger` 字段:
1109 1361
1110```json theme={null}1362```json theme={null}
1111{1363{
1118```1370```
1119 1371
1120<h4 id="setup-decision-control">1372<h4 id="setup-decision-control">
1121 Setup 决定控制1373 Setup 决策控制
1122</h4>1374</h4>
1123 1375
1124Setup hooks 无法阻止。任何非零退出代码(包括 2)都会向用户显示 stderr 作为 `<hook name> hook error` 通知,执行继续。在[非交互模式](/docs/zh-CN/headless)中,hook 输出仅在您使用 `--verbose` 启动时出现。1376Setup hooks 无法阻止;执行在任何退出代码上继续。在每个退出代码上,Claude Code 丢弃 Setup hook 的 [JSON 输出字段](#json-output),如 `systemMessage`、`continue` 和 `hookSpecificOutput.additionalContext`。使用 `-p` 时,Setup hook 的 stdout、stderr 和退出代码仅在您使用 `--output-format stream-json --verbose` 启动时作为 [`hook_response` 事件](/docs/zh-CN/headless#read-session-metadata) 出现在运行的输出中。
1125
1126要将信息传入 Claude 的上下文,在 JSON 输出中返回 `additionalContext`;纯 stdout 仅写入调试日志。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您还可以返回这些事件特定字段:
1127
1128| 字段 | 描述 |
1129| :------------------ | :-------------------------------- |
1130| `additionalContext` | 添加到 Claude 上下文的字符串。多个 hooks 的值被连接 |
1131
1132```json theme={null}
1133{
1134 "hookSpecificOutput": {
1135 "hookEventName": "Setup",
1136 "additionalContext": "Dependencies installed: node_modules, .venv"
1137 }
1138}
1139```
1140 1377
1141Setup hooks 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量持久化到会话的后续 Bash 命令中,就像在[SessionStart hooks](#persist-environment-variables)中一样。仅支持 `type: "command"` 和 `type: "mcp_tool"` hooks。1378Setup hooks 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量持久化到会话的后续 Bash 命令中,就像在 [SessionStart hooks](#persist-environment-variables) 中一样。仅 `type: "command"` hooks 在 `Setup` 上运行。`type: "mcp_tool"` hook 在 `Setup` 上总是被跳过,如 [MCP tool hook 字段](#mcp-tool-hook-fields) 下所述。
1142 1379
1143<h3 id="instructionsloaded">1380<h3 id="instructionsloaded">
1144 InstructionsLoaded1381 InstructionsLoaded
1145</h3>1382</h3>
1146 1383
1147当 `CLAUDE.md` 或 `.claude/rules/*.md` 文件加载到上下文中时触发。此事件在会话启动时为急切加载的文件触发,稍后当文件被懒加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录或条件规则与 `paths:` frontmatter 匹配时。该 hook 不支持阻止或决定控制。它异步运行以用于可观测性目的。1384在加载 `CLAUDE.md` 或 `.claude/rules/*.md` 文件到上下文时触发。此事件在会话启动时对于急切加载的文件触发,稍后当文件被懒加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录或当带有 `paths:` frontmatter 的条件规则匹配时。hook 不支持阻止或决策控制。它异步运行用于可观测性目的。
1148 1385
1149匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅对会话启动时加载的文件触发,或使用 `"matcher": "path_glob_match|nested_traversal"` 仅对懒加载触发。1386当 Claude [直接通过 **Project instructions** 设置读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时它确实触发,`load_reason` 设置为 `include`(与任何其他导入文件一样),以及当 `CLAUDE.md` 是它的符号链接时,作为正常的 `CLAUDE.md` 加载。
1387
1388匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅对会话启动时加载的文件触发,或 `"matcher": "path_glob_match|nested_traversal"` 仅对懒加载触发。
1150 1389
1151<h4 id="instructionsloaded-input">1390<h4 id="instructionsloaded-input">
1152 InstructionsLoaded 输入1391 InstructionsLoaded 输入
1153</h4>1392</h4>
1154 1393
1155除了[通用输入字段](#common-input-fields)外,InstructionsLoaded hooks 还接收这些字段:1394除了 [常见输入字段](#common-input-fields) 外,InstructionsLoaded hooks 接收这些字段:
1156 1395
1157| 字段 | 描述 |1396| 字段 | 描述 |
1158| :------------------ | :--------------------------------------------------------------------------------------------------------------------------- |1397| :------------------ | :-------------------------------------------------------------------------------------------------------------------------- |
1159| `file_path` | 加载的指令文件的绝对路径 |1398| `file_path` | 加载的指令文件的绝对路径 |
1160| `memory_type` | 文件的范围:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |1399| `memory_type` | 文件的范围:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |
1161| `load_reason` | 文件被加载的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值在压缩事件后重新加载指令文件时触发 |1400| `load_reason` | 文件加载的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值在压缩事件后重新加载指令文件时触发 |
1162| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如果有)。仅对 `path_glob_match` 加载存在 |1401| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如果有)。仅对 `path_glob_match` 加载出现 |
1163| `trigger_file_path` | 触发此加载的文件的路径,用于懒加载 |1402| `trigger_file_path` | 触发此加载的文件的路径,用于懒加载 |
1164| `parent_file_path` | 包含此文件的父指令文件的路径,用于 `include` 加载 |1403| `parent_file_path` | 包含此文件的父指令文件的路径,用于 `include` 加载 |
1165 1404
1176```1415```
1177 1416
1178<h4 id="instructionsloaded-decision-control">1417<h4 id="instructionsloaded-decision-control">
1179 InstructionsLoaded 决定控制1418 InstructionsLoaded 决策控制
1180</h4>1419</h4>
1181 1420
1182InstructionsLoaded hooks 没有决定控制。它们无法阻止或修改指令加载。使用此事件进行审计日志记录、合规性跟踪或可观测性。1421InstructionsLoaded hooks 没有决策控制。它们无法阻止或修改指令加载。Claude Code 丢弃它们的 [JSON 输出字段](#json-output),如 `systemMessage` 和 `continue`。使用此事件进行审计日志、合规性跟踪或可观测性。
1183 1422
1184<h3 id="userpromptsubmit">1423<h3 id="userpromptsubmit">
1185 UserPromptSubmit1424 UserPromptSubmit
1186</h3>1425</h3>
1187 1426
1188在用户提交提示时运行,在 Claude 处理之前。这允许您根据提示/对话添加额外上下文、验证提示或阻止某些类型的提示。1427在用户提交提示时运行,在 Claude 处理它之前。这允许您根据提示/对话添加额外上下文、验证提示或阻止某些类型的提示。
1189 1428
1190`UserPromptSubmit` hooks 对 `command`、`http` 和 `mcp_tool` 类型的默认超时为 30 秒,比这些类型在其他事件上的 600 秒默认值更短。因为此 hook 在每个提示之前运行并阻止模型处理直到完成,卡住的 hook 会停滞会话。如果您的 hook 需要更多时间,在 hook 条目中设置 `timeout` 字段。1429`UserPromptSubmit` hooks 对 `command`、`http` 和 `mcp_tool` 类型的默认超时为 30 秒,比大多数其他事件的 600 秒默认值更短。因为此 hook 在每个提示之前运行并阻止模型处理直到它完成,卡住的 hook 会停滞会话。如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1191 1430
1192达到超时的 `UserPromptSubmit` hook 被取消,其输出(包括任何 `additionalContext`)被丢弃。提示仍然到达 Claude,但没有该上下文。从 v2.1.196 开始,成绩单显示一个通知,命名 hook、触发的超时以及输出被丢弃。早期版本取消 hook 而不显示通知。1431除了您使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook 外,达到其超时的 `UserPromptSubmit` 命令、HTTP 或 MCP tool hook 被取消,其输出(包括任何 `additionalContext`)被丢弃。提示仍然到达 Claude 而没有该上下文。成绩单显示一个通知,命名 hook、触发的超时以及输出被丢弃。
1193 1432
1194在 `UserPromptSubmit` 上达到超时的[Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks)会用命名 hook 和超时的消息阻止提示,因为那里的回调可能充当必须不失败打开的策略门。会话继续。在 v2.1.208 之前,该事件上的回调超时以执行错误结束轮次。1433在 `UserPromptSubmit` 上达到其超时的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 用命名 hook 和超时的消息阻止提示,因为那里的回调可以充当不能失败打开的策略门。会话继续。在 v2.1.208 之前,该事件上的回调超时以执行错误结束回合。
1195 1434
1196<h4 id="userpromptsubmit-input">1435<h4 id="userpromptsubmit-input">
1197 UserPromptSubmit 输入1436 UserPromptSubmit 输入
1198</h4>1437</h4>
1199 1438
1200除了[通用输入字段](#common-input-fields)外,UserPromptSubmit hooks 还接收包含用户提交的文本的 `prompt` 字段。1439除了 [常见输入字段](#common-input-fields) 外,UserPromptSubmit hooks 接收包含用户提交的文本的 `prompt` 字段。
1201 1440
1202```json theme={null}1441```json theme={null}
1203{1442{
1211```1450```
1212 1451
1213<h4 id="userpromptsubmit-decision-control">1452<h4 id="userpromptsubmit-decision-control">
1214 UserPromptSubmit 决定控制1453 UserPromptSubmit 决策控制
1215</h4>1454</h4>
1216 1455
1217`UserPromptSubmit` hooks 可以控制用户提示是否被处理并添加上下文。所有[JSON 输出字段](#json-output)都可用。1456`UserPromptSubmit` hooks 可以控制是否处理用户提示并添加上下文。所有 [JSON 输出字段](#json-output) 都可用。
1218 1457
1219有两种方法可以在退出代码 0 时向对话添加上下文:1458有两种方式在退出代码 0 上向对话添加上下文:
1220 1459
1221* **纯文本 stdout**:写入 stdout 的任何非 JSON 文本都作为上下文添加1460* **纯文本 stdout**:Claude Code 将它 [视为纯文本](#exit-code-0) 的 stdout 添加到 Claude 的上下文
1222* **带 `additionalContext` 的 JSON**:使用下面的 JSON 格式以获得更多控制。`additionalContext` 字段作为上下文添加1461* **带有 `additionalContext` 的 JSON**:使用下面的 JSON 格式以获得更多控制。`additionalContext` 字段作为上下文添加
1223 1462
1224纯 stdout 在成绩单中显示为 hook 输出。`additionalContext` 值作为系统提醒注入,Claude 读取而不显示成绩单条目。1463两个通道都不产生可见的成绩单条目。纯 stdout 和 `additionalContext` 值各自作为以 hook 名称开头的系统提醒注入;Claude 读取两者。要确认传递,请检查 [调试日志](#debug-hooks)。
1225 1464
1226要阻止提示,返回一个 JSON 对象,其中 `decision` 设置为 `"block"`:1465要阻止提示,返回一个 JSON 对象,其中 `decision` 设置为 `"block"`:
1227 1466
1228| 字段 | 描述 |1467| 字段 | 描述 |
1229| :----------------------- | :----------------------------------------------------------------------- |1468| :----------------------- | :----------------------------------------------------------------------------------------- |
1230| `decision` | `"block"` 防止提示被处理并从上下文中删除。省略以允许提示继续 |1469| `decision` | `"block"` 防止提示被处理并从上下文中删除它。省略以允许提示继续 |
1231| `reason` | 当 `decision` 为 `"block"` 时向用户显示。不添加到上下文 |1470| `reason` | 当 `decision` 为 `"block"` 时显示给用户。不添加到上下文 |
1232| `additionalContext` | 添加到 Claude 上下文的字符串,与提交的提示一起。请参阅[为 Claude 添加上下文](#add-context-for-claude) |1471| `additionalContext` | 与提交的提示一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1233| `sessionTitle` | 设置会话标题。使用此根据提示内容自动命名会话 |1472| `sessionTitle` | 设置会话标题。用于根据提示内容自动命名会话 |
1234| `suppressOriginalPrompt` | 如果 `true` 当 `decision` 为 `"block"` 时,从向用户显示的阻止消息中省略原始提示文本 |1473| `suppressOriginalPrompt` | 如果在 `decision` 为 `"block"` 时为 `true`,则从显示给用户的阻止消息中省略原始提示文本 |
1474
1475通过退出 2 阻止的 hook 路由方式与 `reason` 相同:阻止消息向用户显示 stderr 文本,它不添加到上下文。
1235 1476
1236```json theme={null}1477```json theme={null}
1237{1478{
1249 UserPromptExpansion1490 UserPromptExpansion
1250</h3>1491</h3>
1251 1492
1252当用户输入的斜杠命令在到达 Claude 之前展开为提示时运行。使用此来阻止特定命令的直接调用、为特定 skill 注入上下文或记录用户调用哪些命令。例如,匹配 `deploy` 的 hook 可以阻止 `/deploy`,除非存在批准文件,或匹配审查 skill 的 hook 可以将团队的审查清单附加为 `additionalContext`。1493当用户输入的命令在到达 Claude 之前扩展为提示时运行。使用此来阻止特定命令的直接调用、为特定 skill 注入上下文或记录用户调用哪些命令。例如,匹配 `deploy` 的 hook 可以阻止 `/deploy`,除非存在批准文件,或匹配审查 skill 的 hook 可以将团队的审查清单附加为 `additionalContext`。
1253 1494
1254此事件涵盖 `PreToolUse` 不涵盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 仅在 Claude 调用工具时触发,但直接输入 `/skillname` 绕过 `PreToolUse`。`UserPromptExpansion` 在该直接路径上触发。1495此事件涵盖 `PreToolUse` 不涵盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 仅在 Claude 调用工具时触发,但直接输入 `/skillname` 绕过 `PreToolUse`。`UserPromptExpansion` 在该直接路径上触发。
1255 1496
1256在 `command_name` 上匹配。留空匹配器以对每个提示类型斜杠命令触发。1497匹配 `command_name`。将匹配器留空以对每个提示类型命令触发。
1257 1498
1258<h4 id="userpromptexpansion-input">1499<h4 id="userpromptexpansion-input">
1259 UserPromptExpansion 输入1500 UserPromptExpansion 输入
1260</h4>1501</h4>
1261 1502
1262除了[通用输入字段](#common-input-fields)外,UserPromptExpansion hooks 还接收 `expansion_type`、`command_name`、`command_args`、`command_source` 和原始 `prompt` 字符串。`expansion_type` 字段对于 skill 和自定义命令为 `slash_command`,或对于 MCP 服务器提示为 `mcp_prompt`。1503除了 [常见输入字段](#common-input-fields) 外,UserPromptExpansion hooks 接收 `expansion_type`、`command_name`、`command_args`、`command_source` 和原始 `prompt` 字符串。`expansion_type` 字段对于 skill 和自定义命令为 `slash_command`,或对于 MCP 服务器提示为 `mcp_prompt`。
1263 1504
1264```json theme={null}1505```json theme={null}
1265{1506{
1277```1518```
1278 1519
1279<h4 id="userpromptexpansion-decision-control">1520<h4 id="userpromptexpansion-decision-control">
1280 UserPromptExpansion 决定控制1521 UserPromptExpansion 决策控制
1281</h4>1522</h4>
1282 1523
1283`UserPromptExpansion` hooks 可以阻止展开或添加上下文。所有[JSON 输出字段](#json-output)都可用。1524`UserPromptExpansion` hooks 可以阻止扩展或添加上下文。所有 [JSON 输出字段](#json-output) 都可用。
1284 1525
1285| 字段 | 描述 |1526| 字段 | 描述 |
1286| :------------------ | :----------------------------------------------------------------------- |1527| :------------------ | :----------------------------------------------------------------------------------------- |
1287| `decision` | `"block"` 防止斜杠命令展开。省略以允许它继续 |1528| `decision` | `"block"` 防止命令扩展。省略以允许它继续 |
1288| `reason` | 当 `decision` 为 `"block"` 时向用户显示 |1529| `reason` | 当 `decision` 为 `"block"` 时显示给用户 |
1289| `additionalContext` | 添加到 Claude 上下文的字符串,与展开的提示一起。请参阅[为 Claude 添加上下文](#add-context-for-claude) |1530| `additionalContext` | 与扩展的提示一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1531
1532通过退出 2 阻止的 hook 路由方式与 `reason` 相同:阻止消息向用户显示 stderr 文本。
1290 1533
1291```json theme={null}1534```json theme={null}
1292{1535{
1303 MessageDisplay1546 MessageDisplay
1304</h3>1547</h3>
1305 1548
1306在助手消息流向屏幕时运行。Claude Code 分批显示消息:每次一批新完成的行准备好渲染时,hook 运行一次,包含这些行,Claude Code 在其位置渲染 hook 的替换文本。长消息产生多个调用;短消息可能只产生一个。1549在助手消息流向屏幕时运行。Claude Code 分批显示消息:每次一批新完成的行准备好渲染时,hook 运行一次,这些行,Claude Code 用 hook 的替换文本渲染它们的位置。长消息产生多个调用;短消息可能只产生一个。
1307 1550
1308使用 MessageDisplay 来:1551使用 MessageDisplay 来:
1309 1552
1310* 剥离 markdown 以获得最小显示1553* 为最小显示剥离 markdown
1311* 转换 Agent SDK 应用向其用户显示的文本1554* 转换 Agent SDK 应用程序向其用户显示的文本
1312* 从 Claude 的响应中编辑 API 密钥或内部主机名1555* 从 Claude 的响应中编辑 API 密钥或内部主机名
1313 1556
1314Claude Code 保持每个批次直到您的 hook 返回,因此保持 hook 快速。如果 hook 失败或超时,Claude Code 显示原始文本。此事件的默认超时为 10 秒;如果您的 hook 需要更多时间,在 hook 条目中设置 `timeout` 字段。1557Claude Code 保持每个批次直到您的 hook 返回,因此保持 hook 快速。如果 hook 失败或超时,Claude Code 显示原始文本。此事件的默认超时为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1315 1558
1316MessageDisplay 仅用于显示:替换文本仅改变屏幕上呈现的内容。成绩单和 Claude 看到的内容保持原始文本,因此 Claude 永远看不到替换,详细模式显示原始内容。Hook 仅接收助手消息文本,因此工具结果和您输入的文本呈现不变。1559MessageDisplay 仅用于显示:替换文本仅更改屏幕上呈现的内容。成绩单和 Claude 看到的内容保持原始文本,因此 Claude 永远看不到替换,详细模式显示原始。hook 仅接收助手消息文本,因此工具结果和您输入的文本呈现不变。
1317 1560
1318MessageDisplay 不支持匹配器,对每个流向文本的助手消息触发;没有文本的消息(如仅工具调用响应)不触发它。1561MessageDisplay 不支持匹配器,对每个流式传输文本的助手消息触发;没有文本的消息(如仅工具调用响应)不触发它。
1319 1562
1320在非交互式运行中,包括 Agent SDK 查询和 `claude -p`,MessageDisplay 每个助手消息运行一次,而不是每批行运行一次。单个调用在消息完成后到达,并携带完整消息文本:`index` 为 `0`,`final` 为 `true`,`delta` 保存整个消息。为每个消息收集 `delta` 文本的 hook 在两种模式中接收相同的总文本。1563在非交互式运行中,包括 Agent SDK 查询和 `claude -p`,MessageDisplay 每个助手消息运行一次而不是每批行一次。单个调用在消息完成后到达并携带完整消息文本:`index` 为 `0`,`final` 为 `true`,`delta` 保持整个消息。为每个消息收集 `delta` 文本的 hook 在两种模式中接收相同的总文本。
1321 1564
1322<h4 id="messagedisplay-input">1565<h4 id="messagedisplay-input">
1323 MessageDisplay 输入1566 MessageDisplay 输入
1324</h4>1567</h4>
1325 1568
1326除了[通用输入字段](#common-input-fields)外,MessageDisplay hooks 还接收轮次和消息的标识符、此调用在消息中的位置以及 `delta` 中的新文本。批次边界取决于文本如何流动,因此使用 `index` 和 `final` 来跟踪通过消息的进度,而不是期望行以特定方式分组。1569除了 [常见输入字段](#common-input-fields) 外,MessageDisplay hooks 接收回合和消息的标识符、此调用在消息中的位置以及 `delta` 中的新文本。批次边界取决于文本流的方式,因此使用 `index` 和 `final` 来跟踪通过消息的进度,而不是期望行以特定方式分组。
1327 1570
1328| 字段 | 描述 |1571| 字段 | 描述 |
1329| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |1572| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
1330| `turn_id` | 当前轮次的 UUID |1573| `turn_id` | 当前回合的 UUID |
1331| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每个批次中稳定。这不是 API `msg_…` id,因此无法与成绩单消息 ids 关联 |1574| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每个批次中稳定。这不是 API `msg_…` id,因此无法与成绩单消息 id 关联 |
1332| `index` | 此批次在消息中的零基索引 |1575| `index` | 此批次在消息中的零基索引 |
1333| `final` | 在消息的最后一个批次上为 `true`。每个消息恰好有一个最终批次 |1576| `final` | 在消息的最后一个批次上为 `true`。每个消息恰好有一个最终批次 |
1334| `delta` | 自上一个批次以来新完成的行,包括终止换行符。始终是完整行,除了最终批次可能在行中间结束。在交互式运行中,当消息以换行符结束时最终批次的 delta 为空,因此将 `final` 而不是非空 delta 视为消息结束信号。在 Agent SDK 和 `claude -p` 运行中,单个调用携带整个消息 |1577| `delta` | 自上一个批次以来新完成的行,包括终止换行符。始终是完整行,除了最终批次可能在行中间结束。在交互式运行中,当消息以换行符结束时最终批次的 delta 为空,因此将 `final` 而不是非空 delta 视为消息结束信号。在 Agent SDK 和 `claude -p` 运行中,单个调用携带整个消息 |
1351 MessageDisplay 输出1594 MessageDisplay 输出
1352</h4>1595</h4>
1353 1596
1354除了所有 hooks 可用的[JSON 输出字段](#json-output)外,MessageDisplay hooks 可以返回 `displayContent` 来替换屏幕上的 delta:1597除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,MessageDisplay hooks 可以返回 `displayContent` 来替换屏幕上的 delta:
1355 1598
1356| 字段 | 描述 |1599| 字段 | 描述 |
1357| :--------------- | :----------------------- |1600| :--------------- | :--------------------- |
1358| `displayContent` | 代替 delta 显示的文本。省略以显示原始内容 |1601| `displayContent` | 显示代替 delta 的文本。省略以显示原始 |
1359 1602
1360MessageDisplay hooks 没有决定控制。它们无法阻止消息或改变成绩单中存储或发送给 Claude 的内容。1603MessageDisplay hooks 没有决策控制。它们无法阻止消息或更改成绩单中存储或发送给 Claude 的内容。Claude Code 作用于它们的 JSON 输出中的 `displayContent` 并丢弃 `systemMessage` 和 `continue`。
1361 1604
1362此示例从 Claude 的响应中剥离 markdown 格式以获得纯文本显示。脚本从 stdin 读取每个批次,从 `delta` 中移除粗体标记和内联代码反引号,并将结果作为 `displayContent` 返回。1605此示例从 Claude 的响应中剥离 markdown 格式以获得纯文本显示。脚本从 stdin 读取每个批次,从 `delta` 中删除粗体标记和内联代码反引号,并将结果作为 `displayContent` 返回。
1363 1606
1364<Tabs>1607<Tabs>
1365 <Tab title="macOS/Linux">1608 <Tab title="macOS/Linux">
1383 }1626 }
1384 ```1627 ```
1385 1628
1386 将此脚本保存到您的项目中的 `.claude/hooks/plain-display.sh` 并使用 `chmod +x` 使其可执行:1629 将此脚本保存到项目中的 `.claude/hooks/plain-display.sh` 并使用 `chmod +x` 使其可执行:
1387 1630
1388 ```bash theme={null}1631 ```bash theme={null}
1389 #!/bin/bash1632 #!/bin/bash
1390 jq '{hookSpecificOutput: {hookEventName: "MessageDisplay", displayContent: (.delta | gsub("\\*\\*"; "") | gsub("`"; ""))}}'1633 jq '{hookSpecificOutput: {hookEventName: "MessageDisplay", displayContent: (.delta | gsub("\\*\\*"; "") | gsub("`"; ""))}}'
1391 ```1634 ```
1392
1393 脚本需要 `jq` 在您的 `PATH` 上。
1394 </Tab>1635 </Tab>
1395 1636
1396 <Tab title="Windows (PowerShell)">1637 <Tab title="Windows (PowerShell)">
1422 1663
1423 `-NoProfile` 标志跳过加载您的 PowerShell 配置文件,以便 hook 快速启动,`-ExecutionPolicy Bypass` 让 PowerShell 运行本地脚本文件。1664 `-NoProfile` 标志跳过加载您的 PowerShell 配置文件,以便 hook 快速启动,`-ExecutionPolicy Bypass` 让 PowerShell 运行本地脚本文件。
1424 1665
1425 将此脚本保存到您的项目中的 `.claude/hooks/plain-display.ps1`:1666 将此脚本保存到项目中的 `.claude/hooks/plain-display.ps1`:
1426 1667
1427 ```powershell theme={null}1668 ```powershell theme={null}
1428 $batch = [Console]::In.ReadToEnd() | ConvertFrom-Json1669 $batch = [Console]::In.ReadToEnd() | ConvertFrom-Json
1437 </Tab>1678 </Tab>
1438</Tabs>1679</Tabs>
1439 1680
1440没有 markdown 的批次通过不变。如果脚本失败,例如因为 `jq` 缺失,Claude Code 显示原始文本并仅在[调试输出](#debug-hooks)中注意失败,而不是在会话中。1681没有 markdown 的批次通过不变。如果脚本失败,例如因为 `jq` 缺失,Claude Code 显示原始文本并仅在 [调试输出](#debug-hooks) 中注意失败,而不是在会话中。
1441 1682
1442<h3 id="pretooluse">1683<h3 id="pretooluse">
1443 PreToolUse1684 PreToolUse
1444</h3>1685</h3>
1445 1686
1446在 Claude 创建工具参数后和处理工具调用之前运行。在工具名称上匹配:`Bash`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`WebFetch`、`WebSearch`、`AskUserQuestion`、`ExitPlanMode` 和任何[MCP 工具名称](#match-mcp-tools)。1687在 Claude 创建工具参数之后和处理工具调用之前运行。匹配除 `EndConversation` 外的任何工具名称:内置工具如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 和 `ExitPlanMode`,以及任何 [MCP 工具名称](#match-mcp-tools)。
1688
1689要在特定文件在磁盘上更改时运行 hook,无论什么写入它,请使用 [FileChanged](#filechanged) 而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在更改后运行 FileChanged hooks,它们没有决策控制,因此无法阻止写入。
1447 1690
1448<Warning>1691<Warning>
1449 PreToolUse 仅在 Claude 调用工具时运行。您[在提示中使用 `@` 引用的文件](/docs/zh-CN/common-workflows#reference-files-and-directories)被添加而不进行任何工具调用:Claude Code 在构建提示时插入其内容,因此没有 PreToolUse hook 对它们触发,包括匹配 `Read` 的 hooks。要阻止特定路径的 `@` 引用,请改用[`Read` 拒绝规则](/docs/zh-CN/permissions#read-and-edit)。1692 PreToolUse 仅在 Claude 调用工具时运行。您 [在提示中使用 `@` 引用的文件](/docs/zh-CN/common-workflows#reference-files-and-directories) 添加时没有任何工具调用:Claude Code 在构建提示时插入它们的内容,因此没有 PreToolUse hook 为它们触发,包括匹配 `Read` 的 hooks。要阻止特定路径的 `@` 引用,请改用 [`Read` 拒绝规则](/docs/zh-CN/permissions#read-and-edit)。
1693
1694 PreToolUse 也不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
1450</Warning>1695</Warning>
1451 1696
1452使用[PreToolUse 决定控制](#pretooluse-decision-control)来允许、拒绝、询问或延迟工具调用。1697使用 [PreToolUse 决策控制](#pretooluse-decision-control) 来允许、拒绝、询问或延迟工具调用。
1698
1699在 `PreToolUse` 上超过其超时的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 阻止工具调用,Claude 接收命名超时的错误结果。另一个 hook 返回的显式拒绝仍然优先。
1453 1700
1454<h4 id="pretooluse-input">1701<h4 id="pretooluse-input">
1455 PreToolUse 输入1702 PreToolUse 输入
1456</h4>1703</h4>
1457 1704
1458除了[通用输入字段](#common-input-fields)外,PreToolUse hooks 还接收 `tool_name`、`tool_input` 和 `tool_use_id`。`tool_input` 字段取决于工具:1705除了 [常见输入字段](#common-input-fields) 外,PreToolUse hooks 接收 `tool_name`、`tool_input` 和 `tool_use_id`。
1706
1707对于 [MCP 工具](#match-mcp-tools),输入还携带 `mcp_server`,一个包含服务器 `name` 和 `source` 的对象,说明服务器定义来自何处。`source` 值包括 `plugin`、`sdk` 和配置范围如 `user` 和 `project`。[Agent SDK 参考中的 `McpServerProvenance`](/docs/zh-CN/agent-sdk/typescript#mcpserverprovenance) 列出了所有内容并说明如何处理您不认识的内容。基于 `source` 而不是 `name` 或 `mcp__<server>__` 工具名称前缀做出信任决定。`mcp_server` 字段需要 Claude Code v2.1.274 或更高版本。
1708
1709对于文件工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 始终是绝对的:
1710
1711* Claude Code 在 hooks 运行之前扩展 `~` 和相对路径,因此匹配路径的 hook 无法通过 `~` 或相同路径的相对拼写绕过
1712* 在 Windows 上,路径到达时带有反斜杠分隔符,即使您的 hook 在 Git Bash 下运行,其中 `$PWD` 看起来像 `/c/project`
1713* 使用正斜杠编写的比较(如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用继续进行,就像 hook 没有什么要阻止的一样
1714* 在比较前规范化分隔符:Bash 中的 `FILE_PATH="${FILE_PATH//\\//}"` 或 Python 中的 `file_path.replace("\\", "/")`,然后匹配路径段如 `/src/` 而不是用 `^` 锚定,因为路径是绝对的
1715
1716Windows 上的 `Write` 调用传递:
1717
1718```json theme={null}
1719{
1720 "hook_event_name": "PreToolUse",
1721 "tool_name": "Write",
1722 "tool_input": {
1723 "file_path": "C:\\project\\src\\index.ts",
1724 "content": "..."
1725 },
1726 ...
1727}
1728```
1729
1730`tool_input` 字段取决于工具:
1731
1732<a id="bash" />
1459 1733
1460<h5 id="bash">1734<h5 id="bash">
1461 Bash1735 Bash
1464执行 shell 命令。1738执行 shell 命令。
1465 1739
1466| 字段 | 类型 | 示例 | 描述 |1740| 字段 | 类型 | 示例 | 描述 |
1467| :------------------ | :------ | :----------------- | :------------------------------------------------------------------------- |1741| :------------------ | :------ | :----------------- | :--------------------------------------------------------------------------- |
1468| `command` | string | `"npm test"` | 要执行的 shell 命令 |1742| `command` | string | `"npm test"` | 要执行的 shell 命令 |
1469| `description` | string | `"Run test suite"` | 命令执行操作的可选描述 |1743| `description` | string | `"Run test suite"` | 命令执行操作的可选描述 |
1470| `timeout` | number | `120000` | 可选超时(毫秒)。高于[最大值](/docs/zh-CN/tools-reference#bash-tool-behavior)的值被减少到最大值而不是被拒绝 |1744| `timeout` | number | `120000` | 可选超时(毫秒)。高于 [最大值](/docs/zh-CN/tools-reference#bash-tool-behavior) 的值被减少到最大值而不是被拒绝 |
1471| `run_in_background` | boolean | `false` | 是否在后台运行命令 |1745| `run_in_background` | boolean | `false` | 是否在后台运行命令 |
1472 1746
1747当 Bash 命令更改 Git 存储库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置打开记录时,它在每个权限模式中记录;该设置的条目说明哪些文件可以设置它。否则它仅在自动模式和 `bypassPermissions` 模式中记录,仅当 Claude Code 指导 Claude 通过 Bash 编辑文件时。设置 `bashEditDiffEnabled` 为 `false` 以关闭记录。后台命令和只读命令不携带 diff。
1748
1749您的 [PostToolUse hook](#posttooluse) 然后在 `tool_response.bashEditDiff` 中接收更改的文件。列表涵盖命令运行时在存储库下更改的内容。Git 忽略的文件和子模块中的文件不被列出。需要 Claude Code v2.1.269 或更高版本。
1750
1751<Note>
1752 列表是尽力而为的,处于公开测试版。Claude Code 可能会错过更改、包含另一个进程同时更改的文件,或在其大小限制处停止。字段形状可能会改变。使用列表查找要审查的内容,而不是强制执行策略。
1753</Note>
1754
1755`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整性和可靠性。
1756
1757| 字段 | 类型 | 示例 | 描述 |
1758| :------------- | :------ | :------------------------------------------------------ | :----------------------------------------------------------------------- |
1759| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令更改的文件的绝对路径,最多 200 个。每当 `files` 保持 diff 或 `moreFiles` 高于零时出现 |
1760| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 个更改文件的 diffs,用于显示。对于命令添加或删除的文件,`created` 或 `deleted` 为 `true` |
1761| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的更改文件的计数 |
1762| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |
1763| `skipped` | boolean | `true` | 对于移动工作树的 Git 命令设置,如 `git checkout` 或 `git stash`,因此 Claude Code 不获取 diff |
1764| `shared` | boolean | `true` | 当另一个 Bash 工具调用(如子 agent 的)同时在同一存储库中运行时设置,因此某些列出的更改可能是该命令的 |
1765
1766<a id="powershell" />
1767
1768<h5 id="powershell">
1769 PowerShell
1770</h5>
1771
1772执行 PowerShell 命令。有关按平台的可用性,请参阅 [PowerShell 工具](/docs/zh-CN/tools-reference#powershell-tool)。
1773
1774字段与 Bash 工具匹配,命令字符串在 `command` 中:
1775
1776| 字段 | 类型 | 示例 | 描述 |
1777| :------------------ | :------ | :------------------------- | :----------------- |
1778| `command` | string | `"Get-ChildItem -Recurse"` | 要执行的 PowerShell 命令 |
1779| `description` | string | `"List files recursively"` | 命令执行操作的可选描述 |
1780| `timeout` | number | `120000` | 可选超时(毫秒) |
1781| `run_in_background` | boolean | `false` | 是否在后台运行命令 |
1782
1783在检查 shell 命令的 hooks 中匹配 `Bash|PowerShell`,以便它们涵盖两个工具:
1784
1785* 在 Windows 上,无论 PowerShell 工具在何处启用,Claude 都将 PowerShell 视为主 shell 并通过它路由 shell 命令。
1786* 在没有 Git Bash 的 Windows 上,工具自动启用,Claude Code 根本不注册 Bash 工具。
1787* 仅匹配 `Bash` 的 hook 永远不会在那里触发。
1788
1473<h5 id="write">1789<h5 id="write">
1474 Write1790 Write
1475</h5>1791</h5>
1503| 字段 | 类型 | 示例 | 描述 |1819| 字段 | 类型 | 示例 | 描述 |
1504| :---------- | :----- | :-------------------- | :---------- |1820| :---------- | :----- | :-------------------- | :---------- |
1505| `file_path` | string | `"/path/to/file.txt"` | 要读取的文件的绝对路径 |1821| `file_path` | string | `"/path/to/file.txt"` | 要读取的文件的绝对路径 |
1506| `offset` | number | `10` | 可选的开始读取的行号 |1822| `offset` | number | `10` | 可选行号以开始读取 |
1507| `limit` | number | `50` | 可选的要读取的行数 |1823| `limit` | number | `50` | 可选要读取的行数 |
1508 1824
1509<h5 id="glob">1825<h5 id="glob">
1510 Glob1826 Glob
1513查找与 glob 模式匹配的文件。1829查找与 glob 模式匹配的文件。
1514 1830
1515| 字段 | 类型 | 示例 | 描述 |1831| 字段 | 类型 | 示例 | 描述 |
1516| :-------- | :----- | :--------------- | :---------------- |1832| :-------- | :----- | :--------------- | :----------------- |
1517| `pattern` | string | `"**/*.ts"` | 要匹配文件的 Glob 模式 |1833| `pattern` | string | `"**/*.ts"` | 要匹配文件的 glob 模式 |
1518| `path` | string | `"/path/to/dir"` | 可选的搜索目录。默认为当前工作目录 |1834| `path` | string | `"/path/to/dir"` | 可选要搜索的目录。默认为当前工作目录 |
1519 1835
1520<h5 id="grep">1836<h5 id="grep">
1521 Grep1837 Grep
1526| 字段 | 类型 | 示例 | 描述 |1842| 字段 | 类型 | 示例 | 描述 |
1527| :------------ | :------ | :--------------- | :------------------------------------------------------------------------ |1843| :------------ | :------ | :--------------- | :------------------------------------------------------------------------ |
1528| `pattern` | string | `"TODO.*fix"` | 要搜索的正则表达式模式 |1844| `pattern` | string | `"TODO.*fix"` | 要搜索的正则表达式模式 |
1529| `path` | string | `"/path/to/dir"` | 可选的要搜索的文件或目录 |1845| `path` | string | `"/path/to/dir"` | 可选要搜索的文件或目录 |
1530| `glob` | string | `"*.ts"` | 可选的 glob 模式以过滤文件 |1846| `glob` | string | `"*.ts"` | 可选 glob 模式以过滤文件 |
1531| `output_mode` | string | `"content"` | `"content"`、`"files_with_matches"` 或 `"count"`。默认为 `"files_with_matches"` |1847| `output_mode` | string | `"content"` | `"content"`、`"files_with_matches"` 或 `"count"`。默认为 `"files_with_matches"` |
1532| `-i` | boolean | `true` | 不区分大小写的搜索 |1848| `-i` | boolean | `true` | 不区分大小写的搜索 |
1533| `multiline` | boolean | `false` | 启用多行匹配 |1849| `multiline` | boolean | `false` | 启用多行匹配 |
1536 WebFetch1852 WebFetch
1537</h5>1853</h5>
1538 1854
1539获取和处理 web 内容。1855获取和处理网络内容。
1540 1856
1541| 字段 | 类型 | 示例 | 描述 |1857| 字段 | 类型 | 示例 | 描述 |
1542| :------- | :----- | :---------------------------- | :----------- |1858| :------- | :----- | :---------------------------- | :----------- |
1543| `url` | string | `"https://example.com/api"` | 要获取内容的 URL |1859| `url` | string | `"https://example.com/api"` | 要从中获取内容的 URL |
1544| `prompt` | string | `"Extract the API endpoints"` | 在获取的内容上运行的提示 |1860| `prompt` | string | `"Extract the API endpoints"` | 在获取的内容上运行的提示 |
1545 1861
1546<h5 id="websearch">1862<h5 id="websearch">
1559 Agent1875 Agent
1560</h5>1876</h5>
1561 1877
1562生成一个[subagent](/docs/zh-CN/sub-agents)。1878生成 [子 agent](/docs/zh-CN/sub-agents)。
1563 1879
1564| 字段 | 类型 | 示例 | 描述 |1880| 字段 | 类型 | 示例 | 描述 |
1565| :-------------- | :----- | :------------------------- | :------------ |1881| :-------------- | :----- | :------------------------- | :-------------- |
1566| `prompt` | string | `"Find all API endpoints"` | 代理要执行的任务 |1882| `prompt` | string | `"Find all API endpoints"` | agent 要执行的任务 |
1567| `description` | string | `"Find API endpoints"` | 任务的简短描述 |1883| `description` | string | `"Find API endpoints"` | 任务的简短描述 |
1568| `subagent_type` | string | `"Explore"` | 要使用的专门代理的类型 |1884| `subagent_type` | string | `"Explore"` | 要使用的专门 agent 类型 |
1569| `model` | string | `"sonnet"` | 可选的模型别名以覆盖默认值 |1885| `model` | string | `"sonnet"` | 可选模型别名以覆盖默认值 |
1570 1886
1571在 `PostToolUse` 中,已完成的 Agent 调用的 `tool_response` 携带 subagent 的最终文本以及使用遥测。读取这些字段以从 hook 记录每个 subagent 的成本:1887当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 在 `tool_response` 中接收子 agent 的结果和运行遥测。读取这些字段以检查运行;对于跨子 agent 的令牌和成本汇总,使用 [令牌和成本计数器](/docs/zh-CN/monitoring-usage#token-counter) 过滤到 `query_source` `"subagent"`,因为 `totalTokens` 和 `usage` 仅涵盖最终请求:
1572 1888
1573| 字段 | 类型 | 示例 | 描述 |1889| 字段 | 类型 | 示例 | 描述 |
1574| :------------------ | :----- | :---------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- |1890| :------------------ | :----- | :---------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- |
1575| `status` | string | `"completed"` | 前台 subagents 为 `"completed"`,后台 subagents 为 `"async_launched"`。从 v2.1.198 开始,subagents 默认在后台运行,因此省略的 `run_in_background` 也产生 `"async_launched"` |1891| `status` | string | `"completed"` | 前台子 agent 为 `"completed"`,后台子 agent 为 `"async_launched"`。从 v2.1.198 起,子 agent 默认在后台运行,因此省略的 `run_in_background` 也产生 `"async_launched"` |
1576| `agentId` | string | `"a4d2c8f1e0b3a297"` | subagent 运行的标识符 |1892| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子 agent 运行的标识符 |
1577| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | subagent 的最终文本块 |1893| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子 agent 的最终文本块,或对于其报告通过 `SubagentHandback` 的子 agent,关于该交接的简短说明代替 |
1578| `resolvedModel` | string | `"claude-sonnet-4-5"` | subagent 运行的模型,可能与请求的模型不同。需要 Claude Code v2.1.174 或更高版本 |1894| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子 agent 启动的模型,可能与请求的模型不同 |
1579| `totalTokens` | number | `12450` | 在 subagent 轮次中计费的总令牌数 |1895| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复折叠;仅在模型在运行中交换时设置。需要 Claude Code v2.1.212 或更高版本 |
1580| `totalDurationMs` | number | `48211` | subagent 运行的挂钟时间 |1896| `totalTokens` | number | `12450` | 子 agent 最终 API 请求的令牌计数:输入、输出和缓存令牌合并。这不是整个运行的总计 |
1581| `totalToolUseCount` | number | `7` | subagent 进行的工具调用计数 |1897| `totalDurationMs` | number | `48211` | 子 agent 运行的挂钟持续时间 |
1582| `usage` | object | `{"input_tokens": 8320, ...}` | 按类型的令牌分解:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |1898| `totalToolUseCount` | number | `7` | 子 agent 进行的工具调用计数 |
1899| `usage` | object | `{"input_tokens": 8320, ...}` | 最终 API 请求的每类型令牌分解:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |
1583 1900
1584对于后台 subagents,工具在启动 subagent 后立即返回,因此 `tool_response` 不携带使用字段。它具有 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。1901在 Claude Code v2.1.271 或更高版本上,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子 agent(Claude Code 在 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 中提供)通过该工具而不是作为文本返回其报告。其 `completed` 结果的 `content` 字段然后携带关于该交接的简短说明而不是报告本身。要读取报告,匹配 `PreToolUse` 或 `PostToolUse` hook 在 `SubagentHandback` 上并读取 `tool_input.message`。
1585 1902
1586`resolvedModel` 字段命名 subagent 实际运行的模型,可能与 `tool_input` 中的 `model` 值不同。它需要 Claude Code v2.1.174 或更高版本。1903对于后台子 agent,工具在任务移到后台时返回,因此 `tool_response` 不携带使用字段:后台启动立即返回,前台任务在运行中被 Claude Code 后台化时返回。它有 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。
1904
1905在 `completed` 响应上,`resolvedModel` 命名子 agent 启动的模型,可能与 `tool_input` 中的 `model` 值不同,如 `availableModels` 或其他覆盖适用时。在 `async_launched` 响应上,`resolvedModel` 命名 agent 移到后台时使用的模型,因此在后台化之前发生的交换反映在那里。`modelsUsed` 和后台化时间 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。
1587 1906
1588<a id="askuserquestion" />1907<a id="askuserquestion" />
1589 1908
1595 1914
1596| 字段 | 类型 | 示例 | 描述 |1915| 字段 | 类型 | 示例 | 描述 |
1597| :---------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------- |1916| :---------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------- |
1598| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | 要呈现的问题,每个都有 `question` 字符串、短 `header`、`options` 数组和可选的 `multiSelect` 标志 |1917| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | 要呈现的问题,每个都有 `question` 字符串、简短 `header`、`options` 数组和可选 `multiSelect` 标志 |
1599| `answers` | object | `{"Which framework?": "React"}` | 可选。将问题文本映射到选定的选项标签。多选答案用逗号连接标签。Claude 不设置此字段;通过 `updatedInput` 提供它以以编程方式回答 |1918| `answers` | object | `{"Which framework?": "React"}` | 可选。将问题文本映射到选定的选项标签。多选答案用逗号连接标签。Claude 不设置此字段;通过 `updatedInput` 提供它以以编程方式回答 |
1600 1919
1601<h5 id="exitplanmode">1920<h5 id="exitplanmode">
1602 ExitPlanMode1921 ExitPlanMode
1603</h5>1922</h5>
1604 1923
1605呈现一个计划并要求用户在 Claude 离开[Plan Mode](/docs/zh-CN/permission-modes#analyze-before-you-edit-with-plan-mode)之前批准它。Claude 在调用工具之前将计划写入磁盘上的文件,因此来自模型的字面 `tool_input` 通常为空。Claude Code 在将输入传递给 hooks 之前注入计划内容和文件路径。1924呈现计划并要求用户在 Claude 离开 [plan mode](/docs/zh-CN/permission-modes#analyze-before-you-edit-with-plan-mode) 之前批准它。Claude 在调用工具之前将计划写入磁盘上的文件,因此来自模型的字面 `tool_input` 通常为空。Claude Code 在将输入传递给 hooks 之前注入计划内容和文件路径。
1606 1925
1607| 字段 | 类型 | 示例 | 描述 |1926| 字段 | 类型 | 示例 | 描述 |
1608| :--------------- | :----- | :------------------------------------------ | :---------------------------------------------------------------- |1927| :--------------- | :----- | :------------------------------------------ | :----------------------------------------------------------------- |
1609| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 中的计划内容。从磁盘上的计划文件注入 |1928| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 中的计划内容。从磁盘上的计划文件注入 |
1610| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |1929| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |
1611| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已弃用。Claude Code 接受该字段但忽略它。在 v2.1.205 之前,它携带 Claude 请求实现计划的基于提示的权限 |1930| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已弃用。Claude Code 接受该字段但忽略它。在 v2.1.205 之前,它携带 Claude 请求以实现计划的基于提示的权限 |
1612 1931
1613在 `PostToolUse` 中,`tool_response` 是一个对象,具有 `plan` 和 `filePath` 字段,保存批准的计划,加上内部状态标志。读取 `tool_response.plan` 以获取计划内容,而不是从磁盘重新读取文件。1932在 `PostToolUse` 中,`tool_response` 是一个包含 `plan` 和 `filePath` 字段的对象,保持批准的计划,加上内部状态标志。读取 `tool_response.plan` 以获取计划内容,而不是从磁盘重新读取文件。
1614 1933
1615<h4 id="pretooluse-decision-control">1934<h4 id="pretooluse-decision-control">
1616 PreToolUse 决定控制1935 PreToolUse 决策控制
1617</h4>1936</h4>
1618 1937
1619`PreToolUse` hooks 可以控制工具调用是否继续。与使用顶级 `decision` 字段的其他 hooks 不同,PreToolUse 在 `hookSpecificOutput` 对象内返回其决定。这给了它更丰富的控制:四个结果(允许、拒绝、询问或延迟)加上在执行前修改工具输入的能力。1938`PreToolUse` hooks 可以控制工具调用是否继续。与使用顶级 `decision` 字段的其他 hooks 不同,PreToolUse 在 `hookSpecificOutput` 对象内返回其决策。这给了它更丰富的控制:四个结果(允许、拒绝、询问或延迟)加上在执行前修改工具输入的能力。
1620 1939
1621| 字段 | 描述 |1940| 字段 | 描述 |
1622| :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1941| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1623| `permissionDecision` | `"allow"` 绕过权限提示,除了[需要用户交互的工具](#pretooluse-decision-control)和连接器工具[您的组织设置为 `ask`](/docs/zh-CN/mcp#organization-controls-on-connector-tools)。`"deny"` 防止工具调用。`"ask"` 提示用户确认。`"defer"` 优雅地退出,以便工具稍后可以恢复。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)在 hook 返回什么时仍然被评估 |1942| `permissionDecision` | `"allow"` 跳过权限提示,除了 [任何模式自动批准的操作](/docs/zh-CN/permission-modes#actions-no-mode-auto-approves) 和对于 `AskUserQuestion` 和 `ExitPlanMode`,需要 [`updatedInput` 与其配对](#allow-with-updatedinput)。`"deny"` 防止工具调用。`"ask"` 提示用户确认。`"defer"` 优雅地退出以便工具稍后可以恢复。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions) 仍然被评估,无论 hook 返回什么 |
1624| `permissionDecisionReason` | 对于 `"allow"` 和 `"ask"`,向用户显示但不向 Claude 显示。对于 `"deny"`,向 Claude 显示。对于 `"defer"`,被忽略 |1943| `permissionDecisionReason` | 对于 `"allow"` 和 `"ask"`,显示给用户但不显示给 Claude。对于 `"deny"`,显示给 Claude。对于 `"defer"`,被忽略 |
1625| `updatedInput` | 在执行前修改工具的输入参数。替换整个输入对象,因此包括未修改的字段以及修改后的字段。与 `"allow"` 结合以自动批准,或与 `"ask"` 结合以向用户显示修改后的输入。对于 `"defer"`,被忽略 |1944| `updatedInput` | 在执行前修改工具的输入参数。替换整个输入对象,因此在修改的输入旁边包含未更改的字段。Claude Code 根据您的 hook 返回的输入而不是 Claude 发送的输入评估权限规则和 Bash 命令的 [自动后台资格](/docs/zh-CN/tools-reference#background-commands)。与 `"allow"` 结合以自动批准,或与 `"ask"` 结合以向用户显示修改的输入。对于 `"defer"`,被忽略 |
1626| `additionalContext` | 在工具执行前添加到 Claude 上下文的字符串。对于 `"defer"`,被忽略。请参阅[为 Claude 添加上下文](#add-context-for-claude) |1945| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。当 `permissionDecision` 为 `"defer"` 时被忽略。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1946
1947当多个 PreToolUse hooks 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。
1627 1948
1628当多个 PreToolUse hooks 返回不同的决定时,优先级是 `deny` > `defer` > `ask` > `allow`。1949通过退出 2 阻止的 hook 路由方式与 `"deny"` 相同:Claude 看到 stderr 消息作为拒绝原因。
1629 1950
1630当 hook 返回 `"ask"` 时,向用户显示的权限提示包括一个标签,标识 hook 来自何处:例如,`[User]`、`[Project]`、`[Plugin]` 或 `[Local]`。这帮助用户了解哪个配置源正在请求确认。1951当 hook 返回 `"ask"` 时,显示给用户的权限提示包括一个标签,标识 hook 来自何处:`[settings]` 对于来自任何设置文件或 agent frontmatter 的 hook,`[plugin:<name>]` 对于插件的 hook,或 `[skill]` 对于来自 skill frontmatter 的 hook。这帮助用户理解哪个配置源请求确认。
1952
1953hook 的 `"ask"` 也在 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 中强制权限提示:分类器仍然可以拒绝工具调用,但它无法静默批准调用。在 v2.1.211 之前,分类器可以批准在 [沙箱](/docs/zh-CN/sandboxing) 外运行的 Bash 命令而不显示 hook 请求的提示;分类器仍然对该命令应用了自己的安全规则,hook `"deny"` 总是被尊重。
1631 1954
1632```json theme={null}1955```json theme={null}
1633{1956{
1643}1966}
1644```1967```
1645 1968
1646`AskUserQuestion` 和 `ExitPlanMode` 需要用户交互,通常在[非交互模式](/docs/zh-CN/headless)中使用 `-p` 标志时阻止。返回 `permissionDecision: "allow"` 以及 `updatedInput` 满足该要求:hook 从 stdin 读取工具的输入,通过您自己的 UI 收集答案,并在 `updatedInput` 中返回它,以便工具运行而不提示。仅返回 `"allow"` 对这些工具不足够。对于 `AskUserQuestion`,回显原始 `questions` 数组并添加一个[`answers`](#askuserquestion)对象,将每个问题的文本映射到选定的答案。1969<span id="allow-with-updatedinput" />
1647 1970
1648连接器工具[您的组织设置为 `ask`](/docs/zh-CN/mcp#organization-controls-on-connector-tools)即使 hook 返回 `"allow"` 也会提示。1971在 [非交互模式](/docs/zh-CN/headless) 中使用 `-p` 标志,Claude Code 仅在运行有 [权限主机](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs) 来接收提示时提供 `AskUserQuestion` 和 `ExitPlanMode`,如 Agent SDK `canUseTool` 回调。这些工具需要用户交互。返回 `permissionDecision: "allow"` 与 `updatedInput` 一起满足该要求:hook 从 stdin 读取工具的输入,通过您自己的 UI 收集答案,并在 `updatedInput` 中返回它,以便工具运行而不提示。仅返回 `"allow"` 对这些工具不充分。对于 `AskUserQuestion`,回显原始 `questions` 数组并添加一个 [`answers`](#askuserquestion) 对象,将每个问题的文本映射到选定的答案。
1649 1972
1650从 v2.1.199 开始,一个 MCP 工具,其服务器用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记它,更严格:hook 不能用 `"allow"` 跳过其批准提示,无论是否有 `updatedInput`,因为 Claude Code 无法确认 hook 收集了工具需要的交互。1973从 v2.1.199 起,其服务器用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记的 MCP 工具更严格:hook 无法用 `"allow"` 跳过其批准提示,无论是否有 `updatedInput`,因为 Claude Code 无法确认 hook 收集了工具需要的交互。
1651 1974
1652<Note>1975<Note>
1653 PreToolUse 之前使用顶级 `decision` 和 `reason` 字段,但这些对此事件已弃用。改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已弃用的值 `"approve"` 和 `"block"` 映射到 `"allow"` 和 `"deny"`。PostToolUse 和 Stop 等其他事件继续使用顶级 `decision` 和 `reason` 作为其当前格式。1976 PreToolUse 之前使用顶级 `decision` 和 `reason` 字段,但这些对此事件已弃用。改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已弃用的值 `"approve"` 和 `"block"` 映射到 `"allow"` 和 `"deny"` 分别。PostToolUse 和 Stop 等其他事件继续使用顶级 `decision` 和 `reason` 作为其当前格式。
1654</Note>1977</Note>
1655 1978
1656<h4 id="defer-a-tool-call-for-later">1979<h4 id="defer-a-tool-call-for-later">
1657 延迟工具调用以供稍后使用1980 延迟工具调用以供稍后使用
1658</h4>1981</h4>
1659 1982
1660`"defer"` 用于运行 `claude -p` 作为子进程并读取其 JSON 输出的集成,例如 Agent SDK 应用或构建在 Claude Code 之上的自定义 UI。它让该调用进程在工具调用处暂停 Claude,通过其自己的界面收集输入,并从中断处恢复。Claude Code 仅在[非交互模式](/docs/zh-CN/headless)中使用 `-p` 标志时遵守此值。在交互式会话中,它记录警告并忽略 hook 结果。1983`"defer"` 用于运行 `claude -p` 作为子进程并读取其 JSON 输出的集成,如 Agent SDK 应用或构建在 Claude Code 之上的自定义 UI。它让该调用进程在工具调用处暂停 Claude,通过其自己的界面收集输入,并从中断处恢复。Claude Code 仅在 [非交互模式](/docs/zh-CN/headless) 中使用 `-p` 标志时尊重此值。在交互式会话中,它记录警告并忽略 hook 结果。
1661 1984
1662`AskUserQuestion` 工具是典型情况:Claude 想要询问用户一些事情,但没有终端来回答。往返工作如下:1985`AskUserQuestion` 工具是典型情况:Claude 想问用户什么,但没有终端来回答。`-p` 运行仅在有 [权限主机](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs) 时提供 `AskUserQuestion`,如您使用 `--permission-prompt-tool` 传递的 MCP 工具,因此使用一个启动运行。往返工作如下:
1663 1986
16641. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。19871. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。
16652. Hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在成绩单中。19882. hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在成绩单中。
16663. 调用进程从 SDK 结果读取 `deferred_tool_use`,在其自己的 UI 中显示问题,并等待答案。19893. 调用进程从 SDK 结果读取 `deferred_tool_use`,在其自己的 UI 中呈现问题,并等待答案。
16674. 调用进程运行 `claude -p --resume <session-id>`。相同的工具调用再次触发 `PreToolUse`。19904. 调用进程运行 `claude -p --resume <session-id>`,带有相同的权限主机。相同的工具调用再次触发 `PreToolUse`。
16685. Hook 返回 `permissionDecision: "allow"` 和 `updatedInput` 中的答案。工具执行,Claude 继续。19915. hook 返回 `permissionDecision: "allow"`,答案在 `updatedInput` 中。工具执行,Claude 继续。
1669 1992
1670`deferred_tool_use` 字段携带工具的 `id`、`name` 和 `input`。`input` 是 Claude 为工具调用生成的参数,在执行前捕获:1993`deferred_tool_use` 字段携带工具的 `id`、`name` 和 `input`。`input` 是 Claude 为工具调用生成的参数,在执行前捕获:
1671 1994
1683}2006}
1684```2007```
1685 2008
1686没有超时或重试限制。会话保留在磁盘上,直到您恢复它,受到 [`cleanupPeriodDays`](/docs/zh-CN/settings#available-settings) 保留扫描的约束,该扫描默认在 30 天后删除会话文件。如果恢复时答案还没有准备好,hook 可以再次返回 `"defer"`,进程以相同的方式退出。调用进程控制何时通过最终返回 `"allow"` 或 `"deny"` 从 hook 中断循环。2009没有超时或重试限制。会话保留在磁盘上直到您恢复它,受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留扫描的约束,默认情况下在 30 天后删除会话文件,遵循 [保留扫描规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果答案在您恢复时还没有准备好,hook 可以再次返回 `"defer"`,进程以相同的方式退出。调用进程通过最终从 hook 返回 `"allow"` 或 `"deny"` 来控制何时打破循环。
1687 2010
1688`"defer"` 仅在 Claude 在轮次中进行单个工具调用时有效。如果 Claude 一次进行多个工具调用,`"defer"` 被忽略并显示警告,工具通过正常权限流程进行。约束存在是因为恢复只能重新运行一个工具:没有办法延迟一个调用而不留下其他调用未解决。2011`"defer"` 仅在 Claude 在回合中进行单个工具调用时有效。如果 Claude 一次进行多个工具调用,`"defer"` 被忽略并显示警告,工具通过正常权限流程进行。约束存在是因为恢复只能重新运行一个工具:没有办法延迟批次中的一个调用而不留下其他未解决的。
1689 2012
1690如果恢复时延迟的工具不再可用,进程以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出,在 hook 触发之前。这发生在为恢复的会话未连接提供工具的 MCP 服务器时。`deferred_tool_use` 有效负载仍然包括,以便您可以识别哪个工具丢失。2013如果恢复时延迟的工具不再可用,进程以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出,hook 触发前。这发生在为恢复的会话未连接提供工具的 MCP 服务器时。`deferred_tool_use` 有效负载仍然包含,以便您可以识别哪个工具丢失。
1691 2014
1692<Note>2015<Note>
1693 `--resume` 恢复工具被延迟时活跃的权限模式,因此您不需要再次传递 `--permission-mode`。例外是 `plan` 和 `bypassPermissions`,它们永远不会被携带。在恢复时显式传递 `--permission-mode` 会覆盖恢复的值。2016 要在 plan mode 中恢复延迟会话,请与 `--resume` 一起传递 [`--permission-prompt-tool`](/docs/zh-CN/cli-reference#cli-flags),以便 Claude Code 可以呈现计划以供批准。没有它,Claude Code 不会恢复 plan mode。需要 Claude Code v2.1.246 或更高版本。
2017
2018 当您使用 `-p` 恢复时,Claude Code 不会恢复任何其他存储的权限模式。它启动运行在新 `claude -p` 运行会启动的权限模式中,因此如果延迟会话使用了一个,请再次传递 `--permission-mode` 或 `--dangerously-skip-permissions`。当您使用 `claude --resume <session-id>` 恢复而不使用 `-p` 时,Claude Code 恢复存储的权限模式,除了 [恢复时的权限模式](/docs/zh-CN/sessions#permission-mode-on-resume) 中列出的例外。
1694</Note>2019</Note>
1695 2020
1696<h3 id="permissionrequest">2021<h3 id="permissionrequest">
1697 PermissionRequest2022 PermissionRequest
1698</h3>2023</h3>
1699 2024
1700在向用户显示权限对话框时运行。使用[PermissionRequest 决定控制](#permissionrequest-decision-control)代表用户允许或拒绝。2025在 Claude Code 即将要求您许可使用工具时运行。在无法显示提示的会话中,如 [非交互模式](/docs/zh-CN/headless) 中的后台子 agent,Claude Code 仍然运行这些 hooks,如果没有 hook 返回决策,它拒绝工具调用。
2026使用 [PermissionRequest 决策控制](#permissionrequest-decision-control) 代表用户允许或拒绝。
1701 2027
1702在工具名称上匹配,与 PreToolUse 相同的值。2028当您需要在 Claude 要求许可使用工具时立即获得信号时使用此事件。Claude Code 仅在提示等待约六秒后运行 [Notification](#notification) hook,其中 `permission_prompt` 类型。
2029
2030Claude Code 不为沙箱命令的 [网络请求](/docs/zh-CN/sandboxing#network-isolation) 运行 PermissionRequest hooks。要获得该提示的信号,请使用 `permission_prompt` 通知类型。
2031
2032匹配工具名称,与 PreToolUse 相同的值。
1703 2033
1704<h4 id="permissionrequest-input">2034<h4 id="permissionrequest-input">
1705 PermissionRequest 输入2035 PermissionRequest 输入
1706</h4>2036</h4>
1707 2037
1708PermissionRequest hooks 接收 `tool_name` 和 `tool_input` 字段,如 PreToolUse hooks,但没有 `tool_use_id`。可选的 `permission_suggestions` 数组包含用户通常在权限对话框中看到的"总是允许"选项。区别在于 hook 何时触发:PermissionRequest hooks 在权限对话框即将显示给用户时运行,而 PreToolUse hooks 在工具执行前运行,无论权限状态如何。2038PermissionRequest hooks 接收 `tool_name` 和 `tool_input` 字段,如 PreToolUse hooks,但没有 `tool_use_id`。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 为此请求建议的 [权限更新](#permission-update-entries),如添加允许规则或更改权限模式。
2039
2040`permission_suggestions` 数组不是您看到的选项的精确列表,因为每个权限对话构建自己的选项。某些对话(如文件编辑的对话)根本不读取数组,并从请求本身派生其选项。读取它的对话仍然可以保留一个选项,其建议保留在数组中,例如当 [`allowManagedPermissionRulesOnly`](/docs/zh-CN/settings-reference#allowmanagedpermissionrulesonly) 隐藏规则保存选项时。它也可以提供没有建议条目的选项,如 [**Yes, and switch to auto mode**](/docs/zh-CN/permission-modes#switch-permission-modes),它直接更改权限模式而不是通过权限更新。
2041
2042PreToolUse hooks 在每个工具调用之前运行,无论它是否需要权限。PermissionRequest hooks 仅在 Claude Code 即将要求您许可时运行,或当它否则会自动拒绝无法提示的调用时。两个事件都不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
1709 2043
1710```json theme={null}2044```json theme={null}
1711{2045{
1731```2065```
1732 2066
1733<h4 id="permissionrequest-decision-control">2067<h4 id="permissionrequest-decision-control">
1734 PermissionRequest 决定控制2068 PermissionRequest 决策控制
1735</h4>2069</h4>
1736 2070
1737`PermissionRequest` hooks 可以允许或拒绝权限请求。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您的 hook 脚本可以返回一个 `decision` 对象,其中包含这些事件特定字段:2071`PermissionRequest` hooks 可以允许或拒绝权限请求。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回一个 `decision` 对象,其中包含这些事件特定的字段:
1738 2072
1739| 字段 | 描述 |2073| 字段 | 描述 |
1740| :------------------- | :------------------------------------------------------------------------------------------------------------------ |2074| :------------------- | :------------------------------------------------------------------------------------------------------------------- |
1741| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝它。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)仍然被评估,所以返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |2075| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝它。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions) 仍然被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |
1742| `updatedInput` | 仅对 `"allow"`:在执行前修改工具的输入参数。替换整个输入对象,因此包括未修改的字段以及修改后的字段。修改后的输入会重新针对拒绝和询问规则进行评估 |2076| `updatedInput` | 仅对 `"allow"`:在执行前修改工具的输入参数。替换整个输入对象,因此在修改的输入旁边包含未更改的字段。修改的输入针对拒绝和询问规则重新评估 |
1743| `updatedPermissions` | 仅对 `"allow"`:应用权限规则更新的[权限更新条目](#permission-update-entries)数组,例如添加允许规则或更改会话权限模式 |2077| `updatedPermissions` | 仅对 `"allow"`:[权限更新条目](#permission-update-entries) 数组以应用,如添加允许规则或更改会话权限模式 |
1744| `message` | 仅对 `"deny"`:告诉 Claude 为什么权限被拒绝 |2078| `message` | 仅对 `"deny"`:告诉 Claude 为什么权限被拒绝 |
1745| `interrupt` | 仅对 `"deny"`:如果为 `true`,停止 Claude |2079| `interrupt` | 仅对 `"deny"`:如果 `true`,停止 Claude |
2080
2081不带 `decision` 对象退出 2 的 hook 保持权限流程不变,其 stderr 被丢弃。仅 `decision` 对象可以授予或拒绝请求。
1746 2082
1747```json theme={null}2083```json theme={null}
1748{2084{
1762 权限更新条目2098 权限更新条目
1763</h4>2099</h4>
1764 2100
1765`updatedPermissions` 输出字段和[`permission_suggestions` 输入字段](#permissionrequest-input)都使用相同的条目对象数组。每个条目都有一个 `type` 来确定其其他字段,以及一个 `destination` 来控制更改的写入位置。2101`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input) 都使用相同的条目对象数组。每个条目有一个 `type` 来确定其他字段,以及一个 `destination` 来控制更改写入的位置。
1766 2102
1767| `type` | 字段 | 效果 |2103| `type` | 字段 | 效果 |
1768| :------------------ | :------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |2104| :------------------ | :------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
1769| `addRules` | `rules`、`behavior`、`destination` | 添加权限规则。`rules` 是 `{toolName, ruleContent?}` 对象的数组。省略 `ruleContent` 以匹配整个工具。`behavior` 是 `"allow"`、`"deny"` 或 `"ask"` |2105| `addRules` | `rules`、`behavior`、`destination` | 添加权限规则。`rules` 是 `{toolName, ruleContent?}` 对象的数组。省略 `ruleContent` 以匹配整个工具。`behavior` 是 `"allow"`、`"deny"` 或 `"ask"` |
1770| `replaceRules` | `rules`、`behavior`、`destination` | 用提供的 `rules` 替换 `destination` 处给定 `behavior` 的所有规则 |2106| `replaceRules` | `rules`、`behavior`、`destination` | 用提供的 `rules` 替换 `destination` 处给定 `behavior` 的所有规则 |
1771| `removeRules` | `rules`、`behavior`、`destination` | 移除给定 `behavior` 的匹配规则 |2107| `removeRules` | `rules`、`behavior`、`destination` | 删除给定 `behavior` 的匹配规则 |
1772| `setMode` | `mode`、`destination` | 更改权限模式。有效模式为 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan` 和 `manual` 作为 `default` 的别名。`manual` 别名需要 Claude Code v2.1.200 或更高版本 |2108| `setMode` | `mode`、`destination` | 更改权限模式。有效模式为 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan` 和 `manual` 作为 `default` 的别名。`manual` 别名需要 Claude Code v2.1.200 或更高版本 |
1773| `addDirectories` | `directories`、`destination` | 添加工作目录。`directories` 是路径字符串的数组 |2109| `addDirectories` | `directories`、`destination` | 添加工作目录。`directories` 是路径字符串的数组 |
1774| `removeDirectories` | `directories`、`destination` | 移除工作目录 |2110| `removeDirectories` | `directories`、`destination` | 删除工作目录 |
1775 2111
1776<Note>2112<Note>
1777 `setMode` 与 `bypassPermissions` 仅在会话已启动时生效,绕过模式已可用:`--dangerously-skip-permissions`、`--permission-mode bypassPermissions`、`--allow-dangerously-skip-permissions` 或设置中的 `permissions.defaultMode: "bypassPermissions"`,且模式未被 [`permissions.disableBypassPermissionsMode`](/docs/zh-CN/permissions#managed-settings) 禁用。否则更新是无操作。`bypassPermissions` 无论 `destination` 如何都永远不会作为 `defaultMode` 持久化。2113 `setMode` 与 `bypassPermissions` 仅在您已经使用 bypass mode 启动会话时生效:`--dangerously-skip-permissions`、`--permission-mode bypassPermissions`、`--allow-dangerously-skip-permissions` 或 [用户、`--settings` 或托管设置](/docs/zh-CN/settings-reference#permissions-defaultmode) 中的 `permissions.defaultMode: "bypassPermissions"`。否则更新是无操作。当 [`permissions.disableBypassPermissionsMode`](/docs/zh-CN/permissions#managed-settings) 禁用模式或会话在 [受限模式](/docs/zh-CN/cli-reference#cli-flags) 中启动时,更新也是无操作。
2114
2115 `bypassPermissions` 永远不会作为 `defaultMode` 持久化,无论 `destination` 如何。
1778</Note>2116</Note>
1779 2117
1780每个条目上的 `destination` 字段确定更改是保留在内存中还是持久化到设置文件。2118每个条目上的 `destination` 字段确定更改是保留在内存中还是持久化到设置文件。
1786| `projectSettings` | `.claude/settings.json` |2124| `projectSettings` | `.claude/settings.json` |
1787| `userSettings` | `~/.claude/settings.json` |2125| `userSettings` | `~/.claude/settings.json` |
1788 2126
1789Hook 可以回显它接收的 `permission_suggestions` 之一作为其自己的 `updatedPermissions` 输出,这等同于用户在对话框中选择该"总是允许"选项。2127hook 可以回显它接收的 `permission_suggestions` 之一作为其自己的 `updatedPermissions` 输出。
1790 2128
1791<h3 id="posttooluse">2129<h3 id="posttooluse">
1792 PostToolUse2130 PostToolUse
1794 2132
1795在工具成功完成后立即运行。2133在工具成功完成后立即运行。
1796 2134
1797在工具名称上匹配,与 PreToolUse 相同的值。2135匹配工具名称,与 PreToolUse 相同的值。
2136
2137当工具名称不是正确的过滤器时更广泛地匹配:
2138
2139* 要在任何工具成功完成后运行 hook,省略 `matcher` 或将其设置为 `"*"`。您的 hook 然后可以自己发现更改了什么,例如通过运行 `git status --porcelain`,它也列出 `git diff` 错过的未跟踪文件。对于失败的工具调用,在 [PostToolUseFailure](#posttoolusefailure) 下添加相同的 hook。
2140* 要在特定文件更改时运行 hook,无论什么写入它,请使用 [FileChanged](#filechanged)。当 `Bash` 命令或 Claude Code 外的进程重写同一文件时,Claude Code 不运行匹配 `Edit|Write` 的 `PostToolUse` hook。
1798 2141
1799<h4 id="posttooluse-input">2142<h4 id="posttooluse-input">
1800 PostToolUse 输入2143 PostToolUse 输入
1801</h4>2144</h4>
1802 2145
1803`PostToolUse` hooks 在工具已经成功执行后触发。输入包括 `tool_input`(发送给工具的参数)和 `tool_response`(它返回的结果)。两者的确切架构取决于工具。2146`PostToolUse` hooks 在工具已经成功执行后触发。输入包括 `tool_input`(发送给工具的参数)和 `tool_response`(它返回的结果)。两者的确切模式取决于工具。文件工具 `tool_input` 路径以与 [PreToolUse](#pretooluse-input) 相同的格式到达:始终绝对,带有平台的本机分隔符,因此 Windows 上的反斜杠。对于 MCP 工具,输入也携带 [`mcp_server`](#pretooluse-input) 对象。
1804 2147
1805```json theme={null}2148```json theme={null}
1806{2149{
1816 },2159 },
1817 "tool_response": {2160 "tool_response": {
1818 "filePath": "/path/to/file.txt",2161 "filePath": "/path/to/file.txt",
1819 "success": true2162 "type": "create"
1820 },2163 },
1821 "tool_use_id": "toolu_01ABC123...",2164 "tool_use_id": "toolu_01ABC123...",
1822 "duration_ms": 122165 "duration_ms": 12
1828| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |2171| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |
1829 2172
1830<h4 id="posttooluse-decision-control">2173<h4 id="posttooluse-decision-control">
1831 PostToolUse 决定控制2174 PostToolUse 决策控制
1832</h4>2175</h4>
1833 2176
1834`PostToolUse` hooks 可以在工具执行后向 Claude 提供反馈。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您的 hook 脚本可以返回这些事件特定字段:2177`PostToolUse` hooks 可以在工具执行后提供反馈给 Claude。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
1835 2178
1836| 字段 | 描述 |2179| 字段 | 描述 |
1837| :--------------------- | :------------------------------------------------------------------------- |2180| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1838| `decision` | `"block"` 用 `reason` 提示 Claude。Claude 仍然看到原始输出;要替换它,使用 `updatedToolOutput` |2181| `decision` | `"block"` 在工具结果旁边添加 `reason`。Claude 仍然看到原始输出;要替换它,请使用 `updatedToolOutput` |
1839| `reason` | 当 `decision` 为 `"block"` 时向 Claude 显示的解释 |2182| `reason` | 当 `decision` 为 `"block"` 时显示给 Claude 的解释 |
1840| `additionalContext` | 添加到 Claude 上下文的字符串,与工具结果一起。请参阅[为 Claude 添加上下文](#add-context-for-claude) |2183| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1841| `updatedToolOutput` | 用提供的值替换工具的输出,然后将其发送给 Claude。该值必须与工具的输出形状匹配 |2184| `classifierContext` | 关于此调用结果的简短说明,用于 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 分类器而不是 Claude。有关详细信息,请参阅 [为自动模式分类器注释结果](#annotate-a-result-for-the-auto-mode-classifier)。需要 Claude Code v2.1.236 或更高版本 |
1842| `updatedMCPToolOutput` | 仅对[MCP 工具](#match-mcp-tools)替换输出。优先使用 `updatedToolOutput`,它适用于所有工具 |2185| `updatedToolOutput` | 在将工具的输出发送给 Claude 之前用提供的值替换它。该值必须与工具的输出形状匹配 |
2186| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools) 的输出。优先使用 `updatedToolOutput`,它适用于所有工具 |
1843 2187
1844下面的示例替换 `Bash` 调用的输出。替换值与 `Bash` 工具的输出形状匹配:2188下面的示例替换 `Bash` 调用的输出。替换值与 `Bash` 工具的输出形状匹配:
1845 2189
1859```2203```
1860 2204
1861<Warning>2205<Warning>
1862 `updatedToolOutput` 仅改变 Claude 看到的内容。工具已经在 hook 触发时运行,所以任何写入的文件、执行的命令或发送的网络请求都已生效。遥测,如 OpenTelemetry 工具跨度和分析事件,也在 hook 运行前捕获原始输出。要在运行前防止或修改工具调用,请改用[PreToolUse](#pretooluse) hook。2206 `updatedToolOutput` 仅更改 Claude 看到的内容。工具已经在 hook 触发时运行,因此任何写入的文件、执行的命令或发送的网络请求已经生效。遥测如 OpenTelemetry 工具跨度和分析事件也在 hook 运行之前捕获原始输出。要在运行前防止或修改工具调用,请改用 [PreToolUse](#pretooluse) hook。
2207
2208 替换值必须与工具的输出形状匹配。内置工具返回结构化对象而不是纯字符串。例如,`Bash` 返回一个带有 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,不与工具的输出模式匹配的值被忽略,使用原始输出。MCP 工具输出通过而不进行模式验证。剥离 Claude 需要的错误详情可能导致它基于错误的假设继续。
2209</Warning>
2210
2211<h4 id="annotate-a-result-for-the-auto-mode-classifier">
2212 为自动模式分类器注释结果
2213</h4>
2214
2215返回 `classifierContext` 以向 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 分类器发送关于工具调用结果的简短说明,而不是向 Claude。分类器 [永远不会接收工具结果本身](/docs/zh-CN/permission-modes#how-the-classifier-evaluates-actions),因此此字段是告诉它在审查后续操作之前关于调用返回的内容的支持方式。该字段需要 Claude Code v2.1.236 或更高版本。
2216
2217下面的示例告诉分类器查询的输出来自何处:
2218
2219```json theme={null}
2220{
2221 "hookSpecificOutput": {
2222 "hookEventName": "PostToolUse",
2223 "classifierContext": "This query ran against the staging database, not production."
2224 }
2225}
2226```
2227
2228分类器给予说明的权重取决于您配置 hook 的位置:
2229
2230* **在 Claude Code 中配置的 Hooks**:对于来自设置文件、插件、skills 和 agent frontmatter 的 hooks,分类器将说明视为未验证的、应用提供的上下文。说明永远不会建立用户意图,如果它声称您批准或请求了什么,分类器会根据您在对话中的自己的消息检查该声明
2231* **进程内 Agent SDK 回调**:当应用嵌入 Claude Code 将 hook 注册为 [TypeScript SDK 回调](/docs/zh-CN/agent-sdk/hooks) 并在实时会话期间返回说明时,分类器可能会将用户声明中继的说明视为用户意图。这样的声明可以满足分类器会接受来自您发送的消息的同意要求,但它永远不会解除您自己的消息也无法解除的阻止。会话恢复后,Claude Code 将恢复的说明视为未验证的上下文。当来自两个组的 hooks 注释同一调用时,分类器将组合说明视为未验证
2232
2233Claude Code 在传递说明时应用这些限制:
1863 2234
1864 替换值必须与工具的输出形状匹配。内置工具返回结构化对象而不是纯字符串。例如,`Bash` 返回一个具有 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,不与工具的输出架构匹配的值被忽略,使用原始输出。MCP 工具输出通过而不进行架构验证。剥离 Claude 需要的错误详细信息可能导致它基于错误的假设继续。2235* **长度**:Claude Code 将一个工具调用的说明上限为 2,000 个字符,并截断其余部分。上限在响应该调用的每个 hook 中共享
2236* **仅同步响应**:Claude Code 忽略 [在后台运行](#run-hooks-in-the-background) 的 hook 响应中的字段,因为该响应在 Claude Code 记录工具结果后到达
2237* **分类器不记录的调用**:分类器的成绩单省略只读查找如文件读取和搜索。Claude Code 丢弃附加到其中一个调用的说明
2238* **与重写的交互**:当说明描述您用 `updatedToolOutput` 替换的输出时,在同一 hook 响应中返回两个字段。如果该重写被拒绝或另一个 hook 的重写替换它,Claude Code 丢弃说明。Claude Code 传递您返回的说明而不重写,即使另一个 hook 重写输出
2239
2240<Warning>
2241 分类器读取您放在 `classifierContext` 中的内容作为来自托管会话的应用的信息,因此不要将不受信任的工具输出或第三方文本复制到其中。将说明保持为关于此一个调用的简短断言,如关于其来源的事实或关于它的用户声明;不要使用该字段传递不相关的消息或事件流。
1865</Warning>2242</Warning>
1866 2243
1867<h3 id="posttoolusefailure">2244<h3 id="posttoolusefailure">
1868 PostToolUseFailure2245 PostToolUseFailure
1869</h3>2246</h3>
1870 2247
1871当工具执行失败时运行:工具抛出错误,或 MCP 工具返回错误结果。使用此来记录失败、发送警报或向 Claude 提供纠正反馈。2248在启动执行的工具失败时运行:工具抛出错误,或 MCP 工具返回错误结果。使用此来记录失败、发送警报或向 Claude 提供纠正反馈。
1872 2249
1873在工具名称上匹配,与 PreToolUse 相同的值。2250匹配工具名称,与 PreToolUse 相同的值。
1874 2251
1875<Note>2252<Note>
1876 此事件不对工具调用在执行前被拒绝时触发:未知工具名称、输入失败架构或工具特定验证,或权限拒绝。验证拒绝作为 `tool_use_error` 结果返回,在 hooks 运行之前发生,因此它们既不触发 `PreToolUse` 也不触发此事件。权限拒绝触发 `PreToolUse` 但不触发此事件;请参阅[PermissionDenied](#permissiondenied)。2253 此事件不为执行前被拒绝的工具调用触发:未知工具名称、失败模式或工具特定验证的输入,或权限拒绝。验证拒绝作为 `tool_use_error` 结果返回,发生在 hooks 运行之前,因此它们既不触发 `PreToolUse` 也不触发此事件。权限拒绝触发 `PreToolUse` 但不触发此事件;请参阅 [PermissionDenied](#permissiondenied)。
1877</Note>2254</Note>
1878 2255
1879<h4 id="posttoolusefailure-input">2256<h4 id="posttoolusefailure-input">
1880 PostToolUseFailure 输入2257 PostToolUseFailure 输入
1881</h4>2258</h4>
1882 2259
1883PostToolUseFailure hooks 接收与 PostToolUse 相同的 `tool_name` 和 `tool_input` 字段,以及作为顶级字段的错误信息:2260PostToolUseFailure hooks 接收与 PostToolUse 相同的 `tool_name` 和 `tool_input` 字段,以及错误信息作为顶级字段。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。例如,失败的 `npm test` 命令可能传递:
1884 2261
1885```json theme={null}2262```json theme={null}
1886{2263{
1895 "description": "Run test suite"2272 "description": "Run test suite"
1896 },2273 },
1897 "tool_use_id": "toolu_01ABC123...",2274 "tool_use_id": "toolu_01ABC123...",
1898 "error": "Command exited with non-zero status code 1",2275 "error": "Exit code 1\nError: Cannot find module 'express'",
1899 "is_interrupt": false,2276 "is_interrupt": false,
1900 "duration_ms": 41872277 "duration_ms": 4187
1901}2278}
1902```2279```
1903 2280
1904| 字段 | 描述 |2281| 字段 | 描述 |
1905| :------------- | :--------------------------------------------- |2282| :------------- | :------------------------------------------------------------------------ |
1906| `error` | 描述出错原因的字符串 |2283| `error` | 描述出错内容的字符串。格式取决于失败的工具 |
1907| `is_interrupt` | 可选的布尔值,指示失败是否由用户中断引起 |2284| `is_interrupt` | 可选布尔值。当失败作为中止而不是工具报告的错误到达 Claude Code 时为 True。取消运行的工具不触发此 hook;工具结果携带中断消息 |
1908| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |2285| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |
1909 2286
2287`error` 字符串通常与 Claude 接收的失败工具结果相同的文本。其格式因工具和失败而异。在 `tool_name`、`is_interrupt` 和第一行 `Exit code N` 上键入您的 hook;将字符串的其余部分视为显示文本,而不是稳定格式。
2288
2289* 对于 Bash 和 PowerShell,运行并退出的命令产生第一行 `Exit code N`,然后是命令产生的任何输出作为一个块,stdout 和 stderr 交错
2290* 有效负载也可能携带裸失败消息,没有退出代码行,当 Claude Code 无法启动 shell 进程本身时
2291* Claude Code 中间截断长字符串,围绕 `... [N characters truncated] ...` 标记,并可以插入自己的行,如 `Command timed out after 2m 0s`
2292
1910<h4 id="posttoolusefailure-decision-control">2293<h4 id="posttoolusefailure-decision-control">
1911 PostToolUseFailure 决定控制2294 PostToolUseFailure 决策控制
1912</h4>2295</h4>
1913 2296
1914`PostToolUseFailure` hooks 可以在工具失败后向 Claude 提供上下文。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您的 hook 脚本可以返回这些事件特定字段:2297`PostToolUseFailure` hooks 可以在工具失败后向 Claude 提供上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
1915 2298
1916| 字段 | 描述 |2299| 字段 | 描述 |
1917| :------------------ | :-------------------------------------------------------------------- |2300| :------------------ | :-------------------------------------------------------------------------------------- |
1918| `additionalContext` | 添加到 Claude 上下文的字符串,与错误一起。请参阅[为 Claude 添加上下文](#add-context-for-claude) |2301| `additionalContext` | 与错误一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1919 2302
1920```json theme={null}2303```json theme={null}
1921{2304{
1930 PostToolBatch2313 PostToolBatch
1931</h3>2314</h3>
1932 2315
1933在批次中的每个工具调用都已解决后运行一次,在 Claude Code 向模型发送下一个请求之前。`PostToolUse` 每个工具触发一次,这意味着当 Claude 进行并行工具调用时它并发触发。`PostToolBatch` 恰好触发一次,包含完整批次,因此它是注入取决于运行的工具集而不是任何单个工具的上下文的正确位置。此事件没有匹配器。2316在批次中的每个工具调用都已解决后运行一次,在 Claude Code 向模型发送下一个请求之前。`PostToolUse` 每个工具运行一次,这意味着当 Claude 进行并行工具调用时它并发运行。`PostToolBatch` 恰好运行一次,带有完整批次,因此它是注入取决于运行的工具集而不是任何单个工具的上下文的正确位置。此事件没有匹配器。
1934 2317
1935<h4 id="posttoolbatch-input">2318<h4 id="posttoolbatch-input">
1936 PostToolBatch 输入2319 PostToolBatch 输入
1937</h4>2320</h4>
1938 2321
1939除了[通用输入字段](#common-input-fields)外,PostToolBatch hooks 还接收 `tool_calls`,一个描述批次中每个工具调用的数组:2322除了 [常见输入字段](#common-input-fields) 外,PostToolBatch hooks 接收 `tool_calls`,一个描述批次中每个工具调用的数组:
1940 2323
1941```json theme={null}2324```json theme={null}
1942{2325{
1962}2345}
1963```2346```
1964 2347
1965`tool_response` 包含与模型在相应 `tool_result` 块中接收的内容相同的内容。该值是序列化的字符串或内容块数组,完全如工具发出的那样。对于 `Read`,这意味着行号前缀的文本而不是原始文件内容。响应可能很大,因此仅解析您需要的字段。2348`tool_response` 包含模型在相应 `tool_result` 块中接收的相同内容。该值是序列化的字符串或内容块数组,完全如工具发出的一样。对于 `Read`,这意味着行号前缀的文本而不是原始文件内容。响应可能很大,因此仅解析您需要的字段。
1966 2349
1967<Note>2350<Note>
1968 `tool_response` 形状与 `PostToolUse` 的不同。`PostToolUse` 传递工具的结构化 `Output` 对象,例如 `{filePath: "...", success: true}` 对于 `Write`;`PostToolBatch` 传递序列化的 `tool_result` 内容模型看到的。2351 `tool_response` 形状与 `PostToolUse` 的不同。`PostToolUse` 传递工具的结构化 `Output` 对象,如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递模型看到的序列化 `tool_result` 内容。
1969</Note>2352</Note>
1970 2353
1971<h4 id="posttoolbatch-decision-control">2354<h4 id="posttoolbatch-decision-control">
1972 PostToolBatch 决定控制2355 PostToolBatch 决策控制
1973</h4>2356</h4>
1974 2357
1975`PostToolBatch` hooks 可以为 Claude 注入上下文。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您的 hook 脚本可以返回这些事件特定字段:2358`PostToolBatch` hooks 可以为 Claude 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
1976 2359
1977| 字段 | 描述 |2360| 字段 | 描述 |
1978| :------------------ | :------------------------------------------------------------------------------------------- |2361| :------------------ | :------------------------------------------------------------------------------------------------ |
1979| `additionalContext` | 在下一个模型调用之前注入的上下文字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude)了解传递详情、放入什么内容以及恢复的会话如何处理过去的值 |2362| `additionalContext` | 在下一个模型调用之前注入一次的上下文字符串。有关传递详情、放入其中的内容以及恢复的会话如何处理过去的值,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1980 2363
1981```json theme={null}2364```json theme={null}
1982{2365{
1987}2370}
1988```2371```
1989 2372
1990返回 `decision: "block"` 或 `continue: false` 在下一个模型调用之前停止代理循环。2373返回 `decision: "block"` 或 `continue: false` 在下一个模型调用之前停止 agentic 循环。阻止消息来自 JSON `reason` 或 `stopReason`,或来自退出 2 时的 stderr。您在成绩单中看到它作为警告,它保留在对话中,因此 Claude 在对话继续时看到它。
1991 2374
1992<h3 id="permissiondenied">2375<h3 id="permissiondenied">
1993 PermissionDenied2376 PermissionDenied
1994</h3>2377</h3>
1995 2378
1996当[自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode)分类器拒绝工具调用时运行。此 hook 仅在自动模式中触发:当您手动拒绝权限对话框、`PreToolUse` hook 阻止调用或 `deny` 规则匹配时,它不运行。使用它来记录分类器拒绝、调整配置或告诉模型它可能重试工具调用。2379在 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 拒绝工具调用时运行,包括当它拒绝而没有分类器判决时,因为 [与自动模式分开的安全检查拒绝了分类器自己的请求](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action) 或其响应没有解析。此 hook 仅在自动模式中触发:当您手动拒绝权限对话、`PreToolUse` hook 阻止调用或 `deny` 规则匹配时不运行。使用它来记录拒绝、调整配置或告诉模型它可能重试工具调用。
1997 2380
1998在工具名称上匹配,与 PreToolUse 相同的值。2381匹配工具名称,与 PreToolUse 相同的值。
1999 2382
2000<h4 id="permissiondenied-input">2383<h4 id="permissiondenied-input">
2001 PermissionDenied 输入2384 PermissionDenied 输入
2002</h4>2385</h4>
2003 2386
2004除了[通用输入字段](#common-input-fields)外,PermissionDenied hooks 还接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。2387除了 [常见输入字段](#common-input-fields) 外,PermissionDenied hooks 接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。
2005 2388
2006```json theme={null}2389```json theme={null}
2007{2390{
2016 "description": "Clean build directory"2399 "description": "Clean build directory"
2017 },2400 },
2018 "tool_use_id": "toolu_01ABC123...",2401 "tool_use_id": "toolu_01ABC123...",
2019 "reason": "Auto mode denied: command targets a path outside the project"2402 "reason": "[Irreversible Local Destruction]"
2020}2403}
2021```2404```
2022 2405
2023| 字段 | 描述 |2406| 字段 | 描述 |
2024| :------- | :----------------- |2407| :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2025| `reason` | 分类器解释为什么工具调用被拒绝的原因 |2408| `reason` | 拒绝原因。对于分类器判决,在大多数会话中它命名方括号中的匹配规则,如 `[Data Exfiltration]`;有关其他形式,请参阅 [审查拒绝](/docs/zh-CN/auto-mode-config#review-denials)。对于 [无判决拒绝](#permissiondenied-decision-control),它以 `Auto mode could not evaluate this action and is blocking it for safety` 开头。对于因分类器模型不可用而拒绝,它是固定文本 `Classifier unavailable` |
2026 2409
2027<h4 id="permissiondenied-decision-control">2410<h4 id="permissiondenied-decision-control">
2028 PermissionDenied 决定控制2411 PermissionDenied 决策控制
2029</h4>2412</h4>
2030 2413
2031PermissionDenied hooks 可以告诉模型它可能重试被拒绝的工具调用。返回一个 JSON 对象,其中 `hookSpecificOutput.retry` 设置为 `true`:2414PermissionDenied hooks 可以告诉模型它可能重试被拒绝的工具调用。返回一个 JSON 对象,其中 `hookSpecificOutput.retry` 设置为 `true`:
2039}2422}
2040```2423```
2041 2424
2042当 `retry` 为 `true` 时,Claude Code 向对话添加一条消息,告诉模型它可能重试工具调用。拒绝本身不被反转。如果您的 hook 不返回 JSON,或返回 `retry: false`,拒绝成立,模型接收原始拒绝消息。2425当 `retry` 为 `true` 时,Claude Code 向对话添加一条消息,告诉模型它可能重试工具调用。Claude Code 不反转拒绝本身。如果您的 hook 不返回 JSON,或返回 `retry: false`,拒绝成立,模型接收原始拒绝消息。
2426
2427当分类器对操作产生 [无判决](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action) 时,Claude Code 忽略 `retry: true`:其响应没有解析,或与自动模式分开的安全检查拒绝了分类器自己的请求。对于这些拒绝,Claude Code 已经在拒绝消息中告诉模型是否稍后重试或继续。
2043 2428
2044<h3 id="notification">2429<h3 id="notification">
2045 Notification2430 Notification
2046</h3>2431</h3>
2047 2432
2048在 Claude Code 发送通知时运行。在通知类型上匹配。省略匹配器以为所有通知类型运行 hooks。2433在 Claude Code 发送通知时运行。匹配通知类型。省略匹配器以对所有通知类型运行 hooks。
2434
2435您即使在关闭桌面通知时也接收这些 hook 事件:`preferredNotifChannel` 设置,包括 `notifications_disabled`,仅更改您如何被警告,而不是您的 hook 是否运行。
2049 2436
2050| 匹配器 | 何时触发 |2437| 匹配器 | 何时触发 |
2051| :--------------------- | :------------------------------------------------ |2438| :--------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2052| `permission_prompt` | Claude 需要您批准工具使用 |2439| `permission_prompt` | Claude 需要您批准工具使用或沙箱命令的 [网络请求](/docs/zh-CN/sandboxing#network-isolation),提示已等待约六秒 |
2053| `idle_prompt` | Claude 完成并等待您的下一个提示 |2440| `idle_prompt` | Claude 约 60 秒前完成响应,您自那以后没有输入 |
2054| `auth_success` | 身份验证完成 |2441| `auth_success` | 身份验证完成 |
2055| `elicitation_dialog` | MCP 服务器打开引出表单 |2442| `elicitation_dialog` | MCP 服务器打开引出表单,您约六秒没有输入 |
2056| `elicitation_complete` | MCP 引出表单被提交或关闭 |2443| `elicitation_url_dialog` | MCP 服务器要求您打开浏览器 URL,您约六秒没有输入 |
2444| `elicitation_complete` | MCP 服务器报告 [URL 模式引出](#elicitation-input) 完成 |
2057| `elicitation_response` | MCP 引出响应被发送回服务器 |2445| `elicitation_response` | MCP 引出响应被发送回服务器 |
2058| `agent_needs_input` | 后台会话开始等待您的输入。仅在[代理视图](/docs/zh-CN/agent-view)在终端中打开时触发 |2446| `agent_needs_input` | 后台会话在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时开始等待您的输入,或当前会话询问您 [agent team](/docs/zh-CN/agent-teams) 队友的终端设置问题,您约六秒没有输入 |
2059| `agent_completed` | 后台会话完成或失败。仅在[代理视图](/docs/zh-CN/agent-view)在终端中打开时触发 |2447| `agent_completed` | 后台会话完成或失败。仅在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时触发 |
2448| `quota_auto_resume_fired` | Claude Code 在 claude.ai 使用限制暂停您的任务后继续它:在重置时,或更早当您在 Claude Code 中做的事情,如添加使用额度、升级您的计划或切换模型,使使用再次可用时,带有 [模型设置异常](/docs/zh-CN/interactive-mode#wait-for-a-usage-limit-to-reset) |
2449| `quota_auto_resume_stale` | claude.ai 使用限制在您的计算机睡眠超过约 30 分钟时重置。Claude Code 等待您按 `Enter` 而不是继续。在更短的睡眠后它继续并改为触发 `quota_auto_resume_fired` |
2450| `quota_auto_resume_disabled` | Claude Code 结束其对 claude.ai 使用限制的等待而不继续您的任务:[`autoContinueAtUsageLimit`](/docs/zh-CN/settings-reference#autocontinueatusagelimit) 关闭或重置在 Claude Code 自己启动的等待期间移动超过 24 小时,继续的任务继续命中限制,或继续在到达模型之前被阻止。当您按 `Esc` 或 `Ctrl+C` 或选择 **Don't continue automatically** 时不触发 |
2060 2451
2061`agent_needs_input` 和 `agent_completed` 类型需要 Claude Code v2.1.198 或更高版本。2452`agent_needs_input` 和 `agent_completed` 类型需要 Claude Code v2.1.198 或更高版本。
2062 2453
2454`quota_auto_resume_fired`、`quota_auto_resume_stale` 和 `quota_auto_resume_disabled` 类型需要 Claude Code v2.1.234 或更高版本。
2455
2456在终端会话中,沙箱命令的网络请求的 `permission_prompt` 需要 Claude Code v2.1.246 或更高版本。
2457
2458队友的终端设置问题的 `agent_needs_input` 需要 Claude Code v2.1.248 或更高版本。
2459
2460<Note>
2461 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享其时序,因此在终端会话中您仅在您似乎远离终端时看到它们:
2462
2463 * 期望 `permission_prompt` 一旦您约六秒没有输入。计时器在权限提示出现时启动,每次按键推迟它。要在 Claude 要求许可使用工具时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。
2464 * 期望 `idle_prompt` 约 60 秒后 Claude 完成响应,仅当您自那以后没有输入时。Claude Code 在等待 claude.ai 使用限制重置时不发送 `idle_prompt`。当等待自己结束时,其中一个 `quota_auto_resume_*` 类型触发。
2465 * 期望 `elicitation_dialog` 用于引出表单,或 `elicitation_url_dialog` 用于浏览器 URL 请求,一旦您约六秒没有输入。两者共享与 `permission_prompt` 相同的六秒门:计时器在对话出现时启动,每次按键推迟它。
2466
2467 在另一个对话在屏幕上时到达的权限请求或引出保持相同的六秒门,从请求到达时计时。其通知可以在请求仍然等待时到达,同时打开的对话仍然在屏幕上。
2468</Note>
2469
2470Claude Code 在会话中以不同方式计时 `permission_prompt`,其中它向 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input) 发送权限请求,这是 Claude Desktop 和 VS Code 扩展如何托管 Claude Code 的方式:
2471
2472* 期望 `permission_prompt` 约六秒后 Claude 要求许可。Claude Code 在您输入时不推迟它。
2473* 如果您或 [PermissionRequest](#permissionrequest) hook 更早回答,Claude Code 不运行 `permission_prompt`。
2474* 设置 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 为 `1` 以在这些会话中关闭 `permission_prompt`。
2475
2476在 v2.1.233 之前,`permission_prompt` 在这些会话中不触发。
2477
2063使用单独的匹配器根据通知类型运行不同的处理程序。此配置在 Claude 需要权限批准时触发权限特定的警报脚本,在 Claude 空闲时触发不同的通知:2478使用单独的匹配器根据通知类型运行不同的处理程序。此配置在 Claude 需要权限批准时触发权限特定的警报脚本,在 Claude 空闲时触发不同的通知:
2064 2479
2065```json theme={null}2480```json theme={null}
2093 Notification 输入2508 Notification 输入
2094</h4>2509</h4>
2095 2510
2096除了[通用输入字段](#common-input-fields)外,Notification hooks 还接收 `message` 和通知文本、可选的 `title` 和 `notification_type` 指示哪个类型触发。2511除了 [常见输入字段](#common-input-fields) 外,Notification hooks 接收 `message` 与通知文本、可选 `title` 和 `notification_type` 指示哪个类型触发。
2097 2512
2098```json theme={null}2513```json theme={null}
2099{2514{
2107}2522}
2108```2523```
2109 2524
2110Notification hooks 无法阻止或修改通知。它们用于副作用,例如将通知转发到外部服务。[通用 JSON 输出字段](#json-output)如 `systemMessage` 适用。2525Notification hooks 无法阻止或修改通知。Claude Code 丢弃它们的 `systemMessage` 和 `continue` 字段,但仍然发出 [`terminalSequence`](#emit-terminal-notifications),这是桌面通知示例所依赖的。Notification hooks 用于副作用,如将通知转发到外部服务。
2111 2526
2112<h3 id="subagentstart">2527<h3 id="subagentstart">
2113 SubagentStart2528 SubagentStart
2114</h3>2529</h3>
2115 2530
2116当通过 Agent 工具生成 Claude Code subagent 时运行。支持匹配器以按代理类型名称过滤。对于内置代理,这是代理名称,如 `general-purpose`、`Explore` 或 `Plan`。对于[自定义 subagents](/docs/zh-CN/sub-agents),这是代理 frontmatter 中的 `name` 字段,而不是文件名。2531在 Claude 使用 Agent 工具生成子 agent 时运行,当 Claude [恢复子 agent](/docs/zh-CN/sub-agents#resume-subagents) 时,以及每次进程内 [agent team](/docs/zh-CN/agent-teams) 队友处理新消息时。支持匹配器以按 agent 类型名称过滤。对于内置 agent,这是 agent 名称如 `general-purpose`、`Explore` 或 `Plan`。对于 [自定义子 agent](/docs/zh-CN/sub-agents),这是 agent 的 frontmatter 中的 `name` 字段,而不是文件名。
2117 2532
2118对于由[插件](/docs/zh-CN/plugins)提供的 subagents,代理类型是插件范围的标识符,例如 `my-plugin:reviewer`,而不是裸 frontmatter 名称。冒号将插件范围的名称放在正则表达式路径上,因此使用 `^` 和 `$` 锚定匹配器以进行精确匹配:`^my-plugin:reviewer$`。2533对于由 [插件](/docs/zh-CN/plugins) 提供的子 agent,agent 类型是插件范围的标识符如 `my-plugin:reviewer`,而不是裸 frontmatter 名称。冒号将插件范围的名称放在正则表达式路径上,因此用 `^` 和 `$` 锚定匹配器以获得精确匹配:`^my-plugin:reviewer$`。
2119 2534
2120<h4 id="subagentstart-input">2535<h4 id="subagentstart-input">
2121 SubagentStart 输入2536 SubagentStart 输入
2122</h4>2537</h4>
2123 2538
2124除了[通用输入字段](#common-input-fields)外,SubagentStart hooks 还接收 `agent_id` 和 subagent 的唯一标识符以及 `agent_type` 和代理名称(匹配器过滤的值)。2539除了 [常见输入字段](#common-input-fields) 外,SubagentStart hooks 接收 `agent_id` 与子 agent 的唯一标识符和 `agent_type` 与匹配器过滤的 agent 名称。
2125 2540
2126```json theme={null}2541```json theme={null}
2127{2542{
2134}2549}
2135```2550```
2136 2551
2137SubagentStart hooks 无法阻止 subagent 创建,但它们可以向 subagent 注入上下文。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您可以返回:2552SubagentStart hooks 无法阻止子 agent 创建,但它们可以向子 agent 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:
2138 2553
2139| 字段 | 描述 |2554| 字段 | 描述 |
2140| :------------------ | :----------------------------------------------------------------------------- |2555| :------------------ | :--------------------------------------------------------------------------------------------------------- |
2141| `additionalContext` | 添加到 subagent 上下文开始处的字符串,在其第一个提示之前。请参阅[为 Claude 添加上下文](#add-context-for-claude) |2556| `additionalContext` | 在子 agent 对话开始时添加到子 agent 上下文的字符串,在其第一个提示之前。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
2142 2557
2143```json theme={null}2558```json theme={null}
2144{2559{
2149}2564}
2150```2565```
2151 2566
2567当 hook 再次为同一子 agent 运行时,Claude Code 仅在子 agent 的上下文还不包含来自早期运行的副本时注入返回的上下文。在启动时注入的副本保留在位置,保持子 agent 的 [prompt cache](/docs/zh-CN/prompt-caching#subagents-and-the-cache) 完整。在 [自动压缩](/docs/zh-CN/sub-agents#auto-compaction) 丢弃该副本后,Claude Code 再次注入下一个运行的上下文。
2568
2152<h3 id="subagentstop">2569<h3 id="subagentstop">
2153 SubagentStop2570 SubagentStop
2154</h3>2571</h3>
2155 2572
2156当 Claude Code subagent 完成响应时运行。在代理类型上匹配,与 SubagentStart 相同的值。2573在 Claude Code 子 agent 完成响应时运行。匹配 agent 类型,与 SubagentStart 相同的值。
2157 2574
2158<h4 id="subagentstop-input">2575<h4 id="subagentstop-input">
2159 SubagentStop 输入2576 SubagentStop 输入
2160</h4>2577</h4>
2161 2578
2162除了[通用输入字段](#common-input-fields)外,SubagentStop hooks 还接收 `stop_hook_active`、`agent_id`、`agent_type`、`agent_transcript_path` 和 `last_assistant_message`。`agent_type` 字段是用于匹配器过滤的值。`transcript_path` 是主会话的成绩单,而 `agent_transcript_path` 是 subagent 自己的成绩单,存储在嵌套的 `subagents/` 文件夹中。`last_assistant_message` 字段包含 subagent 最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。2579除了 [常见输入字段](#common-input-fields) 外,SubagentStop hooks 接收 `stop_hook_active`、`agent_id`、`agent_type`、`agent_transcript_path` 和 `last_assistant_message`。`agent_type` 字段是用于匹配器过滤的值。`transcript_path` 是主会话的成绩单,而 `agent_transcript_path` 是子 agent 自己的成绩单,存储在嵌套 `subagents/` 文件夹中。`last_assistant_message` 字段包含子 agent 最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。
2580
2581在 Claude Code v2.1.271 或更高版本上,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子 agent 在停止之前通过该工具传递其报告。`last_assistant_message` 字段然后保持子 agent 的结束文本(如果有),这不是传递的报告。报告是该调用的 `message` 输入,`PreToolUse` 或 `PostToolUse` hook 匹配 `SubagentHandback` 接收为 `tool_input.message`。
2163 2582
2164SubagentStop hooks 还接收 [Stop input](#stop-input) 中描述的 `background_tasks` 和 `session_crons` 数组,在 Claude Code v2.1.145 或更高版本中可用。两个数组都限定于父会话,而不是 subagent。2583SubagentStop hooks 也接收 [Stop 输入](#stop-input) 下描述的 `background_tasks` 和 `session_crons` 数组。两个数组都限定于父会话,而不是子 agent。
2165 2584
2166```json theme={null}2585```json theme={null}
2167{2586{
2180}2599}
2181```2600```
2182 2601
2183SubagentStop hooks 使用与[Stop hooks](#stop-decision-control)相同的决定控制格式,包括 `hookSpecificOutput.additionalContext` 和 `hookEventName` 设置为 `"SubagentStop"`,用于非错误反馈以保持 subagent 运行。返回 `decision: "block"` 和 `reason` 保持 subagent 运行并将 `reason` 作为其下一个指令传递给 subagent。要在 subagent 返回后向父会话注入上下文,请改用 `Agent` 工具上的[`PostToolUse`](#posttooluse) hook。2602SubagentStop hooks 使用与 [Stop hooks](#stop-decision-control) 相同的决策控制格式,包括 `hookSpecificOutput.additionalContext`,其中 `hookEventName` 设置为 `"SubagentStop"`,用于保持子 agent 运行的非错误反馈。返回 `decision: "block"` 与 `reason` 保持子 agent 运行并将 `reason` 作为其下一个指令传递给子 agent。通过退出 2 阻止的 hook 以相同方式传递其 stderr 消息。要在子 agent 返回后向父会话注入上下文,请改用 `Agent` 工具上的 [`PostToolUse`](#posttooluse) hook。
2184 2603
2185<h3 id="taskcreated">2604<h3 id="taskcreated">
2186 TaskCreated2605 TaskCreated
2187</h3>2606</h3>
2188 2607
2189当通过 `TaskCreate` 工具创建任务时运行。使用此来强制执行命名约定、要求任务描述或防止创建某些任务。2608在通过 `TaskCreate` 工具创建任务时运行。使用此来强制命名约定、要求任务描述或防止某些任务被创建。在 [没有 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability) 中,此事件不触发。
2190 2609
2191当 `TaskCreated` hook 以代码 2 退出时,任务不被创建,stderr 消息作为反馈反馈给模型。要完全停止队友而不是重新运行它,返回 JSON `{"continue": false, "stopReason": "..."}` 。TaskCreated hooks 不支持匹配器,在每次出现时触发。2610TaskCreated hooks 不支持匹配器,对每个出现触发。
2192 2611
2193<h4 id="taskcreated-input">2612<h4 id="taskcreated-input">
2194 TaskCreated 输入2613 TaskCreated 输入
2195</h4>2614</h4>
2196 2615
2197除了[通用输入字段](#common-input-fields)外,TaskCreated hooks 还接收 `task_id`、`task_subject` 和可选的 `task_description`、`teammate_name` 和 `team_name`。2616除了 [常见输入字段](#common-input-fields) 外,TaskCreated hooks 接收 `task_id`、`task_subject` 和可选的 `task_description`、`teammate_name` 和 `team_name`。
2198 2617
2199```json theme={null}2618```json theme={null}
2200{2619{
2201 "session_id": "abc123",2620 "session_id": "abc123",
2202 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",2621 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
2203 "cwd": "/Users/...",2622 "cwd": "/Users/...",
2204 "permission_mode": "default",
2205 "hook_event_name": "TaskCreated",2623 "hook_event_name": "TaskCreated",
2206 "task_id": "task-001",2624 "task_id": "task-001",
2207 "task_subject": "Implement user authentication",2625 "task_subject": "Implement user authentication",
2213 2631
2214| 字段 | 描述 |2632| 字段 | 描述 |
2215| :----------------- | :---------------------- |2633| :----------------- | :---------------------- |
2216| `task_id` | 被创建的任务的标识符 |2634| `task_id` | 正在创建的任务的标识符 |
2217| `task_subject` | 任务的标题 |2635| `task_subject` | 任务的标题 |
2218| `task_description` | 任务的详细描述。可能不存在 |2636| `task_description` | 任务的详细描述。可能不存在 |
2219| `teammate_name` | 创建任务的队友的名称。可能不存在 |2637| `teammate_name` | 创建任务的队友的名称。可能不存在 |
2220| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |2638| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |
2221 2639
2222<h4 id="taskcreated-decision-control">2640<h4 id="taskcreated-decision-control">
2223 TaskCreated 决定控制2641 TaskCreated 决策控制
2224</h4>2642</h4>
2225 2643
2226TaskCreated hooks 支持两种方式来控制任务创建:2644TaskCreated hook 可以通过两种方式阻止创建。任一方式,Claude Code 删除任务并将您的消息作为工具的错误返回给 Claude。Claude Code 忽略此事件的 `continue: false`,Claude 继续工作。
2227 2645
2228* **退出代码 2**:任务不被创建,stderr 消息作为反馈反馈给模型。2646* **退出代码 2**:Claude Code 将 stderr 文本作为消息返回。
2229* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 向用户显示。2647* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。
2230 2648
2231此示例阻止主题不遵循所需格式的任务:2649此示例阻止主题不遵循所需格式的任务:
2232 2650
2247 TaskCompleted2665 TaskCompleted
2248</h3>2666</h3>
2249 2667
2250当任务被标记为已完成时运行。这在两种情况下触发:当任何代理通过 TaskUpdate 工具显式标记任务为已完成时,或当[代理团队](/docs/zh-CN/agent-teams)队友完成其轮次且有进行中的任务时。使用此来强制执行完成标准,如通过测试或 lint 检查,然后任务才能关闭。2668在任务被标记为完成时运行。这在两种情况下触发:当任何 agent 通过 TaskUpdate 工具显式标记任务为完成时,或当 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合时有进行中的任务。使用此来强制完成标准,如通过测试或 lint 检查,然后任务才能关闭。
2251 2669
2252当 `TaskCompleted` hook 以代码 2 退出时,任务不被标记为已完成,stderr 消息作为反馈反馈给模型。要完全停止队友而不是重新运行它,返回 JSON `{"continue": false, "stopReason": "..."}` 。TaskCompleted hooks 不支持匹配器,在每次出现时触发。2670TaskCompleted hooks 不支持匹配器,对每个出现触发。
2253 2671
2254<h4 id="taskcompleted-input">2672<h4 id="taskcompleted-input">
2255 TaskCompleted 输入2673 TaskCompleted 输入
2256</h4>2674</h4>
2257 2675
2258除了[通用输入字段](#common-input-fields)外,TaskCompleted hooks 还接收 `task_id`、`task_subject` 和可选的 `task_description`、`teammate_name` 和 `team_name`。2676除了 [常见输入字段](#common-input-fields) 外,TaskCompleted hooks 接收 `task_id`、`task_subject` 和可选的 `task_description`、`teammate_name` 和 `team_name`。
2259 2677
2260```json theme={null}2678```json theme={null}
2261{2679{
2274 2692
2275| 字段 | 描述 |2693| 字段 | 描述 |
2276| :----------------- | :---------------------- |2694| :----------------- | :---------------------- |
2277| `task_id` | 被完成的任务的标识符 |2695| `task_id` | 正在完成的任务的标识符 |
2278| `task_subject` | 任务的标题 |2696| `task_subject` | 任务的标题 |
2279| `task_description` | 任务的详细描述。可能不存在 |2697| `task_description` | 任务的详细描述。可能不存在 |
2280| `teammate_name` | 完成任务的队友的名称。可能不存在 |2698| `teammate_name` | 完成任务的队友的名称。可能不存在 |
2281| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |2699| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |
2282 2700
2283<h4 id="taskcompleted-decision-control">2701<h4 id="taskcompleted-decision-control">
2284 TaskCompleted 决定控制2702 TaskCompleted 决策控制
2285</h4>2703</h4>
2286 2704
2287TaskCompleted hooks 支持两种方式来控制任务完成:2705TaskCompleted hooks 支持两种方式来控制任务完成:
2288 2706
2289* **退出代码 2**:任务不被标记为已完成,stderr 消息作为反馈反馈给模型。2707* **退出代码 2**:任务未被标记为完成,stderr 消息被反馈给模型作为反馈。
2290* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 向用户显示。2708* **JSON `{"continue": false, "stopReason": "..."}`**:当队友完成其回合触发事件时,完全停止队友,匹配 `Stop` hook 行为。`stopReason` 显示给用户。当 `TaskUpdate` 工具触发事件时,Claude Code 忽略 `continue: false`;退出代码 2 仍然阻止完成。
2291 2709
2292此示例运行测试并在失败时阻止任务完成:2710此示例运行测试并在它们失败时阻止任务完成:
2293 2711
2294```bash theme={null}2712```bash theme={null}
2295#!/bin/bash2713#!/bin/bash
2296INPUT=$(cat)2714INPUT=$(cat)
2297TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')2715TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
2298 2716
2299# 运行测试套件2717# Run the test suite
2300if ! npm test 2>&1; then2718if ! npm test 2>&1; then
2301 echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&22719 echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
2302 exit 22720 exit 2
2309 Stop2727 Stop
2310</h3>2728</h3>
2311 2729
2312在主 Claude Code 代理完成响应时运行。如果停止是由于用户中断,则不运行。API 错误触发[StopFailure](#stopfailure)。2730在主 Claude Code agent 完成响应时运行。如果停止由于用户中断而发生,则不运行。API 错误触发 [StopFailure](#stopfailure)。
2313 2731
2314<Tip>2732<Tip>
2315 [`/goal`](/docs/zh-CN/goal)命令是会话范围的基于提示的 Stop hook 的内置快捷方式。当您想要 Claude 继续工作直到条件成立而不编写 hook 配置时使用它。2733 [`/goal`](/docs/zh-CN/goal) 命令是会话范围的基于提示的 Stop hook 的内置快捷方式。当您想让 Claude 继续朝着条件工作而不编写 hook 配置时使用它。
2316</Tip>2734</Tip>
2317 2735
2318<h4 id="stop-input">2736<h4 id="stop-input">
2319 Stop 输入2737 Stop 输入
2320</h4>2738</h4>
2321 2739
2322除了[通用输入字段](#common-input-fields)外,Stop hooks 还接收 `stop_hook_active`、`last_assistant_message`、`background_tasks` 和 `session_crons`。`stop_hook_active` 字段在 Claude Code 已经作为 stop hook 的结果继续时为 `true`。检查此值或处理成绩单以防止 Claude Code 无限运行。Claude Code 在 8 次连续阻止后覆盖 hook 并结束轮次。2740除了 [常见输入字段](#common-input-fields) 外,Stop hooks 接收 `stop_hook_active`、`last_assistant_message`、`background_tasks` 和 `session_crons`。`stop_hook_active` 字段在 Claude Code 已经作为 stop hook 的结果继续时为 `true`。检查此值或处理成绩单以避免在永远不会解决的条件上阻止。Claude Code 在 8 个连续阻止后覆盖 hook 并结束回合。
2323 2741
2324`last_assistant_message` 字段包含 Claude 最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。2742`last_assistant_message` 字段包含 Claude 最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。对于作用于刚完成的回合的 hooks,如朗读或通知 hooks,使用此字段而不是读取 `transcript_path`:成绩单文件不保证在所有版本的 Stop 时间包含最终消息。
2325 2743
2326`background_tasks` 和 `session_crons` 数组在 Claude Code v2.1.145 或更高版本中可用,让 hooks 区分"会话完成"和"会话暂停等待后台工作唤醒它"。当任务注册表可达时两个数组都存在,当没有任何内容在进行中或计划时为空。2744`background_tasks` 和 `session_crons` 数组让 hooks 区分"会话完成"与"会话暂停等待后台工作唤醒它"。当任务注册表可达时两个数组都出现,当没有任何东西在飞行或计划时为空。
2327 2745
2328`background_tasks` 中的每个条目描述一个进行中的任务,并使用这些字段:2746`background_tasks` 中的每个条目描述一个进行中的任务,并使用这些字段:
2329 2747
2330| 字段 | 描述 |2748| 字段 | 描述 |
2331| :------------ | :----------------------------------------------------------------------------------------------------------------------------------------- |2749| :------------ | :---------------------------------------------------------------------------------------------------------------------------------------- |
2332| `id` | 任务标识符 |2750| `id` | 任务标识符 |
2333| `type` | 友好的任务类型标签,如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识哪个 Claude Code 功能创建了任务。对于无法识别的类型回退到原始判别式 |2751| `type` | 友好的任务类型标签如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识哪个 Claude Code 功能创建了任务。对于无法识别的类型回退到原始判别式 |
2334| `status` | 当前任务状态 |2752| `status` | 当前任务状态 |
2335| `description` | 自由文本描述,上限为 1000 个字符,当被剪切时在字符串中有 `… [+N chars]` 标记 |2753| `description` | 自由文本描述,上限为 1000 个字符,当被剪切时在字符串中有 `… [+N chars]` 标记 |
2336| `command` | Shell 命令行,上限为 1000 个字符。仅对 `shell` 任务存在 |2754| `command` | Shell 命令行,上限为 1000 个字符。仅对 `shell` 任务出现 |
2337| `agent_type` | Subagent 类型名称。仅对 `subagent` 任务存在 |2755| `agent_type` | 子 agent 类型名称。仅对 `subagent` 任务出现 |
2338| `server` | MCP 服务器名称。仅对 `monitor` 和 `MCP task` 任务存在 |2756| `server` | MCP 服务器名称。仅对 `monitor` 和 `MCP task` 任务出现 |
2339| `tool` | MCP 工具名称。仅对 `monitor` 和 `MCP task` 任务存在 |2757| `tool` | MCP 工具名称。仅对 `monitor` 和 `MCP task` 任务出现 |
2340| `name` | 工作流名称。仅对 `workflow` 任务存在 |2758| `name` | Workflow 名称。仅对 `workflow` 任务出现 |
2341 2759
2342`session_crons` 中的每个条目描述一个会话范围的计划唤醒,来自 `CronCreate`、`ScheduleWakeup` 和 `/loop`:2760`session_crons` 中的每个条目描述一个会话范围的计划唤醒,来自 `CronCreate`、`ScheduleWakeup` 和 `/loop`:
2343 2761
2344| 字段 | 描述 |2762| 字段 | 描述 |
2345| :---------- | :--------------------------------------------------- |2763| :---------- | :---------------------------------------------------- |
2346| `id` | Cron 任务标识符 |2764| `id` | Cron 任务标识符 |
2347| `schedule` | Cron 表达式,例如 `0 9 * * 1-5` |2765| `schedule` | Cron 表达式,例如 `0 9 * * 1-5` |
2348| `recurring` | `false` 用于一次性唤醒,其计划编码单个触发时间,`true` 用于在每次匹配时重新触发的任务 |2766| `recurring` | 对于一次性唤醒(其计划编码单个触发时间)为 `false`,对于在每个匹配上重新触发的任务为 `true` |
2349| `prompt` | 当 cron 触发时提交的提示,上限为 1000 个字符,具有相同的 `… [+N chars]` 标记 |2767| `prompt` | 当 cron 触发时提交的提示,上限为 1000 个字符,带有相同的 `… [+N chars]` 标记 |
2350 2768
2351此示例显示一个 Stop 输入,其中有一个进行中的 shell 任务和一个循环 cron:2769此示例显示了一个 Stop 输入,带有一个进行中的 shell 任务和一个循环 cron:
2352 2770
2353```json theme={null}2771```json theme={null}
2354{2772{
2380```2798```
2381 2799
2382<h4 id="stop-decision-control">2800<h4 id="stop-decision-control">
2383 Stop 决定控制2801 Stop 决策控制
2384</h4>2802</h4>
2385 2803
2386`Stop` 和 `SubagentStop` hooks 可以控制 Claude 是否继续。除了所有 hooks 可用的[JSON 输出字段](#json-output)外,您的 hook 脚本可以返回这些事件特定字段:2804`Stop` 和 `SubagentStop` hooks 可以控制 Claude 是否继续。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
2387 2805
2388| 字段 | 描述 |2806| 字段 | 描述 |
2389| :------------------------------------- | :------------------------------------------------------------------------------------------- |2807| :------------------------------------- | :---------------------------------------------------------------------------------------- |
2390| `decision` | `"block"` 防止 Claude 停止。省略以允许 Claude 停止 |2808| `decision` | `"block"` 防止 Claude 停止。省略以允许 Claude 停止 |
2391| `reason` | 当 `decision` 为 `"block"` 时必需。告诉 Claude 为什么它应该继续 |2809| `reason` | 当 `decision` 为 `"block"` 时需要。告诉 Claude 为什么它应该继续 |
2392| `hookSpecificOutput.additionalContext` | 非错误反馈给 Claude。对话继续,以便 Claude 可以对其采取行动,但与 `decision: "block"` 不同,它在成绩单中显示为 hook 反馈而不是 hook 错误 |2810| `hookSpecificOutput.additionalContext` | Claude 的非错误反馈。对话继续以便 Claude 可以作用于它,但与 `decision: "block"` 不同,它在成绩单中显示为 hook 反馈而不是 hook 错误 |
2811
2812通过退出 2 阻止的 hook 路由方式与 `reason` 相同:Claude 接收 stderr 消息作为为什么它应该继续的解释。
2393 2813
2394```json theme={null}2814```json theme={null}
2395{2815{
2398}2818}
2399```2819```
2400 2820
2401当 hook 按设计工作并给予 Claude 指导时使用 `additionalContext`,例如"在完成前运行测试套件"。它通过与 `decision: "block"` 相同的循环保护保持对话进行,即 `stop_hook_active` 输入和 8 次连续继续上限,但成绩单将其标记为 `Stop hook feedback`,不显示 hook 错误通知:2821当 hook 按设计工作并给 Claude 指导时使用 `additionalContext`,如"在完成前运行测试套件"。它通过与 `decision: "block"` 相同的循环保护保持对话进行,即 `stop_hook_active` 输入和 8 个连续继续上限,但成绩单将其标记为 `Stop hook feedback`,不显示 hook 错误通知:
2402 2822
2403```json theme={null}2823```json theme={null}
2404{2824{
2413 StopFailure2833 StopFailure
2414</h3>2834</h3>
2415 2835
2416当轮次因 API 错误而结束时运行,而不是[Stop](#stop)。输出和退出代码被忽略。使用此来记录失败、发送警报或在 Claude 因速率限制、身份验证问题或其他 API 错误而无法完成响应时采取恢复操作。2836在回合由于 API 错误而结束时运行,而不是 [Stop](#stop)。Claude Code 忽略 hook 的输出和退出代码,除了 [`terminalSequence`](#emit-terminal-notifications)。使用此来记录失败、发送警报或在 Claude 由于速率限制、身份验证问题或其他 API 错误无法完成响应时采取恢复操作。
2417 2837
2418<h4 id="stopfailure-input">2838<h4 id="stopfailure-input">
2419 StopFailure 输入2839 StopFailure 输入
2420</h4>2840</h4>
2421 2841
2422除了[通用输入字段](#common-input-fields)外,StopFailure hooks 还接收 `error`、可选的 `error_details` 和可选的 `last_assistant_message`。`error` 字段标识错误类型,用于匹配器过滤。2842除了 [常见输入字段](#common-input-fields) 外,StopFailure hooks 接收 `error`、可选的 `error_details` 和可选的 `last_assistant_message`。`error` 字段标识错误类型,用于匹配器过滤。
2423 2843
2424| 字段 | 描述 |2844| 字段 | 描述 |
2425| :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2845| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2426| `error` | 错误类型:`rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens` 或 `unknown` |2846| `error` | 错误类型:`rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`account_on_hold`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens`、`cloud_credential_error` 或 `unknown` |
2427| `error_details` | 关于错误的额外详细信息(如果可用) |2847| `error_details` | 关于错误的其他详情,当可用时 |
2428| `last_assistant_message` | 在对话中显示的呈现错误文本。与 `Stop` 和 `SubagentStop` 不同,其中此字段包含 Claude 的对话输出,对于 `StopFailure` 它包含 API 错误字符串本身,例如 `"API Error: Rate limit reached"` |2848| `last_assistant_message` | 在对话中显示的呈现错误文本。与 `Stop` 和 `SubagentStop` 不同,其中此字段保持 Claude 的对话输出,对于 `StopFailure` 它包含 API 错误字符串本身,如 `"API Error: Rate limit reached"` |
2429 2849
2430```json theme={null}2850```json theme={null}
2431{2851{
2439}2859}
2440```2860```
2441 2861
2442StopFailure hooks 没有决定控制。它们仅为通知和日志记录目的运行。2862StopFailure hooks 没有决策控制。它们仅用于通知和日志记录目的运行。
2443 2863
2444<h3 id="teammateidle">2864<h3 id="teammateidle">
2445 TeammateIdle2865 TeammateIdle
2446</h3>2866</h3>
2447 2867
2448当[代理团队](/docs/zh-CN/agent-teams)队友在完成其轮次后即将空闲时运行。使用此来强制执行质量门,如要求通过 lint 检查或验证输出文件存在。2868在 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合后即将空闲时运行。使用此来强制质量门,如在队友停止工作之前要求通过 lint 检查或验证输出文件存在。
2449 2869
2450当 `TeammateIdle` hook 以代码 2 退出时,队友接收 stderr 消息作为反馈并继续工作而不是空闲。要完全停止队友而不是重新运行它,返回 JSON `{"continue": false, "stopReason": "..."}` 。TeammateIdle hooks 不支持匹配器,在每次出现时触发。2870TeammateIdle hooks 不支持匹配器,对每个出现触发。
2451 2871
2452<h4 id="teammateidle-input">2872<h4 id="teammateidle-input">
2453 TeammateIdle 输入2873 TeammateIdle 输入
2454</h4>2874</h4>
2455 2875
2456除了[通用输入字段](#common-input-fields)外,TeammateIdle hooks 还接收 `teammate_name` 和 `team_name`。2876除了 [常见输入字段](#common-input-fields) 外,TeammateIdle hooks 接收 `teammate_name` 和 `team_name`。
2457 2877
2458```json theme={null}2878```json theme={null}
2459{2879{
2473| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |2893| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |
2474 2894
2475<h4 id="teammateidle-decision-control">2895<h4 id="teammateidle-decision-control">
2476 TeammateIdle 决定控制2896 TeammateIdle 决策控制
2477</h4>2897</h4>
2478 2898
2479TeammateIdle hooks 支持两种方式来控制队友行为:2899TeammateIdle hooks 支持两种方式来控制队友行为:
2480 2900
2481* **退出代码 2**:队友接收 stderr 消息作为反馈并继续工作而不是空闲。2901* **退出代码 2**:队友接收 stderr 消息作为反馈并继续工作而不是空闲。
2482* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 向用户显示。2902* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 显示给用户。
2483 2903
2484此示例检查构建工件是否存在,然后允许队友空闲:2904此示例检查构建工件存在,然后允许队友空闲:
2485 2905
2486```bash theme={null}2906```bash theme={null}
2487#!/bin/bash2907#!/bin/bash
2498 ConfigChange2918 ConfigChange
2499</h3>2919</h3>
2500 2920
2501当会话期间配置文件更改时运行。使用此来审计设置更改、强制执行安全策略或阻止对配置文件的未授权修改。2921在会话期间配置文件更改时运行。使用此来审计设置更改、强制安全策略或阻止对配置文件的未授权修改。
2502 2922
2503ConfigChange hooks 对设置文件、托管策略设置和 skill 文件的更改触发。输入中的 `source` 字段告诉您哪种类型的配置更改,可选的 `file_path` 字段提供更改文件的路径。2923Claude Code 在设置文件、托管策略文件或 skill 文件更改时运行 ConfigChange hooks。对于托管策略,它仅在 `managed-settings.json` 或 `managed-settings.d/` 中的文件更改时运行。它应用 [服务器托管设置](/docs/zh-CN/server-managed-settings) 和对 macOS 托管首选项或 Windows 注册表策略的更改而不运行它们。在带有 [`wslInheritsWindowsSettings`](/docs/zh-CN/settings-reference#wslinheritswindowssettings) 的 WSL 上,它也在其策略轮询上应用更改的 Windows 端托管设置文件而不运行它们。
2504 2924
2505匹配器在配置源上过滤:2925匹配器过滤配置源:
2506 2926
2507| 匹配器 | 何时触发 |2927| 匹配器 | 何时触发 |
2508| :----------------- | :------------------------------- |2928| :----------------- | :----------------------------------------------------- |
2509| `user_settings` | `~/.claude/settings.json` 更改 |2929| `user_settings` | `~/.claude/settings.json` 更改 |
2510| `project_settings` | `.claude/settings.json` 更改 |2930| `project_settings` | `.claude/settings.json` 更改 |
2511| `local_settings` | `.claude/settings.local.json` 更改 |2931| `local_settings` | `.claude/settings.local.json` 更改 |
2512| `policy_settings` | 托管策略设置更改 |2932| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的文件更改 |
2513| `skills` | `.claude/skills/` 中的 skill 文件更改 |2933| `skills` | `.claude/skills/` 中的 skill 文件更改 |
2514 2934
2515此示例记录所有配置更改以进行安全审计:2935此示例记录所有配置更改以进行安全审计:
2536 ConfigChange 输入2956 ConfigChange 输入
2537</h4>2957</h4>
2538 2958
2539除了[通用输入字段](#common-input-fields)外,ConfigChange hooks 还接收 `source` 和可选的 `file_path`。`source` 字段指示哪种配置类型更改,`file_path` 提供被修改的特定文件的路径。2959除了 [常见输入字段](#common-input-fields) 外,ConfigChange hooks 接收 `source` 和可选的 `file_path`。`source` 字段指示哪个配置类型更改,`file_path` 提供修改的特定文件的路径。
2540 2960
2541```json theme={null}2961```json theme={null}
2542{2962{
2550```2970```
2551 2971
2552<h4 id="configchange-decision-control">2972<h4 id="configchange-decision-control">
2553 ConfigChange 决定控制2973 ConfigChange 决策控制
2554</h4>2974</h4>
2555 2975
2556ConfigChange hooks 可以阻止配置更改生效。使用退出代码 2 或 JSON `decision` 来防止更改。被阻止时,新设置不应用于运行中的会话。2976ConfigChange hooks 可以阻止配置更改生效。使用退出代码 2 或 JSON `decision` 来防止更改。当被阻止时,新设置不应用于运行的会话。
2557 2977
2558| 字段 | 描述 |2978| 字段 | 描述 |
2559| :--------- | :--------------------------------- |2979| :--------- | :-------------------------- |
2560| `decision` | `"block"` 防止配置更改被应用。省略以允许更改 |2980| `decision` | `"block"` 防止配置更改被应用。省略以允许更改 |
2561| `reason` | 当 `decision` 为 `"block"` 时向用户显示的解释 |2981| `reason` | 被接受但永远不显示 |
2562 2982
2563```json theme={null}2983```json theme={null}
2564{2984{
2567}2987}
2568```2988```
2569 2989
2570`policy_settings` 更改无法被阻止。Hooks 仍然对 `policy_settings` 源触发,因此您可以使用它们进行审计日志记录,但任何阻止决定都被忽略。这确保企业管理的设置始终生效。2990`policy_settings` 更改无法被阻止。当机器上的托管设置文件更改时,hooks 仍然为 `policy_settings` 源触发,因此您可以使用它们来记录这些编辑,但任何阻止决策都被忽略。这确保企业托管设置始终生效。当 [服务器托管设置](/docs/zh-CN/server-managed-settings) 到达或刷新时,Claude Code 不运行 `ConfigChange` hooks。
2991
2992Claude Code 作用于 ConfigChange hook 的 JSON 输出中的阻止决策,并丢弃 `systemMessage` 和 `continue`。被阻止的更改不向您或 Claude 显示任何消息,无论您是用 `reason` 还是退出 2 时的 stderr 阻止。Claude Code 仅向调试日志写入一行。
2571 2993
2572<h3 id="cwdchanged">2994<h3 id="cwdchanged">
2573 CwdChanged2995 CwdChanged
2574</h3>2996</h3>
2575 2997
2576当会话期间工作目录更改时运行,例如当 Claude 执行 `cd` 命令时。使用此来对目录更改做出反应:重新加载环境变量、激活项目特定的工具链或自动运行设置脚本。与[FileChanged](#filechanged)配对,用于[direnv](https://direnv.net/)等管理每个目录环境的工具。2998在主对话中的 shell 命令更改工作目录时运行,例如当 Claude 执行 `cd` 命令时。使用此来对目录更改做出反应:重新加载环境变量、激活项目特定的工具链或自动运行设置脚本。与 [FileChanged](#filechanged) 配对,用于像 [direnv](https://direnv.net/) 这样管理每个目录环境的工具。
2577 2999
2578CwdChanged hooks 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量持久化到会话的后续 Bash 命令中,就像在[SessionStart hooks](#persist-environment-variables)中一样。3000CwdChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 CwdChanged 事件,当 Claude Code 清除它们时。
2579 3001
2580CwdChanged 不支持匹配器,在每次目录更改时触发。3002CwdChanged 不支持匹配器,对每个出现触发。
2581 3003
2582<h4 id="cwdchanged-input">3004<h4 id="cwdchanged-input">
2583 CwdChanged 输入3005 CwdChanged 输入
2584</h4>3006</h4>
2585 3007
2586除了[通用输入字段](#common-input-fields)外,CwdChanged hooks 还接收 `old_cwd` 和 `new_cwd`。3008除了 [常见输入字段](#common-input-fields) 外,CwdChanged hooks 接收 `old_cwd` 和 `new_cwd`。
2587 3009
2588```json theme={null}3010```json theme={null}
2589{3011{
2600 CwdChanged 输出3022 CwdChanged 输出
2601</h4>3023</h4>
2602 3024
2603除了所有 hooks 可用的[JSON 输出字段](#json-output)外,CwdChanged hooks 还可以返回 `watchPaths` 来动态设置[FileChanged](#filechanged)监视的文件路径:3025除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,CwdChanged hooks 可以返回 `watchPaths` 来动态设置 [FileChanged](#filechanged) 监视的文件路径:
2604 3026
2605| 字段 | 描述 |3027| 字段 | 描述 |
2606| :----------- | :-------------------------------------------------------------------- |3028| :----------- | :--------------------------------------------------------- |
2607| `watchPaths` | 绝对路径的数组。替换当前动态监视列表。来自您的 `matcher` 配置的路径始终被监视。返回空数组会清除动态列表,这在进入新目录时很典型 |3029| `watchPaths` | 绝对路径数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。进入新目录时返回空数组是典型的 |
2608 3030
2609CwdChanged hooks 没有决定控制。它们无法阻止目录更改。3031CwdChanged hooks 没有决策控制。它们无法阻止目录更改。
3032
3033Claude Code 从它们的 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。
3034
3035<h3 id="directoryadded">
3036 DirectoryAdded
3037</h3>
3038
3039在您使用 `/add-dir` 命令在会话中添加工作目录后运行,或在 SDK 客户端使用 `register_repo_root` 控制请求添加一个后运行。使用此来准备新添加的存储库,例如安装其依赖。
3040
3041Claude Code 在以下情况下不触发此事件:
3042
3043* 您使用 `--add-dir` 启动标志传递目录;[SessionStart](#sessionstart) 涵盖这些目录
3044* 您在 `/permissions` Workspace 标签上添加目录
3045* 您添加已经是工作目录或在其中的目录
3046
3047Claude Code 在刷新沙箱和权限状态后触发 DirectoryAdded,因此沙箱工具已经在您的 hook 运行时看到新目录。Hook 命令本身运行未沙箱化。
3048
3049Claude Code 不等待 hook:添加立即完成,hook 在后台以 600 秒默认超时运行。
3050
3051匹配器过滤目录添加的方式:
3052
3053| 匹配器 | 何时触发 |
3054| :------------------- | :-------------------------------------- |
3055| `slash_command` | 您使用 `/add-dir` 添加目录 |
3056| `register_repo_root` | SDK 客户端使用 `register_repo_root` 控制请求添加目录 |
3057
3058<h4 id="directoryadded-input">
3059 DirectoryAdded 输入
3060</h4>
3061
3062除了 [常见输入字段](#common-input-fields) 外,DirectoryAdded hooks 接收 `directory` 和 `source`。
3063
3064| 字段 | 描述 |
3065| :---------- | :----------------------------------------------------------------------- |
3066| `directory` | 添加的目录的绝对路径 |
3067| `source` | 目录如何添加,`/add-dir` 为 `"slash_command"` 或 SDK 控制请求为 `"register_repo_root"` |
3068
3069```json theme={null}
3070{
3071 "session_id": "abc123",
3072 "transcript_path": "/Users/.../.claude/projects/.../transcript.jsonl",
3073 "cwd": "/Users/my-project",
3074 "hook_event_name": "DirectoryAdded",
3075 "directory": "/Users/my-other-repo",
3076 "source": "slash_command"
3077}
3078```
3079
3080DirectoryAdded hooks 没有决策控制。它们无法阻止添加,这在 hook 运行时已经完成。Claude Code 从它们的 JSON 输出丢弃 `continue` 字段,并根据源以不同方式呈现其余部分:
3081
3082* `slash_command`:Claude Code 将 hook 的 `systemMessage` 作为对话的下一个回合的上下文传递给 Claude,而不是向您显示它。失败 hooks 的计数出现在成绩单中。完整失败输出进入调试日志
3083* `register_repo_root`:Claude Code 仅将 `systemMessage` 输出和失败输出写入调试日志
2610 3084
2611<h3 id="filechanged">3085<h3 id="filechanged">
2612 FileChanged3086 FileChanged
2613</h3>3087</h3>
2614 3088
2615当监视的文件在磁盘上更改时运行。用于在项目配置文件修改时重新加载环境变量。3089在监视的文件在磁盘上更改时运行。Claude Code 使用文件系统监视器检测更改,而不是通过检查工具调用,因此它运行 hook,无论什么更改了文件:`Edit` 或 `Write` 工具调用、Claude 使用 `Bash` 运行的脚本或 Claude Code 外的进程。常见用途是在项目配置文件更改时重新加载环境变量。
2616 3090
2617此事件的 `matcher` 有两个作用:3091此事件的 `matcher` 有两个角色:
2618 3092
2619* **构建监视列表**:值在 `|` 上分割,每个段注册为工作目录中的文字文件名,因此 `".envrc|.env"` 监视恰好这两个文件。正则表达式模式在这里不有用:像 `^\.env` 这样的值会监视一个字面上名为 `^\.env` 的文件。3093* **构建监视列表**:值在 `|` 上分割,每个段注册为工作目录中的字面文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里不有用:像 `^\.env` 这样的值会监视字面名为 `^\.env` 的文件。
2620* **过滤哪些 hooks 运行**:当监视的文件更改时,相同的值使用标准[匹配器规则](#matcher-patterns)针对更改文件的基名过滤哪些 hook 组运行。3094* **过滤哪些 hooks 运行**:当监视的文件更改时,相同的值使用标准 [匹配器规则](#matcher-patterns) 针对更改文件的基名过滤哪些 hook 组运行。
2621 3095
2622FileChanged hooks 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量持久化到会话的后续 Bash 命令中,就像在[SessionStart hooks](#persist-environment-variables)中一样。3096此示例在任何更改后规范化 `data.csv` 中的行结尾,包括 `Bash` 命令或外部脚本重写文件:
3097
3098```json theme={null}
3099{
3100 "hooks": {
3101 "FileChanged": [
3102 {
3103 "matcher": "data.csv",
3104 "hooks": [
3105 {
3106 "type": "command",
3107 "command": "/path/to/normalize-line-endings.sh"
3108 }
3109 ]
3110 }
3111 ]
3112 }
3113}
3114```
3115
3116hook 从 [JSON 输入](#filechanged-input) 的 `file_path` 字段读取更改文件的绝对路径,在 stdin 上。其 `grep` 守卫测试与 `perl` 删除的相同内容,行末的 CR,因此规范化后的运行退出而不触及文件。更松散的守卫循环永远,因为 `perl -i` 重写文件即使它替换了什么都没有,Claude Code 在每次重写后运行 hook。保存此脚本到 `/path/to/normalize-line-endings.sh` 并使其可执行:
3117
3118```bash theme={null}
3119#!/bin/bash
3120FILE=$(jq -r .file_path)
3121if grep -q $'\r$' "$FILE"; then
3122 perl -pi -e 's/\r$//' "$FILE"
3123fi
3124```
3125
3126要确认 hook 工作,要求 Claude 使用 Bash 命令向 `data.csv` 追加 CRLF 行。Claude Code 运行 hook,文件最终以 LF 结尾。
3127
3128要监视您无法提前命名的文件,从 hook 返回 [`watchPaths`](#filechanged-output) 来动态更新监视列表。Claude Code 仅在某些东西命名要监视的文件时启动监视器,因此使用至少命名一个文件的 FileChanged 组为列表播种,或使用 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 返回 `watchPaths`。匹配器仍然过滤当监视的文件更改时哪些 hook 组运行,因此给处理动态路径的组一个省略的匹配器,它匹配每个监视的文件并不向监视列表添加任何内容。`"*"` 匹配器也匹配每个文件,但 Claude Code 像任何其他值一样在监视列表中注册它,作为字面名为 `*` 的文件。
3129
3130FileChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 [CwdChanged](#cwdchanged) 事件,当 Claude Code 清除它们时。
2623 3131
2624<h4 id="filechanged-input">3132<h4 id="filechanged-input">
2625 FileChanged 输入3133 FileChanged 输入
2626</h4>3134</h4>
2627 3135
2628除了[通用输入字段](#common-input-fields)外,FileChanged hooks 还接收 `file_path` 和 `event`。3136除了 [常见输入字段](#common-input-fields) 外,FileChanged hooks 接收 `file_path` 和 `event`。
2629 3137
2630| 字段 | 描述 |3138| 字段 | 描述 |
2631| :---------- | :----------------------------------------------------- |3139| :---------- | :------------------------------------------------------- |
2632| `file_path` | 更改文件的绝对路径 |3140| `file_path` | 更改的文件的绝对路径 |
2633| `event` | 发生了什么:`"change"`(文件修改)、`"add"`(文件创建)或 `"unlink"`(文件删除) |3141| `event` | 发生了什么:修改文件为 `"change"`、创建的文件为 `"add"` 或删除的文件为 `"unlink"` |
2634 3142
2635```json theme={null}3143```json theme={null}
2636{3144{
2647 FileChanged 输出3155 FileChanged 输出
2648</h4>3156</h4>
2649 3157
2650除了所有 hooks 可用的[JSON 输出字段](#json-output)外,FileChanged hooks 还可以返回 `watchPaths` 来动态更新监视的文件路径:3158除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,FileChanged hooks 可以返回 `watchPaths` 来动态更新监视的文件路径:
2651 3159
2652| 字段 | 描述 |3160| 字段 | 描述 |
2653| :----------- | :----------------------------------------------------------------------------- |3161| :----------- | :-------------------------------------------------------------------------- |
2654| `watchPaths` | 绝对路径的数组。替换当前动态监视列表。来自您的 `matcher` 配置的路径始终被监视。当您的 hook 脚本根据更改的文件发现要监视的其他文件时使用此项 |3162| `watchPaths` | 绝对路径数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。当您的 hook 脚本根据更改的文件发现要监视的其他文件时使用此 |
3163
3164FileChanged hooks 没有决策控制。它们无法阻止文件更改发生。
2655 3165
2656FileChanged hooks 没有决定控制。它们无法阻止文件更改的发生。3166Claude Code 从它们的 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。
2657 3167
2658<h3 id="worktreecreate">3168<h3 id="worktreecreate">
2659 WorktreeCreate3169 WorktreeCreate
2660</h3>3170</h3>
2661 3171
2662当您运行 `claude --worktree` 或[subagent 使用 `isolation: "worktree"`](/docs/zh-CN/sub-agents#choose-the-subagent-scope)时运行。默认情况下,Claude Code 使用 `git worktree` 创建隔离的工作副本。配置 WorktreeCreate hook 替换该默认 git 行为,让您使用不同的版本控制系统,如 SVN、Perforce 或 Mercurial。3172在创建 worktree 时运行,无论是从 `claude --worktree`、从 [使用 `isolation: "worktree"` 的子 agent](/docs/zh-CN/sub-agents#choose-the-subagent-scope),还是对于 Claude Code 在其自己的 worktree 中隔离的 [后台会话](/docs/zh-CN/agent-view#how-file-edits-are-isolated)。默认情况下,Claude Code 使用 `git worktree` 创建隔离的工作副本。配置 WorktreeCreate hook 替换该默认 git 行为,让您使用不同的版本控制系统,如 SVN、Perforce 或 Mercurial。
2663 3173
2664因为 hook 完全替换默认行为,[`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees)不被处理。如果您需要将本地配置文件(如 `.env`)复制到新 worktree,请在您的 hook 脚本内执行。3174因为 hook 完全替换默认行为,[`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees) 不被处理。如果您需要将本地配置文件如 `.env` 复制到新 worktree,请在您的 hook 脚本内执行。
2665 3175
2666Hook 必须返回创建的 worktree 目录的绝对路径。Claude Code 使用此路径作为隔离会话的工作目录。请参阅[WorktreeCreate 输出](#worktreecreate-output)了解每个 hook 类型如何返回路径。3176hook 必须返回创建的 worktree 目录的路径。Claude Code 使用此路径作为隔离会话的工作目录。有关每个 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。
2667 3177
2668此示例创建 SVN 工作副本并打印路径供 Claude Code 使用。用您自己的替换仓库 URL:3178Claude Code 作用于 hook 的成功和返回的路径,并丢弃 `systemMessage` 和 `continue`。
3179
3180此示例创建 SVN 工作副本并打印路径供 Claude Code 使用。将存储库 URL 替换为您自己的:
2669 3181
2670```json theme={null}3182```json theme={null}
2671{3183{
2684}3196}
2685```3197```
2686 3198
2687Hook 从 stdin 上的 JSON 输入读取 worktree `name`,将新副本检出到新目录,并打印目录路径。最后一行的 `echo` 是 Claude Code 读取的 worktree 路径。将任何其他输出重定向到 stderr,以便它不会干扰路径。3199hook 从 stdin 上的 JSON 输入读取 worktree `name`,检出一个新副本到新目录,并打印目录路径。最后一行的 `echo` 是 Claude Code 读取为 worktree 路径的内容。将任何其他输出重定向到 stderr,以便它不干扰路径。
2688 3200
2689<h4 id="worktreecreate-input">3201<h4 id="worktreecreate-input">
2690 WorktreeCreate 输入3202 WorktreeCreate 输入
2691</h4>3203</h4>
2692 3204
2693除了[通用输入字段](#common-input-fields)外,WorktreeCreate hooks 还接收 `name` 字段。这是新 worktree 的 slug 标识符,由用户指定或自动生成,例如 `bold-oak-a3f2`。3205除了 [常见输入字段](#common-input-fields) 外,WorktreeCreate hooks 接收 `name` 字段。这是新 worktree 的 slug 标识符,由用户指定或自动生成,例如 `bold-oak-a3f2`。
2694 3206
2695```json theme={null}3207```json theme={null}
2696{3208{
2706 WorktreeCreate 输出3218 WorktreeCreate 输出
2707</h4>3219</h4>
2708 3220
2709WorktreeCreate hooks 不使用标准的允许/阻止决定模型。相反,hook 的成功或失败决定结果。Hook 必须返回创建的 worktree 目录的绝对路径:3221WorktreeCreate hooks 不使用标准允许/阻止决策模型。相反,hook 的成功或失败确定结果。hook 必须返回创建的 worktree 目录的路径:
3222
3223* **命令 hooks** (`type: "command"`):将路径打印为 stdout 的最后一个非空行。Claude Code 在读取该行之前剥离 ANSI 转义代码,因此在您的 `echo` 之前打印的 shell 启动横幅被忽略。将任何其他 hook 输出重定向到 stderr。
3224* **HTTP hooks** (`type: "http"`):在响应体中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。
2710 3225
2711* **命令 hooks**(`type: "command"`):在 stdout 上打印路径作为最后一个非空行。Claude Code 在读取该行之前剥离 ANSI 转义代码,因此在您的 `echo` 之前打印的 shell 启动横幅被忽略。将任何其他 hook 输出重定向到 stderr。3226如果 hook 失败或产生无路径,worktree 创建失败并出现错误。
2712* **HTTP hooks**(`type: "http"`):在响应体中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。
2713 3227
2714如果 hook 失败或不产生路径,worktree 创建失败并出现错误。3228Claude Code 根据 hook 运行的目录解析相对路径,折叠其中的任何 `.` 或 `..` 段。如果结果路径不是 Claude Code 可以进入的目录,会话打印命名路径的错误并以代码 1 退出。
2715 3229
2716Claude Code 根据 hook 运行的目录解析相对路径。如果生成的路径不是 Claude Code 可以进入的目录,会话打印一个错误,命名路径并以代码 1 退出。在 v2.1.205 之前,相对路径或磁盘上不存在的路径会在启动时使会话崩溃,使用 `-p` 时会停滞约 30 秒,然后以代码 0 退出。3230Claude Code 拒绝包含 `.` 或 `..` 段的绝对路径,以及通过存储库根下的符号链接的任何路径,因为提交到存储库的符号链接可能会将 worktree 重定向到其外。错误命名被拒绝的组件。返回不通过存储库内符号链接的规范化路径。在 v2.1.216 之前,worktree 创建遵循 hook 的路径而不进行此筛选。
2717 3231
2718<h3 id="worktreeremove">3232<h3 id="worktreeremove">
2719 WorktreeRemove3233 WorktreeRemove
2720</h3>3234</h3>
2721 3235
2722当 worktree 被移除时运行,要么当您退出 `--worktree` 会话并选择移除它时,要么当具有 `isolation: "worktree"` 的 subagent 完成时。这是[WorktreeCreate](#worktreecreate)的清理对应物。3236在删除 worktree 时运行。这是 [WorktreeCreate](#worktreecreate) 的清理对应物。事件在以下情况下触发:
2723 3237
2724对于基于 git 的 worktrees,Claude Code 使用 `git worktree remove` 自动处理清理。如果您为非 git 版本控制系统配置了 WorktreeCreate hook,将其与 WorktreeRemove hook 配对以处理清理。没有它,worktree 目录留在磁盘上。3238* 您退出 `--worktree` 会话并选择删除它
3239* 带有 `isolation: "worktree"` 的子 agent 完成
3240* 您删除 [后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes),其 worktree hook 创建
2725 3241
2726Claude Code 将 WorktreeCreate 返回的路径作为 `worktree_path` 在 hook 输入中传递。此示例读取该路径并移除目录:3242对于基于 git 的 worktrees,Claude Code 使用 `git worktree remove` 自动处理清理。如果您为非 git 版本控制系统配置了 WorktreeCreate hook,将其与 WorktreeRemove hook 配对来处理清理。没有它,worktree 目录留在磁盘上。
3243
3244Claude Code 丢弃 WorktreeRemove hook 的 [JSON 输出字段](#json-output),如 `systemMessage` 和 `continue`。
3245
3246对于后台会话删除,Claude Code 在运行 hook 之前验证存储的 worktree 路径,并拒绝是符号链接或通过存储库根下的符号链接的路径。hook 仅对仍包含文件的 worktree 运行,当您在 [agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中确认删除时;对于这样的 worktree,[`claude rm`](/docs/zh-CN/agent-view#manage-sessions-from-the-shell) 保持会话和 worktree。在 v2.1.216 之前,hook 在存储的路径上运行而不进行这些检查。
3247
3248Claude Code 将 WorktreeCreate 返回的路径作为 `worktree_path` 在 hook 输入中传递。此示例读取该路径并删除目录:
2727 3249
2728```json theme={null}3250```json theme={null}
2729{3251{
2746 WorktreeRemove 输入3268 WorktreeRemove 输入
2747</h4>3269</h4>
2748 3270
2749除了[通用输入字段](#common-input-fields)外,WorktreeRemove hooks 还接收 `worktree_path` 字段,这是被移除的 worktree 的绝对路径。3271除了 [常见输入字段](#common-input-fields) 外,WorktreeRemove hooks 接收 `worktree_path` 字段,这是被删除的 worktree 的绝对路径。
2750 3272
2751```json theme={null}3273```json theme={null}
2752{3274{
2758}3280}
2759```3281```
2760 3282
2761WorktreeRemove hooks 没有决定控制。它们无法阻止 worktree 移除,但可以执行清理任务,如移除版本控制状态或存档更改。Hook 失败仅在调试模式下记录。3283WorktreeRemove hook 的退出代码决定结果。当 hook 以非零退出且 `worktree_path` 处的目录之后仍然存在时,删除失败:
3284
3285* worktree 保留在磁盘上,hook 的命令和 stderr 进入 [调试日志](#debug-hooks)。
3286* 如果您删除后台会话,会话也保留。[agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中的拒绝消息报告 hook 如何结束,如 `exited 1`,引用其 stderr 的开头,并说删除会话再次是否无论如何删除目录。
2762 3287
2763<h3 id="precompact">3288<h3 id="precompact">
2764 PreCompact3289 PreCompact
2766 3291
2767在 Claude Code 即将运行压缩操作之前运行。3292在 Claude Code 即将运行压缩操作之前运行。
2768 3293
2769匹配器值指示压缩是手动还是自动触发:3294匹配器值指示压缩是手动触发还是自动触发:
2770 3295
2771| 匹配器 | 何时触发 |3296| 匹配器 | 何时触发 |
2772| :------- | :----------- |3297| :------- | :-------------------------------------------------------------------- |
2773| `manual` | `/compact` |3298| `manual` | `/compact` |
2774| `auto` | 当上下文窗口满时自动压缩 |3299| `auto` | 当对话到达 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) 时自动压缩 |
2775 3300
2776退出代码 2 以阻止压缩。对于手动 `/compact`,stderr 消息向用户显示。您也可以通过返回带有 `"decision": "block"` 的 JSON 来阻止。3301以代码 2 退出以阻止压缩。对于手动 `/compact`,stderr 消息显示给用户。您也可以通过返回 JSON 与 `"decision": "block"` 来阻止。
2777 3302
2778阻止自动压缩有不同的效果,取决于何时触发。如果压缩在上下文限制之前主动触发,Claude Code 跳过它,对话继续未压缩。如果压缩被触发以从已由 API 返回的上下文限制错误恢复,底层错误浮出并且当前请求失败。3303阻止自动压缩根据何时触发有不同的效果。如果压缩在上下文限制之前主动触发,Claude Code 跳过它,对话继续未压缩。如果压缩被触发以从 API 已经返回的上下文限制错误恢复,底层错误浮出,当前请求失败。
3304
3305Claude Code 丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。
2779 3306
2780<h4 id="precompact-input">3307<h4 id="precompact-input">
2781 PreCompact 输入3308 PreCompact 输入
2782</h4>3309</h4>
2783 3310
2784除了[通用输入字段](#common-input-fields)外,PreCompact hooks 还接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传入 `/compact` 的内容。对于 `auto`,`custom_instructions` 为空。3311除了 [常见输入字段](#common-input-fields) 外,PreCompact hooks 接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传递到 `/compact` 的内容,当他们传递什么都没有时为 `null`。对于 `auto`,`custom_instructions` 为 `null`。
2785 3312
2786```json theme={null}3313```json theme={null}
2787{3314{
2790 "cwd": "/Users/...",3317 "cwd": "/Users/...",
2791 "hook_event_name": "PreCompact",3318 "hook_event_name": "PreCompact",
2792 "trigger": "manual",3319 "trigger": "manual",
2793 "custom_instructions": ""3320 "custom_instructions": null
2794}3321}
2795```3322```
2796 3323
2798 PostCompact3325 PostCompact
2799</h3>3326</h3>
2800 3327
2801在 Claude Code 完成压缩操作后运行。使用此事件对新的压缩状态做出反应,例如记录生成的摘要或更新外部状态。3328在 Claude Code 完成压缩操作后运行。使用此事件对新压缩状态做出反应,例如记录生成的摘要或更新外部状态。Claude Code 丢弃 PostCompact hook 的 `systemMessage` 和 `continue` 字段。
2802 3329
2803与 `PreCompact` 相同的匹配器值适用:3330与 `PreCompact` 相同的匹配器值适用:
2804 3331
2805| 匹配器 | 何时触发 |3332| 匹配器 | 何时触发 |
2806| :------- | :------------- |3333| :------- | :--------------------------------------------------------------------- |
2807| `manual` | 在 `/compact` 后 |3334| `manual` | 在 `/compact` 后 |
2808| `auto` | 在上下文窗口满时自动压缩后 |3335| `auto` | 在自动压缩后,当对话到达 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) |
2809 3336
2810<h4 id="postcompact-input">3337<h4 id="postcompact-input">
2811 PostCompact 输入3338 PostCompact 输入
2812</h4>3339</h4>
2813 3340
2814除了[通用输入字段](#common-input-fields)外,PostCompact hooks 还接收 `trigger` 和 `compact_summary`。`compact_summary` 字段包含压缩操作生成的对话摘要。3341除了 [常见输入字段](#common-input-fields) 外,PostCompact hooks 接收 `trigger` 和 `compact_summary`。`compact_summary` 字段包含压缩操作生成的对话摘要。
2815 3342
2816```json theme={null}3343```json theme={null}
2817{3344{
2824}3351}
2825```3352```
2826 3353
2827PostCompact hooks 没有决定控制。它们无法影响压缩结果,但可以执行后续任务。3354PostCompact hooks 没有决策控制。它们无法影响压缩结果,但可以执行后续任务。
3355
3356<h3 id="premodelswitch">
3357 PreModelSwitch
3358</h3>
3359
3360在 Claude Code 应用您或客户端请求的模型切换之前运行。使用它来阻止切换、要求确认或在切换发生之前显示它将花费什么。
3361
3362PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 为这些请求运行它:
3363
3364* `/model <name>` 和 `/model` 选择器
3365* `Option+P` 或 `Alt+P` 模型选择器
3366* `/config` 中的 Model 设置
3367* 当那改变会话的模型时打开 [快速模式](/docs/zh-CN/fast-mode)
3368* 来自 [Agent SDK](/docs/zh-CN/agent-sdk/typescript#query-object) 主机或 [Remote Control](/docs/zh-CN/remote-control) 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改
3369
3370Claude Code 不为它自己进行的切换运行 PreModelSwitch hooks,如 [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback) 或恢复会话时恢复模型。这些更改仅到达 [PostModelSwitch](#postmodelswitch)。
3371
3372Claude Code 将匹配器与会话切换到的模型的规范名称进行比较,忽略任何 `[1m]` 后缀。别名如 `opus`、日期模型 ID 和提供商特定 ID 如 Amazon Bedrock 模型 ID 都匹配它们解析到的一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的每个拼写。
3373
3374当 Claude Code 无法确定目标的规范名称时,例如仅您的 [LLM 网关](/docs/zh-CN/llm-gateway) 知道的自定义模型 ID,它运行每个 PreModelSwitch hook,无论匹配器如何。阻止的 hook 应该从其输入检查 `to_model` 而不是仅依赖匹配器。
3375
3376将匹配器写为精确名称、`|` 分隔列表如 `claude-opus-4-6|claude-opus-5` 或正则表达式如 `.*opus.*`。此示例使用精确名称匹配器,也从 hook 输入检查 `to_model`,因此它拒绝切换到 Opus 4.6,通过以代码 2 退出,并让任何其他目标通过:
3377
3378<Tabs>
3379 <Tab title="macOS/Linux">
3380 命令使用 `jq` 检查 `to_model`:
3381
3382 ```json theme={null}
3383 {
3384 "hooks": {
3385 "PreModelSwitch": [
3386 {
3387 "matcher": "claude-opus-4-6",
3388 "hooks": [
3389 {
3390 "type": "command",
3391 "command": "jq -e '.to_model | test(\"opus-4-6\")' > /dev/null && { echo 'Opus 4.6 is retired for this project. Use a newer model.' >&2; exit 2; }; exit 0"
3392 }
3393 ]
3394 }
3395 ]
3396 }
3397 }
3398 ```
3399 </Tab>
3400
3401 <Tab title="Windows (PowerShell)">
3402 注册一个通过 PowerShell 运行脚本的命令 hook:
3403
3404 ```json theme={null}
3405 {
3406 "hooks": {
3407 "PreModelSwitch": [
3408 {
3409 "matcher": "claude-opus-4-6",
3410 "hooks": [
3411 {
3412 "type": "command",
3413 "command": "powershell.exe",
3414 "args": [
3415 "-NoProfile",
3416 "-ExecutionPolicy",
3417 "Bypass",
3418 "-File",
3419 "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-opus-46.ps1"
3420 ]
3421 }
3422 ]
3423 }
3424 ]
3425 }
3426 }
3427 ```
3428
3429 将此脚本保存到项目中的 `.claude/hooks/block-opus-46.ps1`:
3430
3431 ```powershell theme={null}
3432 $hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
3433 if ($hookInput.to_model -match 'opus-4-6') {
3434 [Console]::Error.WriteLine('Opus 4.6 is retired for this project. Use a newer model.')
3435 exit 2
3436 }
3437 exit 0
3438 ```
3439 </Tab>
3440</Tabs>
3441
3442要确认 hook 工作,从运行不同模型的会话运行 `/model claude-opus-4-6`。Claude Code 保持当前模型并报告 PreModelSwitch hook 阻止了切换,您的消息作为原因。
3443
3444<h4 id="premodelswitch-input">
3445 PreModelSwitch 输入
3446</h4>
3447
3448除了 [常见输入字段](#common-input-fields) 外,PreModelSwitch hooks 接收此表中的字段。最后五个描述重新发送对话到新模型的成本,因此 hook 可以在切换发生之前显示该数字。
3449
3450| 字段 | 类型 | 描述 |
3451| :-------------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3452| `from_model` | string | 切换改变的模型 ID |
3453| `to_model` | string | 切换改变到的模型 ID。匹配器与此模型的规范名称进行比较 |
3454| `requested_model` | string or `null` | 请求命名的模型:别名如 `opus`、完整模型 ID 或当请求是默认模型时 `null` |
3455| `source` | string | 请求来自何处:`"command"` 对于 `/model <name>`、`/config` 中的 Model 设置或打开快速模式;`"picker"` 对于模型选择器;`"sdk"` 对于 `set_model` 请求,或来自 Agent SDK 主机或 Remote Control 的 `apply_flag_settings` 请求中的模型更改 |
3456| `context_tokens` | number | 下一个请求重新发送作为其提示的令牌:主对话中最后响应的输入、缓存读取、缓存创建和输出令牌,合并。第一个响应前为 `0` |
3457| `prompt_cache_warm` | boolean | 当前模型的 prompt cache 是否可能仍然温暖,意味着切换放弃它 |
3458| `cache_ttl` | string | [Prompt cache 生命周期](/docs/zh-CN/prompt-caching#cache-lifetime) Claude Code 为此会话请求:`"5m"` 或 `"1h"` |
3459| `estimated_cache_write_usd` | number | 将 `context_tokens` 写入 `to_model` 上的 prompt cache 的估计成本(美元),以 `cache_ttl` 速率,不包括下一个响应。服务器可能不需要重新缓存整个上下文,因此将其视为估计 |
3460| `pricing` | string | Claude Code 如何定价 `estimated_cache_write_usd`:当您的组织配置了自己的速率时为 `"configured"`,列表价格为 `"catalog"`,或当 `to_model` 没有已知价格且 Claude Code 假设默认速率时为 `"default"` |
3461
3462此示例显示了在运行 Sonnet 5 的会话中 `/model opus` 的输入:
3463
3464```json theme={null}
3465{
3466 "session_id": "abc123",
3467 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
3468 "cwd": "/Users/...",
3469 "hook_event_name": "PreModelSwitch",
3470 "from_model": "claude-sonnet-5",
3471 "to_model": "claude-opus-5",
3472 "requested_model": "opus",
3473 "source": "command",
3474 "context_tokens": 182340,
3475 "prompt_cache_warm": true,
3476 "cache_ttl": "5m",
3477 "estimated_cache_write_usd": 1.1396,
3478 "pricing": "catalog"
3479}
3480```
3481
3482<h4 id="premodelswitch-decision-control">
3483 PreModelSwitch 决策控制
3484</h4>
3485
3486`PreModelSwitch` hooks 可以取消切换、要求用户确认或让它继续。退出代码 2 或顶级 `decision: "block"` 取消切换。
3487
3488为了更精细的控制,在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,如 [PreToolUse](#pretooluse-decision-control)。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述两个字段:
3489
3490| 字段 | 描述 |
3491| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------- |
3492| `permissionDecision` | `"allow"` 继续并跳过 [当 prompt cache 温暖时 Claude Code 显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户确认它 |
3493| `permissionDecisionReason` | 对于 `"deny"`,显示给用户作为切换被阻止的原因,或作为 `set_model` 请求的错误返回。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 被忽略 |
3494
3495仅交互式会话中的 `/model` 可以显示 `"ask"` 提示。在每个其他表面,包括带 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 将 `"ask"` 视为拒绝。
3496
3497此示例要求用户确认并引用来自 `context_tokens` 的令牌计数:
3498
3499```json theme={null}
3500{
3501 "hookSpecificOutput": {
3502 "hookEventName": "PreModelSwitch",
3503 "permissionDecision": "ask",
3504 "permissionDecisionReason": "Switching now re-sends about 180k tokens to the new model. Continue?"
3505 }
3506}
3507```
3508
3509当多个 PreModelSwitch hooks 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。
3510
3511Claude Code 显示用户您的 hook 返回的任何 `systemMessage`,无论决策如何,因此成本报告 hook 可以返回 `{"systemMessage": "..."}` 并退出 0。
3512
3513在其超时之前不响应的 PreModelSwitch hook 阻止切换。在 [PreToolUse](#timeouts) 上,相比之下,超时的命令 hook 让工具调用继续。此事件的默认超时为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hooks,因此 `prompt` 和 `agent` 默认不适用。
3514
3515以 0 或 2 以外的代码退出且不打印 JSON 决策的 hook 不阻止:Claude Code 显示其 stderr 并应用切换,如 [其他退出代码](#other-exit-codes) 下所述。
3516
3517<h3 id="postmodelswitch">
3518 PostModelSwitch
3519</h3>
3520
3521在会话的模型更改后运行。使用它来给 Claude 模型特定的指导,而不编辑每个 CLAUDE.md。
3522
3523PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。Claude Code 在任何这些更改后运行 PostModelSwitch hooks:
3524
3525* 您或客户端请求的切换
3526* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),改变会话的模型
3527* 设置如 [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting) 进入或离开 plan mode
3528* Claude Code 恢复会话时恢复模型
3529
3530Claude Code 不为来自 [回退模型链](/docs/zh-CN/model-config#fallback-model-chains) 的模型运行 PostModelSwitch hooks,因为该替换持续一个回合并保持会话的模型不变。
3531
3532匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 将其与会话切换到的模型的规范名称进行比较。
3533
3534此示例在会话的模型更改为任何 Opus 模型时添加指导:
3535
3536```json theme={null}
3537{
3538 "hooks": {
3539 "PostModelSwitch": [
3540 {
3541 "matcher": ".*opus.*",
3542 "hooks": [
3543 {
3544 "type": "command",
3545 "command": "echo 'On Opus, delegate implementation work to subagents and keep this conversation for planning and review.'"
3546 }
3547 ]
3548 }
3549 ]
3550 }
3551}
3552```
3553
3554要确认 hook 工作,从运行不同模型的会话切换到 Opus 模型,例如从 Sonnet 会话运行 `/model opus`,然后询问 Claude 它对当前模型有什么指导。
3555
3556<h4 id="postmodelswitch-input">
3557 PostModelSwitch 输入
3558</h4>
3559
3560PostModelSwitch hooks 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,其中 `hook_event_name` 设置为 `"PostModelSwitch"` 和两个更多 `source` 值:`"auto"` 对于自动回退或 Claude Code 自己进行的其他更改,以及 `"resume"` 对于恢复会话时恢复的模型。
3561
3562当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 恢复的保存模型设置。
3563
3564<h4 id="postmodelswitch-decision-control">
3565 PostModelSwitch 决策控制
3566</h4>
3567
3568Claude Code 获取您的 hook 在退出 0 时的 [纯文本 stdout](#exit-code-0),或来自 JSON 输出的 `additionalContext`,并在切换后的下一个请求中将其传递给 Claude。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:
3569
3570| 字段 | 描述 |
3571| :------------------ | :----------------------------------------------------------------------------------------- |
3572| `additionalContext` | 与下一个请求一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
3573
3574如果 hook 在您发送下一个提示后五秒内未完成,Claude Code 发送该请求而不输出,并将其附加到以下请求。如果模型在下一个请求之前更改多次,Claude Code 仅传递最后一个切换目标模型的输出。
2828 3575
2829<h3 id="sessionend">3576<h3 id="sessionend">
2830 SessionEnd3577 SessionEnd
2831</h3>3578</h3>
2832 3579
2833当 Claude Code 会话结束时运行。用于清理任务、记录会话统计或保存会话状态。支持匹配器以按退出原因过滤。3580在 Claude Code 会话结束时运行。对于清理任务、记录会话统计或保存会话状态很有用。支持匹配器以按退出原因过滤。
2834 3581
2835hook 输入中的 `reason` 字段指示会话为何结束:3582`reason` 字段在 hook 输入中指示会话为什么结束:
2836 3583
2837| 原因 | 描述 |3584| 原因 | 描述 |
2838| :---------------------------- | :------------------- |3585| :---------------------------- | :------------------------------------------------------- |
2839| `clear` | 会话使用 `/clear` 命令清除 |3586| `clear` | 使用 `/clear` 命令清除会话 |
2840| `resume` | 通过交互式 `/resume` 切换会话 |3587| `resume` | 通过交互式 `/resume` 切换会话 |
2841| `logout` | 用户登出 |3588| `logout` | 用户登出 |
2842| `prompt_input_exit` | 用户在提示输入可见时退出 |3589| `prompt_input_exit` | 用户在提示输入可见时退出 |
2843| `bypass_permissions_disabled` | 绕过权限模式被禁用 |
2844| `other` | 其他退出原因 |3590| `other` | 其他退出原因 |
3591| `bypass_permissions_disabled` | 在 v2.1.234 中删除;Claude Code 不发送它。从您的 `SessionEnd` 匹配器中删除它 |
2845 3592
2846<h4 id="sessionend-input">3593<h4 id="sessionend-input">
2847 SessionEnd 输入3594 SessionEnd 输入
2848</h4>3595</h4>
2849 3596
2850除了[通用输入字段](#common-input-fields)外,SessionEnd hooks 还接收 `reason` 字段,指示会话为何结束。有关所有值,请参阅上面的原因表。3597除了 [常见输入字段](#common-input-fields) 外,SessionEnd hooks 接收指示会话为什么结束的 `reason` 字段。有关所有值,请参阅上面的 [原因表](#sessionend)。
2851 3598
2852```json theme={null}3599```json theme={null}
2853{3600{
2859}3606}
2860```3607```
2861 3608
2862SessionEnd hooks 没有决定控制。它们无法阻止会话终止,但可以执行清理任务。3609SessionEnd hooks 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 丢弃它们的 [JSON 输出字段](#json-output),如 `systemMessage`。
3610
3611SessionEnd hooks 的默认超时为 1.5 秒。当您退出、运行 `/clear` 或使用交互式 `/resume` 切换会话时它适用。您可以通过两种方式给 hook 更多时间:
2863 3612
2864SessionEnd hooks 的默认超时为 1.5 秒。这适用于会话退出、`/clear` 和通过交互式 `/resume` 切换会话。如果 hook 需要更多时间,在 hook 配置中设置 `timeout`。总体预算自动提高到配置的最高每个 hook 超时,最多 60 秒。在插件提供的 hooks 上设置的超时不会提高预算。要显式覆盖预算,请在毫秒中设置 `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 环境变量。3613* **每个 hook `timeout`**:在该 hook 的配置中设置 `timeout`。整体预算自动上升以匹配您的设置文件中最高的每个 hook `timeout`,最多 60 秒。如果您以这种方式提高预算,没有自己的 `timeout` 的 hook 仍然保持默认值。在插件提供的 hooks 上设置的超时不提高预算。
3614* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:设置此环境变量(毫秒)以显式覆盖预算。您设置的值也成为每个没有自己的 `timeout` 的 hook 的超时。
3615
3616此示例将预算设置为 5 秒:
2865 3617
2866```bash theme={null}3618```bash theme={null}
2867CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude3619CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
2868```3620```
2869 3621
3622在 v2.1.268 之前,`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 仅提高整体预算,没有自己的 `timeout` 的 hook 在 1.5 秒后仍然被取消。
3623
2870<h3 id="elicitation">3624<h3 id="elicitation">
2871 Elicitation3625 Elicitation
2872</h3>3626</h3>
2873 3627
2874当 MCP 服务器在任务中途请求用户输入时运行。默认情况下,Claude Code 显示交互式对话供用户响应。Hooks 可以拦截此请求并以编程方式响应,完全跳过对话。3628在 MCP 服务器请求用户输入中任务时运行。默认情况下,Claude Code 显示交互式对话供用户响应。Hooks 可以拦截此请求并以编程方式响应,完全跳过对话。
2875 3629
2876匹配器字段与 MCP 服务器名称匹配。3630匹配器字段匹配 MCP 服务器名称。
2877 3631
2878<h4 id="elicitation-input">3632<h4 id="elicitation-input">
2879 Elicitation 输入3633 Elicitation 输入
2880</h4>3634</h4>
2881 3635
2882除了[通用输入字段](#common-input-fields)外,Elicitation hooks 还接收 `mcp_server_name`、`message` 和可选的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 字段。3636除了 [常见输入字段](#common-input-fields) 外,Elicitation hooks 接收 `mcp_server_name`、`message` 和可选的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 字段。
2883 3637
2884对于 form 模式 elicitation(最常见的情况):3638对于表单模式引出,最常见的情况:
2885 3639
2886```json theme={null}3640```json theme={null}
2887{3641{
2888 "session_id": "abc123",3642 "session_id": "abc123",
2889 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",3643 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
2890 "cwd": "/Users/...",3644 "cwd": "/Users/...",
2891 "permission_mode": "default",
2892 "hook_event_name": "Elicitation",3645 "hook_event_name": "Elicitation",
2893 "mcp_server_name": "my-mcp-server",3646 "mcp_server_name": "my-mcp-server",
2894 "message": "Please provide your credentials",3647 "message": "Please provide your credentials",
2902}3655}
2903```3656```
2904 3657
2905对于 URL 模式 elicitation(基于浏览器的身份验证):3658对于 URL 模式引出,用于基于浏览器的身份验证:
2906 3659
2907```json theme={null}3660```json theme={null}
2908{3661{
2909 "session_id": "abc123",3662 "session_id": "abc123",
2910 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",3663 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
2911 "cwd": "/Users/...",3664 "cwd": "/Users/...",
2912 "permission_mode": "default",
2913 "hook_event_name": "Elicitation",3665 "hook_event_name": "Elicitation",
2914 "mcp_server_name": "my-mcp-server",3666 "mcp_server_name": "my-mcp-server",
2915 "message": "Please authenticate",3667 "message": "Please authenticate",
2922 Elicitation 输出3674 Elicitation 输出
2923</h4>3675</h4>
2924 3676
2925要以编程方式响应而不显示对话,返回带有 `hookSpecificOutput` 的 JSON 对象:3677要以编程方式响应而不显示对话,返回一个带有 `hookSpecificOutput` 的 JSON 对象:
2926 3678
2927```json theme={null}3679```json theme={null}
2928{3680{
2937```3689```
2938 3690
2939| 字段 | 值 | 描述 |3691| 字段 | 值 | 描述 |
2940| :-------- | :-------------------------- | :--------------------------------------- |3692| :-------- | :-------------------------- | :----------------------------------- |
2941| `action` | `accept`、`decline`、`cancel` | 是否接受、拒绝或取消请求 |3693| `action` | `accept`、`decline`、`cancel` | 是否接受、拒绝或取消请求 |
2942| `content` | object | 要提交的 form 字段值。仅在 `action` 为 `accept` 时使用 |3694| `content` | object | 要提交的表单字段值。仅在 `action` 为 `accept` 时使用 |
3695
3696退出代码 2 拒绝引出。Claude Code 不在任何地方显示您的 stderr 消息。
2943 3697
2944退出代码 2 拒绝 elicitation 并向用户显示 stderr。3698Claude Code 作用于 Elicitation hook 的 JSON 输出中的 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。
2945 3699
2946<h3 id="elicitationresult">3700<h3 id="elicitationresult">
2947 ElicitationResult3701 ElicitationResult
2948</h3>3702</h3>
2949 3703
2950在用户响应 MCP elicitation 后运行。Hooks 可以观察、修改或阻止响应,然后将其发送回 MCP 服务器。3704在用户响应 MCP 引出后运行。Hooks 可以观察、修改或阻止响应,然后将其发送回 MCP 服务器。
2951 3705
2952匹配器字段与 MCP 服务器名称匹配。3706匹配器字段匹配 MCP 服务器名称。
2953 3707
2954<h4 id="elicitationresult-input">3708<h4 id="elicitationresult-input">
2955 ElicitationResult 输入3709 ElicitationResult 输入
2956</h4>3710</h4>
2957 3711
2958除了[通用输入字段](#common-input-fields)外,ElicitationResult hooks 还接收 `mcp_server_name`、`action` 和可选的 `mode`、`elicitation_id` 和 `content` 字段。3712除了 [常见输入字段](#common-input-fields) 外,ElicitationResult hooks 接收 `mcp_server_name`、`action` 和可选的 `mode`、`elicitation_id` 和 `content` 字段。
2959 3713
2960```json theme={null}3714```json theme={null}
2961{3715{
2962 "session_id": "abc123",3716 "session_id": "abc123",
2963 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",3717 "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
2964 "cwd": "/Users/...",3718 "cwd": "/Users/...",
2965 "permission_mode": "default",
2966 "hook_event_name": "ElicitationResult",3719 "hook_event_name": "ElicitationResult",
2967 "mcp_server_name": "my-mcp-server",3720 "mcp_server_name": "my-mcp-server",
2968 "action": "accept",3721 "action": "accept",
2976 ElicitationResult 输出3729 ElicitationResult 输出
2977</h4>3730</h4>
2978 3731
2979要覆盖用户的响应,返回带有 `hookSpecificOutput` 的 JSON 对象:3732要覆盖用户的响应,返回一个带有 `hookSpecificOutput` 的 JSON 对象:
2980 3733
2981```json theme={null}3734```json theme={null}
2982{3735{
2989```3742```
2990 3743
2991| 字段 | 值 | 描述 |3744| 字段 | 值 | 描述 |
2992| :-------- | :-------------------------- | :-------------------------------------- |3745| :-------- | :-------------------------- | :---------------------------------- |
2993| `action` | `accept`、`decline`、`cancel` | 覆盖用户的操作 |3746| `action` | `accept`、`decline`、`cancel` | 覆盖用户的操作 |
2994| `content` | object | 覆盖 form 字段值。仅在 `action` 为 `accept` 时有意义 |3747| `content` | object | 覆盖表单字段值。仅在 `action` 为 `accept` 时有意义 |
3748
3749退出代码 2 阻止响应,将有效操作更改为 `decline`。Claude Code 不在任何地方显示您的 stderr 消息。
2995 3750
2996退出代码 2 阻止响应,将有效操作更改为 `decline`。3751Claude Code 作用于 ElicitationResult hook 的 JSON 输出中的 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。
2997 3752
2998<h2 id="prompt-based-hooks">3753<h2 id="prompt-based-hooks">
2999 基于提示的 hooks3754 基于提示的 hooks
3021 3776
3022* `ConfigChange`3777* `ConfigChange`
3023* `CwdChanged`3778* `CwdChanged`
3779* `DirectoryAdded`
3024* `Elicitation`3780* `Elicitation`
3025* `ElicitationResult`3781* `ElicitationResult`
3026* `FileChanged`3782* `FileChanged`
3027* `InstructionsLoaded`3783* `InstructionsLoaded`
3784* `MessageDisplay`
3028* `Notification`3785* `Notification`
3029* `PostCompact`3786* `PostCompact`
3787* `PostModelSwitch`
3030* `PreCompact`3788* `PreCompact`
3789* `PreModelSwitch`
3031* `SessionEnd`3790* `SessionEnd`
3032* `StopFailure`3791* `StopFailure`
3033* `SubagentStart`3792* `SubagentStart`
3034* `WorktreeCreate`3793* `WorktreeCreate`
3035* `WorktreeRemove`3794* `WorktreeRemove`
3036 3795
3037`SessionStart` 和 `Setup` 支持 `command` 和 `mcp_tool` hooks。它们不支持 `http`、`prompt` 或 `agent` hooks。3796`SessionStart` 和 `Setup` 支持 `command` 和 `mcp_tool` hooks,[MCP tool hook 字段](#mcp-tool-hook-fields)描述了它们的 `mcp_tool` hooks 何时运行。它们不支持 `http`、`prompt` 或 `agent` hooks。
3038 3797
3039<h3 id="how-prompt-based-hooks-work">3798<h3 id="how-prompt-based-hooks-work">
3040 基于提示的 hooks 如何工作3799 基于提示的 hooks 如何工作
3050 提示 hook 配置3809 提示 hook 配置
3051</h3>3810</h3>
3052 3811
3053将 `type` 设置为 `"prompt"` 并提供 `prompt` 字符串而不是 `command`。使用 `$ARGUMENTS` 占位符将 hook 的 JSON 输入数据注入到您的提示文本中。Claude Code 将组合的提示和输入发送到快速 Claude 模型,该模型返回 JSON 决定。3812将 `type` 设置为 `"prompt"` 并提供 `prompt` 字符串而不是 `command`。使用 `$ARGUMENTS` 占位符将 hook 的 JSON 输入数据注入到您的提示文本中。
3054 3813
3055此 `Stop` hook 要求 LLM 在允许 Claude 完成之前评估是否应该停止:3814此 `Stop` hook 要求 LLM 在允许 Claude 完成之前评估是否应该停止:
3056 3815
3072```3831```
3073 3832
3074| 字段 | 必需 | 描述 |3833| 字段 | 必需 | 描述 |
3075| :---------------- | :- | :-------------------------------------------------------------------------------------------------------------------------------------------- |3834| :---------------- | :- | :----------------------------------------------------------------------------------------------------- |
3076| `type` | 是 | 必须是 `"prompt"` |3835| `type` | 是 | 必须是 `"prompt"` |
3077| `prompt` | 是 | 要发送给 LLM 的提示文本。使用 `$ARGUMENTS` 作为 hook 输入 JSON 的占位符。如果 `$ARGUMENTS` 不存在,输入 JSON 被追加到提示 |3836| `prompt` | 是 | 要发送给 LLM 的提示文本。使用 `$ARGUMENTS` 作为 hook 输入 JSON 的占位符。如果 `$ARGUMENTS` 不存在,输入 JSON 被追加到提示 |
3078| `model` | 否 | 用于评估的模型。默认为快速模型 |3837| `model` | 否 | 用于评估的模型。默认为快速模型 |
3079| `timeout` | 否 | 超时(秒)。默认值:30 |3838| `timeout` | 否 | 超时(秒)。默认值:30 |
3080| `continueOnBlock` | 否 | 当提示返回 `ok: false` 时,将原因反馈给 Claude 并继续转轮而不是停止。默认值:`false`。在生成的 `decision: "block"` 上实现为 `continue: true`。有关每个事件的行为,请参阅[响应架构](#response-schema) |3839| `continueOnBlock` | 否 | 在适用的事件上,`true` 将 `ok: false` 原因反馈给 Claude 并继续而不是结束转轮。默认值:`false`。有关每个事件的行为,请参阅[响应架构](#response-schema) |
3081 3840
3082<h3 id="response-schema">3841<h3 id="response-schema">
3083 响应架构3842 响应架构
3088```json theme={null}3847```json theme={null}
3089{3848{
3090 "ok": true | false,3849 "ok": true | false,
3091 "reason": "Explanation for the decision"3850 "reason": "Explanation for the decision",
3851 "impossible": true | false
3092}3852}
3093```3853```
3094 3854
3095| 字段 | 描述 |3855| 字段 | 描述 |
3096| :------- | :---------------------------------------------------- |3856| :----------- | :-------------------------------------------------------------------------------------------------------------- |
3097| `ok` | `true` 允许。`false` 产生 `decision: "block"`。请参阅下面的每个事件行为 |3857| `ok` | `true` 允许。对于 `false`,请参阅下面的每个事件行为 |
3098| `reason` | 当 `ok` 为 `false` 时必需。用作阻止原因 |3858| `reason` | 当 `ok` 为 `false` 时必需 |
3859| `impossible` | 可选。当模型判断条件永远无法满足时,模型使用 `ok: false` 返回它。在 `Stop` 和 `SubagentStop` 上,Claude Code 随后让转轮结束而不是反馈原因。代理 hooks 和其他事件忽略它 |
3099 3860
3100`ok: false` 时发生的情况取决于事件:3861`ok: false` 时发生的情况取决于事件:
3101 3862
3102* `Stop` 和 `SubagentStop`:原因被反馈给 Claude 作为其下一条指令,转轮继续3863* `Stop` 和 `SubagentStop`:原因被反馈给 Claude 作为其下一条指令,转轮继续,除非响应也设置 `impossible: true`,在这种情况下 Claude Code 允许停止,转轮结束
3103* `PreToolUse`:工具调用被拒绝,原因作为工具错误返回给 Claude,等同于命令 hook 的 `permissionDecision: "deny"`3864* `PreToolUse`:工具调用被拒绝;默认情况下转轮结束,拒绝原因在聊天中显示为警告行。设置 `continueOnBlock: true` 以改为将原因返回给 Claude 作为工具错误,以便它可以调整并继续,等同于命令 hook 的 `permissionDecision: "deny"`。在 v2.1.210 之前,拒绝原因被返回给 Claude 作为工具错误,转轮继续
3104* `PostToolUse`:默认情况下转轮结束,原因在聊天中显示为警告行。设置 `continueOnBlock: true` 以将原因反馈给 Claude 并继续转轮3865* `PostToolUse`:默认情况下转轮结束,原因在聊天中显示为警告行。设置 `continueOnBlock: true` 以将原因反馈给 Claude 并继续转轮
3105* `PostToolBatch`、`UserPromptSubmit` 和 `UserPromptExpansion`:转轮结束,原因显示为警告行。这些事件在 `decision: "block"` 上结束转轮,无论 `continue` 如何3866* `PostToolBatch`、`UserPromptSubmit` 和 `UserPromptExpansion`:转轮结束,原因显示为警告行。这些事件在 `decision: "block"` 上结束转轮,无论 `continue` 如何
3106* `PostToolUseFailure`、`TaskCreated` 和 `TaskCompleted`:原因作为工具错误返回给 Claude,类似于 `PreToolUse`3867* `PostToolUseFailure` 和 `TaskCreated`:原因作为工具错误返回给 Claude,转轮继续,无论 `continueOnBlock` 如何
3868* `TaskCompleted`:当任务在转轮期间被标记为完成时触发时,原因作为工具错误返回给 Claude,转轮继续,无论 `continueOnBlock` 如何。当它因队友停止而触发时,它的行为类似于 `TeammateIdle` 并默认停止队友
3107* `TeammateIdle`:默认情况下队友停止,原因显示为警告行。设置 `continueOnBlock: true` 以将原因反馈给队友并保持其继续工作3869* `TeammateIdle`:默认情况下队友停止,原因显示为警告行。设置 `continueOnBlock: true` 以将原因反馈给队友并保持其继续工作
3108* `PermissionRequest`:`ok: false` 无效。要从 hook 拒绝批准,请使用[命令 hook](#command-hook-fields),返回 `hookSpecificOutput.decision.behavior: "deny"`3870* `PermissionRequest`:`ok: false` 无效。要从 hook 拒绝批准,请使用[命令 hook](#command-hook-fields),返回 `hookSpecificOutput.decision.behavior: "deny"`
3109* `PermissionDenied`:`ok: false` 无效,因为拒绝已经发生。此事件读取的唯一输出是 `hookSpecificOutput.retry`,提示和代理 hooks 无法设置 — 它们在此事件上运行,但其输出被丢弃。使用[命令 hook](#command-hook-fields)返回 `retry`3871* `PermissionDenied`:`ok: false` 无效,因为拒绝已经发生。此事件读取的唯一输出是 `hookSpecificOutput.retry`,提示和代理 hooks 无法设置。它们在此事件上运行,但其输出被丢弃。使用[命令 hook](#command-hook-fields)返回 `retry`
3110 3872
3111如果您需要对任何事件进行更精细的控制,请使用[命令 hook](#command-hook-fields),其中包含[决定控制](#decision-control)中描述的每个事件字段。3873如果您需要对任何事件进行更精细的控制,请使用[命令 hook](#command-hook-fields),其中包含[决定控制](#decision-control)中描述的每个事件字段。
3112 3874
3114 检查多个条件后再停止3876 检查多个条件后再停止
3115</h3>3877</h3>
3116 3878
3117此 `Stop` hook 使用详细提示检查三个条件,然后允许 Claude 停止。`SubagentStop` hooks 使用相同的格式来评估[子代理](/docs/zh-CN/sub-agents)是否应该停止。如果 `"ok"` 为 `false`,Claude 继续工作,提供的原因作为其下一条指令:3879此 `Stop` hook 使用详细提示检查三个条件,然后允许 Claude 停止。`SubagentStop` hooks 使用相同的格式来评估[子代理](/docs/zh-CN/sub-agents)是否应该停止。如果模型因条件尚未满足而返回 `"ok": false`,Claude 继续工作,提供的原因作为其下一条指令:
3118 3880
3119```json theme={null}3881```json theme={null}
3120{3882{
31531. Claude Code 生成一个 subagent,带有您的提示和 hook 的 JSON 输入39151. Claude Code 生成一个 subagent,带有您的提示和 hook 的 JSON 输入
31542. Subagent 可以使用 Read、Grep 和 Glob 等工具进行调查39162. Subagent 可以使用 Read、Grep 和 Glob 等工具进行调查
31553. 在最多 50 轮后,subagent 返回结构化的 `{ "ok": true/false }` 决定39173. 在最多 50 轮后,subagent 返回结构化的 `{ "ok": true/false }` 决定
31564. Claude Code 以与提示 hook 相同的方式处理决定39184. Claude Code 允许该操作(如果 `ok` 是 `true`)。如果 `ok` 是 `false`,Claude Code 处理阻止的方式与提示 hook 在该事件上具有 `continueOnBlock: true` 的方式相同,如[响应架构](#response-schema)下所列
3157 3919
3158代理 hooks 在验证需要检查实际文件或测试输出时很有用,而不仅仅是评估 hook 输入数据。3920代理 hooks 在验证需要检查实际文件或测试输出时很有用,而不仅仅是单独评估 hook 输入数据。
3159 3921
3160<h3 id="agent-hook-configuration">3922<h3 id="agent-hook-configuration">
3161 代理 hook 配置3923 代理 hook 配置
3162</h3>3924</h3>
3163 3925
3164将 `type` 设置为 `"agent"` 并提供 `prompt` 字符串。配置字段与[提示 hooks](#prompt-hook-configuration)相同,但超时更长:3926将 `type` 设置为 `"agent"` 并提供 `prompt` 字符串,使用 `$ARGUMENTS` 作为 hook 输入 JSON 的占位符。配置字段与[提示 hooks](#prompt-hook-configuration)相同,除了代理 hooks 具有更长的默认超时时间 60 秒,并且没有 `continueOnBlock` 字段。
3165
3166| 字段 | 必需 | 描述 |
3167| :-------- | :- | :----------------------------------------------- |
3168| `type` | 是 | 必须是 `"agent"` |
3169| `prompt` | 是 | 描述要验证的内容的提示。使用 `$ARGUMENTS` 作为 hook 输入 JSON 的占位符 |
3170| `model` | 否 | 要使用的模型。默认为快速模型 |
3171| `timeout` | 否 | 超时(秒)。默认值:60 |
3172 3927
3173响应架构与提示 hooks 相同:`{ "ok": true }` 允许或 `{ "ok": false, "reason": "..." }` 阻止。3928响应架构是 `{ "ok": true }` 允许或 `{ "ok": false, "reason": "..." }` 阻止。在 `ok: false` 时,Claude Code 处理代理 hook 的方式与处理同一事件上具有 `continueOnBlock: true` 的[提示 hook](#response-schema) 的方式相同;代理 hooks 没有 `continueOnBlock` 字段,并且不支持提示 hook 的 `impossible` 字段。
3174 3929
3175此 `Stop` hook 验证所有单元测试通过,然后允许 Claude 完成:3930此 `Stop` hook 验证所有单元测试通过,然后允许 Claude 完成:
3176 3931
3204 3959
3205将 `"async": true` 添加到命令 hook 的配置以在后台运行它而不阻止 Claude。此字段仅在 `type: "command"` hooks 上可用。3960将 `"async": true` 添加到命令 hook 的配置以在后台运行它而不阻止 Claude。此字段仅在 `type: "command"` hooks 上可用。
3206 3961
3207此 hook 在每个 `Write` 工具调用后运行测试脚本。Claude 立即继续工作,同时 `run-tests.sh` 执行最多 120 秒。脚本完成时,其输出在下一个对话轮次上传递:3962此 hook 在每个 `Write` 工具调用后运行测试脚本。Claude 立即继续工作,同时 `run-tests.sh` 执行。脚本完成时,其输出在下一个对话轮次上传递:
3208 3963
3209```json theme={null}3964```json theme={null}
3210{3965{
3216 {3971 {
3217 "type": "command",3972 "type": "command",
3218 "command": "/path/to/run-tests.sh",3973 "command": "/path/to/run-tests.sh",
3219 "async": true,3974 "async": true
3220 "timeout": 120
3221 }3975 }
3222 ]3976 ]
3223 }3977 }
3226}3980}
3227```3981```
3228 3982
3229`timeout` 字段设置后台进程的最大时间(秒)。如果未指定,异步 hooks 使用与同步 hooks 相同的 10 分钟默认值。3983一旦异步 hook 在后台运行,Claude Code 不会对其强制执行 `timeout`。Claude Code 仍然对使用 `asyncRewake` 运行的 hook 强制执行 `timeout`。
3984
3985Claude Code 仅在会话运行时传递异步 hook 的结果:
3986
3987* 在[非交互模式](/docs/zh-CN/headless)中使用 `-p` 标志,Claude Code 在拆卸时杀死任何仍在运行的异步 hook,并以 `cancelled` 结果完成它
3988* 如果你的 hook 的工作必须超越 `claude -p` 会话,从它启动一个完全分离的进程
3230 3989
3231<h3 id="how-async-hooks-execute">3990<h3 id="how-async-hooks-execute">
3232 异步 Hooks 如何执行3991 异步 Hooks 如何执行
3234 3993
3235当异步 hook 触发时,Claude Code 启动 hook 进程并立即继续,不等待其完成。Hook 通过 stdin 接收与同步 hook 相同的 JSON 输入。3994当异步 hook 触发时,Claude Code 启动 hook 进程并立即继续,不等待其完成。Hook 通过 stdin 接收与同步 hook 相同的 JSON 输入。
3236 3995
3237后台进程退出后,如果 hook 产生了带有 `additionalContext` 字段的 JSON 响应,该内容在下一个对话轮次作为上下文传递给 Claude。`systemMessage` 字段显示给你,而不是 Claude。3996后台进程退出后,Claude Code 从 hook 的 JSON 响应中传递 `additionalContext` 和 `systemMessage` 字段给 Claude 在下一个对话轮次。与同步 hook 的 `systemMessage` 不同,这两个字段都不会显示给你。
3238 3997
3239Claude Code 根据与同步 hooks 相同的[输出架构](#json-output)验证 JSON 响应,并删除任何值类型错误的字段,例如不是字符串的 `systemMessage`,而不是传递它。使用 `--debug` 运行以查看命名每个删除字段的警告。在 v2.1.202 之前,来自异步 hook 的格式错误的 JSON 输出可能会导致会话崩溃,并且每次恢复会话时崩溃都会重复发生。3998Claude Code 根据与同步 hooks 相同的[输出架构](#json-output)验证 JSON 响应,并删除任何值类型错误的字段,例如不是字符串的 `systemMessage`,而不是传递它。使用 `--debug` 运行以查看命名每个删除字段的警告。在 v2.1.202 之前,来自异步 hook 的格式错误的 JSON 输出可能会导致会话崩溃,并且每次恢复会话时崩溃都会重复发生。
3240 3999
3284 "type": "command",4043 "type": "command",
3285 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/run-tests-async.sh",4044 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/run-tests-async.sh",
3286 "args": [],4045 "args": [],
3287 "async": true,4046 "async": true
3288 "timeout": 300
3289 }4047 }
3290 ]4048 ]
3291 }4049 }
3298 限制4056 限制
3299</h3>4057</h3>
3300 4058
3301异步 hooks 与同步 hooks 相比有几个限制:4059异步 hooks 与同步 hooks 相比有额外的约束:
3302 4060
3303* 仅 `type: "command"` hooks 支持 `async`。基于提示的 hooks 无法异步运行。4061* Hook 输出在下一个对话轮次传递。如果会话空闲,响应等待直到下一个用户交互。例外:退出代码为 2 的 `asyncRewake` hook 即使在会话空闲时也会立即唤醒 Claude。
3304* 异步 hooks 无法阻止工具调用或返回决定。到 hook 完成时,触发操作已经进行。
3305* Hook 输出在下一个对话轮次传递。如果会话空闲,响应等待直到下一个用户交互。例外:`asyncRewake` hook 在退出代码 2 时立即唤醒 Claude,即使会话空闲。
3306* 每次执行创建一个单独的后台进程。同一异步 hook 的多个触发之间没有去重。4062* 每次执行创建一个单独的后台进程。同一异步 hook 的多个触发之间没有去重。
3307 4063
3308<h2 id="security-considerations">4064<h2 id="security-considerations">
3313 免责声明4069 免责声明
3314</h3>4070</h3>
3315 4071
3316命令 hooks 使用您的系统用户的完整权限运行。
3317
3318<Warning>4072<Warning>
3319 命令 hooks 使用您的完整用户权限执行 shell 命令。它们可以修改、删除或访问您的用户帐户可以访问的任何文件。在将任何 hook 命令添加到您的配置之前,请审查并测试它们。4073 命令 hooks 使用您的完整用户权限执行 shell 命令。它们可以修改、删除或访问您的用户帐户可以访问的任何文件。在将任何 hook 命令添加到您的配置之前,请审查并测试它们。
3320</Warning>4074</Warning>
3321 4075
4076<h3 id="workspace-trust">
4077 工作区信任
4078</h3>
4079
4080Claude Code 在运行来自设置文件的任何 hook 之前会检查工作区信任。什么被视为受信任取决于会话类型:
4081
4082* **交互式会话**:Claude Code 会保留来自每个设置文件的 hooks,包括您自己的 `~/.claude/settings.json`,直到您为该文件夹接受[工作区信任对话框](/docs/zh-CN/permissions#project-allow-rules-and-workspace-trust),或为其信任扩展到的父目录接受
4083* **`-p` 或 SDK 会话**:Claude Code 从不显示对话框,并将该文件夹视为受信任的,因此在您从未信任过的文件夹中运行存储库的 `.claude/settings.json` 中提交的 hooks
4084
4085在您对存储库进行脚本化 `claude -p` 之前,如果您没有编写该存储库,请审查其 `.claude/` 设置文件,使用 [`--bare`](/docs/zh-CN/headless#start-faster-with-bare-mode) 开始,或[为该运行关闭 hooks](#disable-or-remove-hooks),使用 `--settings '{"disableAllHooks": true}'`。项目子代理中的 Frontmatter hooks 遵循比设置文件 hooks 更严格的规则。[在您信任文件夹之前运行的内容](/docs/zh-CN/permissions#what-runs-before-you-trust-a-folder)按会话类型列出每种存储库内容。
4086
3322<h3 id="security-best-practices">4087<h3 id="security-best-practices">
3323 安全最佳实践4088 安全最佳实践
3324</h3>4089</h3>
3335 Windows PowerShell 工具4100 Windows PowerShell 工具
3336</h2>4101</h2>
3337 4102
3338在 Windows 上,您可以通过在命令 hook 上设置 `"shell": "powershell"` 在 PowerShell 中运行单个 hooks。Hooks 直接生成 PowerShell,因此这适用于是否设置了 `CLAUDE_CODE_USE_POWERSHELL_TOOL`。Claude Code 自动检测 `pwsh.exe`(PowerShell 7 及更高版本的可执行文件),并回退到 `powershell.exe`(Windows PowerShell 5.1)。4103在 Windows 上,您可以通过在命令 hook 上设置 `"shell": "powershell"` 在 PowerShell 中运行单个 hooks。Claude Code 自动检测 `pwsh.exe`(PowerShell 7 及更高版本的可执行文件),并回退到 `powershell.exe`(Windows PowerShell 5.1)。
3339 4104
3340```json theme={null}4105```json theme={null}
3341{4106{
3376 调试 hooks4141 调试 hooks
3377</h2>4142</h2>
3378 4143
3379Hook 执行详细信息,包括哪些 hooks 匹配、它们的退出代码和完整 stdout 和 stderr,被写入调试日志文件。使用 `claude --debug-file <path>` 启动 Claude Code 以将日志写入已知位置,或运行 `claude --debug` 并在 `~/.claude/debug/<session-id>.txt` 读取日志。`--debug` 标志不打印到终端。4144Hook 执行详细信息被写入调试日志文件。使用 `claude --debug-file <path>` 启动 Claude Code 以将日志写入已知位置,或运行 `claude --debug` 并在 `~/.claude/debug/<session-id>.txt` 读取日志。`--debug` 标志不打印到终端。
4145
4146例如,在 `Write` 上的 `PostToolUse` hook,其命令打印 `hook-ran` 会产生如下条目:
3380 4147
3381```text theme={null}4148```text theme={null}
3382[DEBUG] Executing hooks for PostToolUse:Write41492026-07-19T02:03:24.382Z [DEBUG] Hook output does not start with {, treating as plain text
3383[DEBUG] Found 1 hook commands to execute41502026-07-19T02:03:24.382Z [DEBUG] "Hook PostToolUse:Write (PostToolUse) success:\nhook-ran"
3384[DEBUG] Executing hook command: <Your command> with timeout 600000ms
3385[DEBUG] Hook command completed with status 0: <Your stdout>
3386```4151```
3387 4152
3388对于更细粒度的 hook 匹配详细信息,设置 `CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose` 以查看额外的日志行,例如 hook 匹配器计数和查询匹配。4153对于更细粒度的 hook 匹配详细信息,设置 `CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose` 以查看额外的日志行,例如 hook 匹配器计数和查询匹配。