268| [Skill](/docs/zh-CN/skills) frontmatter | 调用 skill 后的会话其余部分。请参阅[Skills 和代理中的 Hooks](#hooks-in-skills-and-agents) | 是,在 skill 文件中定义 |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 文件中定义 |269| [Subagent](/docs/zh-CN/sub-agents) frontmatter | 该 subagent 运行时 | 是,在 subagent 文件中定义 |
270 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)。271[Cloud sessions](/docs/zh-CN/claude-code-on-the-web)不读取您的本地 `~/.claude/settings.json`;那里的 hooks 来自仓库的 `.claude/settings.json` 在具有一个仓库的会话中,来自[从您的 claude.ai 账户同步的插件](/docs/zh-CN/plugins-reference#synced-plugins),以及来自您组织的服务器管理的设置。在[自托管环境](/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)。
272 272
273有关设置文件解析的详细信息,请参阅[设置](/docs/zh-CN/settings)。273有关设置文件解析的详细信息,请参阅[设置](/docs/zh-CN/settings)。
274 274
1181 Hook 事件1181 Hook 事件
1182</h2>1182</h2>
1183 1183
1184每个事件对应于 Claude Code 生命周期中的一个点,hooks 可以在该点运行。下面的部分按照生命周期顺序排列:从会话设置到 agentic 循环再到会话结束。每个部分描述事件何时触发、它支持的匹配器、它接收的 JSON 输入,以及如何通过输出控制行为。1184每个事件对应于 Claude Code 生命周期中的一个点,hooks 可以在该点运行。下面的部分按照生命周期顺序排列:从会话设置到 agentic 循环再到会话结束。每个部分描述事件何时触发、它支持哪些匹配器、它接收的 JSON 输入,以及如何通过输出控制行为。
1185 1185
1186<h3 id="sessionstart">1186<h3 id="sessionstart">
1187 SessionStart1187 SessionStart
1203 1203
1204在 v2.1.214 之前,分叉的会话报告源为 `"resume"`。1204在 v2.1.214 之前,分叉的会话报告源为 `"resume"`。
1205 1205
1206当您启动交互式会话、使用 `--continue` 或 `--resume` 在启动时恢复对话、或运行 `/clear` 时,SessionStart hooks 在后台运行。您可以立即输入,恢复的对话出现时无需等待 hooks。Claude 的第一个响应仍然等待 hooks 完成,因此它们的上下文到达 Claude。1206当您启动交互式会话、使用 `--continue` 或 `--resume` 在启动时恢复对话、或运行 `/clear` 时,SessionStart hooks 在后台运行。您可以立即输入,恢复的对话显示时无需等待 hooks。Claude 的第一个响应仍然等待 hooks 完成,因此它们的上下文到达 Claude。
1207 1207
1208当您在会话内使用 `/resume` 切换对话时,切换等待 hooks 完成。如果您在后台 hooks 仍在运行时运行 `/clear` 或切换到另一个对话,它们返回的任何内容都不适用于会话。1208当您在会话内使用 `/resume` 切换对话时,切换等待 hooks 完成。如果您在后台 hooks 仍在运行时运行 `/clear` 或切换到另一个对话,它们返回的任何内容都不适用于会话。
1209 1209
1219 1219
1220| 字段 | 描述 |1220| 字段 | 描述 |
1221| :-------------- | :------------------------------------------------------------------------------------------------------ |1221| :-------------- | :------------------------------------------------------------------------------------------------------ |
1222| `source` | 会话如何启动:新会话为 `"startup"`、恢复的会话为 `"resume"`、`/clear` 后为 `"clear"`、压缩后为 `"compact"`、或从现有会话分叉的新会话为 `"fork"` |1222| `source` | 会话如何启动:新会话为 `"startup"`、恢复的会话为 `"resume"`、`/clear` 后为 `"clear"`、压缩后为 `"compact"`,或从现有会话分叉的新会话为 `"fork"` |
1223| `model` | 活跃的模型标识符。例如在 `/clear` 后或通过对话恢复恢复会话时可能被省略,因此在读取前检查该字段 |1223| `model` | 活跃的模型标识符。它可以被省略,例如在 `/clear` 后或通过对话恢复恢复会话时,因此在读取它之前检查该字段 |
1224| `agent_type` | agent 名称,当您使用 `claude --agent <name>` 启动 Claude Code 时出现 |1224| `agent_type` | agent 名称,当您使用 `claude --agent <name>` 启动 Claude Code 时出现 |
1225| `session_title` | 当前会话标题(如果已设置),例如通过 `--name` 或 `/rename`。发出 `sessionTitle` 的 hook 可以先检查 `session_title` 以避免覆盖用户明确设置的标题 |1225| `session_title` | 当前会话标题(如果已设置),例如通过 `--name` 或 `/rename`。一个发出 `sessionTitle` 的 hook 可以先检查 `session_title` 以避免覆盖用户明确设置的标题 |
1226 1226
1227当 `source` 为 `"resume"` 或 `"fork"` 且成绩单包含至少一个来自 Claude 的响应时,SessionStart hooks 也会接收下面的四个字段。您的 hook 可以使用它们来报告在第一个请求之前恢复陈旧对话的成本,例如在 [`systemMessage`](#json-output) 中。这些字段需要 Claude Code v2.1.251 或更高版本。1227当 `source` 为 `"resume"` 或 `"fork"` 且成绩单包含至少一个来自 Claude 的响应时,SessionStart hooks 还接收下面的四个字段。您的 hook 可以使用它们在第一个请求之前报告恢复陈旧对话的成本,例如在 [`systemMessage`](#json-output) 中。这些字段需要 Claude Code v2.1.251 或更高版本。
1228 1228
1229| 字段 | 描述 |1229| 字段 | 描述 |
1230| :---------------------------- | :--------------------------------------------------------------------------------------------- |1230| :---------------------------- | :--------------------------------------------------------------------------------------------- |
1261| `additionalContext` | 在对话开始时添加到 Claude 上下文的字符串,在第一个提示之前。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1261| `additionalContext` | 在对话开始时添加到 Claude 上下文的字符串,在第一个提示之前。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1262| `initialUserMessage` | 用作会话第一个用户消息的字符串。适用于 [非交互模式](/docs/zh-CN/headless),带有 `-p` 标志,即使未提供提示,它也成为第一个回合。如果提供了提示,它作为下一个回合跟随。与 `additionalContext` 不同,后者附加到现有回合,这会创建回合 |1262| `initialUserMessage` | 用作会话第一个用户消息的字符串。适用于 [非交互模式](/docs/zh-CN/headless),带有 `-p` 标志,即使未提供提示,它也成为第一个回合。如果提供了提示,它作为下一个回合跟随。与 `additionalContext` 不同,后者附加到现有回合,这会创建回合 |
1263| `sessionTitle` | 设置会话标题,与 `/rename` 效果相同。用于从启动文件夹、git 分支或 worktree 名称自动命名会话。当 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时适用;在 `"clear"` 和 `"compact"` 上被忽略 |1263| `sessionTitle` | 设置会话标题,与 `/rename` 效果相同。用于从启动文件夹、git 分支或 worktree 名称自动命名会话。当 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时适用;在 `"clear"` 和 `"compact"` 上被忽略 |
1264| `watchPaths` | 绝对路径数组,用于在此会话期间监视 [FileChanged](#filechanged) 事件 |1264| `watchPaths` | 要在此会话期间监视 [FileChanged](#filechanged) 事件的绝对路径数组 |
1265| `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 在同一会话中可用,从第一个提示开始 |
1266 1266
1267```json theme={null}1267```json theme={null}
1274}1274}
1275```1275```
1276 1276
1277由于纯 stdout 已经为此事件到达 Claude,仅加载上下文的 hook 可以直接打印到 stdout 而无需构建 JSON。当您需要将上下文与其他字段(如 `sessionTitle`)结合时,使用 JSON 形式。1277由于纯 stdout 已经为此事件到达 Claude,仅加载上下文的 hook 可以直接打印到 stdout,而无需构建 JSON。当您需要将上下文与其他字段(如 `sessionTitle`)结合时,使用 JSON 形式。
1278 1278
1279当 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 存储库并请求重新扫描:
1280 1280
1287echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'1287echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'
1288```1288```
1289 1289
1290存储库 URL 是占位符;将其替换为您自己的 skills 存储库。使用占位符,克隆失败并打印 `fatal:` 消息到 stderr。来自以 0 退出的 SessionStart hook 的 Stderr 仅供参考,因此 `reloadSkills` 请求仍然适用。1290存储库 URL 是占位符;将其替换为您自己的 skills 存储库。使用占位符,克隆失败并打印 `fatal:` 消息到 stderr。来自退出 0 的 SessionStart hook 的 stderr 仅供参考,因此 `reloadSkills` 请求仍然适用。
1291 1291
1292<h4 id="persist-environment-variables">1292<h4 id="persist-environment-variables">
1293 持久化环境变量1293 持久化环境变量
1351 1351
1352成功时,`--init-only` 不向终端打印任何内容。要确认 hooks 运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,并检查日志中的 Setup 和 SessionStart hook 条目。1352成功时,`--init-only` 不向终端打印任何内容。要确认 hooks 运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,并检查日志中的 Setup 和 SessionStart hook 条目。
1353 1353
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)。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)。
1355 1355
1356<h4 id="setup-input">1356<h4 id="setup-input">
1357 Setup 输入1357 Setup 输入
1381 InstructionsLoaded1381 InstructionsLoaded
1382</h3>1382</h3>
1383 1383
1384在加载 `CLAUDE.md` 或 `.claude/rules/*.md` 文件到上下文时触发。此事件在会话启动时对于急切加载的文件触发,稍后当文件被懒加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录或当带有 `paths:` frontmatter 的条件规则匹配时。hook 不支持阻止或决策控制。它异步运行用于可观测性目的。1384在加载 `CLAUDE.md` 或 `.claude/rules/*.md` 文件到上下文时触发。此事件在会话启动时为急切加载的文件触发,稍后当文件被懒加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录或当带有 `paths:` frontmatter 的条件规则匹配时。hook 不支持阻止或决策控制。它异步运行以用于可观测性目的。
1385 1385
1386当 Claude [直接通过 **Project instructions** 设置读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时它确实触发,`load_reason` 设置为 `include`(与任何其他导入文件一样),以及当 `CLAUDE.md` 是它的符号链接时,作为正常的 `CLAUDE.md` 加载。1386当 Claude [直接通过 **Project instructions** 设置读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时,它会触发,`load_reason` 设置为 `include`(与任何其他导入文件一样),以及当 `CLAUDE.md` 是它的符号链接时,作为正常的 `CLAUDE.md` 加载。
1387 1387
1388匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅对会话启动时加载的文件触发,或 `"matcher": "path_glob_match|nested_traversal"` 仅对懒加载触发。1388匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅为在会话启动时加载的文件触发,或 `"matcher": "path_glob_match|nested_traversal"` 仅为懒加载触发。
1389 1389
1390<h4 id="instructionsloaded-input">1390<h4 id="instructionsloaded-input">
1391 InstructionsLoaded 输入1391 InstructionsLoaded 输入
1398| `file_path` | 加载的指令文件的绝对路径 |1398| `file_path` | 加载的指令文件的绝对路径 |
1399| `memory_type` | 文件的范围:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |1399| `memory_type` | 文件的范围:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |
1400| `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"` 值在压缩事件后重新加载指令文件时触发 |
1401| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如果有)。仅对 `path_glob_match` 加载出现 |1401| `globs` | 文件的 `paths:` frontmatter 中的路径 glob 模式(如果有)。仅对 `path_glob_match` 加载出现 |
1402| `trigger_file_path` | 触发此加载的文件的路径,用于懒加载 |1402| `trigger_file_path` | 其访问触发此加载的文件的路径,用于懒加载 |
1403| `parent_file_path` | 包含此文件的父指令文件的路径,用于 `include` 加载 |1403| `parent_file_path` | 包含此文件的父指令文件的路径,用于 `include` 加载 |
1404 1404
1405```json theme={null}1405```json theme={null}
1426 1426
1427在用户提交提示时运行,在 Claude 处理它之前。这允许您根据提示/对话添加额外上下文、验证提示或阻止某些类型的提示。1427在用户提交提示时运行,在 Claude 处理它之前。这允许您根据提示/对话添加额外上下文、验证提示或阻止某些类型的提示。
1428 1428
1429`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` 字段。
1430 1430
1431除了您使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook 外,达到其超时的 `UserPromptSubmit` 命令、HTTP 或 MCP tool hook 被取消,其输出(包括任何 `additionalContext`)被丢弃。提示仍然到达 Claude 而没有该上下文。成绩单显示一个通知,命名 hook、触发的超时以及输出被丢弃。1431除了您使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook 外,达到其超时的 `UserPromptSubmit` 命令、HTTP 或 MCP tool hook 被取消,其输出(包括任何 `additionalContext`)被丢弃。提示仍然到达 Claude 而没有该上下文。成绩单显示一个通知,命名 hook、触发的超时以及输出被丢弃。
1432 1432
1433在 `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 之前,该事件上的回调超时以执行错误结束回合。
1434 1434
1435<h4 id="userpromptsubmit-input">1435<h4 id="userpromptsubmit-input">
1436 UserPromptSubmit 输入1436 UserPromptSubmit 输入
1437</h4>1437</h4>
1438 1438
1439除了 [常见输入字段](#common-input-fields) 外,UserPromptSubmit hooks 接收包含用户提交的文本的 `prompt` 字段。1439除了 [常见输入字段](#common-input-fields) 外,UserPromptSubmit hooks 接收包含用户提交的文本的 `prompt` 字段。粘贴的内容折叠到 `[Pasted text #N]` 占位符会在原位展开到达。在 Claude Code [为 Claude 标记粘贴文本](/docs/zh-CN/terminal-config#how-claude-treats-pasted-text) 的会话中,该展开的内容位于 `<pasted_content id="…">` 行和 `</pasted_content id="…">` 行之间,因此如果您的 hook 解析提示,请考虑这些行。
1440 1440
1441```json theme={null}1441```json theme={null}
1442{1442{
1462 1462
1463两个通道都不产生可见的成绩单条目。纯 stdout 和 `additionalContext` 值各自作为以 hook 名称开头的系统提醒注入;Claude 读取两者。要确认传递,请检查 [调试日志](#debug-hooks)。1463两个通道都不产生可见的成绩单条目。纯 stdout 和 `additionalContext` 值各自作为以 hook 名称开头的系统提醒注入;Claude 读取两者。要确认传递,请检查 [调试日志](#debug-hooks)。
1464 1464
1465要阻止提示,返回一个 JSON 对象,其中 `decision` 设置为 `"block"`:1465要阻止提示,返回一个 `decision` 设置为 `"block"` 的 JSON 对象:
1466 1466
1467| 字段 | 描述 |1467| 字段 | 描述 |
1468| :----------------------- | :----------------------------------------------------------------------------------------- |1468| :----------------------- | :------------------------------------------------------------------------------ |
1469| `decision` | `"block"` 防止提示被处理并从上下文中删除它。省略以允许提示继续 |1469| `decision` | `"block"` 防止提示被处理并从上下文中删除它。省略以允许提示继续 |
1470| `reason` | 当 `decision` 为 `"block"` 时显示给用户。不添加到上下文 |1470| `reason` | 当 `decision` 为 `"block"` 时显示给用户。不添加到上下文 |
1471| `additionalContext` | 与提交的提示一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1471| `additionalContext` | 与提交的提示一起添加到 Claude 上下文的字符串。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1472| `sessionTitle` | 设置会话标题。用于根据提示内容自动命名会话 |1472| `sessionTitle` | 设置会话标题。用于根据提示内容自动命名会话 |
1473| `suppressOriginalPrompt` | 如果在 `decision` 为 `"block"` 时为 `true`,则从显示给用户的阻止消息中省略原始提示文本 |1473| `suppressOriginalPrompt` | 如果在 `decision` 为 `"block"` 时为 `true`,则从显示给用户的阻止消息中省略原始提示文本 |
1474 1474
1494 1494
1495此事件涵盖 `PreToolUse` 不涵盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 仅在 Claude 调用工具时触发,但直接输入 `/skillname` 绕过 `PreToolUse`。`UserPromptExpansion` 在该直接路径上触发。1495此事件涵盖 `PreToolUse` 不涵盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 仅在 Claude 调用工具时触发,但直接输入 `/skillname` 绕过 `PreToolUse`。`UserPromptExpansion` 在该直接路径上触发。
1496 1496
1497匹配 `command_name`。将匹配器留空以对每个提示类型命令触发。1497匹配 `command_name`。将匹配器留空以在每个提示类型命令上触发。
1498 1498
1499<h4 id="userpromptexpansion-input">1499<h4 id="userpromptexpansion-input">
1500 UserPromptExpansion 输入1500 UserPromptExpansion 输入
1524`UserPromptExpansion` hooks 可以阻止扩展或添加上下文。所有 [JSON 输出字段](#json-output) 都可用。1524`UserPromptExpansion` hooks 可以阻止扩展或添加上下文。所有 [JSON 输出字段](#json-output) 都可用。
1525 1525
1526| 字段 | 描述 |1526| 字段 | 描述 |
1527| :------------------ | :----------------------------------------------------------------------------------------- |1527| :------------------ | :------------------------------------------------------------------------------ |
1528| `decision` | `"block"` 防止命令扩展。省略以允许它继续 |1528| `decision` | `"block"` 防止命令扩展。省略以允许它继续 |
1529| `reason` | 当 `decision` 为 `"block"` 时显示给用户 |1529| `reason` | 当 `decision` 为 `"block"` 时显示给用户 |
1530| `additionalContext` | 与扩展的提示一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1530| `additionalContext` | 与扩展的提示一起添加到 Claude 上下文的字符串。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1531 1531
1532通过退出 2 阻止的 hook 路由方式与 `reason` 相同:阻止消息向用户显示 stderr 文本。1532通过退出 2 阻止的 hook 路由方式与 `reason` 相同:阻止消息向用户显示 stderr 文本。
1533 1533
1546 MessageDisplay1546 MessageDisplay
1547</h3>1547</h3>
1548 1548
1549在助手消息流向屏幕时运行。Claude Code 分批显示消息:每次一批新完成的行准备好渲染时,hook 运行一次,这些行,Claude Code 用 hook 的替换文本渲染它们的位置。长消息产生多个调用;短消息可能只产生一个。1549在助手消息流向屏幕时运行。Claude Code 分批显示消息:每次一批新完成的行准备好渲染时,hook 运行一次,这些行,Claude Code 用 hook 的替换文本替换它们。长消息产生多个调用;短消息可能只产生一个。
1550 1550
1551使用 MessageDisplay 来:1551使用 MessageDisplay 来:
1552 1552
1556 1556
1557Claude Code 保持每个批次直到您的 hook 返回,因此保持 hook 快速。如果 hook 失败或超时,Claude Code 显示原始文本。此事件的默认超时为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。1557Claude Code 保持每个批次直到您的 hook 返回,因此保持 hook 快速。如果 hook 失败或超时,Claude Code 显示原始文本。此事件的默认超时为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1558 1558
1559MessageDisplay 仅用于显示:替换文本仅更改屏幕上呈现的内容。成绩单和 Claude 看到的内容保持原始文本,因此 Claude 永远看不到替换,详细模式显示原始。hook 仅接收助手消息文本,因此工具结果和您输入的文本呈现不变。1559MessageDisplay 仅用于显示:替换文本仅更改屏幕上呈现的内容。成绩单和 Claude 看到的内容保持原始文本,因此 Claude 永远看不到替换,详细模式显示原始文本。hook 仅接收助手消息文本,因此工具结果和您输入的文本呈现不变。
1560 1560
1561MessageDisplay 不支持匹配器,对每个流式传输文本的助手消息触发;没有文本的消息(如仅工具调用响应)不触发它。1561MessageDisplay 不支持匹配器,对每个流式传输文本的助手消息触发;没有文本的消息(如仅工具调用响应)不触发它。
1562 1562
1563在非交互式运行中,包括 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 在两种模式中接收相同的总文本。
1564 1564
1565<h4 id="messagedisplay-input">1565<h4 id="messagedisplay-input">
1566 MessageDisplay 输入1566 MessageDisplay 输入
1567</h4>1567</h4>
1568 1568
1569除了 [常见输入字段](#common-input-fields) 外,MessageDisplay hooks 接收回合和消息的标识符、此调用在消息中的位置以及 `delta` 中的新文本。批次边界取决于文本流的方式,因此使用 `index` 和 `final` 来跟踪通过消息的进度,而不是期望行以特定方式分组。1569除了 [常见输入字段](#common-input-fields) 外,MessageDisplay hooks 接收回合和消息的标识符、此调用在消息中的位置以及 `delta` 中的新文本。批次边界取决于文本如何流式传输,因此使用 `index` 和 `final` 来跟踪通过消息的进度,而不是期望行以特定方式分组。
1570 1570
1571| 字段 | 描述 |1571| 字段 | 描述 |
1572| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |1572| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
1573| `turn_id` | 当前回合的 UUID |1573| `turn_id` | 当前回合的 UUID |
1574| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每个批次中稳定。这不是 API `msg_…` id,因此无法与成绩单消息 id 关联 |1574| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每个批次中稳定。这不是 API `msg_…` id,因此无法与成绩单消息 id 关联 |
1575| `index` | 此批次在消息中的零基索引 |1575| `index` | 此批次在消息中的零基索引 |
1576| `final` | 在消息的最后一个批次上为 `true`。每个消息恰好有一个最终批次 |1576| `final` | 在消息的最后一个批次上为 `true`。每个消息恰好有一个最终批次 |
1577| `delta` | 自上一个批次以来新完成的行,包括终止换行符。始终是完整行,除了最终批次可能在行中间结束。在交互式运行中,当消息以换行符结束时最终批次的 delta 为空,因此将 `final` 而不是非空 delta 视为消息结束信号。在 Agent SDK 和 `claude -p` 运行中,单个调用携带整个消息 |1577| `delta` | 自上一个批次以来新完成的行,包括终止换行符。始终是完整行,除了最终批次可能在行中间结束。在交互式运行中,当消息以换行符结束时,最终批次的 delta 为空,因此将 `final` 而不是非空 delta 视为消息结束信号。在 Agent SDK 和 `claude -p` 运行中,单个调用携带整个消息 |
1578 1578
1579```json theme={null}1579```json theme={null}
1580{1580{
1597除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,MessageDisplay hooks 可以返回 `displayContent` 来替换屏幕上的 delta:1597除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,MessageDisplay hooks 可以返回 `displayContent` 来替换屏幕上的 delta:
1598 1598
1599| 字段 | 描述 |1599| 字段 | 描述 |
1600| :--------------- | :--------------------- |1600| :--------------- | :----------------------- |
1601| `displayContent` | 显示代替 delta 的文本。省略以显示原始 |1601| `displayContent` | 显示代替 delta 的文本。省略以显示原始文本 |
1602 1602
1603MessageDisplay hooks 没有决策控制。它们无法阻止消息或更改成绩单中存储或发送给 Claude 的内容。Claude Code 作用于它们的 JSON 输出中的 `displayContent` 并丢弃 `systemMessage` 和 `continue`。1603MessageDisplay hooks 没有决策控制。它们无法阻止消息或更改成绩单中存储或发送给 Claude 的内容。Claude Code 从其 JSON 输出中作用于 `displayContent` 并丢弃 `systemMessage` 和 `continue`。
1604 1604
1605此示例从 Claude 的响应中剥离 markdown 格式以获得纯文本显示。脚本从 stdin 读取每个批次,从 `delta` 中删除粗体标记和内联代码反引号,并将结果作为 `displayContent` 返回。1605此示例从 Claude 的响应中剥离 markdown 格式以获得纯文本显示。脚本从 stdin 读取每个批次,从 `delta` 中删除粗体标记和内联代码反引号,并将结果作为 `displayContent` 返回。
1606 1606
1684 PreToolUse1684 PreToolUse
1685</h3>1685</h3>
1686 1686
1687在 Claude 创建工具参数之后和处理工具调用之前运行。匹配除 `EndConversation` 外的任何工具名称:内置工具如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`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 1688
1689要在特定文件在磁盘上更改时运行 hook,无论什么写入它,请使用 [FileChanged](#filechanged) 而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在更改后运行 FileChanged hooks,它们没有决策控制,因此无法阻止写入。1689要在特定文件在磁盘上更改时运行 hook,无论什么写入它,请改用 [FileChanged](#filechanged) 而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在更改后运行 FileChanged hooks,它们没有决策控制,因此无法阻止写入。
1690 1690
1691<Warning>1691<Warning>
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)。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 1693
1694 PreToolUse 也不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。1694 PreToolUse 也不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
1695</Warning>1695</Warning>
1704 1704
1705除了 [常见输入字段](#common-input-fields) 外,PreToolUse hooks 接收 `tool_name`、`tool_input` 和 `tool_use_id`。1705除了 [常见输入字段](#common-input-fields) 外,PreToolUse hooks 接收 `tool_name`、`tool_input` 和 `tool_use_id`。
1706 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 或更高版本。1707对于 [MCP 工具](#match-mcp-tools),输入还携带 `mcp_server`,一个包含服务器 `name` 和 `source` 的对象,说明服务器定义来自何处。`source` 值包括 `plugin`、`sdk` 和配置范围,如 `user` 和 `project`。[Agent SDK 参考](/docs/zh-CN/agent-sdk/typescript#mcpserverprovenance) 中的 [`McpServerProvenance`](/docs/zh-CN/agent-sdk/typescript#mcpserverprovenance) 列出了所有内容并说明如何处理您不认识的内容。基于 `source` 而不是 `name` 或 `mcp__<server>__` 工具名称前缀做出信任决定。`mcp_server` 字段需要 Claude Code v2.1.274 或更高版本。
1708 1708
1709对于文件工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 始终是绝对的:1709对于文件工具 Write、Edit 和 Read,`tool_input.file_path` 始终是绝对的:
1710 1710
1711* Claude Code 在 hooks 运行之前扩展 `~` 和相对路径,因此匹配路径的 hook 无法通过 `~` 或相同路径的相对拼写绕过1711* Claude Code 在 hooks 运行之前扩展 `~` 和相对路径,因此匹配路径的 hook 无法通过 `~` 或相同路径的相对拼写绕过
1712* 在 Windows 上,路径到达时带有反斜杠分隔符,即使您的 hook 在 Git Bash 下运行,其中 `$PWD` 看起来像 `/c/project`1712* 在 Windows 上,路径到达时带有反斜杠分隔符,即使您的 hook 在 Git Bash 下运行,其中 `$PWD` 看起来像 `/c/project`
1713* 使用正斜杠编写的比较(如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用继续进行,就像 hook 没有什么要阻止的一样1713* 使用正斜杠编写的比较(如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用继续,就像 hook 没有什么要阻止的一样
1714* 在比较前规范化分隔符:Bash 中的 `FILE_PATH="${FILE_PATH//\\//}"` 或 Python 中的 `file_path.replace("\\", "/")`,然后匹配路径段如 `/src/` 而不是用 `^` 锚定,因为路径是绝对的1714* 在比较之前规范化分隔符:Bash 中的 `FILE_PATH="${FILE_PATH//\\//}"`,或 Python 中的 `file_path.replace("\\", "/")`,然后匹配路径段,如 `/src/`,而不是使用 `^` 锚定,因为路径是绝对的
1715 1715
1716Windows 上的 `Write` 调用传递:1716Windows 上的 Write 调用传递:
1717 1717
1718```json theme={null}1718```json theme={null}
1719{1719{
1741| :------------------ | :------ | :----------------- | :--------------------------------------------------------------------------- |1741| :------------------ | :------ | :----------------- | :--------------------------------------------------------------------------- |
1742| `command` | string | `"npm test"` | 要执行的 shell 命令 |1742| `command` | string | `"npm test"` | 要执行的 shell 命令 |
1743| `description` | string | `"Run test suite"` | 命令执行操作的可选描述 |1743| `description` | string | `"Run test suite"` | 命令执行操作的可选描述 |
1744| `timeout` | number | `120000` | 可选超时(毫秒)。高于 [最大值](/docs/zh-CN/tools-reference#bash-tool-behavior) 的值被减少到最大值而不是被拒绝 |1744| `timeout` | number | `120000` | 可选超时(毫秒)。超过 [最大值](/docs/zh-CN/tools-reference#bash-tool-behavior) 的值被减少到最大值而不是被拒绝 |
1745| `run_in_background` | boolean | `false` | 是否在后台运行命令 |1745| `run_in_background` | boolean | `false` | 是否在后台运行命令 |
1746 1746
1747当 Bash 命令更改 Git 存储库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置打开记录时,它在每个权限模式中记录;该设置的条目说明哪些文件可以设置它。否则它仅在自动模式和 `bypassPermissions` 模式中记录,仅当 Claude Code 指导 Claude 通过 Bash 编辑文件时。设置 `bashEditDiffEnabled` 为 `false` 以关闭记录。后台命令和只读命令不携带 diff。1747当 Bash 命令更改 Git 存储库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置打开记录时,它在每个权限模式中记录更改;该设置的条目说明哪些文件可以设置它。否则它仅在自动模式和 `bypassPermissions` 模式中记录它们,并且仅当 Claude Code 指导 Claude 通过 Bash 编辑文件时。设置 `bashEditDiffEnabled` 为 `false` 以关闭记录。后台命令和只读命令不携带 diff。
1748 1748
1749您的 [PostToolUse hook](#posttooluse) 然后在 `tool_response.bashEditDiff` 中接收更改的文件。列表涵盖命令运行时在存储库下更改的内容。Git 忽略的文件和子模块中的文件不被列出。需要 Claude Code v2.1.269 或更高版本。1749您的 [PostToolUse hook](#posttooluse) 然后在 `tool_response.bashEditDiff` 中接收更改的文件。列表涵盖命令运行时在存储库下更改的内容。Git 忽略的文件和子模块中的文件不被列出。需要 Claude Code v2.1.269 或更高版本。
1750 1750
1755`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整性和可靠性。1755`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整性和可靠性。
1756 1756
1757| 字段 | 类型 | 示例 | 描述 |1757| 字段 | 类型 | 示例 | 描述 |
1758| :------------- | :------ | :------------------------------------------------------ | :----------------------------------------------------------------------- |1758| :------------- | :------ | :------------------------------------------------------ | :---------------------------------------------------------------------- |
1759| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令更改的文件的绝对路径,最多 200 个。每当 `files` 保持 diff 或 `moreFiles` 高于零时出现 |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` |1760| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 个更改文件的 diffs,用于显示。对于命令添加或删除的文件,`created` 或 `deleted` 为 `true` |
1761| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的更改文件的计数 |1761| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的更改文件的计数 |
1762| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |1762| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |
1763| `skipped` | boolean | `true` | 对于移动工作树的 Git 命令设置,如 `git checkout` 或 `git stash`,因此 Claude Code 不获取 diff |1763| `skipped` | boolean | `true` | 为移动工作树的 Git 命令设置,如 `git checkout` 或 `git stash`,因此 Claude Code 不获取 diff |
1764| `shared` | boolean | `true` | 当另一个 Bash 工具调用(如子 agent 的)同时在同一存储库中运行时设置,因此某些列出的更改可能是该命令的 |1764| `shared` | boolean | `true` | 当另一个 Bash 工具调用(如子代理的)在同一存储库中同时运行时设置,因此某些列出的更改可能是该命令的 |
1765 1765
1766<a id="powershell" />1766<a id="powershell" />
1767 1767
1875 Agent1875 Agent
1876</h5>1876</h5>
1877 1877
1878生成 [子 agent](/docs/zh-CN/sub-agents)。1878生成 [子代理](/docs/zh-CN/sub-agents)。
1879 1879
1880| 字段 | 类型 | 示例 | 描述 |1880| 字段 | 类型 | 示例 | 描述 |
1881| :-------------- | :----- | :------------------------- | :-------------- |1881| :-------------- | :----- | :------------------------- | :-------------- |
1884| `subagent_type` | string | `"Explore"` | 要使用的专门 agent 类型 |1884| `subagent_type` | string | `"Explore"` | 要使用的专门 agent 类型 |
1885| `model` | string | `"sonnet"` | 可选模型别名以覆盖默认值 |1885| `model` | string | `"sonnet"` | 可选模型别名以覆盖默认值 |
1886 1886
1887当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 在 `tool_response` 中接收子 agent 的结果和运行遥测。读取这些字段以检查运行;对于跨子 agent 的令牌和成本汇总,使用 [令牌和成本计数器](/docs/zh-CN/monitoring-usage#token-counter) 过滤到 `query_source` `"subagent"`,因为 `totalTokens` 和 `usage` 仅涵盖最终请求:1887当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 在 `tool_response` 中接收子代理的结果和运行遥测。读取这些字段以检查运行;对于跨子代理的令牌和成本汇总,使用 [令牌和成本计数器](/docs/zh-CN/monitoring-usage#token-counter) 过滤到 `query_source` `"subagent"`,因为 `totalTokens` 和 `usage` 仅涵盖最终请求:
1888 1888
1889| 字段 | 类型 | 示例 | 描述 |1889| 字段 | 类型 | 示例 | 描述 |
1890| :------------------ | :----- | :---------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- |1890| :------------------ | :----- | :---------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------- |
1891| `status` | string | `"completed"` | 前台子 agent 为 `"completed"`,后台子 agent 为 `"async_launched"`。从 v2.1.198 起,子 agent 默认在后台运行,因此省略的 `run_in_background` 也产生 `"async_launched"` |1891| `status` | string | `"completed"` | 前台子代理为 `"completed"`,后台子代理为 `"async_launched"`。从 v2.1.198 起,子代理默认在后台运行,因此省略的 `run_in_background` 也产生 `"async_launched"` |
1892| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子 agent 运行的标识符 |1892| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子代理运行的标识符 |
1893| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子 agent 的最终文本块,或对于其报告通过 `SubagentHandback` 的子 agent,关于该交接的简短说明代替 |1893| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子代理的最终文本块,或对于其报告通过 `SubagentHandback` 的子代理,关于该交接的简短说明代替 |
1894| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子 agent 启动的模型,可能与请求的模型不同 |1894| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子代理启动的模型,可能与请求的模型不同 |
1895| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复折叠;仅在模型在运行中交换时设置。需要 Claude Code v2.1.212 或更高版本 |1895| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复折叠;仅在模型在运行中交换时设置。需要 Claude Code v2.1.212 或更高版本 |
1896| `totalTokens` | number | `12450` | 子 agent 最终 API 请求的令牌计数:输入、输出和缓存令牌合并。这不是整个运行的总计 |1896| `totalTokens` | number | `12450` | 来自子代理最终 API 请求的令牌计数:输入、输出和缓存令牌合并。这不是整个运行的总计 |
1897| `totalDurationMs` | number | `48211` | 子 agent 运行的挂钟持续时间 |1897| `totalDurationMs` | number | `48211` | 子代理运行的挂钟持续时间 |
1898| `totalToolUseCount` | number | `7` | 子 agent 进行的工具调用计数 |1898| `totalToolUseCount` | number | `7` | 子代理进行的工具调用计数 |
1899| `usage` | object | `{"input_tokens": 8320, ...}` | 最终 API 请求的每类型令牌分解:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |1899| `usage` | object | `{"input_tokens": 8320, ...}` | 最终 API 请求的每类型令牌分解:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |
1900 1900
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`。1901在 Claude Code v2.1.271 或更高版本上,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子代理(Claude Code 在 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 中提供)通过该工具而不是作为文本返回其报告。其 `completed` 结果的 `content` 字段然后携带关于该交接的简短说明,而不是报告本身。要读取报告,匹配 `PreToolUse` 或 `PostToolUse` hook 在 `SubagentHandback` 上并读取 `tool_input.message`。
1902 1902
1903对于后台子 agent,工具在任务移到后台时返回,因此 `tool_response` 不携带使用字段:后台启动立即返回,前台任务在运行中被 Claude Code 后台化时返回。它有 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。1903对于后台子代理,工具在任务移到后台时返回,因此 `tool_response` 不携带使用字段:后台启动立即返回,前台任务在运行中被后台化时返回。它有 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。
1904 1904
1905在 `completed` 响应上,`resolvedModel` 命名子 agent 启动的模型,可能与 `tool_input` 中的 `model` 值不同,如 `availableModels` 或其他覆盖适用时。在 `async_launched` 响应上,`resolvedModel` 命名 agent 移到后台时使用的模型,因此在后台化之前发生的交换反映在那里。`modelsUsed` 和后台化时间 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。1905在 `completed` 响应上,`resolvedModel` 命名子代理启动的模型,可能与 `tool_input` 中的 `model` 值不同,例如当 `availableModels` 或另一个覆盖适用时。在 `async_launched` 响应上,`resolvedModel` 命名代理移到后台时使用的模型,因此在该之前发生的交换反映在那里。`modelsUsed` 和后台化时间 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。
1906 1906
1907<a id="askuserquestion" />1907<a id="askuserquestion" />
1908 1908
1921 ExitPlanMode1921 ExitPlanMode
1922</h5>1922</h5>
1923 1923
1924呈现计划并要求用户在 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 之前注入计划内容和文件路径。
1925 1925
1926| 字段 | 类型 | 示例 | 描述 |1926| 字段 | 类型 | 示例 | 描述 |
1927| :--------------- | :----- | :------------------------------------------ | :----------------------------------------------------------------- |1927| :--------------- | :----- | :------------------------------------------ | :---------------------------------------------------------------- |
1928| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 中的计划内容。从磁盘上的计划文件注入 |1928| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 中的计划内容。从磁盘上的计划文件注入 |
1929| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |1929| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |
1930| `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 请求实现计划的基于提示的权限 |
1931 1931
1932在 `PostToolUse` 中,`tool_response` 是一个包含 `plan` 和 `filePath` 字段的对象,保持批准的计划,加上内部状态标志。读取 `tool_response.plan` 以获取计划内容,而不是从磁盘重新读取文件。1932在 `PostToolUse` 中,`tool_response` 是一个包含 `plan` 和 `filePath` 字段的对象,保持批准的计划,加上内部状态标志。读取 `tool_response.plan` 以获取计划内容,而不是从磁盘重新读取文件。
1933 1933
1938`PreToolUse` hooks 可以控制工具调用是否继续。与使用顶级 `decision` 字段的其他 hooks 不同,PreToolUse 在 `hookSpecificOutput` 对象内返回其决策。这给了它更丰富的控制:四个结果(允许、拒绝、询问或延迟)加上在执行前修改工具输入的能力。1938`PreToolUse` hooks 可以控制工具调用是否继续。与使用顶级 `decision` 字段的其他 hooks 不同,PreToolUse 在 `hookSpecificOutput` 对象内返回其决策。这给了它更丰富的控制:四个结果(允许、拒绝、询问或延迟)加上在执行前修改工具输入的能力。
1939 1939
1940| 字段 | 描述 |1940| 字段 | 描述 |
1941| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1941| :------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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 返回什么 |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 返回什么 |
1943| `permissionDecisionReason` | 对于 `"allow"` 和 `"ask"`,显示给用户但不显示给 Claude。对于 `"deny"`,显示给 Claude。对于 `"defer"`,被忽略 |1943| `permissionDecisionReason` | 对于 `"allow"` 和 `"ask"`,显示给用户但不显示给 Claude。对于 `"deny"`,显示给 Claude。对于 `"defer"`,被忽略 |
1944| `updatedInput` | 在执行前修改工具的输入参数。替换整个输入对象,因此在修改的输入旁边包含未更改的字段。Claude Code 根据您的 hook 返回的输入而不是 Claude 发送的输入评估权限规则和 Bash 命令的 [自动后台资格](/docs/zh-CN/tools-reference#background-commands)。与 `"allow"` 结合以自动批准,或与 `"ask"` 结合以向用户显示修改的输入。对于 `"defer"`,被忽略 |1944| `updatedInput` | 在执行前修改工具的输入参数。替换整个输入对象,因此在修改的字段旁边包含未更改的字段。Claude Code 根据您的 hook 返回的输入而不是 Claude 发送的输入评估权限规则和 Bash 命令的 [自动后台资格](/docs/zh-CN/tools-reference#background-commands)。与 `"allow"` 结合以自动批准,或与 `"ask"` 结合以向用户显示修改的输入。对于 `"defer"`,被忽略 |
1945| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。当 `permissionDecision` 为 `"defer"` 时被忽略。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1945| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。当 `permissionDecision` 为 `"defer"` 时被忽略。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
1946 1946
1947当多个 PreToolUse hooks 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。1947当多个 PreToolUse hooks 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。
1948 1948
1968 1968
1969<span id="allow-with-updatedinput" />1969<span id="allow-with-updatedinput" />
1970 1970
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) 对象,将每个问题的文本映射到选定的答案。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) 对象,将每个问题的文本映射到选定的答案。
1972 1972
1973从 v2.1.199 起,其服务器用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记的 MCP 工具更严格:hook 无法用 `"allow"` 跳过其批准提示,无论是否有 `updatedInput`,因为 Claude Code 无法确认 hook 收集了工具需要的交互。1973从 v2.1.199 起,一个 MCP 工具,其服务器用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记它,更严格:hook 无法用 `"allow"` 跳过其批准提示,无论是否有 `updatedInput`,因为 Claude Code 无法确认 hook 收集了工具需要的交互。
1974 1974
1975<Note>1975<Note>
1976 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` 作为其当前格式。
1977</Note>1977</Note>
1978 1978
1979<h4 id="defer-a-tool-call-for-later">1979<h4 id="defer-a-tool-call-for-later">
1980 延迟工具调用以供稍后使用1980 延迟工具调用以供稍后使用
1981</h4>1981</h4>
1982 1982
1983`"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 结果。
1984 1984
1985`AskUserQuestion` 工具是典型情况:Claude 想问用户什么,但没有终端来回答。`-p` 运行仅在有 [权限主机](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs) 时提供 `AskUserQuestion`,如您使用 `--permission-prompt-tool` 传递的 MCP 工具,因此使用一个启动运行。往返工作如下:1985`AskUserQuestion` 工具是典型情况:Claude 想问用户什么,但没有终端来回答。`-p` 运行仅在有 [权限主机](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs) 时提供 `AskUserQuestion`,例如您使用 `--permission-prompt-tool` 传递的 MCP 工具,因此使用一个启动运行。往返工作如下:
1986 1986
19871. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。19871. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。
19882. hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在成绩单中。19882. hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在成绩单中。
2006}2006}
2007```2007```
2008 2008
2009没有超时或重试限制。会话保留在磁盘上直到您恢复它,受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留扫描的约束,默认情况下在 30 天后删除会话文件,遵循 [保留扫描规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果答案在您恢复时还没有准备好,hook 可以再次返回 `"defer"`,进程以相同的方式退出。调用进程通过最终从 hook 返回 `"allow"` 或 `"deny"` 来控制何时打破循环。2009没有超时或重试限制。会话保留在磁盘上,直到您恢复它,受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留扫描的约束,默认情况下在 30 天后删除会话文件,遵循 [保留扫描规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果恢复时答案还没准备好,hook 可以再次返回 `"defer"`,进程以相同的方式退出。调用进程通过最终从 hook 返回 `"allow"` 或 `"deny"` 来控制何时打破循环。
2010 2010
2011`"defer"` 仅在 Claude 在回合中进行单个工具调用时有效。如果 Claude 一次进行多个工具调用,`"defer"` 被忽略并显示警告,工具通过正常权限流程进行。约束存在是因为恢复只能重新运行一个工具:没有办法延迟批次中的一个调用而不留下其他未解决的。2011`"defer"` 仅在 Claude 在回合中进行单个工具调用时有效。如果 Claude 一次进行多个工具调用,`"defer"` 被忽略并显示警告,工具通过正常权限流程进行。约束存在是因为恢复只能重新运行一个工具:没有办法从批次中延迟一个调用而不留下其他未解决的。
2012 2012
2013如果恢复时延迟的工具不再可用,进程以 `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` 有效负载仍然包含,以便您可以识别哪个工具丢失。
2014 2014
2015<Note>2015<Note>
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 或更高版本。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 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) 中列出的例外。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) 中列出的例外。
2019</Note>2019</Note>
2020 2020
2021<h3 id="permissionrequest">2021<h3 id="permissionrequest">
2022 PermissionRequest2022 PermissionRequest
2023</h3>2023</h3>
2024 2024
2025在 Claude Code 即将要求您许可使用工具时运行。在无法显示提示的会话中,如 [非交互模式](/docs/zh-CN/headless) 中的后台子 agent,Claude Code 仍然运行这些 hooks,如果没有 hook 返回决策,它拒绝工具调用。2025在 Claude Code 即将要求您获得工具使用权限时运行。在无法显示提示的会话中,例如 [非交互模式](/docs/zh-CN/headless) 中的后台子代理,Claude Code 仍然运行这些 hooks,如果没有 hook 返回决策,它拒绝工具调用。
2026使用 [PermissionRequest 决策控制](#permissionrequest-decision-control) 代表用户允许或拒绝。2026使用 [PermissionRequest 决策控制](#permissionrequest-decision-control) 代表用户允许或拒绝。
2027 2027
2028当您需要在 Claude 要求许可使用工具时立即获得信号时使用此事件。Claude Code 仅在提示等待约六秒后运行 [Notification](#notification) hook,其中 `permission_prompt` 类型。2028当您需要 Claude 要求使用工具权限时的信号时使用此事件。Claude Code 仅在提示等待约六秒后运行带有 `permission_prompt` 类型的 [Notification](#notification) hook。
2029 2029
2030Claude Code 不为沙箱命令的 [网络请求](/docs/zh-CN/sandboxing#network-isolation) 运行 PermissionRequest hooks。要获得该提示的信号,请使用 `permission_prompt` 通知类型。2030Claude Code 不为沙箱命令的 [网络请求](/docs/zh-CN/sandboxing#network-isolation) 运行 PermissionRequest hooks。要获得该提示的信号,请使用 `permission_prompt` 通知类型。
2031 2031
2035 PermissionRequest 输入2035 PermissionRequest 输入
2036</h4>2036</h4>
2037 2037
2038PermissionRequest hooks 接收 `tool_name` 和 `tool_input` 字段,如 PreToolUse hooks,但没有 `tool_use_id`。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 为此请求建议的 [权限更新](#permission-update-entries),如添加允许规则或更改权限模式。2038PermissionRequest hooks 接收 `tool_name` 和 `tool_input` 字段,如 PreToolUse hooks,但没有 `tool_use_id`。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 为此请求建议的 [权限更新](#permission-update-entries),例如添加允许规则或更改权限模式。
2039 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),它直接更改权限模式而不是通过权限更新。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 2041
2042PreToolUse hooks 在每个工具调用之前运行,无论它是否需要权限。PermissionRequest hooks 仅在 Claude Code 即将要求您许可时运行,或当它否则会自动拒绝无法提示的调用时。两个事件都不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。2042PreToolUse hooks 在每个工具调用之前运行,无论它是否需要权限。PermissionRequest hooks 仅在 Claude Code 即将要求您获得权限时运行,或当它否则会自动拒绝无法提示的调用时。两个事件都不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
2043 2043
2044```json theme={null}2044```json theme={null}
2045{2045{
2068 PermissionRequest 决策控制2068 PermissionRequest 决策控制
2069</h4>2069</h4>
2070 2070
2071`PermissionRequest` hooks 可以允许或拒绝权限请求。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回一个 `decision` 对象,其中包含这些事件特定的字段:2071`PermissionRequest` hooks 可以允许或拒绝权限请求。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回一个带有这些事件特定字段的 `decision` 对象:
2072 2072
2073| 字段 | 描述 |2073| 字段 | 描述 |
2074| :------------------- | :------------------------------------------------------------------------------------------------------------------- |2074| :------------------- | :------------------------------------------------------------------------------------------------------------------- |
2075| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝它。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions) 仍然被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |2075| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝它。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions) 仍然被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |
2076| `updatedInput` | 仅对 `"allow"`:在执行前修改工具的输入参数。替换整个输入对象,因此在修改的输入旁边包含未更改的字段。修改的输入针对拒绝和询问规则重新评估 |2076| `updatedInput` | 仅对 `"allow"`:在执行前修改工具的输入参数。替换整个输入对象,因此在修改的字段旁边包含未更改的字段。修改的输入针对拒绝和询问规则重新评估 |
2077| `updatedPermissions` | 仅对 `"allow"`:[权限更新条目](#permission-update-entries) 数组以应用,如添加允许规则或更改会话权限模式 |2077| `updatedPermissions` | 仅对 `"allow"`:要应用的 [权限更新条目](#permission-update-entries) 数组,例如添加允许规则或更改会话权限模式 |
2078| `message` | 仅对 `"deny"`:告诉 Claude 为什么权限被拒绝 |2078| `message` | 仅对 `"deny"`:告诉 Claude 为什么权限被拒绝 |
2079| `interrupt` | 仅对 `"deny"`:如果 `true`,停止 Claude |2079| `interrupt` | 仅对 `"deny"`:如果为 `true`,停止 Claude |
2080 2080
2081不带 `decision` 对象退出 2 的 hook 保持权限流程不变,其 stderr 被丢弃。仅 `decision` 对象可以授予或拒绝请求。2081不带 `decision` 对象退出 2 的 hook 保持权限流程不变,其 stderr 被丢弃。仅 `decision` 对象可以授予或拒绝请求。
2082 2082
2098 权限更新条目2098 权限更新条目
2099</h4>2099</h4>
2100 2100
2101`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input) 都使用相同的条目对象数组。每个条目有一个 `type` 来确定其他字段,以及一个 `destination` 来控制更改写入的位置。2101`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input) 都使用相同的条目对象数组。每个条目有一个 `type` 来确定其他字段,以及一个 `destination` 来控制更改的写入位置。
2102 2102
2103| `type` | 字段 | 效果 |2103| `type` | 字段 | 效果 |
2104| :------------------ | :------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |2104| :------------------ | :------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
2110| `removeDirectories` | `directories`、`destination` | 删除工作目录 |2110| `removeDirectories` | `directories`、`destination` | 删除工作目录 |
2111 2111
2112<Note>2112<Note>
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) 中启动时,更新也是无操作。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 2114
2115 `bypassPermissions` 永远不会作为 `defaultMode` 持久化,无论 `destination` 如何。2115 `bypassPermissions` 永远不会作为 `defaultMode` 持久化,无论 `destination` 如何。
2116</Note>2116</Note>
2137当工具名称不是正确的过滤器时更广泛地匹配:2137当工具名称不是正确的过滤器时更广泛地匹配:
2138 2138
2139* 要在任何工具成功完成后运行 hook,省略 `matcher` 或将其设置为 `"*"`。您的 hook 然后可以自己发现更改了什么,例如通过运行 `git status --porcelain`,它也列出 `git diff` 错过的未跟踪文件。对于失败的工具调用,在 [PostToolUseFailure](#posttoolusefailure) 下添加相同的 hook。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。2140* 要在特定文件在磁盘上更改时运行 hook,无论什么写入它,请使用 [FileChanged](#filechanged)。当 `Bash` 命令或 Claude Code 外的进程重写相同文件时,Claude Code 不运行匹配 `Edit|Write` 的 `PostToolUse` hook。
2141 2141
2142<h4 id="posttooluse-input">2142<h4 id="posttooluse-input">
2143 PostToolUse 输入2143 PostToolUse 输入
2180| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |2180| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
2181| `decision` | `"block"` 在工具结果旁边添加 `reason`。Claude 仍然看到原始输出;要替换它,请使用 `updatedToolOutput` |2181| `decision` | `"block"` 在工具结果旁边添加 `reason`。Claude 仍然看到原始输出;要替换它,请使用 `updatedToolOutput` |
2182| `reason` | 当 `decision` 为 `"block"` 时显示给 Claude 的解释 |2182| `reason` | 当 `decision` 为 `"block"` 时显示给 Claude 的解释 |
2183| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2183| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-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 或更高版本 |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 或更高版本 |
2185| `updatedToolOutput` | 在将工具的输出发送给 Claude 之前用提供的值替换它。该值必须与工具的输出形状匹配 |2185| `updatedToolOutput` | 在将工具的输出发送给 Claude 之前用提供的值替换它。该值必须与工具的输出形状匹配 |
2186| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools) 的输出。优先使用 `updatedToolOutput`,它适用于所有工具 |2186| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools) 的输出。优先使用 `updatedToolOutput`,它适用于所有工具 |
2203```2203```
2204 2204
2205<Warning>2205<Warning>
2206 `updatedToolOutput` 仅更改 Claude 看到的内容。工具已经在 hook 触发时运行,因此任何写入的文件、执行的命令或发送的网络请求已经生效。遥测如 OpenTelemetry 工具跨度和分析事件也在 hook 运行之前捕获原始输出。要在运行前防止或修改工具调用,请改用 [PreToolUse](#pretooluse) hook。2206 `updatedToolOutput` 仅更改 Claude 看到的内容。工具已经在 hook 触发时运行,因此任何写入的文件、执行的命令或发送的网络请求已经生效。遥测(如 OpenTelemetry 工具跨度和分析事件)也在 hook 运行之前捕获原始输出。要在运行前防止或修改工具调用,请改用 [PreToolUse](#pretooluse) hook。
2207 2207
2208 替换值必须与工具的输出形状匹配。内置工具返回结构化对象而不是纯字符串。例如,`Bash` 返回一个带有 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,不与工具的输出模式匹配的值被忽略,使用原始输出。MCP 工具输出通过而不进行模式验证。剥离 Claude 需要的错误详情可能导致它基于错误的假设继续。2208 替换值必须与工具的输出形状匹配。内置工具返回结构化对象而不是纯字符串。例如,`Bash` 返回一个带有 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,与工具的输出模式不匹配的值被忽略,使用原始输出。MCP 工具输出通过而不进行模式验证。剥离 Claude 需要的错误详细信息可能导致它在错误的假设下继续。
2209</Warning>2209</Warning>
2210 2210
2211<h4 id="annotate-a-result-for-the-auto-mode-classifier">2211<h4 id="annotate-a-result-for-the-auto-mode-classifier">
2212 为自动模式分类器注释结果2212 为自动模式分类器注释结果
2213</h4>2213</h4>
2214 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 或更高版本。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 2216
2217下面的示例告诉分类器查询的输出来自何处:2217下面的示例告诉分类器查询的输出来自何处:
2218 2218
2227 2227
2228分类器给予说明的权重取决于您配置 hook 的位置:2228分类器给予说明的权重取决于您配置 hook 的位置:
2229 2229
2230* **在 Claude Code 中配置的 Hooks**:对于来自设置文件、插件、skills 和 agent frontmatter 的 hooks,分类器将说明视为未验证的、应用提供的上下文。说明永远不会建立用户意图,如果它声称您批准或请求了什么,分类器会根据您在对话中的自己的消息检查该声明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 注释同一调用时,分类器将组合说明视为未验证2231* **进程内 Agent SDK 回调**:当应用程序嵌入 Claude Code 并将 hook 注册为 [TypeScript SDK 回调](/docs/zh-CN/agent-sdk/hooks) 并在实时会话期间返回说明时,分类器可能会将用户声明中继的说明视为用户意图。这样的声明可以满足分类器会从您发送的消息接受的同意要求,但它永远不会解除您自己的消息也无法解除的阻止。会话恢复后,Claude Code 将恢复的说明视为未验证的上下文。当两个组的 hooks 注释相同的调用时,分类器将组合说明视为未验证
2232 2232
2233Claude Code 在传递说明时应用这些限制:2233Claude Code 在传递说明时应用这些限制:
2234 2234
2235* **长度**:Claude Code 将一个工具调用的说明上限为 2,000 个字符,并截断其余部分。上限在响应该调用的每个 hook 中共享2235* **长度**:Claude Code 将一个工具调用的说明上限为 2,000 个字符,并截断其余部分。上限在响应该调用的每个 hook 中共享
2236* **仅同步响应**:Claude Code 忽略 [在后台运行](#run-hooks-in-the-background) 的 hook 响应中的字段,因为该响应在 Claude Code 记录工具结果后到达2236* **仅同步响应**:Claude Code 忽略 [在后台运行](#run-hooks-in-the-background) 的 hook 响应中的字段,因为该响应在 Claude Code 记录工具结果后到达
2237* **分类器不记录的调用**:分类器的成绩单省略只读查找如文件读取和搜索。Claude Code 丢弃附加到其中一个调用的说明2237* **分类器不记录的调用**:分类器的成绩单省略只读查找,例如文件读取和搜索。Claude Code 丢弃附加到其中一个调用的说明
2238* **与重写的交互**:当说明描述您用 `updatedToolOutput` 替换的输出时,在同一 hook 响应中返回两个字段。如果该重写被拒绝或另一个 hook 的重写替换它,Claude Code 丢弃说明。Claude Code 传递您返回的说明而不重写,即使另一个 hook 重写输出2238* **与重写的交互**:当说明描述您用 `updatedToolOutput` 替换的输出时,在同一 hook 响应中返回两个字段。如果该重写被拒绝或另一个 hook 的重写替换它,Claude Code 丢弃说明。Claude Code 传递您返回的说明而不重写,即使另一个 hook 重写输出
2239 2239
2240<Warning>2240<Warning>
2241 分类器读取您放在 `classifierContext` 中的内容作为来自托管会话的应用的信息,因此不要将不受信任的工具输出或第三方文本复制到其中。将说明保持为关于此一个调用的简短断言,如关于其来源的事实或关于它的用户声明;不要使用该字段传递不相关的消息或事件流。2241 分类器将您放在 `classifierContext` 中的内容读取为来自托管会话的应用程序的信息,因此不要将不受信任的工具输出或第三方文本复制到其中。将说明保持为关于此一个调用的简短断言,例如关于其来源的事实或用户关于它的声明;不要使用该字段传递不相关的消息或事件流。
2242</Warning>2242</Warning>
2243 2243
2244<h3 id="posttoolusefailure">2244<h3 id="posttoolusefailure">
2280 2280
2281| 字段 | 描述 |2281| 字段 | 描述 |
2282| :------------- | :------------------------------------------------------------------------ |2282| :------------- | :------------------------------------------------------------------------ |
2283| `error` | 描述出错内容的字符串。格式取决于失败的工具 |2283| `error` | 描述出错的字符串。格式取决于失败的工具 |
2284| `is_interrupt` | 可选布尔值。当失败作为中止而不是工具报告的错误到达 Claude Code 时为 True。取消运行的工具不触发此 hook;工具结果携带中断消息 |2284| `is_interrupt` | 可选布尔值。当失败作为中止而不是工具报告的错误到达 Claude Code 时为 True。取消运行的工具不触发此 hook;工具结果携带中断消息 |
2285| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |2285| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |
2286 2286
2288 2288
2289* 对于 Bash 和 PowerShell,运行并退出的命令产生第一行 `Exit code N`,然后是命令产生的任何输出作为一个块,stdout 和 stderr 交错2289* 对于 Bash 和 PowerShell,运行并退出的命令产生第一行 `Exit code N`,然后是命令产生的任何输出作为一个块,stdout 和 stderr 交错
2290* 有效负载也可能携带裸失败消息,没有退出代码行,当 Claude Code 无法启动 shell 进程本身时2290* 有效负载也可能携带裸失败消息,没有退出代码行,当 Claude Code 无法启动 shell 进程本身时
2291* Claude Code 中间截断长字符串,围绕 `... [N characters truncated] ...` 标记,并可以插入自己的行,如 `Command timed out after 2m 0s`2291* Claude Code 中间截断长字符串,围绕 `... [N characters truncated] ...` 标记,并可以插入自己的行,例如 `Command timed out after 2m 0s`
2292 2292
2293<h4 id="posttoolusefailure-decision-control">2293<h4 id="posttoolusefailure-decision-control">
2294 PostToolUseFailure 决策控制2294 PostToolUseFailure 决策控制
2297`PostToolUseFailure` hooks 可以在工具失败后向 Claude 提供上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2297`PostToolUseFailure` hooks 可以在工具失败后向 Claude 提供上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
2298 2298
2299| 字段 | 描述 |2299| 字段 | 描述 |
2300| :------------------ | :-------------------------------------------------------------------------------------- |2300| :------------------ | :--------------------------------------------------------------------------- |
2301| `additionalContext` | 与错误一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2301| `additionalContext` | 与错误一起添加到 Claude 上下文的字符串。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
2302 2302
2303```json theme={null}2303```json theme={null}
2304{2304{
2345}2345}
2346```2346```
2347 2347
2348`tool_response` 包含模型在相应 `tool_result` 块中接收的相同内容。该值是序列化的字符串或内容块数组,完全如工具发出的一样。对于 `Read`,这意味着行号前缀的文本而不是原始文件内容。响应可能很大,因此仅解析您需要的字段。2348`tool_response` 包含模型在相应 `tool_result` 块中接收的相同内容。该值是序列化字符串或内容块数组,完全如工具发出的那样。对于 `Read`,这意味着行号前缀文本而不是原始文件内容。响应可能很大,因此仅解析您需要的字段。
2349 2349
2350<Note>2350<Note>
2351 `tool_response` 形状与 `PostToolUse` 的不同。`PostToolUse` 传递工具的结构化 `Output` 对象,如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递模型看到的序列化 `tool_result` 内容。2351 `tool_response` 形状与 `PostToolUse` 的不同。`PostToolUse` 传递工具的结构化 `Output` 对象,例如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递序列化 `tool_result` 内容模型看到的。
2352</Note>2352</Note>
2353 2353
2354<h4 id="posttoolbatch-decision-control">2354<h4 id="posttoolbatch-decision-control">
2358`PostToolBatch` hooks 可以为 Claude 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2358`PostToolBatch` hooks 可以为 Claude 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
2359 2359
2360| 字段 | 描述 |2360| 字段 | 描述 |
2361| :------------------ | :------------------------------------------------------------------------------------------------ |2361| :------------------ | :-------------------------------------------------------------------------------------------------- |
2362| `additionalContext` | 在下一个模型调用之前注入一次的上下文字符串。有关传递详情、放入其中的内容以及恢复的会话如何处理过去的值,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2362| `additionalContext` | 在下一个模型调用之前注入一次的上下文字符串。有关传递详细信息、放入其中的内容以及恢复的会话如何处理过去的值,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
2363 2363
2364```json theme={null}2364```json theme={null}
2365{2365{
2370}2370}
2371```2371```
2372 2372
2373返回 `decision: "block"` 或 `continue: false` 在下一个模型调用之前停止 agentic 循环。阻止消息来自 JSON `reason` 或 `stopReason`,或来自退出 2 时的 stderr。您在成绩单中看到它作为警告,它保留在对话中,因此 Claude 在对话继续时看到它。2373返回 `decision: "block"` 或 `continue: false` 在下一个模型调用之前停止 agentic 循环。阻止消息来自 JSON `reason` 或 `stopReason`,或来自退出 2 的 stderr。您在成绩单中看到它作为警告,它保留在对话中,因此当对话继续时 Claude 看到它。
2374 2374
2375<h3 id="permissiondenied">2375<h3 id="permissiondenied">
2376 PermissionDenied2376 PermissionDenied
2377</h3>2377</h3>
2378 2378
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` 规则匹配时不运行。使用它来记录拒绝、调整配置或告诉模型它可能重试工具调用。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` 规则匹配时,它不运行。使用它来记录拒绝、调整配置或告诉模型它可能重试工具调用。
2380 2380
2381匹配工具名称,与 PreToolUse 相同的值。2381匹配工具名称,与 PreToolUse 相同的值。
2382 2382
2404```2404```
2405 2405
2406| 字段 | 描述 |2406| 字段 | 描述 |
2407| :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2407| :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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` |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` |
2409 2409
2410<h4 id="permissiondenied-decision-control">2410<h4 id="permissiondenied-decision-control">
2411 PermissionDenied 决策控制2411 PermissionDenied 决策控制
2412</h4>2412</h4>
2413 2413
2414PermissionDenied hooks 可以告诉模型它可能重试被拒绝的工具调用。返回一个 JSON 对象,其中 `hookSpecificOutput.retry` 设置为 `true`:2414PermissionDenied hooks 可以告诉模型它可能重试被拒绝的工具调用。返回一个 `hookSpecificOutput.retry` 设置为 `true` 的 JSON 对象:
2415 2415
2416```json theme={null}2416```json theme={null}
2417{2417{
2424 2424
2425当 `retry` 为 `true` 时,Claude Code 向对话添加一条消息,告诉模型它可能重试工具调用。Claude Code 不反转拒绝本身。如果您的 hook 不返回 JSON,或返回 `retry: false`,拒绝成立,模型接收原始拒绝消息。2425当 `retry` 为 `true` 时,Claude Code 向对话添加一条消息,告诉模型它可能重试工具调用。Claude Code 不反转拒绝本身。如果您的 hook 不返回 JSON,或返回 `retry: false`,拒绝成立,模型接收原始拒绝消息。
2426 2426
2427当分类器对操作产生 [无判决](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action) 时,Claude Code 忽略 `retry: true`:其响应没有解析,或与自动模式分开的安全检查拒绝了分类器自己的请求。对于这些拒绝,Claude Code 已经在拒绝消息中告诉模型是否稍后重试或继续。2427当分类器对操作 [产生无判决](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action) 时,Claude Code 忽略 `retry: true`:其响应没有解析,或独立于自动模式的安全检查拒绝了分类器自己的请求。对于这些拒绝,Claude Code 已经在拒绝消息中告诉模型是否稍后重试或继续。
2428 2428
2429<h3 id="notification">2429<h3 id="notification">
2430 Notification2430 Notification
2431</h3>2431</h3>
2432 2432
2433在 Claude Code 发送通知时运行。匹配通知类型。省略匹配器以对所有通知类型运行 hooks。2433在 Claude Code 发送通知时运行。匹配通知类型。省略匹配器以为所有通知类型运行 hooks。
2434 2434
2435您即使在关闭桌面通知时也接收这些 hook 事件:`preferredNotifChannel` 设置,包括 `notifications_disabled`,仅更改您如何被警告,而不是您的 hook 是否运行。2435即使关闭了桌面通知,您也会接收这些 hook 事件:`preferredNotifChannel` 设置(包括 `notifications_disabled`)仅更改您如何被警告,而不是您的 hook 是否运行。
2436 2436
2437| 匹配器 | 何时触发 |2437| 匹配器 | 何时触发 |
2438| :--------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2438| :--------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2445| `elicitation_response` | MCP 引出响应被发送回服务器 |2445| `elicitation_response` | MCP 引出响应被发送回服务器 |
2446| `agent_needs_input` | 后台会话在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时开始等待您的输入,或当前会话询问您 [agent team](/docs/zh-CN/agent-teams) 队友的终端设置问题,您约六秒没有输入 |2446| `agent_needs_input` | 后台会话在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时开始等待您的输入,或当前会话询问您 [agent team](/docs/zh-CN/agent-teams) 队友的终端设置问题,您约六秒没有输入 |
2447| `agent_completed` | 后台会话完成或失败。仅在 [agent view](/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) |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` |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** 时不触发 |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** 时不触发 |
2451 2451
2460<Note>2460<Note>
2461 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享其时序,因此在终端会话中您仅在您似乎远离终端时看到它们:2461 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享其时序,因此在终端会话中您仅在您似乎远离终端时看到它们:
2462 2462
2463 * 期望 `permission_prompt` 一旦您约六秒没有输入。计时器在权限提示出现时启动,每次按键推迟它。要在 Claude 要求许可使用工具时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。2463 * 期望 `permission_prompt` 一旦您约六秒没有输入。计时器在权限提示出现时启动,每次按键推迟它。要在 Claude 要求使用工具权限时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。
2464 * 期望 `idle_prompt` 约 60 秒后 Claude 完成响应,仅当您自那以后没有输入时。Claude Code 在等待 claude.ai 使用限制重置时不发送 `idle_prompt`。当等待自己结束时,其中一个 `quota_auto_resume_*` 类型触发。2464 * 期望 `idle_prompt` 约 60 秒后 Claude 完成响应,仅当您自那以后没有输入时。Claude Code 在等待 claude.ai 使用限制重置时不发送 `idle_prompt`。当等待自己结束时,其中一个 `quota_auto_resume_*` 类型触发。
2465 * 期望 `elicitation_dialog` 用于引出表单,或 `elicitation_url_dialog` 用于浏览器 URL 请求,一旦您约六秒没有输入。两者共享与 `permission_prompt` 相同的六秒门:计时器在对话出现时启动,每次按键推迟它。2465 * 期望 `elicitation_dialog` 用于引出表单,或 `elicitation_url_dialog` 用于浏览器 URL 请求,一旦您约六秒没有输入。两者共享与 `permission_prompt` 相同的六秒门:计时器在对话出现时启动,每次按键推迟它。
2466 2466
2467 在另一个对话在屏幕上时到达的权限请求或引出保持相同的六秒门,从请求到达时计时。其通知可以在请求仍然等待时到达,同时打开的对话仍然在屏幕上。2467 权限请求或引出在另一个对话在屏幕上时到达保持相同的六秒门,从请求到达时计时。其通知可以在请求仍然等待打开的对话后面时到达您。
2468</Note>2468</Note>
2469 2469
2470Claude Code 在会话中以不同方式计时 `permission_prompt`,其中它向 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input) 发送权限请求,这是 Claude Desktop 和 VS Code 扩展如何托管 Claude Code 的方式:2470Claude Code 在发送权限请求给 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input) 的会话中以不同方式计时 `permission_prompt`,这是 Claude Desktop 和 VS Code 扩展如何托管 Claude Code 的方式:
2471 2471
2472* 期望 `permission_prompt` 约六秒后 Claude 要求许可。Claude Code 在您输入时不推迟它。2472* 期望 `permission_prompt` 约六秒后 Claude 要求权限。Claude Code 在您输入时不推迟它。
2473* 如果您或 [PermissionRequest](#permissionrequest) hook 更早回答,Claude Code 不运行 `permission_prompt`。2473* 如果您或 [PermissionRequest](#permissionrequest) hook 更早回答,Claude Code 不运行 `permission_prompt`。
2474* 设置 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 为 `1` 以在这些会话中关闭 `permission_prompt`。2474* 设置 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 为 `1` 以在这些会话中关闭 `permission_prompt`。
2475 2475
2476在 v2.1.233 之前,`permission_prompt` 在这些会话中不触发。2476在 v2.1.233 之前,`permission_prompt` 在这些会话中不触发。
2477 2477
2478使用单独的匹配器根据通知类型运行不同的处理程序。此配置在 Claude 需要权限批准时触发权限特定的警报脚本,在 Claude 空闲时触发不同的通知:2478使用单独的匹配器根据通知类型运行不同的处理程序。此配置在 Claude 需要权限批准时触发权限特定的警报脚本,以及当 Claude 空闲时触发不同的通知:
2479 2479
2480```json theme={null}2480```json theme={null}
2481{2481{
2522}2522}
2523```2523```
2524 2524
2525Notification hooks 无法阻止或修改通知。Claude Code 丢弃它们的 `systemMessage` 和 `continue` 字段,但仍然发出 [`terminalSequence`](#emit-terminal-notifications),这是桌面通知示例所依赖的。Notification hooks 用于副作用,如将通知转发到外部服务。2525Notification hooks 无法阻止或修改通知。Claude Code 丢弃它们的 `systemMessage` 和 `continue` 字段,但仍然发出 [`terminalSequence`](#emit-terminal-notifications),这是桌面通知示例所依赖的。Notification hooks 用于副作用,例如将通知转发到外部服务。
2526 2526
2527<h3 id="subagentstart">2527<h3 id="subagentstart">
2528 SubagentStart2528 SubagentStart
2529</h3>2529</h3>
2530 2530
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` 字段,而不是文件名。2531在 Claude 使用 Agent 工具生成子代理时运行,当 Claude [恢复子代理](/docs/zh-CN/sub-agents#resume-subagents) 时,以及每次进程内 [agent team](/docs/zh-CN/agent-teams) 队友处理新消息时。支持匹配器以按 agent 类型名称过滤。对于内置 agents,这是 agent 名称,如 `general-purpose`、`Explore` 或 `Plan`。对于 [自定义子代理](/docs/zh-CN/sub-agents),这是 agent 的 frontmatter 中的 `name` 字段,而不是文件名。
2532 2532
2533对于由 [插件](/docs/zh-CN/plugins) 提供的子 agent,agent 类型是插件范围的标识符如 `my-plugin:reviewer`,而不是裸 frontmatter 名称。冒号将插件范围的名称放在正则表达式路径上,因此用 `^` 和 `$` 锚定匹配器以获得精确匹配:`^my-plugin:reviewer$`。2533对于由 [插件](/docs/zh-CN/plugins) 提供的子代理,agent 类型是插件范围的标识符,例如 `my-plugin:reviewer`,而不是裸 frontmatter 名称。冒号将插件范围的名称放在正则表达式路径上,因此用 `^` 和 `$` 锚定匹配器以获得精确匹配:`^my-plugin:reviewer$`。
2534 2534
2535<h4 id="subagentstart-input">2535<h4 id="subagentstart-input">
2536 SubagentStart 输入2536 SubagentStart 输入
2537</h4>2537</h4>
2538 2538
2539除了 [常见输入字段](#common-input-fields) 外,SubagentStart hooks 接收 `agent_id` 与子 agent 的唯一标识符和 `agent_type` 与匹配器过滤的 agent 名称。2539除了 [常见输入字段](#common-input-fields) 外,SubagentStart hooks 接收 `agent_id` 与子代理的唯一标识符和 `agent_type` 与匹配器过滤的 agent 名称。
2540 2540
2541```json theme={null}2541```json theme={null}
2542{2542{
2549}2549}
2550```2550```
2551 2551
2552SubagentStart hooks 无法阻止子 agent 创建,但它们可以向子 agent 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:2552SubagentStart hooks 无法阻止子代理创建,但它们可以向子代理注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:
2553 2553
2554| 字段 | 描述 |2554| 字段 | 描述 |
2555| :------------------ | :--------------------------------------------------------------------------------------------------------- |2555| :------------------ | :------------------------------------------------------------------------------------ |
2556| `additionalContext` | 在子 agent 对话开始时添加到子 agent 上下文的字符串,在其第一个提示之前。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2556| `additionalContext` | 在子代理对话开始时添加到子代理上下文的字符串,在其第一个提示之前。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
2557 2557
2558```json theme={null}2558```json theme={null}
2559{2559{
2564}2564}
2565```2565```
2566 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 再次注入下一个运行的上下文。2567当 hook 再次为同一子代理运行时,Claude Code 仅在子代理的上下文还不包含早期运行副本时注入返回的上下文。在启动时注入的副本保留在位置,保持子代理的 [prompt cache](/docs/zh-CN/prompt-caching#subagents-and-the-cache) 完整。在 [自动压缩](/docs/zh-CN/sub-agents#auto-compaction) 丢弃该副本后,Claude Code 再次注入下一个运行的上下文。
2568 2568
2569<h3 id="subagentstop">2569<h3 id="subagentstop">
2570 SubagentStop2570 SubagentStop
2571</h3>2571</h3>
2572 2572
2573在 Claude Code 子 agent 完成响应时运行。匹配 agent 类型,与 SubagentStart 相同的值。2573在 Claude Code 子代理完成响应时运行。匹配 agent 类型,与 SubagentStart 相同的值。
2574 2574
2575<h4 id="subagentstop-input">2575<h4 id="subagentstop-input">
2576 SubagentStop 输入2576 SubagentStop 输入
2577</h4>2577</h4>
2578 2578
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 可以访问它而无需解析成绩单文件。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` 是子代理自己的成绩单,存储在嵌套 `subagents/` 文件夹中。`last_assistant_message` 字段包含子代理最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。
2580 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`。2581不是每个 SubagentStop 事件都来自 Claude 生成的子代理。Claude Code 也为其某些自己的功能运行内部 agents,例如 [prompt suggestions](/docs/zh-CN/interactive-mode#prompt-suggestions) 和 [`/btw` side questions](/docs/zh-CN/interactive-mode#side-questions-with-%2Fbtw),当其中一个完成时 SubagentStop 触发。对于这些事件,`agent_type` 是会话本身运行的 agent 名称,例如使用 [`--agent`](/docs/zh-CN/cli-reference#cli-flags) 或 [`agent` 设置](/docs/zh-CN/settings-reference#agent) 设置的,以及当会话运行时没有一个时的空字符串。
2582 2582
2583SubagentStop hooks 也接收 [Stop 输入](#stop-input) 下描述的 `background_tasks` 和 `session_crons` 数组。两个数组都限定于父会话,而不是子 agent。2583不匹配空 `agent_type` 的命名 agent 类型的 `matcher`。一个其匹配器被省略、`""`、`"*"` 或是匹配空字符串的正则表达式的 hook 也为带有空 `agent_type` 的事件运行。
2584
2585在 Claude Code v2.1.271 或更高版本上,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子代理在停止之前通过该工具传递其报告。`last_assistant_message` 字段然后保持子代理的结束文本(如果有),这不是传递的报告。报告是该调用的 `message` 输入,`PreToolUse` 或 `PostToolUse` hook 匹配 `SubagentHandback` 接收作为 `tool_input.message`。
2586
2587SubagentStop hooks 也接收 [Stop input](#stop-input) 下描述的 `background_tasks` 和 `session_crons` 数组。两个数组都限定于父会话,而不是子代理。
2584 2588
2585```json theme={null}2589```json theme={null}
2586{2590{
2599}2603}
2600```2604```
2601 2605
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。2606SubagentStop hooks 使用与 [Stop hooks](#stop-decision-control) 相同的决策控制格式,包括 `hookSpecificOutput.additionalContext`,`hookEventName` 设置为 `"SubagentStop"`,用于保持子代理运行的非错误反馈。返回 `decision: "block"` 与 `reason` 保持子代理运行并将 `reason` 作为其下一个指令传递给子代理。通过退出 2 阻止的 hook 以相同方式传递其 stderr 消息。要在子代理返回后向父会话注入上下文,请改用 [`PostToolUse`](#posttooluse) hook 在 `Agent` 工具上。
2603 2607
2604<h3 id="taskcreated">2608<h3 id="taskcreated">
2605 TaskCreated2609 TaskCreated
2607 2611
2608在通过 `TaskCreate` 工具创建任务时运行。使用此来强制命名约定、要求任务描述或防止某些任务被创建。在 [没有 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability) 中,此事件不触发。2612在通过 `TaskCreate` 工具创建任务时运行。使用此来强制命名约定、要求任务描述或防止某些任务被创建。在 [没有 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability) 中,此事件不触发。
2609 2613
2610TaskCreated hooks 不支持匹配器,对每个出现触发。2614TaskCreated hooks 不支持匹配器,在每个出现时触发。
2611 2615
2612<h4 id="taskcreated-input">2616<h4 id="taskcreated-input">
2613 TaskCreated 输入2617 TaskCreated 输入
2641 TaskCreated 决策控制2645 TaskCreated 决策控制
2642</h4>2646</h4>
2643 2647
2644TaskCreated hook 可以通过两种方式阻止创建。任一方式,Claude Code 删除任务并将您的消息作为工具的错误返回给 Claude。Claude Code 忽略此事件的 `continue: false`,Claude 继续工作。2648TaskCreated hook 可以通过两种方式阻止创建。无论哪种方式,Claude Code 删除任务并将您的消息作为工具的错误返回给 Claude。Claude Code 忽略此事件的 `continue: false`,Claude 继续工作。
2645 2649
2646* **退出代码 2**:Claude Code 将 stderr 文本作为消息返回。2650* **退出代码 2**:Claude Code 将 stderr 文本作为消息返回。
2647* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。2651* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。
2665 TaskCompleted2669 TaskCompleted
2666</h3>2670</h3>
2667 2671
2668在任务被标记为完成时运行。这在两种情况下触发:当任何 agent 通过 TaskUpdate 工具显式标记任务为完成时,或当 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合时有进行中的任务。使用此来强制完成标准,如通过测试或 lint 检查,然后任务才能关闭。2672在任务被标记为完成时运行。这在两种情况下触发:当任何 agent 通过 TaskUpdate 工具显式标记任务为完成时,或当 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合与进行中的任务时。使用此来强制完成标准,如通过测试或 lint 检查,然后任务才能关闭。
2669 2673
2670TaskCompleted hooks 不支持匹配器,对每个出现触发。2674TaskCompleted hooks 不支持匹配器,在每个出现时触发。
2671 2675
2672<h4 id="taskcompleted-input">2676<h4 id="taskcompleted-input">
2673 TaskCompleted 输入2677 TaskCompleted 输入
2739 2743
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 并结束回合。2744除了 [常见输入字段](#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 并结束回合。
2741 2745
2742`last_assistant_message` 字段包含 Claude 最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。对于作用于刚完成的回合的 hooks,如朗读或通知 hooks,使用此字段而不是读取 `transcript_path`:成绩单文件不保证在所有版本的 Stop 时间包含最终消息。2746`last_assistant_message` 字段包含 Claude 最终响应的文本内容,因此 hooks 可以访问它而无需解析成绩单文件。对于作用于刚完成的回合的 hooks,例如朗读或通知 hooks,使用此字段而不是读取 `transcript_path`:成绩单文件不保证在所有版本的 Stop 时包含最终消息。
2743 2747
2744`background_tasks` 和 `session_crons` 数组让 hooks 区分"会话完成"与"会话暂停等待后台工作唤醒它"。当任务注册表可达时两个数组都出现,当没有任何东西在飞行或计划时为空。2748`background_tasks` 和 `session_crons` 数组让 hooks 区分"会话完成"与"会话暂停等待后台工作唤醒它"。当任务注册表可达时两个数组都出现,当没有任何东西在飞行或计划时为空。
2745 2749
2746`background_tasks` 中的每个条目描述一个进行中的任务,并使用这些字段:2750`background_tasks` 中的每个条目描述一个进行中的任务,并使用这些字段:
2747 2751
2748| 字段 | 描述 |2752| 字段 | 描述 |
2749| :------------ | :---------------------------------------------------------------------------------------------------------------------------------------- |2753| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------ |
2750| `id` | 任务标识符 |2754| `id` | 任务标识符 |
2751| `type` | 友好的任务类型标签如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识哪个 Claude Code 功能创建了任务。对于无法识别的类型回退到原始判别式 |2755| `type` | 友好的任务类型标签,例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识哪个 Claude Code 功能创建了任务。对于无法识别的类型回退到原始判别式 |
2752| `status` | 当前任务状态 |2756| `status` | 当前任务状态 |
2753| `description` | 自由文本描述,上限为 1000 个字符,当被剪切时在字符串中有 `… [+N chars]` 标记 |2757| `description` | 自由文本描述,上限为 1000 个字符,当剪裁时带有字符串内 `… [+N chars]` 标记 |
2754| `command` | Shell 命令行,上限为 1000 个字符。仅对 `shell` 任务出现 |2758| `command` | Shell 命令行,上限为 1000 个字符。仅对 `shell` 任务出现 |
2755| `agent_type` | 子 agent 类型名称。仅对 `subagent` 任务出现 |2759| `agent_type` | 子代理类型名称。仅对 `subagent` 任务出现 |
2756| `server` | MCP 服务器名称。仅对 `monitor` 和 `MCP task` 任务出现 |2760| `server` | MCP 服务器名称。仅对 `monitor` 和 `MCP task` 任务出现 |
2757| `tool` | MCP 工具名称。仅对 `monitor` 和 `MCP task` 任务出现 |2761| `tool` | MCP 工具名称。仅对 `monitor` 和 `MCP task` 任务出现 |
2758| `name` | Workflow 名称。仅对 `workflow` 任务出现 |2762| `name` | 工作流名称。仅对 `workflow` 任务出现 |
2759 2763
2760`session_crons` 中的每个条目描述一个会话范围的计划唤醒,来自 `CronCreate`、`ScheduleWakeup` 和 `/loop`:2764`session_crons` 中的每个条目描述一个会话范围的计划唤醒,来自 `CronCreate`、`ScheduleWakeup` 和 `/loop`:
2761 2765
2766| `recurring` | 对于一次性唤醒(其计划编码单个触发时间)为 `false`,对于在每个匹配上重新触发的任务为 `true` |2770| `recurring` | 对于一次性唤醒(其计划编码单个触发时间)为 `false`,对于在每个匹配上重新触发的任务为 `true` |
2767| `prompt` | 当 cron 触发时提交的提示,上限为 1000 个字符,带有相同的 `… [+N chars]` 标记 |2771| `prompt` | 当 cron 触发时提交的提示,上限为 1000 个字符,带有相同的 `… [+N chars]` 标记 |
2768 2772
2769此示例显示了一个 Stop 输入,带有一个进行中的 shell 任务和一个循环 cron:2773此示例显示了一个进行中的 shell 任务和一个循环 cron 的 Stop 输入:
2770 2774
2771```json theme={null}2775```json theme={null}
2772{2776{
2804`Stop` 和 `SubagentStop` hooks 可以控制 Claude 是否继续。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2808`Stop` 和 `SubagentStop` hooks 可以控制 Claude 是否继续。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:
2805 2809
2806| 字段 | 描述 |2810| 字段 | 描述 |
2807| :------------------------------------- | :---------------------------------------------------------------------------------------- |2811| :------------------------------------- | :--------------------------------------------------------------------------------------------- |
2808| `decision` | `"block"` 防止 Claude 停止。省略以允许 Claude 停止 |2812| `decision` | `"block"` 防止 Claude 停止。省略以允许 Claude 停止 |
2809| `reason` | 当 `decision` 为 `"block"` 时需要。告诉 Claude 为什么它应该继续 |2813| `reason` | 当 `decision` 为 `"block"` 时需要。告诉 Claude 为什么它应该继续 |
2810| `hookSpecificOutput.additionalContext` | Claude 的非错误反馈。对话继续以便 Claude 可以作用于它,但与 `decision: "block"` 不同,它在成绩单中显示为 hook 反馈而不是 hook 错误 |2814| `hookSpecificOutput.additionalContext` | 对 Claude 的非错误反馈。对话继续,以便 Claude 可以对其采取行动,但与 `decision: "block"` 不同,它在成绩单中显示为 hook 反馈而不是 hook 错误 |
2811 2815
2812通过退出 2 阻止的 hook 路由方式与 `reason` 相同:Claude 接收 stderr 消息作为为什么它应该继续的解释。2816通过退出 2 阻止的 hook 路由方式与 `reason` 相同:Claude 接收 stderr 消息作为为什么它应该继续的解释。
2813 2817
2818}2822}
2819```2823```
2820 2824
2821当 hook 按设计工作并给 Claude 指导时使用 `additionalContext`,如"在完成前运行测试套件"。它通过与 `decision: "block"` 相同的循环保护保持对话进行,即 `stop_hook_active` 输入和 8 个连续继续上限,但成绩单将其标记为 `Stop hook feedback`,不显示 hook 错误通知:2825当 hook 按设计工作并给 Claude 指导时使用 `additionalContext`,例如"在完成前运行测试套件"。它通过与 `decision: "block"` 相同的循环保护保持对话进行,即 `stop_hook_active` 输入和 8 个连续继续上限,但成绩单将其标记为 `Stop hook feedback`,不显示 hook 错误通知:
2822 2826
2823```json theme={null}2827```json theme={null}
2824{2828{
2833 StopFailure2837 StopFailure
2834</h3>2838</h3>
2835 2839
2836在回合由于 API 错误而结束时运行,而不是 [Stop](#stop)。Claude Code 忽略 hook 的输出和退出代码,除了 [`terminalSequence`](#emit-terminal-notifications)。使用此来记录失败、发送警报或在 Claude 由于速率限制、身份验证问题或其他 API 错误无法完成响应时采取恢复操作。2840在回合由于 API 错误而结束时运行,而不是 [Stop](#stop)。Claude Code 忽略 hook 的输出和退出代码,除了 [`terminalSequence`](#emit-terminal-notifications)。使用此来记录失败、发送警报或在 Claude 由于速率限制、身份验证问题或其他 API 错误而无法完成响应时采取恢复操作。
2837 2841
2838<h4 id="stopfailure-input">2842<h4 id="stopfailure-input">
2839 StopFailure 输入2843 StopFailure 输入
2844| 字段 | 描述 |2848| 字段 | 描述 |
2845| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2849| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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` |2850| `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` |
2847| `error_details` | 关于错误的其他详情,当可用时 |2851| `error_details` | 关于错误的其他详细信息(如果可用) |
2848| `last_assistant_message` | 在对话中显示的呈现错误文本。与 `Stop` 和 `SubagentStop` 不同,其中此字段保持 Claude 的对话输出,对于 `StopFailure` 它包含 API 错误字符串本身,如 `"API Error: Rate limit reached"` |2852| `last_assistant_message` | 在对话中显示的呈现错误文本。与 `Stop` 和 `SubagentStop` 不同,其中此字段保持 Claude 的对话输出,对于 `StopFailure` 它包含 API 错误字符串本身,例如 `"API Error: Rate limit reached"` |
2849 2853
2850```json theme={null}2854```json theme={null}
2851{2855{
2859}2863}
2860```2864```
2861 2865
2862StopFailure hooks 没有决策控制。它们仅用于通知和日志记录目的运行。2866StopFailure hooks 没有决策控制。它们仅为通知和日志记录目的运行。
2863 2867
2864<h3 id="teammateidle">2868<h3 id="teammateidle">
2865 TeammateIdle2869 TeammateIdle
2866</h3>2870</h3>
2867 2871
2868在 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合后即将空闲时运行。使用此来强制质量门,如在队友停止工作之前要求通过 lint 检查或验证输出文件存在。2872在 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合后即将空闲时运行。使用此来强制质量门,如要求通过 lint 检查或验证输出文件存在。
2869 2873
2870TeammateIdle hooks 不支持匹配器,对每个出现触发。2874TeammateIdle hooks 不支持匹配器,在每个出现时触发。
2871 2875
2872<h4 id="teammateidle-input">2876<h4 id="teammateidle-input">
2873 TeammateIdle 输入2877 TeammateIdle 输入
2901* **退出代码 2**:队友接收 stderr 消息作为反馈并继续工作而不是空闲。2905* **退出代码 2**:队友接收 stderr 消息作为反馈并继续工作而不是空闲。
2902* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 显示给用户。2906* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 显示给用户。
2903 2907
2904此示例检查构建工件存在,然后允许队友空闲:2908此示例检查构建工件是否存在,然后允许队友空闲:
2905 2909
2906```bash theme={null}2910```bash theme={null}
2907#!/bin/bash2911#!/bin/bash
2920 2924
2921在会话期间配置文件更改时运行。使用此来审计设置更改、强制安全策略或阻止对配置文件的未授权修改。2925在会话期间配置文件更改时运行。使用此来审计设置更改、强制安全策略或阻止对配置文件的未授权修改。
2922 2926
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 端托管设置文件而不运行它们。2927Claude Code 在设置文件、托管策略文件或 skill 文件更改时运行 ConfigChange hooks。对于托管策略,它仅在 `managed-settings.json` 或 `managed-settings.d/` 中的文件更改时运行它们。它应用 [服务器托管设置](/docs/zh-CN/server-managed-settings) 和对 macOS 托管首选项或 Windows 注册表策略的更改而不运行它们。在 WSL 上使用 [`wslInheritsWindowsSettings`](/docs/zh-CN/settings-reference#wslinheritswindowssettings),它也在其策略轮询上应用更改的 Windows 端托管设置文件而不运行它们。
2924 2928
2925匹配器过滤配置源:2929匹配器过滤配置源:
2926 2930
2978| 字段 | 描述 |2982| 字段 | 描述 |
2979| :--------- | :-------------------------- |2983| :--------- | :-------------------------- |
2980| `decision` | `"block"` 防止配置更改被应用。省略以允许更改 |2984| `decision` | `"block"` 防止配置更改被应用。省略以允许更改 |
2981| `reason` | 被接受但永远不显示 |2985| `reason` | 接受但永远不显示 |
2982 2986
2983```json theme={null}2987```json theme={null}
2984{2988{
2987}2991}
2988```2992```
2989 2993
2990`policy_settings` 更改无法被阻止。当机器上的托管设置文件更改时,hooks 仍然为 `policy_settings` 源触发,因此您可以使用它们来记录这些编辑,但任何阻止决策都被忽略。这确保企业托管设置始终生效。当 [服务器托管设置](/docs/zh-CN/server-managed-settings) 到达或刷新时,Claude Code 不运行 `ConfigChange` hooks。2994`policy_settings` 更改无法被阻止。当机器上的托管设置文件更改时,Hooks 仍然为 `policy_settings` 源触发,因此您可以使用它们来记录这些编辑,但任何阻止决策都被忽略。这确保企业托管设置始终生效。当 [服务器托管设置](/docs/zh-CN/server-managed-settings) 到达或刷新时,Claude Code 不运行 `ConfigChange` hooks。
2991 2995
2992Claude Code 作用于 ConfigChange hook 的 JSON 输出中的阻止决策,并丢弃 `systemMessage` 和 `continue`。被阻止的更改不向您或 Claude 显示任何消息,无论您是用 `reason` 还是退出 2 时的 stderr 阻止。Claude Code 仅向调试日志写入一行。2996Claude Code 从 ConfigChange hook 的 JSON 输出中作用于阻止决策,并丢弃 `systemMessage` 和 `continue`。被阻止的更改不向您或 Claude 显示任何消息,无论您是用 `reason` 还是退出 2 的 stderr 阻止。Claude Code 仅向调试日志写入一行。
2993 2997
2994<h3 id="cwdchanged">2998<h3 id="cwdchanged">
2995 CwdChanged2999 CwdChanged
2996</h3>3000</h3>
2997 3001
2998在主对话中的 shell 命令更改工作目录时运行,例如当 Claude 执行 `cd` 命令时。使用此来对目录更改做出反应:重新加载环境变量、激活项目特定的工具链或自动运行设置脚本。与 [FileChanged](#filechanged) 配对,用于像 [direnv](https://direnv.net/) 这样管理每个目录环境的工具。3002在主对话中的 shell 命令更改工作目录时运行,例如当 Claude 执行 `cd` 命令时。使用此来对目录更改做出反应:重新加载环境变量、激活项目特定的工具链或自动运行设置脚本。与 [FileChanged](#filechanged) 配对,用于 [direnv](https://direnv.net/) 等管理每个目录环境的工具。
2999 3003
3000CwdChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 CwdChanged 事件,当 Claude Code 清除它们时。3004CwdChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 CwdChanged 事件,当 Claude Code 清除它们时。
3001 3005
3002CwdChanged 不支持匹配器,对每个出现触发。3006CwdChanged 不支持匹配器,在每个出现时触发。
3003 3007
3004<h4 id="cwdchanged-input">3008<h4 id="cwdchanged-input">
3005 CwdChanged 输入3009 CwdChanged 输入
3022 CwdChanged 输出3026 CwdChanged 输出
3023</h4>3027</h4>
3024 3028
3025除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,CwdChanged hooks 可以返回 `watchPaths` 来动态设置 [FileChanged](#filechanged) 监视的文件路径:3029除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,CwdChanged hooks 可以返回 `watchPaths` 来动态设置哪些文件路径 [FileChanged](#filechanged) 监视:
3026 3030
3027| 字段 | 描述 |3031| 字段 | 描述 |
3028| :----------- | :--------------------------------------------------------- |3032| :----------- | :------------------------------------------------------------------- |
3029| `watchPaths` | 绝对路径数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。进入新目录时返回空数组是典型的 |3033| `watchPaths` | 绝对路径的数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。返回空数组清除动态列表,这在进入新目录时是典型的 |
3030 3034
3031CwdChanged hooks 没有决策控制。它们无法阻止目录更改。3035CwdChanged hooks 没有决策控制。它们无法阻止目录更改。
3032 3036
3033Claude Code 从它们的 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。3037Claude Code 从其 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。
3034 3038
3035<h3 id="directoryadded">3039<h3 id="directoryadded">
3036 DirectoryAdded3040 DirectoryAdded
3037</h3>3041</h3>
3038 3042
3039在您使用 `/add-dir` 命令在会话中添加工作目录后运行,或在 SDK 客户端使用 `register_repo_root` 控制请求添加一个后运行。使用此来准备新添加的存储库,例如安装其依赖。3043在您使用 `/add-dir` 命令或 SDK 客户端使用 `register_repo_root` 控制请求在会话中添加工作目录后运行。使用此来准备新添加的存储库,例如安装其依赖。
3040 3044
3041Claude Code 在以下情况下不触发此事件:3045Claude Code 在以下情况下不触发此事件:
3042 3046
3043* 您使用 `--add-dir` 启动标志传递目录;[SessionStart](#sessionstart) 涵盖这些目录3047* 您使用 `--add-dir` 启动标志传递目录;[SessionStart](#sessionstart) 涵盖这些目录
3044* 您在 `/permissions` Workspace 标签上添加目录3048* 您在 `/permissions` Workspace 选项卡上添加目录
3045* 您添加已经是工作目录或在其中的目录3049* 您添加已经是工作目录或在其中的目录
3046 3050
3047Claude Code 在刷新沙箱和权限状态后触发 DirectoryAdded,因此沙箱工具已经在您的 hook 运行时看到新目录。Hook 命令本身运行未沙箱化。3051Claude Code 在刷新沙箱和权限状态后触发 DirectoryAdded,因此沙箱工具已经在您的 hook 运行时看到新目录。Hook 命令本身运行未沙箱化。
3048 3052
3049Claude Code 不等待 hook:添加立即完成,hook 在后台以 600 秒默认超时运行。3053Claude Code 不等待 hook:添加立即完成,hook 在后台以 600 秒默认超时运行。
3050 3054
3051匹配器过滤目录添加的方式:3055匹配器过滤目录的添加方式:
3052 3056
3053| 匹配器 | 何时触发 |3057| 匹配器 | 何时触发 |
3054| :------------------- | :-------------------------------------- |3058| :------------------- | :-------------------------------------- |
3062除了 [常见输入字段](#common-input-fields) 外,DirectoryAdded hooks 接收 `directory` 和 `source`。3066除了 [常见输入字段](#common-input-fields) 外,DirectoryAdded hooks 接收 `directory` 和 `source`。
3063 3067
3064| 字段 | 描述 |3068| 字段 | 描述 |
3065| :---------- | :----------------------------------------------------------------------- |3069| :---------- | :------------------------------------------------------------------------ |
3066| `directory` | 添加的目录的绝对路径 |3070| `directory` | 添加的目录的绝对路径 |
3067| `source` | 目录如何添加,`/add-dir` 为 `"slash_command"` 或 SDK 控制请求为 `"register_repo_root"` |3071| `source` | 目录如何被添加,`/add-dir` 为 `"slash_command"` 或 SDK 控制请求为 `"register_repo_root"` |
3068 3072
3069```json theme={null}3073```json theme={null}
3070{3074{
3077}3081}
3078```3082```
3079 3083
3080DirectoryAdded hooks 没有决策控制。它们无法阻止添加,这在 hook 运行时已经完成。Claude Code 从它们的 JSON 输出丢弃 `continue` 字段,并根据源以不同方式呈现其余部分:3084DirectoryAdded hooks 没有决策控制。它们无法阻止添加,这在 hook 运行时已经完成。Claude Code 根据源以不同方式处理其 JSON 输出中的 `systemMessage` 和失败输出:
3081 3085
3082* `slash_command`:Claude Code 将 hook 的 `systemMessage` 作为对话的下一个回合的上下文传递给 Claude,而不是向您显示它。失败 hooks 的计数出现在成绩单中。完整失败输出进入调试日志3086* `slash_command`:Claude Code 将 hook 的 `systemMessage` 传递给 Claude 作为下一个对话回合的上下文,而不是向您显示它。失败 hooks 的计数出现在成绩单中。完整失败输出进入调试日志
3083* `register_repo_root`:Claude Code 仅将 `systemMessage` 输出和失败输出写入调试日志3087* `register_repo_root`:Claude Code 仅将 `systemMessage` 输出和失败输出写入调试日志
3084 3088
3085<h3 id="filechanged">3089<h3 id="filechanged">
3086 FileChanged3090 FileChanged
3087</h3>3091</h3>
3088 3092
3089在监视的文件在磁盘上更改时运行。Claude Code 使用文件系统监视器检测更改,而不是通过检查工具调用,因此它运行 hook,无论什么更改了文件:`Edit` 或 `Write` 工具调用、Claude 使用 `Bash` 运行的脚本或 Claude Code 外的进程。常见用途是在项目配置文件更改时重新加载环境变量。3093在监视的文件在磁盘上更改时运行。Claude Code 使用文件系统监视器检测更改,而不是通过检查工具调用,因此无论什么更改文件,它都运行 hook:Write 或 Edit 工具调用、Claude 使用 Bash 运行的脚本或 Claude Code 外的进程。常见用途是在项目配置文件更改时重新加载环境变量。
3090 3094
3091此事件的 `matcher` 有两个角色:3095此事件的 `matcher` 有两个角色:
3092 3096
3093* **构建监视列表**:值在 `|` 上分割,每个段注册为工作目录中的字面文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里不有用:像 `^\.env` 这样的值会监视字面名为 `^\.env` 的文件。3097* **构建监视列表**:值在 `|` 上分割,每个段注册为工作目录中的文字文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里不有用:像 `^\.env` 这样的值会监视一个字面上命名为 `^\.env` 的文件。
3094* **过滤哪些 hooks 运行**:当监视的文件更改时,相同的值使用标准 [匹配器规则](#matcher-patterns) 针对更改文件的基名过滤哪些 hook 组运行。3098* **过滤哪些 hooks 运行**:当监视的文件更改时,相同的值使用标准 [匹配器规则](#matcher-patterns) 针对更改文件的基名过滤哪些 hook 组运行。
3095 3099
3096此示例在任何更改后规范化 `data.csv` 中的行结尾,包括 `Bash` 命令或外部脚本重写文件:3100此示例在任何更改后规范化 `data.csv` 中的行结尾,包括 Bash 命令或外部脚本重写文件:
3097 3101
3098```json theme={null}3102```json theme={null}
3099{3103{
3113}3117}
3114```3118```
3115 3119
3116hook 从 [JSON 输入](#filechanged-input) 的 `file_path` 字段读取更改文件的绝对路径,在 stdin 上。其 `grep` 守卫测试与 `perl` 删除的相同内容,行末的 CR,因此规范化后的运行退出而不触及文件。更松散的守卫循环永远,因为 `perl -i` 重写文件即使它替换了什么都没有,Claude Code 在每次重写后运行 hook。保存此脚本到 `/path/to/normalize-line-endings.sh` 并使其可执行:3120hook 从 stdin 上的 [JSON 输入](#filechanged-input) 的 `file_path` 字段读取更改文件的绝对路径。其 `grep` 守卫测试与 `perl` 删除的相同内容,行末的 CR,因此规范化后的运行退出而不触及文件。更松散的守卫循环永远,因为 `perl -i` 重写文件,即使它替换了什么,Claude Code 在每次重写后运行 hook。将此脚本保存在 `/path/to/normalize-line-endings.sh` 并使其可执行:
3117 3121
3118```bash theme={null}3122```bash theme={null}
3119#!/bin/bash3123#!/bin/bash
3123fi3127fi
3124```3128```
3125 3129
3126要确认 hook 工作,要求 Claude 使用 Bash 命令向 `data.csv` 追加 CRLF 行。Claude Code 运行 hook,文件最终以 LF 结尾。3130要确认 hook 有效,要求 Claude 使用 Bash 命令将 CRLF 行附加到 `data.csv`。Claude Code 运行 hook,文件最终以 LF 结尾。
3127 3131
3128要监视您无法提前命名的文件,从 hook 返回 [`watchPaths`](#filechanged-output) 来动态更新监视列表。Claude Code 仅在某些东西命名要监视的文件时启动监视器,因此使用至少命名一个文件的 FileChanged 组为列表播种,或使用 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 返回 `watchPaths`。匹配器仍然过滤当监视的文件更改时哪些 hook 组运行,因此给处理动态路径的组一个省略的匹配器,它匹配每个监视的文件并不向监视列表添加任何内容。`"*"` 匹配器也匹配每个文件,但 Claude Code 像任何其他值一样在监视列表中注册它,作为字面名为 `*` 的文件。3132要监视您无法提前命名的文件,从 hook 返回 [`watchPaths`](#filechanged-output) 来动态更新监视列表。Claude Code 仅在某些东西命名要监视的文件时启动监视器,因此使用至少命名一个文件的 FileChanged 组为列表播种,或使用 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 返回 `watchPaths`。匹配器仍然过滤当监视的文件更改时哪些 hook 组运行,因此给处理动态路径的组一个省略的匹配器,它匹配每个监视的文件并不向监视列表添加任何内容。`"*"` 匹配器也匹配每个文件,但 Claude Code 像任何其他值一样在监视列表中注册它,作为一个字面上命名为 `*` 的文件。
3129 3133
3130FileChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 [CwdChanged](#cwdchanged) 事件,当 Claude Code 清除它们时。3134FileChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 [CwdChanged](#cwdchanged) 事件,当 Claude Code 清除它们时。
3131 3135
3155 FileChanged 输出3159 FileChanged 输出
3156</h4>3160</h4>
3157 3161
3158除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,FileChanged hooks 可以返回 `watchPaths` 来动态更新监视的文件路径:3162除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,FileChanged hooks 可以返回 `watchPaths` 来动态更新哪些文件路径被监视:
3159 3163
3160| 字段 | 描述 |3164| 字段 | 描述 |
3161| :----------- | :-------------------------------------------------------------------------- |3165| :----------- | :--------------------------------------------------------------------------- |
3162| `watchPaths` | 绝对路径数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。当您的 hook 脚本根据更改的文件发现要监视的其他文件时使用此 |3166| `watchPaths` | 绝对路径的数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。当您的 hook 脚本根据更改的文件发现要监视的其他文件时使用此 |
3163 3167
3164FileChanged hooks 没有决策控制。它们无法阻止文件更改发生。3168FileChanged hooks 没有决策控制。它们无法阻止文件更改发生。
3165 3169
3166Claude Code 从它们的 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。3170Claude Code 从其 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。
3167 3171
3168<h3 id="worktreecreate">3172<h3 id="worktreecreate">
3169 WorktreeCreate3173 WorktreeCreate
3170</h3>3174</h3>
3171 3175
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。3176在创建 worktree 时运行,无论是从 `claude --worktree`、从 [使用 `isolation: "worktree"` 的子代理](/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。
3173 3177
3174因为 hook 完全替换默认行为,[`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees) 不被处理。如果您需要将本地配置文件如 `.env` 复制到新 worktree,请在您的 hook 脚本内执行。3178因为 hook 完全替换默认行为,[`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees) 不被处理。如果您需要将本地配置文件(如 `.env`)复制到新 worktree,请在您的 hook 脚本中执行。
3175 3179
3176hook 必须返回创建的 worktree 目录的路径。Claude Code 使用此路径作为隔离会话的工作目录。有关每个 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。3180hook 必须返回创建的 worktree 目录的路径。Claude Code 使用此路径作为隔离会话的工作目录。有关每个 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。
3177 3181
3196}3200}
3197```3201```
3198 3202
3199hook 从 stdin 上的 JSON 输入读取 worktree `name`,检出一个新副本到新目录,并打印目录路径。最后一行的 `echo` 是 Claude Code 读取为 worktree 路径的内容。将任何其他输出重定向到 stderr,以便它不干扰路径。3203hook 从 stdin 上的 JSON 输入读取 worktree `name`,检出一个新副本到新目录,并打印目录路径。最后一行的 `echo` 是 Claude Code 读取为 worktree 路径的内容。将任何其他输出重定向到 stderr,以便它不会干扰路径。
3200 3204
3201<h4 id="worktreecreate-input">3205<h4 id="worktreecreate-input">
3202 WorktreeCreate 输入3206 WorktreeCreate 输入
3220 3224
3221WorktreeCreate hooks 不使用标准允许/阻止决策模型。相反,hook 的成功或失败确定结果。hook 必须返回创建的 worktree 目录的路径:3225WorktreeCreate hooks 不使用标准允许/阻止决策模型。相反,hook 的成功或失败确定结果。hook 必须返回创建的 worktree 目录的路径:
3222 3226
3223* **命令 hooks** (`type: "command"`):将路径打印为 stdout 的最后一个非空行。Claude Code 在读取该行之前剥离 ANSI 转义代码,因此在您的 `echo` 之前打印的 shell 启动横幅被忽略。将任何其他 hook 输出重定向到 stderr。3227* **命令 hooks** (`type: "command"`):将路径打印为 stdout 的最后一个非空行。Claude Code 在读取该行之前剥离 ANSI 转义代码,因此在您的 `echo` 之前打印的 shell 启动横幅被忽略。将任何其他 hook 输出重定向到 stderr。
3224* **HTTP hooks** (`type: "http"`):在响应体中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。3228* **HTTP hooks** (`type: "http"`):在响应体中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。
3225 3229
3226如果 hook 失败或产生无路径,worktree 创建失败并出现错误。3230如果 hook 失败或产生无路径,worktree 创建失败并出现错误。
3227 3231
3236在删除 worktree 时运行。这是 [WorktreeCreate](#worktreecreate) 的清理对应物。事件在以下情况下触发:3240在删除 worktree 时运行。这是 [WorktreeCreate](#worktreecreate) 的清理对应物。事件在以下情况下触发:
3237 3241
3238* 您退出 `--worktree` 会话并选择删除它3242* 您退出 `--worktree` 会话并选择删除它
3239* 带有 `isolation: "worktree"` 的子 agent 完成3243* 带有 `isolation: "worktree"` 的子代理完成
3240* 您删除 [后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes),其 worktree hook 创建3244* 您删除 [后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes),其 worktree hook 创建
3241 3245
3242对于基于 git 的 worktrees,Claude Code 使用 `git worktree remove` 自动处理清理。如果您为非 git 版本控制系统配置了 WorktreeCreate hook,将其与 WorktreeRemove hook 配对来处理清理。没有它,worktree 目录留在磁盘上。3246对于基于 git 的 worktrees,Claude Code 使用 `git worktree remove` 自动处理清理。如果您为非 git 版本控制系统配置了 WorktreeCreate hook,请将其与 WorktreeRemove hook 配对以处理清理。没有它,worktree 目录留在磁盘上。
3243
3244Claude Code 丢弃 WorktreeRemove hook 的 [JSON 输出字段](#json-output),如 `systemMessage` 和 `continue`。
3245 3247
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 在存储的路径上运行而不进行这些检查。3248对于后台会话删除,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 3249
3280}3282}
3281```3283```
3282 3284
3283WorktreeRemove hook 的退出代码决定结果。当 hook 以非零退出且 `worktree_path` 处的目录之后仍然存在时,删除失败:3285WorktreeRemove hook 的退出代码决定结果。当 hook 退出非零且 `worktree_path` 处的目录仍然存在时,删除失败:
3284 3286
3285* worktree 保留在磁盘上,hook 的命令和 stderr 进入 [调试日志](#debug-hooks)。3287* worktree 保留在磁盘上,hook 的命令和 stderr 进入 [调试日志](#debug-hooks)。
3286* 如果您删除后台会话,会话也保留。[agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中的拒绝消息报告 hook 如何结束,如 `exited 1`,引用其 stderr 的开头,并说删除会话再次是否无论如何删除目录。3288* 如果您删除后台会话,会话也保留。[agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中的拒绝消息报告 hook 如何结束,例如 `exited 1`,引用其 stderr 的开头,并说是否再次删除会话无论如何删除目录。
3287 3289
3288<h3 id="precompact">3290<h3 id="precompact">
3289 PreCompact3291 PreCompact
3291 3293
3292在 Claude Code 即将运行压缩操作之前运行。3294在 Claude Code 即将运行压缩操作之前运行。
3293 3295
3294匹配器值指示压缩是手动触发还是自动触发:3296匹配器值指示压缩是手动还是自动触发:
3295 3297
3296| 匹配器 | 何时触发 |3298| 匹配器 | 何时触发 |
3297| :------- | :-------------------------------------------------------------------- |3299| :------- | :-------------------------------------------------------------------- |
3298| `manual` | `/compact` |3300| `manual` | `/compact` |
3299| `auto` | 当对话到达 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) 时自动压缩 |3301| `auto` | 当对话达到 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) 时自动压缩 |
3300 3302
3301以代码 2 退出以阻止压缩。对于手动 `/compact`,stderr 消息显示给用户。您也可以通过返回 JSON 与 `"decision": "block"` 来阻止。3303使用代码 2 退出以阻止压缩。对于手动 `/compact`,stderr 消息显示给用户。您也可以通过返回带有 `"decision": "block"` 的 JSON 来阻止。
3302 3304
3303阻止自动压缩根据何时触发有不同的效果。如果压缩在上下文限制之前主动触发,Claude Code 跳过它,对话继续未压缩。如果压缩被触发以从 API 已经返回的上下文限制错误恢复,底层错误浮出,当前请求失败。3305阻止自动压缩根据何时触发有不同的效果。如果压缩在上下文限制之前主动触发,Claude Code 跳过它,对话继续未压缩。如果压缩被触发以从 API 已返回的上下文限制错误恢复,基础错误浮出并且当前请求失败。
3304 3306
3305Claude Code 丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。3307Claude Code 丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。
3306 3308
3308 PreCompact 输入3310 PreCompact 输入
3309</h4>3311</h4>
3310 3312
3311除了 [常见输入字段](#common-input-fields) 外,PreCompact hooks 接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传递到 `/compact` 的内容,当他们传递什么都没有时为 `null`。对于 `auto`,`custom_instructions` 为 `null`。3313除了 [常见输入字段](#common-input-fields) 外,PreCompact hooks 接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传递到 `/compact` 的内容,当他们传递什么都不传递时为 `null`。对于 `auto`,`custom_instructions` 为 `null`。
3312 3314
3313```json theme={null}3315```json theme={null}
3314{3316{
3332| 匹配器 | 何时触发 |3334| 匹配器 | 何时触发 |
3333| :------- | :--------------------------------------------------------------------- |3335| :------- | :--------------------------------------------------------------------- |
3334| `manual` | 在 `/compact` 后 |3336| `manual` | 在 `/compact` 后 |
3335| `auto` | 在自动压缩后,当对话到达 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) |3337| `auto` | 当对话达到 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) 时自动压缩后 |
3336 3338
3337<h4 id="postcompact-input">3339<h4 id="postcompact-input">
3338 PostCompact 输入3340 PostCompact 输入
3357 PreModelSwitch3359 PreModelSwitch
3358</h3>3360</h3>
3359 3361
3360在 Claude Code 应用您或客户端请求的模型切换之前运行。使用它来阻止切换、要求确认或在切换发生之前显示它将花费什么。3362在 Claude Code 应用您或客户端请求的模型切换之前运行。使用它来阻止切换、要求确认或在切换发生之前显示成本。
3361 3363
3362PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 为这些请求运行它:3364PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 为这些请求运行它:
3363 3365
3364* `/model <name>` 和 `/model` 选择器3366* `/model <name>` 和 `/model` 选择器
3365* `Option+P` 或 `Alt+P` 模型选择器3367* `Option+P` 或 `Alt+P` 模型选择器
3366* `/config` 中的 Model 设置3368* `/config` 中的 Model 设置
3367* 当那改变会话的模型时打开 [快速模式](/docs/zh-CN/fast-mode)3369* 当那改变会话的模型时打开 [fast mode](/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` 请求中的模型更改3370* 来自 [Agent SDK](/docs/zh-CN/agent-sdk/typescript#query-object) 主机或 [Remote Control](/docs/zh-CN/remote-control) 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改
3369 3371
3370Claude Code 不为它自己进行的切换运行 PreModelSwitch hooks,如 [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback) 或恢复会话时恢复模型。这些更改仅到达 [PostModelSwitch](#postmodelswitch)。3372Claude Code 不为它自己进行的切换运行 PreModelSwitch hooks,例如 [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback) 或恢复会话时恢复模型。这些更改仅到达 [PostModelSwitch](#postmodelswitch)。
3371 3373
3372Claude Code 将匹配器与会话切换到的模型的规范名称进行比较,忽略任何 `[1m]` 后缀。别名如 `opus`、日期模型 ID 和提供商特定 ID 如 Amazon Bedrock 模型 ID 都匹配它们解析到的一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的每个拼写。3374Claude Code 将匹配器与会话切换到的模型的规范名称进行比较,忽略任何 `[1m]` 后缀。别名(如 `opus`)、日期模型 ID 和提供商特定 ID(如 Amazon Bedrock 模型 ID)都匹配它们解析到的一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的每个拼写。
3373 3375
3374当 Claude Code 无法确定目标的规范名称时,例如仅您的 [LLM 网关](/docs/zh-CN/llm-gateway) 知道的自定义模型 ID,它运行每个 PreModelSwitch hook,无论匹配器如何。阻止的 hook 应该从其输入检查 `to_model` 而不是仅依赖匹配器。3376当 Claude Code 无法确定目标的规范名称时,例如仅您的 [LLM gateway](/docs/zh-CN/llm-gateway) 知道的自定义模型 ID,它运行每个 PreModelSwitch hook,无论匹配器如何。阻止的 hook 应该从其输入检查 `to_model` 而不是仅依赖匹配器。
3375 3377
3376将匹配器写为精确名称、`|` 分隔列表如 `claude-opus-4-6|claude-opus-5` 或正则表达式如 `.*opus.*`。此示例使用精确名称匹配器,也从 hook 输入检查 `to_model`,因此它拒绝切换到 Opus 4.6,通过以代码 2 退出,并让任何其他目标通过:3378将匹配器写为精确名称、`|` 分隔列表(如 `claude-opus-4-6|claude-opus-5`)或正则表达式(如 `.*opus.*`)。此示例使用精确名称匹配器,也从 hook 输入检查 `to_model`,因此它拒绝切换到 Opus 4.6,通过退出代码 2,并让任何其他目标通过:
3377 3379
3378<Tabs>3380<Tabs>
3379 <Tab title="macOS/Linux">3381 <Tab title="macOS/Linux">
3439 </Tab>3441 </Tab>
3440</Tabs>3442</Tabs>
3441 3443
3442要确认 hook 工作,从运行不同模型的会话运行 `/model claude-opus-4-6`。Claude Code 保持当前模型并报告 PreModelSwitch hook 阻止了切换,您的消息作为原因。3444要确认 hook 有效,从运行不同模型的会话运行 `/model claude-opus-4-6`。Claude Code 保持当前模型并报告 PreModelSwitch hook 阻止了切换,以您的消息作为原因。
3443 3445
3444<h4 id="premodelswitch-input">3446<h4 id="premodelswitch-input">
3445 PreModelSwitch 输入3447 PreModelSwitch 输入
3448除了 [常见输入字段](#common-input-fields) 外,PreModelSwitch hooks 接收此表中的字段。最后五个描述重新发送对话到新模型的成本,因此 hook 可以在切换发生之前显示该数字。3450除了 [常见输入字段](#common-input-fields) 外,PreModelSwitch hooks 接收此表中的字段。最后五个描述重新发送对话到新模型的成本,因此 hook 可以在切换发生之前显示该数字。
3449 3451
3450| 字段 | 类型 | 描述 |3452| 字段 | 类型 | 描述 |
3451| :-------------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |3453| :-------------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3452| `from_model` | string | 切换改变的模型 ID |3454| `from_model` | string | 切换更改的模型 ID |
3453| `to_model` | string | 切换改变到的模型 ID。匹配器与此模型的规范名称进行比较 |3455| `to_model` | string | 切换更改为的模型 ID。匹配器与此模型的规范名称进行比较 |
3454| `requested_model` | string or `null` | 请求命名的模型:别名如 `opus`、完整模型 ID 或当请求是默认模型时 `null` |3456| `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` 请求中的模型更改 |3457| `source` | string | 请求来自何处:`"command"` 用于 `/model <name>`、`/config` 中的 Model 设置或打开 fast mode;`"picker"` 用于模型选择器;`"sdk"` 用于 `set_model` 请求,或来自 Agent SDK 主机或 Remote Control 的 `apply_flag_settings` 请求中的模型更改 |
3456| `context_tokens` | number | 下一个请求重新发送作为其提示的令牌:主对话中最后响应的输入、缓存读取、缓存创建和输出令牌,合并。第一个响应前为 `0` |3458| `context_tokens` | number | 下一个请求重新发送作为其提示的令牌:主对话中最后响应的输入、缓存读取、缓存创建和输出令牌,合并。第一个响应前为 `0` |
3457| `prompt_cache_warm` | boolean | 当前模型的 prompt cache 是否可能仍然温暖,意味着切换放弃它 |3459| `prompt_cache_warm` | boolean | 当前模型的 prompt cache 是否可能仍然温暖,意味着切换放弃它 |
3458| `cache_ttl` | string | [Prompt cache 生命周期](/docs/zh-CN/prompt-caching#cache-lifetime) Claude Code 为此会话请求:`"5m"` 或 `"1h"` |3460| `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` 速率,不包括下一个响应。服务器可能不需要重新缓存整个上下文,因此将其视为估计 |3461| `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"` |3462| `pricing` | string | Claude Code 如何定价 `estimated_cache_write_usd`:当您的组织配置了它们时在您的组织自己的速率处为 `"configured"`,在列表价格处为 `"catalog"`,或当 `to_model` 没有已知价格且 Claude Code 假设默认速率时为 `"default"` |
3461 3463
3462此示例显示了在运行 Sonnet 5 的会话中 `/model opus` 的输入:3464此示例显示了在运行 Sonnet 5 的会话中 `/model opus` 的输入:
3463 3465
3485 3487
3486`PreModelSwitch` hooks 可以取消切换、要求用户确认或让它继续。退出代码 2 或顶级 `decision: "block"` 取消切换。3488`PreModelSwitch` hooks 可以取消切换、要求用户确认或让它继续。退出代码 2 或顶级 `decision: "block"` 取消切换。
3487 3489
3488为了更精细的控制,在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,如 [PreToolUse](#pretooluse-decision-control)。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述两个字段:3490为了更精细的控制,在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,如 [PreToolUse](#pretooluse-decision-control) 上。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述两个字段:
3489 3491
3490| 字段 | 描述 |3492| 字段 | 描述 |
3491| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------- |3493| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------- |
3492| `permissionDecision` | `"allow"` 继续并跳过 [当 prompt cache 温暖时 Claude Code 显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户确认它 |3494| `permissionDecision` | `"allow"` 继续并跳过 [Claude Code 在 prompt cache 温暖时显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户确认它 |
3493| `permissionDecisionReason` | 对于 `"deny"`,显示给用户作为切换被阻止的原因,或作为 `set_model` 请求的错误返回。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 被忽略 |3495| `permissionDecisionReason` | 对于 `"deny"`,显示给用户作为切换被阻止的原因,或为 `set_model` 请求返回为错误。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 被忽略 |
3494 3496
3495仅交互式会话中的 `/model` 可以显示 `"ask"` 提示。在每个其他表面,包括带 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 将 `"ask"` 视为拒绝。3497仅交互式会话中的 `/model` 可以显示 `"ask"` 提示。在每个其他表面,包括带 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 将 `"ask"` 视为拒绝。
3496 3498
3508 3510
3509当多个 PreModelSwitch hooks 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。3511当多个 PreModelSwitch hooks 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。
3510 3512
3511Claude Code 显示用户您的 hook 返回的任何 `systemMessage`,无论决策如何,因此成本报告 hook 可以返回 `{"systemMessage": "..."}` 并退出 0。3513Claude Code 显示您的 hook 返回的任何 `systemMessage` 给用户,无论决策如何,因此成本报告 hook 可以返回 `{"systemMessage": "..."}` 并退出 0。
3512 3514
3513在其超时之前不响应的 PreModelSwitch hook 阻止切换。在 [PreToolUse](#timeouts) 上,相比之下,超时的命令 hook 让工具调用继续。此事件的默认超时为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hooks,因此 `prompt` 和 `agent` 默认不适用。3515在其超时前不响应的 PreModelSwitch hook 阻止切换。在 [PreToolUse](#timeouts) 上,相比之下,超时的命令 hook 让工具调用继续。此事件的默认超时为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hooks,因此 `prompt` 和 `agent` 默认不适用。
3514 3516
3515以 0 或 2 以外的代码退出且不打印 JSON 决策的 hook 不阻止:Claude Code 显示其 stderr 并应用切换,如 [其他退出代码](#other-exit-codes) 下所述。3517退出代码不是 0 或 2 且不打印 JSON 决策的 hook 不阻止:Claude Code 显示其 stderr 并应用切换,如 [其他退出代码](#other-exit-codes) 下所述。
3516 3518
3517<h3 id="postmodelswitch">3519<h3 id="postmodelswitch">
3518 PostModelSwitch3520 PostModelSwitch
3519</h3>3521</h3>
3520 3522
3521在会话的模型更改后运行。使用它来给 Claude 模型特定的指导,而不编辑每个 CLAUDE.md。3523在会话的模型更改后运行。使用它来给 Claude 模型特定的指导,而不编辑每个 CLAUDE.md,例如仅在某些模型上适用的组织范围指令。
3522 3524
3523PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。Claude Code 在任何这些更改后运行 PostModelSwitch hooks:3525PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。Claude Code 在这些更改后运行 PostModelSwitch hooks:
3524 3526
3525* 您或客户端请求的切换3527* 您或客户端请求的切换
3526* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),改变会话的模型3528* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),改变会话的模型
3527* 设置如 [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting) 进入或离开 plan mode3529* 设置(如 [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting))进入或离开 plan mode
3528* Claude Code 恢复会话时恢复模型3530* Claude Code 恢复会话时恢复模型
3529 3531
3530Claude Code 不为来自 [回退模型链](/docs/zh-CN/model-config#fallback-model-chains) 的模型运行 PostModelSwitch hooks,因为该替换持续一个回合并保持会话的模型不变。3532当 [回退模型链](/docs/zh-CN/model-config#fallback-model-chains) 中的模型服务回合时,Claude Code 不运行 PostModelSwitch hooks,因为该替换持续一个回合并保持会话的模型不变。
3531 3533
3532匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 将其与会话切换到的模型的规范名称进行比较。3534匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 将其与会话切换到的模型的规范名称进行比较。
3533 3535
3551}3553}
3552```3554```
3553 3555
3554要确认 hook 工作,从运行不同模型的会话切换到 Opus 模型,例如从 Sonnet 会话运行 `/model opus`,然后询问 Claude 它对当前模型有什么指导。3556要确认 hook 有效,从运行不同模型的会话切换到 Opus 模型,例如从 Sonnet 会话运行 `/model opus`,然后询问 Claude 它对当前模型有什么指导。
3555 3557
3556<h4 id="postmodelswitch-input">3558<h4 id="postmodelswitch-input">
3557 PostModelSwitch 输入3559 PostModelSwitch 输入
3558</h4>3560</h4>
3559 3561
3560PostModelSwitch hooks 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,其中 `hook_event_name` 设置为 `"PostModelSwitch"` 和两个更多 `source` 值:`"auto"` 对于自动回退或 Claude Code 自己进行的其他更改,以及 `"resume"` 对于恢复会话时恢复的模型。3562PostModelSwitch hooks 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,`hook_event_name` 设置为 `"PostModelSwitch"` 和两个更多 `source` 值:`"auto"` 用于自动回退或 Claude Code 自己进行的其他更改,以及 `"resume"` 用于恢复会话时恢复的模型。
3561 3563
3562当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 恢复的保存模型设置。3564当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 恢复的保存模型设置。
3563 3565
3565 PostModelSwitch 决策控制3567 PostModelSwitch 决策控制
3566</h4>3568</h4>
3567 3569
3568Claude Code 获取您的 hook 在退出 0 时的 [纯文本 stdout](#exit-code-0),或来自 JSON 输出的 `additionalContext`,并在切换后的下一个请求中将其传递给 Claude。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:3570Claude Code 在切换后的下一个请求中获取您的 hook 的 [纯文本 stdout](#exit-code-0) 退出 0,或 JSON 输出中的 `additionalContext`,并将其传递给 Claude。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:
3569 3571
3570| 字段 | 描述 |3572| 字段 | 描述 |
3571| :------------------ | :----------------------------------------------------------------------------------------- |3573| :------------------ | :------------------------------------------------------------------------------ |
3572| `additionalContext` | 与下一个请求一起添加到 Claude 上下文的字符串。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |3574| `additionalContext` | 与下一个请求一起添加到 Claude 上下文的字符串。有关详细信息,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |
3573 3575
3574如果 hook 在您发送下一个提示后五秒内未完成,Claude Code 发送该请求而不输出,并将其附加到以下请求。如果模型在下一个请求之前更改多次,Claude Code 仅传递最后一个切换目标模型的输出。3576如果 hook 在您发送下一个提示后五秒内未完成,Claude Code 发送该请求而不输出,并将其附加到以下请求。如果模型在下一个请求之前更改多次,Claude Code 仅传递最后一个切换目标模型的输出。
3575 3577
3583 3585
3584| 原因 | 描述 |3586| 原因 | 描述 |
3585| :---------------------------- | :------------------------------------------------------- |3587| :---------------------------- | :------------------------------------------------------- |
3586| `clear` | 使用 `/clear` 命令清除会话 |3588| `clear` | 会话使用 `/clear` 命令清除 |
3587| `resume` | 通过交互式 `/resume` 切换会话 |3589| `resume` | 会话通过交互式 `/resume` 切换 |
3588| `logout` | 用户登出 |3590| `logout` | 用户登出 |
3589| `prompt_input_exit` | 用户在提示输入可见时退出 |3591| `prompt_input_exit` | 用户在提示输入可见时退出 |
3590| `other` | 其他退出原因 |3592| `other` | 其他退出原因 |
3608 3610
3609SessionEnd hooks 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 丢弃它们的 [JSON 输出字段](#json-output),如 `systemMessage`。3611SessionEnd hooks 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 丢弃它们的 [JSON 输出字段](#json-output),如 `systemMessage`。
3610 3612
3611SessionEnd hooks 的默认超时为 1.5 秒。当您退出、运行 `/clear` 或使用交互式 `/resume` 切换会话时它适用。您可以通过两种方式给 hook 更多时间:3613SessionEnd hooks 的默认超时为 1.5 秒。当您退出、运行 `/clear` 或使用交互式 `/resume` 切换会话时适用。您可以通过两种方式给 hook 更多时间:
3612 3614
3613* **每个 hook `timeout`**:在该 hook 的配置中设置 `timeout`。整体预算自动上升以匹配您的设置文件中最高的每个 hook `timeout`,最多 60 秒。如果您以这种方式提高预算,没有自己的 `timeout` 的 hook 仍然保持默认值。在插件提供的 hooks 上设置的超时不提高预算。3615* **每个 hook `timeout`**:在该 hook 的配置中设置 `timeout`。整体预算自动上升以匹配您设置文件中最高的每个 hook `timeout`,最多 60 秒。如果您以这种方式提高预算,没有自己的 `timeout` 的 hook 仍然保持默认值。在插件提供的 hooks 上设置的超时不提高预算。
3614* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:设置此环境变量(毫秒)以显式覆盖预算。您设置的值也成为每个没有自己的 `timeout` 的 hook 的超时。3616* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:以毫秒为单位设置此环境变量以显式覆盖预算。您设置的值也成为每个没有自己的 `timeout` 的 hook 的超时。
3615 3617
3616此示例将预算设置为 5 秒:3618此示例将预算设置为 5 秒:
3617 3619
3627 3629
3628在 MCP 服务器请求用户输入中任务时运行。默认情况下,Claude Code 显示交互式对话供用户响应。Hooks 可以拦截此请求并以编程方式响应,完全跳过对话。3630在 MCP 服务器请求用户输入中任务时运行。默认情况下,Claude Code 显示交互式对话供用户响应。Hooks 可以拦截此请求并以编程方式响应,完全跳过对话。
3629 3631
3630匹配器字段匹配 MCP 服务器名称。3632匹配器字段与 MCP 服务器名称匹配。
3631 3633
3632<h4 id="elicitation-input">3634<h4 id="elicitation-input">
3633 Elicitation 输入3635 Elicitation 输入
3695 3697
3696退出代码 2 拒绝引出。Claude Code 不在任何地方显示您的 stderr 消息。3698退出代码 2 拒绝引出。Claude Code 不在任何地方显示您的 stderr 消息。
3697 3699
3698Claude Code 作用于 Elicitation hook 的 JSON 输出中的 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。3700Claude Code 从 Elicitation hook 的 JSON 输出中作用于 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。
3699 3701
3700<h3 id="elicitationresult">3702<h3 id="elicitationresult">
3701 ElicitationResult3703 ElicitationResult
3703 3705
3704在用户响应 MCP 引出后运行。Hooks 可以观察、修改或阻止响应,然后将其发送回 MCP 服务器。3706在用户响应 MCP 引出后运行。Hooks 可以观察、修改或阻止响应,然后将其发送回 MCP 服务器。
3705 3707
3706匹配器字段匹配 MCP 服务器名称。3708匹配器字段与 MCP 服务器名称匹配。
3707 3709
3708<h4 id="elicitationresult-input">3710<h4 id="elicitationresult-input">
3709 ElicitationResult 输入3711 ElicitationResult 输入
3748 3750
3749退出代码 2 阻止响应,将有效操作更改为 `decline`。Claude Code 不在任何地方显示您的 stderr 消息。3751退出代码 2 阻止响应,将有效操作更改为 `decline`。Claude Code 不在任何地方显示您的 stderr 消息。
3750 3752
3751Claude Code 作用于 ElicitationResult hook 的 JSON 输出中的 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。3753Claude Code 从 ElicitationResult hook 的 JSON 输出中作用于 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。
3752 3754
3753<h2 id="prompt-based-hooks">3755<h2 id="prompt-based-hooks">
3754 基于提示的 hooks3756 基于提示的 hooks
3759支持所有五种 hook 类型(`command`、`http`、`mcp_tool`、`prompt` 和 `agent`)的事件:3761支持所有五种 hook 类型(`command`、`http`、`mcp_tool`、`prompt` 和 `agent`)的事件:
3760 3762
3761* `PermissionDenied`3763* `PermissionDenied`
3762* `PermissionRequest`
3763* `PostToolBatch`3764* `PostToolBatch`
3764* `PostToolUse`3765* `PostToolUse`
3765* `PostToolUseFailure`3766* `PostToolUseFailure`
3772* `UserPromptExpansion`3773* `UserPromptExpansion`
3773* `UserPromptSubmit`3774* `UserPromptSubmit`
3774 3775
3776`PermissionRequest` 支持 `command`、`http`、`mcp_tool` 和 `prompt` hooks,但不支持 `agent` hooks。如果您在此事件上配置代理 hook,Claude Code 会跳过它,权限流程保持不变。要从 hook 允许或拒绝,请从命令或 HTTP hook 返回[决定对象](#permissionrequest-decision-control)。
3777
3775支持 `command`、`http` 和 `mcp_tool` hooks 但不支持 `prompt` 或 `agent` 的事件:3778支持 `command`、`http` 和 `mcp_tool` hooks 但不支持 `prompt` 或 `agent` 的事件:
3776 3779
3777* `ConfigChange`3780* `ConfigChange`
3904 代理 hooks 是实验性的。行为和配置可能在未来版本中更改。对于生产工作流,建议使用[命令 hooks](#command-hook-fields)。3907 代理 hooks 是实验性的。行为和配置可能在未来版本中更改。对于生产工作流,建议使用[命令 hooks](#command-hook-fields)。
3905</Warning>3908</Warning>
3906 3909
3907基于代理的 hooks(`type: "agent"`)类似于基于提示的 hooks,但具有多轮工具访问。代理 hook 生成一个可以读取文件、搜索代码和检查代码库以验证条件的 subagent,而不是单个 LLM 调用。代理 hooks 支持与基于提示的 hooks 相同的事件。3910基于代理的 hooks(`type: "agent"`)类似于基于提示的 hooks,但具有多轮工具访问。代理 hook 生成一个可以读取文件、搜索代码和检查代码库以验证条件的 subagent,而不是单个 LLM 调用。代理 hooks 支持与[基于提示的 hooks](#prompt-based-hooks) 相同的事件,除了 `PermissionRequest`。
3908 3911
3909<h3 id="how-agent-hooks-work">3912<h3 id="how-agent-hooks-work">
3910 基于代理的 hooks 如何工作3913 基于代理的 hooks 如何工作