40| :- | :- |40| :- | :- |
41| `SessionStart` | 当会话开始或恢复时 |41| `SessionStart` | 当会话开始或恢复时 |
42| `Setup` | 当你使用 `--init-only` 启动 Claude Code,或在 `-p` 模式下使用 `--init` 或 `--maintenance` 时。用于 CI 或脚本中的一次性准备 |42| `Setup` | 当你使用 `--init-only` 启动 Claude Code,或在 `-p` 模式下使用 `--init` 或 `--maintenance` 时。用于 CI 或脚本中的一次性准备 |
43| `UserPromptSubmit` | 当你提交提示词时,在 Claude 处理之前 |43| `UserPromptSubmit` | 当提交提示词时,在 Claude 处理之前。对于 [Claude Code 自行发起的轮次](/docs/zh-CN/hooks#userpromptsubmit)也会触发 |
44| `UserPromptExpansion` | 当用户输入的命令扩展为提示词时,在到达 Claude 之前。可以阻止扩展 |44| `UserPromptExpansion` | 当用户输入的命令扩展为提示词时,在到达 Claude 之前。可以阻止扩展 |
45| `PreToolUse` | 在工具调用执行之前。可以阻止它 |45| `PreToolUse` | 在工具调用执行之前。可以阻止它 |
46| `PermissionRequest` | 当工具调用需要权限决策时 |46| `PermissionRequest` | 当工具调用需要权限决策时 |
1159 Hook 事件1159 Hook 事件
1160</h2>1160</h2>
1161 1161
1162每个事件对应于 Claude Code 生命周期中的一个点,hooks 可以在该点运行。下面的部分按照生命周期顺序排列:从会话设置到 agentic 循环再到会话结束。每个部分描述事件何时触发、它支持哪些匹配器、它接收的 JSON 输入以及如何通过输出控制行为。1162每个事件都对应 Claude Code 生命周期中可以运行 hook 的一个时间点。以下各节按照生命周期的顺序排列:从会话设置开始,经过智能体循环,直到会话结束。每一节都会说明事件何时触发、支持哪些匹配器、接收什么 JSON 输入,以及如何通过输出控制行为。
1163 1163
1164<h3 id="sessionstart">1164<h3 id="sessionstart">
1165 SessionStart1165 SessionStart
1166</h3>1166</h3>
1167 1167
1168在 Claude Code 启动新会话或恢复现有会话时运行。对于加载开发上下文(如现有问题或代码库的最近更改)或设置环境变量很有用。对于不需要脚本的静态上下文,请改用 [CLAUDE.md](/docs/zh-CN/memory)。1168在 Claude Code 启动新会话或恢复现有会话时运行。适用于加载开发上下文(例如现有 issue 或代码库的最近更改),或设置环境变量。对于不需要脚本的静态上下文,请改用 [CLAUDE.md](/docs/zh-CN/memory)。
1169 1169
1170SessionStart 在每个会话上运行,因此请保持这些 hooks 快速。仅支持 `type: "command"` 和 `type: "mcp_tool"` hooks。有关 `mcp_tool` hooks 何时运行,请参阅 [MCP tool hook 字段](#mcp-tool-hook-fields)。1170SessionStart 在每个会话中都会运行,因此请保持这些 hook 快速执行。仅支持 `type: "command"` 和 `type: "mcp_tool"` hook。有关 `mcp_tool` hook 何时运行,请参阅 [MCP 工具 hook 字段](#mcp-tool-hook-fields)。
1171 1171
1172匹配器值对应于会话的启动方式:1172匹配器值对应于会话的启动方式:
1173 1173
1174| 匹配器 | 何时触发 |1174| 匹配器 | 触发时机 |
1175| :- | :- |1175| :- | :- |
1176| `startup` | 新会话 |1176| `startup` | 新会话 |
1177| `resume` | `--resume`、`--continue` 或 `/resume` |1177| `resume` | `--resume`、`--continue` 或 `/resume` |
1178| `clear` | `/clear` |1178| `clear` | `/clear` |
1179| `compact` | 自动或手动压缩 |1179| `compact` | 自动或手动压缩 |
1180| `fork` | 从现有会话分叉的新会话:`--fork-session` 与 `--resume` 或 `--continue`、`/fork` 后台副本、`/branch` 或您 [移到后台](/docs/zh-CN/agent-view#from-inside-a-session) 的对话 |1180| `fork` | 从现有会话分叉出的新会话:与 `--resume` 或 `--continue` 一起使用的 `--fork-session`、`/fork` 后台副本、`/branch`,或您[移至后台](/docs/zh-CN/agent-view#from-inside-a-session)的对话 |
1181 1181
1182在 v2.1.214 之前,分叉的会话报告源为 `"resume"`。1182在 v2.1.214 之前,分叉的会话报告的 source 为 `"resume"`。
1183 1183
1184当您启动交互式会话、使用 `--continue` 或 `--resume` 在启动时恢复对话或运行 `/clear` 时,SessionStart hooks 在后台运行。您可以立即输入,恢复的对话显示时无需等待 hooks。Claude 的第一个响应仍然等待 hooks 完成,因此它们的上下文到达 Claude。1184当您启动交互式会话、在启动时使用 `--continue` 或 `--resume` 恢复对话,或运行 `/clear` 时,SessionStart hook 会在后台运行。您可以立即输入,恢复的对话也会直接显示,无需等待 hook。Claude 的第一条回复仍会等待 hook 完成,以便其上下文能够传递给 Claude。
1185 1185
1186当您在会话内使用 `/resume` 切换对话时,切换等待 hooks 完成。如果您在后台 hooks 仍在运行时运行 `/clear` 或切换到另一个对话,它们返回的任何内容都不适用于该会话。1186当您在会话中使用 `/resume` 切换对话时,切换操作则会等待 hook 完成。如果您在后台 hook 仍在运行时运行 `/clear` 或切换到其他对话,它们返回的任何内容都不会应用于该会话。
1187 1187
1188在启动时也适用相同的等待,包括恢复的会话:您在 SessionStart hooks 仍在运行时发送的提示不会到达 Claude,直到它们完成。1188启动时也存在同样的等待,包括恢复的会话:在 SessionStart hook 仍在运行时发送的提示词,要等到它们完成后才会传递给 Claude。
1189 1189
1190在任一等待期间,按 `Esc` 将提示返回到输入中而不发送它。hooks 继续运行。1190在上述任一等待期间,按 `Esc` 可将提示词收回到输入框中而不发送。hook 会继续运行。
1191 1191
1192<h4 id="sessionstart-input">1192<h4 id="sessionstart-input">
1193 SessionStart 输入1193 SessionStart 输入
1194</h4>1194</h4>
1195 1195
1196除了 [常见输入字段](#common-input-fields) 外,SessionStart hooks 还接收 `source` 和可选的 `model`、`agent_type` 和 `session_title`:1196除了[通用输入字段](#common-input-fields)之外,SessionStart hook 还会接收 `source`,以及可选的 `model`、`agent_type` 和 `session_title`:
1197 1197
1198| 字段 | 描述 |1198| 字段 | 描述 |
1199| :- | :- |1199| :- | :- |
1200| `source` | 会话如何启动:新会话为 `"startup"`、恢复的会话为 `"resume"`、`/clear` 后为 `"clear"`、压缩后为 `"compact"` 或从现有会话分叉的新会话为 `"fork"` |1200| `source` | 会话的启动方式:新会话为 `"startup"`,恢复的会话为 `"resume"`,`/clear` 之后为 `"clear"`,压缩之后为 `"compact"`,从现有会话分叉出的新会话为 `"fork"` |
1201| `model` | 活跃的模型标识符。例如在 `/clear` 后或通过对话恢复恢复会话时可能被省略,因此在读取前检查该字段 |1201| `model` | 当前活动的模型标识符。该字段可能被省略,例如在 `/clear` 之后或通过对话恢复还原会话时,因此请在读取前检查该字段是否存在 |
1202| `agent_type` | agent 名称,当您使用 `claude --agent <name>` 启动 Claude Code 时出现 |1202| `agent_type` | Agent 名称,在您使用 `claude --agent <name>` 启动 Claude Code 时出现 |
1203| `session_title` | 当前会话标题(如果已设置),例如通过 `--name`、`/rename`、发出 `sessionTitle` 的 hook 或 Agent SDK 的 `renameSession()`。发出 `sessionTitle` 的 hook 可以先检查此字段以避免覆盖现有的自定义标题 |1203| `session_title` | 会话的自定义标题,在已设置时出现,例如通过 `--name`、`/rename`、hook 的 `sessionTitle` 输出或 Agent SDK 的 `renameSession()` 设置。输出 `sessionTitle` 的 hook 可以先检查此字段,以避免覆盖现有的自定义标题 |
1204 1204
1205一个您未命名的会话仍然可以有 [生成的标题](/docs/zh-CN/sessions#name-your-sessions)。该标题不是自定义标题,不出现在 `session_title` 中。1205您未命名的会话仍可能拥有[自动生成的标题](/docs/zh-CN/sessions#name-your-sessions)。该标题不是自定义标题,不会出现在 `session_title` 中。
1206 1206
1207当 `source` 为 `"resume"` 或 `"fork"` 且成绩单包含至少一个来自 Claude 的响应时,SessionStart hooks 也会接收下面的四个字段。您的 hook 可以使用它们在第一个请求之前报告恢复陈旧对话的成本,例如在 [`systemMessage`](#json-output) 中。这些字段需要 Claude Code v2.1.251 或更高版本。1207当 `source` 为 `"resume"` 或 `"fork"`,且会话记录中至少包含一条 Claude 的回复时,SessionStart hook 还会接收以下四个字段。您的 hook 可以使用它们在第一个请求之前报告恢复一个陈旧对话的成本,例如通过 [`systemMessage`](#json-output)。这些字段需要 Claude Code v2.1.251 或更高版本。
1208 1208
1209| 字段 | 描述 |1209| 字段 | 描述 |
1210| :- | :- |1210| :- | :- |
1211| `seconds_since_last_response` | 自恢复成绩单中最后一个响应以来的挂钟秒数 |1211| `seconds_since_last_response` | 自恢复的会话记录中最后一条回复以来经过的实际秒数 |
1212| `context_tokens` | 恢复会话的第一个请求作为其提示重新发送的令牌 |1212| `context_tokens` | 恢复的会话的第一个请求作为提示词重新发送的 token 数 |
1213| `prompt_cache_likely_expired` | 当最后一个响应早于会话的 [prompt cache 生命周期](/docs/zh-CN/prompt-caching#cache-lifetime) 或更晚的压缩替换了缓存的对话时为 `true` |1213| `prompt_cache_likely_expired` | 当最后一条回复早于会话的[提示缓存生命周期](/docs/zh-CN/prompt-caching#cache-lifetime),或之后的压缩替换了已缓存的对话时为 `true` |
1214| `estimated_cache_write_usd` | 将 `context_tokens` 写入会话模型的 prompt cache 的估计成本(美元),不包括响应 |1214| `estimated_cache_write_usd` | 在会话所用模型上将 `context_tokens` 写入提示缓存的估计成本(美元),不包括回复 |
1215 1215
1216此示例显示了在最后一个响应后 90 分钟恢复的会话的输入:1216以下示例展示了在最后一条回复 90 分钟后恢复的会话的输入:
1217 1217
1218```json theme={null}1218```json theme={null}
1219{1219{
1234 SessionStart 决策控制1234 SessionStart 决策控制
1235</h4>1235</h4>
1236 1236
1237Claude Code 将它 [视为纯文本](#exit-code-0) 的 stdout 添加到 Claude 的上下文中。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您还可以返回这些事件特定的字段:1237Claude Code 会将其[视为纯文本](#exit-code-0)的 stdout 添加到 Claude 的上下文中。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您还可以返回以下特定于事件的字段:
1238 1238
1239| 字段 | 描述 |1239| 字段 | 描述 |
1240| :- | :- |1240| :- | :- |
1241| `additionalContext` | 在对话开始时添加到 Claude 上下文的字符串,在第一个提示之前。有关文本如何传递以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1241| `additionalContext` | 在对话开始时、第一个提示词之前添加到 Claude 上下文中的字符串。有关文本的传递方式以及应放入的内容,请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1242| `initialUserMessage` | 用作会话第一个用户消息的字符串。适用于 [非交互模式](/docs/zh-CN/headless),带有 `-p` 标志,即使未提供提示,它也成为第一个回合。如果提供了提示,它作为下一个回合跟随。与 `additionalContext` 不同,后者附加到现有回合,这会创建回合 |1242| `initialUserMessage` | 用作会话第一条用户消息的字符串。适用于使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless),此时即使未提供提示词,它也会成为第一轮。如果提供了提示词,则提示词作为下一轮紧随其后。与附加到现有轮次的 `additionalContext` 不同,此字段会创建轮次 |
1243| `sessionTitle` | 设置会话标题,效果与 `/rename` 相同。用于从启动文件夹、git 分支或 worktree 名称自动命名会话。当 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时适用;在 `"clear"` 和 `"compact"` 上被忽略 |1243| `sessionTitle` | 设置会话标题,效果与 `/rename` 相同。可用于根据启动文件夹、git 分支或 worktree 名称自动命名会话。在 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时生效;在 `"clear"` 和 `"compact"` 时被忽略 |
1244| `watchPaths` | 绝对路径数组,用于在此会话期间监视 [FileChanged](#filechanged) 事件 |1244| `watchPaths` | 在此会话期间要监视 [FileChanged](#filechanged) 事件的绝对路径数组 |
1245| `reloadSkills` | 布尔值。当为 `true` 时,Claude Code 在 SessionStart hooks 完成后重新扫描 [skill](/docs/zh-CN/skills) 和命令目录,因此 hook 安装的 skills 在同一会话中可用,从第一个提示开始 |1245| `reloadSkills` | 布尔值。为 `true` 时,Claude Code 会在 SessionStart hook 完成后重新扫描 [skill](/docs/zh-CN/skills) 和命令目录,使 hook 安装的 skill 在同一会话中从第一个提示词开始即可使用 |
1246 1246
1247```json theme={null}1247```json theme={null}
1248{1248{
1254}1254}
1255```1255```
1256 1256
1257由于纯 stdout 已经为此事件到达 Claude,仅加载上下文的 hook 可以直接打印到 stdout 而无需构建 JSON。当您需要将上下文与其他字段(如 `sessionTitle`)结合时,使用 JSON 形式。1257由于对于此事件,纯 stdout 已经会传递给 Claude,因此仅加载上下文的 hook 可以直接打印到 stdout,无需构建 JSON。当您需要将上下文与 `sessionTitle` 等其他字段组合时,请使用 JSON 形式。
1258 1258
1259当 SessionStart hook 安装或更新 skills 时使用 `reloadSkills`。Skill 发现通常在 SessionStart hooks 完成之前运行,因此 hook 写入 `~/.claude/skills/` 或 `.claude/skills/` 的文件否则只会在下一个会话中出现。此示例同步共享 skills 存储库并请求重新扫描:1259当 SessionStart hook 安装或更新 skill 时,请使用 `reloadSkills`。skill 发现通常在 SessionStart hook 完成之前运行,因此 hook 写入 `~/.claude/skills/` 或 `.claude/skills/` 的文件原本只会在下一个会话中出现。以下示例同步一个共享的 skill 仓库并请求重新扫描:
1260 1260
1261```bash theme={null}1261```bash theme={null}
1262#!/bin/bash1262#!/bin/bash
1267echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'1267echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'
1268```1268```
1269 1269
1270存储库 URL 是占位符;将其替换为您自己的 skills 存储库。使用占位符,克隆失败并打印 `fatal:` 消息到 stderr。来自退出 0 的 SessionStart hook 的 stderr 仅供参考,因此 `reloadSkills` 请求仍然适用。1270该仓库 URL 是一个占位符;请将其替换为您自己的 skill 仓库。使用占位符时,克隆会失败并向 stderr 打印一条 `fatal:` 消息。以 0 退出的 SessionStart hook 的 stderr 仅供参考,因此 `reloadSkills` 请求仍然生效。
1271 1271
1272<h4 id="persist-environment-variables">1272<h4 id="persist-environment-variables">
1273 持久化环境变量1273 持久化环境变量
1274</h4>1274</h4>
1275 1275
1276SessionStart hooks 可以访问 `CLAUDE_ENV_FILE` 环境变量,它提供一个文件路径,您可以在其中为后续 Bash 命令持久化环境变量。1276SessionStart hook 可以访问 `CLAUDE_ENV_FILE` 环境变量,该变量提供一个文件路径,您可以在其中为后续的 Bash 命令持久化环境变量。
1277 1277
1278要设置单个环境变量,请将 `export` 语句写入 `CLAUDE_ENV_FILE`。使用追加 (`>>`) 来保留由其他 hooks 设置的变量:1278要设置单个环境变量,请将 `export` 语句写入 `CLAUDE_ENV_FILE`。使用追加(`>>`)以保留其他 hook 设置的变量:
1279 1279
1280```bash theme={null}1280```bash theme={null}
1281#!/bin/bash1281#!/bin/bash
1289exit 01289exit 0
1290```1290```
1291 1291
1292要捕获设置命令中的所有环境更改,请比较之前和之后导出的变量:1292要捕获设置命令产生的所有环境更改,请比较执行前后导出的变量:
1293 1293
1294```bash theme={null}1294```bash theme={null}
1295#!/bin/bash1295#!/bin/bash
1309```1309```
1310 1310
1311<Note>1311<Note>
1312 `CLAUDE_ENV_FILE` 可用于 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hooks。其他 hook 类型无法访问此变量。1312 `CLAUDE_ENV_FILE` 可用于 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hook。其他类型的 hook 无法访问此变量。
1313</Note>1313</Note>
1314 1314
1315<h3 id="setup">1315<h3 id="setup">
1316 Setup1316 Setup
1317</h3>1317</h3>
1318 1318
1319仅当您使用 `--init-only` 启动 Claude Code,或在 [非交互模式](/docs/zh-CN/headless) 中使用 `--init` 或 `--maintenance` 与 `-p` 标志时触发。它不会在正常启动时触发。用于一次性依赖安装或您从 CI 或脚本显式触发的计划清理,与正常会话启动分开。对于每个会话的初始化,请改用 [SessionStart](#sessionstart)。1319仅在您使用 `--init-only` 启动 Claude Code,或在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下使用 `--init` 或 `--maintenance` 启动时触发。正常启动时不会触发。可将其用于从 CI 或脚本中显式触发的一次性依赖安装或定期清理,与正常的会话启动分开。对于每个会话的初始化,请改用 [SessionStart](#sessionstart)。
1320 1320
1321匹配器值对应于触发 hook 的 CLI 标志:1321匹配器值对应于触发该 hook 的 CLI 标志:
1322 1322
1323| 匹配器 | 何时触发 |1323| 匹配器 | 触发时机 |
1324| :- | :- |1324| :- | :- |
1325| `init` | `claude --init-only` 或 `claude -p --init` |1325| `init` | `claude --init-only` 或 `claude -p --init` |
1326| `maintenance` | `claude -p --maintenance` |1326| `maintenance` | `claude -p --maintenance` |
1327 1327
1328当您运行 `claude --init-only` 时,Claude Code 运行 Setup hooks 和带有 `startup` 匹配器的 `SessionStart` hooks,然后退出而不启动对话。1328当您运行 `claude --init-only` 时,Claude Code 会运行 Setup hook 以及带有 `startup` 匹配器的 `SessionStart` hook,然后退出,不会开始对话。
1329 1329
1330当您使用 `-p` 启动或继续对话时,您还需要提供提示,作为参数或通过 stdin 管道传输。当 `SessionStart` hook 提供 [`initialUserMessage`](#sessionstart-decision-control) 或当您恢复带有 [延迟工具调用](#defer-a-tool-call-for-later) 的会话时,您可以跳过提示。1330当您使用 `-p` 开始或继续对话时,还需要提供提示词,可以作为参数提供,也可以通过 stdin 管道传入。当 `SessionStart` hook 提供了 [`initialUserMessage`](#sessionstart-decision-control),或者您恢复带有[延迟工具调用](#defer-a-tool-call-for-later)的会话时,可以省略提示词。
1331 1331
1332成功时,`--init-only` 不向终端打印任何内容。要确认 hooks 运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,并检查日志中的 Setup 和 SessionStart hook 条目。1332成功时,`--init-only` 不会向终端打印任何内容。要确认 hook 已运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,然后在日志中检查 Setup 和 SessionStart hook 条目。
1333 1333
1334由于 Setup 不会在每次启动时触发,需要安装依赖的插件不能仅依赖 Setup。实际的模式是在首次使用时检查依赖并在缺失时安装,例如测试 `${CLAUDE_PLUGIN_DATA}/node_modules` 的 hook 或 skill,如果不存在则运行 `npm install`。有关存储已安装依赖的位置,请参阅 [持久数据目录](/docs/zh-CN/plugins/components#path-variables-and-persistent-data)。如果您通过市场分发插件,您可能不需要此模式:Claude Code [在缓存插件时自动安装符合条件的 Node.js 包依赖](/docs/zh-CN/plugins/loading#node-js-package-dependencies)。1334由于 Setup 并非每次启动都会触发,需要安装依赖的插件不能仅依赖 Setup。实用的模式是在首次使用时检查依赖,缺失时再安装,例如由 hook 或 skill 检测 `${CLAUDE_PLUGIN_DATA}/node_modules`,若不存在则运行 `npm install`。有关存储已安装依赖的位置,请参阅[持久数据目录](/docs/zh-CN/plugins/components#path-variables-and-persistent-data)。如果您通过市场分发插件,则可能不需要此模式:Claude Code 在缓存插件时会[自动安装符合条件的 Node.js 包依赖](/docs/zh-CN/plugins/loading#node-js-package-dependencies)。
1335 1335
1336<h4 id="setup-input">1336<h4 id="setup-input">
1337 Setup 输入1337 Setup 输入
1338</h4>1338</h4>
1339 1339
1340除了 [常见输入字段](#common-input-fields) 外,Setup hooks 接收设置为 `"init"` 或 `"maintenance"` 的 `trigger` 字段:1340除了[通用输入字段](#common-input-fields)之外,Setup hook 还会接收一个 `trigger` 字段,其值为 `"init"` 或 `"maintenance"`:
1341 1341
1342```json theme={null}1342```json theme={null}
1343{1343{
1353 Setup 决策控制1353 Setup 决策控制
1354</h4>1354</h4>
1355 1355
1356Setup hooks 无法阻止;执行在任何退出代码上继续。在每个退出代码上,Claude Code 丢弃 Setup hook 的 [JSON 输出字段](#json-output),如 `systemMessage`、`continue` 和 `hookSpecificOutput.additionalContext`。使用 `-p`,Setup hook 的 stdout、stderr 和退出代码仅在您使用 `--output-format stream-json --verbose` 启动时作为 [`hook_response` 事件](/docs/zh-CN/headless#read-session-metadata) 出现在运行的输出中。1356Setup hook 无法阻止执行;无论退出码如何,执行都会继续。对于任何退出码,Claude Code 都会丢弃 Setup hook 的 [JSON 输出字段](#json-output),例如 `systemMessage`、`continue` 和 `hookSpecificOutput.additionalContext`。使用 `-p` 时,只有在以 `--output-format stream-json --verbose` 启动时,Setup hook 的 stdout、stderr 和退出码才会作为 [`hook_response` 事件](/docs/zh-CN/headless#read-session-metadata)出现在运行输出中。
1357 1357
1358Setup hooks 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量持久化到会话的后续 Bash 命令中,就像在 [SessionStart hooks](#persist-environment-variables) 中一样。仅 `type: "command"` hooks 在 `Setup` 上运行。`type: "mcp_tool"` hook 在 `Setup` 上总是被跳过,如 [MCP tool hook 字段](#mcp-tool-hook-fields) 下所述。1358Setup hook 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量会持久保留到该会话的后续 Bash 命令中,与 [SessionStart hook](#persist-environment-variables) 中相同。只有 `type: "command"` hook 会在 `Setup` 上运行。`Setup` 上的 `type: "mcp_tool"` hook 总是会被跳过,如 [MCP 工具 hook 字段](#mcp-tool-hook-fields)中所述。
1359 1359
1360<h3 id="instructionsloaded">1360<h3 id="instructionsloaded">
1361 InstructionsLoaded1361 InstructionsLoaded
1362</h3>1362</h3>
1363 1363
1364当 `CLAUDE.md` 或 `.claude/rules/*.md` 文件加载到上下文中时触发。此事件在会话启动时对于急切加载的文件触发,稍后当文件被懒加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录或当带有 `paths:` frontmatter 的条件规则匹配时。hook 不支持阻止或决策控制。它异步运行以用于可观测性目的。1364在 `CLAUDE.md` 或 `.claude/rules/*.md` 文件被加载到上下文中时触发。此事件会在会话开始时针对预先加载的文件触发,之后在文件被延迟加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录时,或当带有 `paths:` frontmatter 的条件规则匹配时。该 hook 不支持阻止或决策控制。它以异步方式运行,用于可观测性目的。
1365 1365
1366当 Claude [直接通过 **Project instructions** 设置读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时它会触发,`load_reason` 设置为 `include`(与任何其他导入文件一样),以及当 `CLAUDE.md` 是它的符号链接时,作为正常的 `CLAUDE.md` 加载。1366当 Claude 通过 **Project instructions** 设置[直接读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不会触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时,此事件会触发,`load_reason` 与其他任何导入文件一样设置为 `include`;当 `CLAUDE.md` 是指向它的符号链接时,此事件也会作为普通的 `CLAUDE.md` 加载而触发。
1367 1367
1368匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅对在会话启动时加载的文件触发,或 `"matcher": "path_glob_match|nested_traversal"` 仅对懒加载触发。1368匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅针对会话开始时加载的文件触发,或使用 `"matcher": "path_glob_match|nested_traversal"` 仅针对延迟加载触发。
1369 1369
1370<h4 id="instructionsloaded-input">1370<h4 id="instructionsloaded-input">
1371 InstructionsLoaded 输入1371 InstructionsLoaded 输入
1372</h4>1372</h4>
1373 1373
1374除了 [常见输入字段](#common-input-fields) 外,InstructionsLoaded hooks 接收这些字段:1374除了[通用输入字段](#common-input-fields)之外,InstructionsLoaded hook 还会接收以下字段:
1375 1375
1376| 字段 | 描述 |1376| 字段 | 描述 |
1377| :- | :- |1377| :- | :- |
1378| `file_path` | 加载的指令文件的绝对路径 |1378| `file_path` | 已加载的指令文件的绝对路径 |
1379| `memory_type` | 文件的范围:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |1379| `memory_type` | 文件的作用域:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |
1380| `load_reason` | 文件加载的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值在压缩事件后重新加载指令文件时触发 |1380| `load_reason` | 文件被加载的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值在压缩事件后重新加载指令文件时触发 |
1381| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如果有)。仅对 `path_glob_match` 加载出现 |1381| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如有)。仅在 `path_glob_match` 加载时出现 |
1382| `trigger_file_path` | 触发此加载的文件的路径,用于懒加载 |1382| `trigger_file_path` | 对于延迟加载,指其访问触发了此次加载的文件的路径 |
1383| `parent_file_path` | 包含此文件的父指令文件的路径,用于 `include` 加载 |1383| `parent_file_path` | 对于 `include` 加载,指包含此文件的父指令文件的路径 |
1384 1384
1385```json theme={null}1385```json theme={null}
1386{1386{
1398 InstructionsLoaded 决策控制1398 InstructionsLoaded 决策控制
1399</h4>1399</h4>
1400 1400
1401InstructionsLoaded hooks 没有决策控制。它们无法阻止或修改指令加载。Claude Code 丢弃它们的 [JSON 输出字段](#json-output),如 `systemMessage` 和 `continue`。使用此事件进行审计日志、合规性跟踪或可观测性。1401InstructionsLoaded hook 没有决策控制。它们无法阻止或修改指令加载。Claude Code 会丢弃它们的 [JSON 输出字段](#json-output),例如 `systemMessage` 和 `continue`。可将此事件用于审计日志记录、合规跟踪或可观测性。
1402 1402
1403<h3 id="userpromptsubmit">1403<h3 id="userpromptsubmit">
1404 UserPromptSubmit1404 UserPromptSubmit
1405</h3>1405</h3>
1406 1406
1407在用户提交提示时运行,在 Claude 处理它之前。这允许您根据提示/对话添加额外上下文、验证提示或阻止某些类型的提示。1407在提交提示词时、Claude 处理它之前运行。这使您可以
1408根据提示词/对话添加额外的上下文、验证提示词,或
1409阻止某些类型的提示词。
1408 1410
1409`UserPromptSubmit` hooks 对 `command`、`http` 和 `mcp_tool` 类型的默认超时为 30 秒,比大多数其他事件的 600 秒默认值更短。因为此 hook 在每个提示之前运行并阻止模型处理直到它完成,卡住的 hook 会停滞会话。如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。1411`UserPromptSubmit` hook 不仅在您输入的提示词上触发。Claude Code 还会在以下情况下运行它们:
1410 1412
1411除了您使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook,达到超时的 `UserPromptSubmit` 命令、HTTP 或 MCP tool hook 被取消,其输出(包括任何 `additionalContext`)被丢弃。提示仍然到达 Claude 而没有该上下文。成绩单显示一个通知,命名 hook、触发的超时以及输出被丢弃。1413* [定时任务](/docs/zh-CN/scheduled-tasks)触发,包括 `/loop` 的每次迭代
1414* [后台子代理](/docs/zh-CN/sub-agents#run-subagents-in-foreground-or-background)向启动它的会话回报
1415* [另一个会话发送的消息](/docs/zh-CN/cross-session-messaging)到达您的主对话
1412 1416
1413在 `UserPromptSubmit` 上达到超时的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 用命名 hook 和超时的消息阻止提示,因为那里的回调可能充当必须不能失败打开的策略门。会话继续。在 v2.1.208 之前,该事件上的回调超时以执行错误结束回合。1417对于 `command`、`http` 和 `mcp_tool` 类型,`UserPromptSubmit` hook 的默认超时时间为 30 秒,短于这些类型在大多数其他事件上的 600 秒默认值。由于此 hook 在每个提示词之前运行,并会阻塞模型处理直到完成,卡住的 hook 会使会话停滞。如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1418
1419除了您使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook 之外,达到超时的 `UserPromptSubmit` 命令、HTTP 或 MCP 工具 hook 会被取消,其输出(包括任何 `additionalContext`)会被丢弃。提示词仍会传递给 Claude,但不带该上下文。会话记录中会显示一条通知,指明该 hook、触发的超时时间,以及输出已被丢弃。
1420
1421`UserPromptSubmit` 上达到超时的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 会阻止该提示词,并显示一条指明该 hook 和超时时间的消息,因为此处的回调可能充当不能在失败时放行的策略关卡。会话会继续。在 v2.1.208 之前,该事件上的回调超时会以执行错误结束该轮次。
1414 1422
1415<h4 id="userpromptsubmit-input">1423<h4 id="userpromptsubmit-input">
1416 UserPromptSubmit 输入1424 UserPromptSubmit 输入
1417</h4>1425</h4>
1418 1426
1419除了 [常见输入字段](#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 解析提示,请考虑这些行。1427除了[通用输入字段](#common-input-fields)之外,UserPromptSubmit hook 还会接收包含所提交文本的 `prompt` 字段。折叠为 `[Pasted text #N]` 占位符的粘贴内容会在原位置展开后传入。在 Claude Code [为 Claude 标记粘贴文本](/docs/zh-CN/terminal-config#how-claude-treats-pasted-text)的会话中,展开的内容位于 `<pasted_content id="…">` 行和 `</pasted_content id="…">` 行之间,因此如果您的 hook 解析提示词,请考虑这些行。
1420 1428
1421UserPromptSubmit hooks 也在会话有自定义标题时接收 `session_title`,含义与 [SessionStart `session_title` 字段](#sessionstart-input) 相同。1429当会话具有自定义标题时,UserPromptSubmit hook 还会接收 `session_title`,其含义与 [SessionStart 的 `session_title` 字段](#sessionstart-input)相同。
1422 1430
1423```json theme={null}1431```json theme={null}
1424{1432{
1435 UserPromptSubmit 决策控制1443 UserPromptSubmit 决策控制
1436</h4>1444</h4>
1437 1445
1438`UserPromptSubmit` hooks 可以控制是否处理用户提示并添加上下文。所有 [JSON 输出字段](#json-output) 都可用。1446`UserPromptSubmit` hook 可以控制是否处理已提交的提示词,并添加上下文。所有 [JSON 输出字段](#json-output)均可用。
1439 1447
1440有两种方式在退出代码 0 上向对话添加上下文:1448在退出码为 0 时,有两种方式向对话添加上下文:
1441 1449
1442* **纯文本 stdout**:Claude Code 添加它 [视为纯文本](#exit-code-0) 的 stdout 到 Claude 的上下文1450* **纯文本 stdout**:Claude Code 会将其[视为纯文本](#exit-code-0)的 stdout 添加到 Claude 的上下文中
1443* **带有 `additionalContext` 的 JSON**:使用下面的 JSON 格式以获得更多控制。`additionalContext` 字段作为上下文添加1451* **带有 `additionalContext` 的 JSON**:使用下面的 JSON 格式以获得更多控制。`additionalContext` 字段会作为上下文添加
1444 1452
1445两个通道都不产生可见的成绩单条目。纯 stdout 和 `additionalContext` 值各自作为以 hook 名称开头的系统提醒注入;Claude 读取两者。要确认传递,请检查 [调试日志](#debug-hooks)。1453这两种方式都不会在会话记录中产生可见条目。纯 stdout 和 `additionalContext` 值各自作为以 hook 名称开头的系统提醒注入;Claude 会读取两者。要确认是否已传递,请查看[调试日志](#debug-hooks)。
1446 1454
1447要阻止提示,返回一个 JSON 对象,其中 `decision` 设置为 `"block"`:1455要阻止提示词,请返回一个 `decision` 设置为 `"block"` 的 JSON 对象:
1448 1456
1449| 字段 | 描述 |1457| 字段 | 描述 |
1450| :- | :- |1458| :- | :- |
1451| `decision` | `"block"` 防止提示被处理。省略以允许提示继续 |1459| `decision` | `"block"` 会在提示词到达 Claude 之前将其拦截。省略则允许提示词继续 |
1452| `reason` | 当 `decision` 为 `"block"` 时显示给用户。不添加到上下文 |1460| `reason` | 当 `decision` 为 `"block"` 时显示给用户。不会添加到上下文中 |
1453| `additionalContext` | 与提交的提示一起添加到 Claude 上下文的字符串。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1461| `additionalContext` | 与提交的提示词一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1454| `sessionTitle` | 设置会话标题。用于根据提示内容自动命名会话 |1462| `sessionTitle` | 设置会话标题。可用于根据提示词内容自动命名会话 |
1455| `suppressOriginalPrompt` | 如果在 hook 阻止提示时为 `true`,则从阻止消息中省略原始提示文本。请参阅 [被阻止的提示留下什么](#what-a-blocked-prompt-leaves-behind) |1463| `suppressOriginalPrompt` | 如果在 hook 阻止提示词时为 `true`,则阻止消息中不包含提示词文本。请参阅[被阻止的提示词会留下什么](#what-a-blocked-prompt-leaves-behind) |
1456 1464
1457通过退出 2 阻止的 hook 路由方式与 `reason` 相同:阻止消息向用户显示 stderr 文本,它不添加到上下文。1465通过以退出码 2 退出来阻止的 hook,其处理方式与 `reason` 相同:阻止消息会向用户显示 stderr 文本,且不会添加到上下文中。
1458 1466
1459```json theme={null}1467```json theme={null}
1460{1468{
1470```1478```
1471 1479
1472<h4 id="what-a-blocked-prompt-leaves-behind">1480<h4 id="what-a-blocked-prompt-leaves-behind">
1473 被阻止的提示留下什么1481 被阻止的提示词会留下什么
1474</h4>1482</h4>
1475 1483
1476被阻止的提示永远不会到达 Claude,但其文本不会从任何地方删除。默认情况下,显示给用户的阻止消息以 `Original prompt:` 结尾,后跟提交的文本,Claude Code 将该消息写入会话的成绩单文件。要从消息中省略文本,打印 JSON,其中 `hookSpecificOutput` 中的 `"suppressOriginalPrompt": true`。无论 hook 是用 `decision: "block"` 还是通过退出 2 阻止,这都有效。不打印 JSON 的退出 2 hook 总是在其阻止消息中获得提示文本。1484被阻止的提示词永远不会到达 Claude,但其文本并不会从所有地方移除。默认情况下,显示给用户的阻止消息以 `Original prompt:` 结尾,后跟提交的文本,并且 Claude Code 会将该消息写入磁盘上的会话记录文件。要在消息中省略该文本,请在 `hookSpecificOutput` 中打印带有 `"suppressOriginalPrompt": true` 的 JSON。无论 hook 是通过 `decision: "block"` 还是以退出码 2 退出来阻止,此方法都有效。以退出码 2 退出且未打印 JSON 的 hook,其阻止消息中总是会包含提示词文本。
1477 1485
1478`suppressOriginalPrompt` 仅更改阻止消息。提交的文本仍然可以出现在本地文件中,如会话成绩单和您的提示历史,因此阻止 hook 不是将秘密保留在磁盘外的方式。要限制或删除这些文件,请参阅 [纯文本存储](/docs/zh-CN/claude-directory#plaintext-storage) 和 [清除本地数据](/docs/zh-CN/claude-directory#clear-local-data)。1486`suppressOriginalPrompt` 仅更改阻止消息。提交的文本仍可能出现在本地文件中,例如会话记录和您的提示词历史记录,因此阻止型 hook 并不是防止机密写入磁盘的方法。要限制或删除这些文件,请参阅[明文存储](/docs/zh-CN/claude-directory#plaintext-storage)和[清除本地数据](/docs/zh-CN/claude-directory#clear-local-data)。
1479 1487
1480<h3 id="userpromptexpansion">1488<h3 id="userpromptexpansion">
1481 UserPromptExpansion1489 UserPromptExpansion
1482</h3>1490</h3>
1483 1491
1484当用户输入的命令在到达 Claude 之前展开为提示时运行。使用此来阻止特定命令的直接调用、为特定 skill 注入上下文或记录用户调用哪些命令。例如,匹配 `deploy` 的 hook 可以阻止 `/deploy`,除非存在批准文件,或匹配审查 skill 的 hook 可以将团队的审查清单附加为 `additionalContext`。1492在用户输入的命令展开为提示词、到达 Claude 之前运行。可用于阻止直接调用特定命令、为特定 skill 注入上下文,或记录用户调用了哪些命令。例如,匹配 `deploy` 的 hook 可以在不存在批准文件时阻止 `/deploy`,或者匹配某个审查 skill 的 hook 可以将团队的审查清单作为 `additionalContext` 追加。
1485 1493
1486此事件涵盖 `PreToolUse` 不涵盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 仅在 Claude 调用工具时触发,但直接输入 `/skillname` 绕过 `PreToolUse`。`UserPromptExpansion` 在该直接路径上触发。1494此事件覆盖了 `PreToolUse` 未覆盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 只在 Claude 调用该工具时触发,而直接输入 `/skillname` 会绕过 `PreToolUse`。`UserPromptExpansion` 会在这条直接路径上触发。
1487 1495
1488在 `command_name` 上匹配。将匹配器留空以对每个提示类型命令触发。1496针对 `command_name` 进行匹配。将匹配器留空可在每个提示词类型的命令上触发。
1489 1497
1490<h4 id="userpromptexpansion-input">1498<h4 id="userpromptexpansion-input">
1491 UserPromptExpansion 输入1499 UserPromptExpansion 输入
1492</h4>1500</h4>
1493 1501
1494除了 [常见输入字段](#common-input-fields) 外,UserPromptExpansion hooks 接收 `expansion_type`、`command_name`、`command_args`、`command_source` 和原始 `prompt` 字符串。`expansion_type` 字段对于 skill 和自定义命令为 `slash_command`,或对于 MCP 服务器提示为 `mcp_prompt`。1502除了[通用输入字段](#common-input-fields)之外,UserPromptExpansion hook 还会接收 `expansion_type`、`command_name`、`command_args`、`command_source` 以及原始的 `prompt` 字符串。对于 skill 和自定义命令,`expansion_type` 字段为 `slash_command`;对于 MCP 服务器提示词,该字段为 `mcp_prompt`。
1495 1503
1496```json theme={null}1504```json theme={null}
1497{1505{
1512 UserPromptExpansion 决策控制1520 UserPromptExpansion 决策控制
1513</h4>1521</h4>
1514 1522
1515`UserPromptExpansion` hooks 可以阻止展开或添加上下文。所有 [JSON 输出字段](#json-output) 都可用。1523`UserPromptExpansion` hook 可以阻止展开或添加上下文。所有 [JSON 输出字段](#json-output)均可使用。
1516 1524
1517| 字段 | 描述 |1525| 字段 | 描述 |
1518| :- | :- |1526| :- | :- |
1519| `decision` | `"block"` 防止命令展开。省略以允许它继续 |1527| `decision` | `"block"` 会阻止命令展开。省略则允许其继续 |
1520| `reason` | 当 `decision` 为 `"block"` 时显示给用户 |1528| `reason` | 当 `decision` 为 `"block"` 时显示给用户 |
1521| `additionalContext` | 与展开的提示一起添加到 Claude 上下文的字符串。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1529| `additionalContext` | 与展开后的提示词一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1522 1530
1523通过退出 2 阻止的 hook 路由方式与 `reason` 相同:阻止消息向用户显示 stderr 文本。1531通过以退出码 2 退出来阻止的 hook,其处理方式与 `reason` 相同:阻止消息会向用户显示 stderr 文本。
1524 1532
1525```json theme={null}1533```json theme={null}
1526{1534{
1537 MessageDisplay1545 MessageDisplay
1538</h3>1546</h3>
1539 1547
1540在助手消息流向屏幕时运行。Claude Code 分批显示消息:每次一批新完成的行准备好渲染时,hook 运行一次,这些行和 Claude Code 渲染 hook 的替换文本代替它们。长消息产生多个调用;短消息可能只产生一个。1548在助手消息流式显示到屏幕上时运行。Claude Code 以增量方式显示消息:每当一批新完成的行准备好渲染时,hook 就会以这些行运行一次,Claude Code 会在原位置渲染 hook 的替换文本。长消息会产生多次调用;短消息可能只产生一次。
1541 1549
1542使用 MessageDisplay 来:1550可使用 MessageDisplay 来:
1543 1551
1544* 为最小显示剥离 markdown1552* 去除 markdown 以实现极简显示
1545* 转换 Agent SDK 应用程序向其用户显示的文本1553* 转换 Agent SDK 应用程序向其用户显示的文本
1546* 从 Claude 的响应中编辑 API 密钥或内部主机名1554* 从 Claude 的回复中编辑隐去 API 密钥或内部主机名
1547 1555
1548Claude Code 保持每个批次直到您的 hook 返回,因此保持 hook 快速。如果 hook 失败或超时,Claude Code 显示原始文本。此事件的默认超时为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。1556Claude Code 会保留每一批内容直到您的 hook 返回,因此请保持 hook 快速执行。如果 hook 失败或超时,Claude Code 会显示原始文本。此事件的默认超时时间为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1549 1557
1550MessageDisplay 仅用于显示:替换文本仅更改屏幕上呈现的内容。成绩单和 Claude 看到的内容保持原始文本,因此 Claude 永远看不到替换,详细模式显示原始。hook 仅接收助手消息文本,因此工具结果和您输入的文本呈现不变。1558MessageDisplay 仅影响显示:替换文本只改变屏幕上渲染的内容。会话记录和 Claude 看到的内容保留原始文本,因此 Claude 永远看不到替换内容,详细模式也会显示原始文本。该 hook 仅接收助手消息文本,因此工具结果和您输入的文本会原样渲染。
1551 1559
1552MessageDisplay 不支持匹配器,对每个流文本的助手消息触发;没有文本的消息(如仅工具调用响应)不触发它。1560MessageDisplay 不支持匹配器,会针对每条流式输出文本的助手消息触发;不含文本的消息(例如仅包含工具调用的回复)不会触发它。
1553 1561
1554在非交互式运行中,包括 Agent SDK 查询和 `claude -p`,MessageDisplay 每个助手消息运行一次而不是每批行运行一次。单个调用在消息完成后到达并携带完整消息文本:`index` 为 `0`,`final` 为 `true`,`delta` 保持整个消息。为每个消息收集 `delta` 文本的 hook 在两种模式中接收相同的总文本。1562在非交互运行中(包括 Agent SDK 查询和 `claude -p`),MessageDisplay 对每条助手消息运行一次,而不是对每批行运行一次。这一次调用在消息完成后到达,并携带完整的消息文本:`index` 为 `0`,`final` 为 `true`,`delta` 包含整条消息。收集每条消息 `delta` 文本的 hook 在两种模式下收到的总文本相同。
1555 1563
1556<h4 id="messagedisplay-input">1564<h4 id="messagedisplay-input">
1557 MessageDisplay 输入1565 MessageDisplay 输入
1558</h4>1566</h4>
1559 1567
1560除了 [常见输入字段](#common-input-fields) 外,MessageDisplay hooks 接收回合和消息的标识符、此调用在消息中的位置以及 `delta` 中的新文本。批次边界取决于文本如何流,因此使用 `index` 和 `final` 来跟踪通过消息的进度,而不是期望行以特定方式分组。1568除了[通用输入字段](#common-input-fields)之外,MessageDisplay hook 还会接收轮次和消息的标识符、此次调用在消息中的位置,以及 `delta` 中的新文本。批次边界取决于文本的流式传输方式,因此请使用 `index` 和 `final` 跟踪消息的进度,而不要期望行以特定方式分组。
1561 1569
1562| 字段 | 描述 |1570| 字段 | 描述 |
1563| :- | :- |1571| :- | :- |
1564| `turn_id` | 当前回合的 UUID |1572| `turn_id` | 当前轮次的 UUID |
1565| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每个批次中稳定。这不是 API `msg_…` id,因此无法与成绩单消息 ids 关联 |1573| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每一批中保持不变。这不是 API 的 `msg_…` id,因此无法与会话记录中的消息 id 关联 |
1566| `index` | 此批次在消息中的零基索引 |1574| `index` | 此批次在消息中的从零开始的索引 |
1567| `final` | 在消息的最后一个批次上为 `true`。每个消息恰好有一个最终批次 |1575| `final` | 在消息的最后一批上为 `true`。每条消息恰好有一个最终批次 |
1568| `delta` | 自上一个批次以来新完成的行,包括终止换行符。始终是完整行,除了可能以行中间结束的最终批次。在交互式运行中,当消息以换行符结束时最终批次的 delta 为空,因此将 `final` 而不是非空 delta 视为消息结束信号。在 Agent SDK 和 `claude -p` 运行中,单个调用携带整个消息 |1576| `delta` | 自上一批次以来新完成的行,包含结尾的换行符。始终为完整的行,但最终批次可能在行中间结束。在交互运行中,当消息以换行符结尾时,最终批次的 delta 为空,因此请将 `final`(而非非空的 delta)视为消息结束的信号。在 Agent SDK 和 `claude -p` 运行中,单次调用携带整条消息 |
1569 1577
1570```json theme={null}1578```json theme={null}
1571{1579{
1585 MessageDisplay 输出1593 MessageDisplay 输出
1586</h4>1594</h4>
1587 1595
1588除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,MessageDisplay hooks 可以返回 `displayContent` 来替换屏幕上的 delta:1596除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,MessageDisplay hook 还可以返回 `displayContent`,以在屏幕上替换 delta:
1589 1597
1590| 字段 | 描述 |1598| 字段 | 描述 |
1591| :- | :- |1599| :- | :- |
1592| `displayContent` | 显示代替 delta 的文本。省略以显示原始 |1600| `displayContent` | 代替 delta 显示的文本。省略则显示原始内容 |
1593 1601
1594MessageDisplay hooks 没有决策控制。它们无法阻止消息或更改存储在成绩单中或发送给 Claude 的内容。Claude Code 作用于它们的 JSON 输出中的 `displayContent` 并丢弃 `systemMessage` 和 `continue`。1602MessageDisplay hook 没有决策控制。它们无法阻止消息,也无法更改存储在会话记录中或发送给 Claude 的内容。Claude Code 会处理其 JSON 输出中的 `displayContent`,并丢弃 `systemMessage` 和 `continue`。
1595 1603
1596此示例从 Claude 的响应中剥离 markdown 格式以获得纯文本显示。脚本从 stdin 读取每个批次,从 `delta` 中删除粗体标记和内联代码反引号,并将结果作为 `displayContent` 返回。1604以下示例从 Claude 的回复中去除 markdown 格式,以实现纯文本显示。该脚本从 stdin 读取每一批内容,从 `delta` 中移除粗体标记和行内代码反引号,并将结果作为 `displayContent` 返回。
1597 1605
1598<Tabs>1606<Tabs>
1599 <Tab title="macOS/Linux">1607 <Tab title="macOS/Linux">
1600 在您的设置文件中为事件注册命令 hook:1608 在您的设置文件中为该事件注册一个命令 hook:
1601 1609
1602 ```json theme={null}1610 ```json theme={null}
1603 {1611 {
1617 }1625 }
1618 ```1626 ```
1619 1627
1620 将此脚本保存到项目中的 `.claude/hooks/plain-display.sh` 并使用 `chmod +x` 使其可执行:1628 将此脚本保存到项目中的 `.claude/hooks/plain-display.sh`,并使用 `chmod +x` 使其可执行:
1621 1629
1622 ```bash theme={null}1630 ```bash theme={null}
1623 #!/bin/bash1631 #!/bin/bash
1626 </Tab>1634 </Tab>
1627 1635
1628 <Tab title="Windows (PowerShell)">1636 <Tab title="Windows (PowerShell)">
1629 注册一个命令 hook,通过 PowerShell 运行脚本:1637 注册一个通过 PowerShell 运行脚本的命令 hook:
1630 1638
1631 ```json theme={null}1639 ```json theme={null}
1632 {1640 {
1652 }1660 }
1653 ```1661 ```
1654 1662
1655 `-NoProfile` 标志跳过加载您的 PowerShell 配置文件,以便 hook 快速启动,`-ExecutionPolicy Bypass` 让 PowerShell 运行本地脚本文件。1663 `-NoProfile` 标志会跳过加载您的 PowerShell 配置文件,使 hook 快速启动;`-ExecutionPolicy Bypass` 则允许 PowerShell 运行本地脚本文件。
1656 1664
1657 将此脚本保存到项目中的 `.claude/hooks/plain-display.ps1`:1665 将此脚本保存到项目中的 `.claude/hooks/plain-display.ps1`:
1658 1666
1669 </Tab>1677 </Tab>
1670</Tabs>1678</Tabs>
1671 1679
1672没有 markdown 的批次通过不变。如果脚本失败,例如因为 `jq` 缺失,Claude Code 显示原始文本并仅在 [调试输出](#debug-hooks) 中注意失败,而不是在会话中。1680不含 markdown 的批次会原样通过。如果脚本失败(例如因为缺少 `jq`),Claude Code 会显示原始文本,并且仅在[调试输出](#debug-hooks)中记录该失败,而不会在会话中显示。
1673 1681
1674<h3 id="pretooluse">1682<h3 id="pretooluse">
1675 PreToolUse1683 PreToolUse
1676</h3>1684</h3>
1677 1685
1678在 Claude 创建工具参数之后和处理工具调用之前运行。在除 `EndConversation` 之外的任何工具名称上匹配:内置工具如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 和 `ExitPlanMode`,以及任何 [MCP 工具名称](#match-mcp-tools)。1686在 Claude 创建工具参数之后、处理工具调用之前运行。可匹配除 `EndConversation` 以外的任何工具名称:内置工具,例如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 和 `ExitPlanMode`,以及任何 [MCP 工具名称](#match-mcp-tools)。
1679 1687
1680要在特定文件在磁盘上更改时运行 hook,无论什么写入它,请使用 [FileChanged](#filechanged) 而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在更改后运行 FileChanged hooks,它们没有决策控制,因此它们无法阻止写入。1688要在特定文件于磁盘上发生更改时运行 hook(无论是什么写入的),请使用 [FileChanged](#filechanged),而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在更改之后运行 FileChanged hook,且它们没有决策控制,因此无法阻止写入。
1681 1689
1682<Warning>1690<Warning>
1683 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)。1691 PreToolUse 仅在 Claude 调用工具时运行。您[在提示词中使用 `@` 引用](/docs/zh-CN/common-workflows#reference-files-and-directories)的文件是在没有任何工具调用的情况下添加的:Claude Code 在构建提示词时插入其内容,因此不会为它们触发任何 PreToolUse hook,包括匹配 `Read` 的 hook。要阻止特定路径被 `@` 引用,请改用 [`Read` 拒绝规则](/docs/zh-CN/permissions#read-and-edit)。
1684 1692
1685 PreToolUse 也不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。1693 PreToolUse 也不会为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
1686</Warning>1694</Warning>
1687 1695
1688使用 [PreToolUse 决策控制](#pretooluse-decision-control) 来允许、拒绝、询问或延迟工具调用。1696使用 [PreToolUse 决策控制](#pretooluse-decision-control)来允许、拒绝、询问或延迟工具调用。
1689 1697
1690在 `PreToolUse` 上超过其超时的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 阻止工具调用,Claude 接收命名超时的错误结果。另一个 hook 返回的显式拒绝仍然优先。1698`PreToolUse` 上超过其超时时间的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 会阻止该工具调用,Claude 会收到一个指明该超时的错误结果。其他 hook 返回的显式拒绝仍然优先。
1691 1699
1692<h4 id="pretooluse-input">1700<h4 id="pretooluse-input">
1693 PreToolUse 输入1701 PreToolUse 输入
1694</h4>1702</h4>
1695 1703
1696除了 [常见输入字段](#common-input-fields) 外,PreToolUse hooks 接收 `tool_name`、`tool_input` 和 `tool_use_id`。1704除了[通用输入字段](#common-input-fields)之外,PreToolUse hook 还会接收 `tool_name`、`tool_input` 和 `tool_use_id`。
1697 1705
1698对于 [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 或更高版本。1706对于 [MCP 工具](#match-mcp-tools),输入中还会携带 `mcp_server`,这是一个包含服务器 `name` 和 `source` 的对象,`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 或更高版本。
1699 1707
1700对于文件工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 始终是绝对的:1708对于文件工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 始终是绝对路径:
1701 1709
1702* Claude Code 在 hooks 运行之前展开 `~` 和相对路径,因此匹配路径的 hook 无法通过 `~` 或相同路径的相对拼写绕过1710* Claude Code 会在 hook 运行之前展开 `~` 和相对路径,因此基于路径匹配的 hook 无法通过 `~` 或同一路径的相对写法被绕过
1703* 在 Windows 上,路径到达时带有反斜杠分隔符,即使您的 hook 在 Git Bash 下运行,其中 `$PWD` 看起来像 `/c/project`1711* 在 Windows 上,路径以反斜杠分隔符传入,即使您的 hook 在 Git Bash 下运行且 `$PWD` 看起来像 `/c/project`
1704* 用正斜杠编写的比较(如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用继续,就像 hook 没有什么要阻止的一样1712* 使用正斜杠编写的比较(例如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用会像 hook 没有可阻止的内容一样继续进行
1705* 在比较前规范化分隔符:Bash 中的 `FILE_PATH="${FILE_PATH//\\//}"` 或 Python 中的 `file_path.replace("\\", "/")`,然后匹配路径段如 `/src/` 而不是用 `^` 锚定,因为路径是绝对的1713* 在比较之前规范化分隔符:Bash 中使用 `FILE_PATH="${FILE_PATH//\\//}"`,Python 中使用 `file_path.replace("\\", "/")`,然后匹配诸如 `/src/` 之类的路径片段,而不是用 `^` 锚定,因为路径是绝对路径
1706 1714
1707Windows 上的 `Write` 调用传递:1715Windows 上的 `Write` 调用会传入:
1708 1716
1709```json theme={null}1717```json theme={null}
1710{1718{
1718}1726}
1719```1727```
1720 1728
1721`tool_input` 字段取决于工具:1729`tool_input` 字段取决于具体工具:
1722 1730
1723<a id="bash" />1731<a id="bash" />
1724 1732
1731| 字段 | 类型 | 示例 | 描述 |1739| 字段 | 类型 | 示例 | 描述 |
1732| :- | :- | :- | :- |1740| :- | :- | :- | :- |
1733| `command` | string | `"npm test"` | 要执行的 shell 命令 |1741| `command` | string | `"npm test"` | 要执行的 shell 命令 |
1734| `description` | string | `"Run test suite"` | 命令执行内容的可选描述 |1742| `description` | string | `"Run test suite"` | 可选的命令功能描述 |
1735| `timeout` | number | `120000` | 可选超时(毫秒)。高于 [最大值](/docs/zh-CN/tools-reference#bash-tool-behavior) 的值被减少到最大值而不是被拒绝 |1743| `timeout` | number | `120000` | 可选的超时时间(毫秒)。超过[最大值](/docs/zh-CN/tools-reference#bash-tool-behavior)的值会被降低为最大值,而不会被拒绝 |
1736| `run_in_background` | boolean | `false` | 是否在后台运行命令 |1744| `run_in_background` | boolean | `false` | 是否在后台运行命令 |
1737 1745
1738当 Bash 命令更改 Git 存储库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置打开记录时,它在每个权限模式中记录;该设置的条目说明哪些文件可以设置它。否则它仅在自动模式和 `bypassPermissions` 模式中记录,并且仅当 Claude Code 指导 Claude 通过 Bash 编辑文件时。设置 `bashEditDiffEnabled` 为 `false` 以关闭记录。后台命令和只读命令不携带 diff。1746当 Bash 命令更改 Git 仓库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置启用记录时,它会在所有权限模式下记录更改;该设置的条目说明了哪些文件可以设置它。否则,它仅在自动模式和 `bypassPermissions` 模式下记录,并且仅在 Claude Code 指示 Claude 通过 Bash 编辑文件时记录。将 `bashEditDiffEnabled` 设置为 `false` 可关闭记录。后台命令和只读命令不携带 diff。
1739 1747
1740您的 [PostToolUse hook](#posttooluse) 然后在 `tool_response.bashEditDiff` 中接收更改的文件。列表涵盖命令运行时存储库下更改的内容。Git 忽略的文件和子模块中的文件不列出。需要 Claude Code v2.1.269 或更高版本。1748随后,您的 [PostToolUse hook](#posttooluse) 会在 `tool_response.bashEditDiff` 中接收更改的文件。该列表涵盖命令运行期间仓库下发生更改的内容。Git 忽略的文件和子模块中的文件不会列出。需要 Claude Code v2.1.269 或更高版本。
1741 1749
1742<Note>1750<Note>
1743 列表是尽力而为的,处于公开测试版。Claude Code 可能会错过更改、包含另一个进程同时更改的文件或在其大小限制处停止。字段形状可能会改变。使用列表查找要审查的内容,而不是强制执行策略。1751 该列表是尽力而为的,目前处于公测阶段。Claude Code 可能会遗漏更改、包含同时被另一个进程更改的文件,或在达到大小限制时停止。字段结构可能会发生变化。请使用该列表来确定需要审查的内容,而不要用它来执行策略。
1744</Note>1752</Note>
1745 1753
1746`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整性和可靠性。1754`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整程度和可靠程度。
1747 1755
1748| 字段 | 类型 | 示例 | 描述 |1756| 字段 | 类型 | 示例 | 描述 |
1749| :- | :- | :- | :- |1757| :- | :- | :- | :- |
1750| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令更改的文件的绝对路径,最多 200 个。每当 `files` 保持 diff 或 `moreFiles` 高于零时出现 |1758| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令更改的文件的绝对路径,最多 200 个。只要 `files` 包含 diff 或 `moreFiles` 大于零,该字段就会出现 |
1751| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 个更改文件的 diffs,用于显示。对于命令添加或删除的文件,`created` 或 `deleted` 为 `true` |1759| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 个已更改文件的 diff,用于显示。对于命令添加或删除的文件,`created` 或 `deleted` 为 `true` |
1752| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的更改文件计数 |1760| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的已更改文件数量 |
1753| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |1761| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |
1754| `skipped` | boolean | `true` | 对于移动工作树的 Git 命令设置,如 `git checkout` 或 `git stash`,因此 Claude Code 不取 diff |1762| `skipped` | boolean | `true` | 针对会移动工作树的 Git 命令(例如 `git checkout` 或 `git stash`)设置,此时 Claude Code 不获取 diff |
1755| `shared` | boolean | `true` | 当另一个 Bash 工具调用(如子 agent 的)同时在同一存储库中运行时设置,因此某些列出的更改可能是该命令的 |1763| `shared` | boolean | `true` | 当另一个 Bash 工具调用(例如子代理的调用)同时在同一仓库中运行时设置,因此列出的部分更改可能来自该命令 |
1756 1764
1757<a id="powershell" />1765<a id="powershell" />
1758 1766
1760 PowerShell1768 PowerShell
1761</h5>1769</h5>
1762 1770
1763执行 PowerShell 命令。有关按平台的可用性,请参阅 [PowerShell 工具](/docs/zh-CN/tools-reference#powershell-tool)。1771执行 PowerShell 命令。有关各平台的可用性,请参阅 [PowerShell 工具](/docs/zh-CN/tools-reference#powershell-tool)。
1764 1772
1765字段与 Bash 工具匹配,命令字符串在 `command` 中:1773字段与 Bash 工具相同,命令字符串位于 `command` 中:
1766 1774
1767| 字段 | 类型 | 示例 | 描述 |1775| 字段 | 类型 | 示例 | 描述 |
1768| :- | :- | :- | :- |1776| :- | :- | :- | :- |
1769| `command` | string | `"Get-ChildItem -Recurse"` | 要执行的 PowerShell 命令 |1777| `command` | string | `"Get-ChildItem -Recurse"` | 要执行的 PowerShell 命令 |
1770| `description` | string | `"List files recursively"` | 命令执行内容的可选描述 |1778| `description` | string | `"List files recursively"` | 可选的命令功能描述 |
1771| `timeout` | number | `120000` | 可选超时(毫秒) |1779| `timeout` | number | `120000` | 可选的超时时间(毫秒) |
1772| `run_in_background` | boolean | `false` | 是否在后台运行命令 |1780| `run_in_background` | boolean | `false` | 是否在后台运行命令 |
1773 1781
1774在检查 shell 命令的 hooks 中匹配 `Bash|PowerShell`,以便它们涵盖两个工具:1782在检查 shell 命令的 hook 中匹配 `Bash|PowerShell`,以便同时覆盖这两个工具:
1775 1783
1776* 在 Windows 上,无论 PowerShell 工具在何处启用,Claude 将 PowerShell 视为主 shell 并通过它路由 shell 命令。1784* 在 Windows 上,只要启用了 PowerShell 工具,Claude 就会将 PowerShell 视为主 shell,并通过它执行 shell 命令。
1777* 在没有 Git Bash 的 Windows 上,工具自动启用,Claude Code 根本不注册 Bash 工具。1785* 在没有 Git Bash 的 Windows 上,该工具会自动启用,且 Claude Code 根本不会注册 Bash 工具。
1778* 仅匹配 `Bash` 的 hook 永远不会在那里触发。1786* 仅匹配 `Bash` 的 hook 在那里永远不会触发。
1779 1787
1780<h5 id="write">1788<h5 id="write">
1781 Write1789 Write
1797| 字段 | 类型 | 示例 | 描述 |1805| 字段 | 类型 | 示例 | 描述 |
1798| :- | :- | :- | :- |1806| :- | :- | :- | :- |
1799| `file_path` | string | `"/path/to/file.txt"` | 要编辑的文件的绝对路径 |1807| `file_path` | string | `"/path/to/file.txt"` | 要编辑的文件的绝对路径 |
1800| `old_string` | string | `"original text"` | 要查找和替换的文本 |1808| `old_string` | string | `"original text"` | 要查找并替换的文本 |
1801| `new_string` | string | `"replacement text"` | 替换文本 |1809| `new_string` | string | `"replacement text"` | 替换文本 |
1802| `replace_all` | boolean | `false` | 是否替换所有出现 |1810| `replace_all` | boolean | `false` | 是否替换所有匹配项 |
1803 1811
1804<h5 id="read">1812<h5 id="read">
1805 Read1813 Read
1810| 字段 | 类型 | 示例 | 描述 |1818| 字段 | 类型 | 示例 | 描述 |
1811| :- | :- | :- | :- |1819| :- | :- | :- | :- |
1812| `file_path` | string | `"/path/to/file.txt"` | 要读取的文件的绝对路径 |1820| `file_path` | string | `"/path/to/file.txt"` | 要读取的文件的绝对路径 |
1813| `offset` | number | `10` | 可选行号以开始读取 |1821| `offset` | number | `10` | 可选的开始读取的行号 |
1814| `limit` | number | `50` | 可选要读取的行数 |1822| `limit` | number | `50` | 可选的要读取的行数 |
1815 1823
1816<h5 id="glob">1824<h5 id="glob">
1817 Glob1825 Glob
1818</h5>1826</h5>
1819 1827
1820查找与 glob 模式匹配的文件。1828查找匹配 glob 模式的文件。
1821 1829
1822| 字段 | 类型 | 示例 | 描述 |1830| 字段 | 类型 | 示例 | 描述 |
1823| :- | :- | :- | :- |1831| :- | :- | :- | :- |
1824| `pattern` | string | `"**/*.ts"` | 要匹配文件的 glob 模式 |1832| `pattern` | string | `"**/*.ts"` | 用于匹配文件的 glob 模式 |
1825| `path` | string | `"/path/to/dir"` | 可选要搜索的目录。默认为当前工作目录 |1833| `path` | string | `"/path/to/dir"` | 可选的搜索目录。默认为当前工作目录 |
1826 1834
1827<h5 id="grep">1835<h5 id="grep">
1828 Grep1836 Grep
1833| 字段 | 类型 | 示例 | 描述 |1841| 字段 | 类型 | 示例 | 描述 |
1834| :- | :- | :- | :- |1842| :- | :- | :- | :- |
1835| `pattern` | string | `"TODO.*fix"` | 要搜索的正则表达式模式 |1843| `pattern` | string | `"TODO.*fix"` | 要搜索的正则表达式模式 |
1836| `path` | string | `"/path/to/dir"` | 可选要搜索的文件或目录 |1844| `path` | string | `"/path/to/dir"` | 可选的搜索文件或目录 |
1837| `glob` | string | `"*.ts"` | 可选 glob 模式以过滤文件 |1845| `glob` | string | `"*.ts"` | 可选的用于过滤文件的 glob 模式 |
1838| `output_mode` | string | `"content"` | `"content"`、`"files_with_matches"` 或 `"count"`。默认为 `"files_with_matches"` |1846| `output_mode` | string | `"content"` | `"content"`、`"files_with_matches"` 或 `"count"`。默认为 `"files_with_matches"` |
1839| `-i` | boolean | `true` | 不区分大小写的搜索 |1847| `-i` | boolean | `true` | 不区分大小写的搜索 |
1840| `multiline` | boolean | `false` | 启用多行匹配 |1848| `multiline` | boolean | `false` | 启用多行匹配 |
1843 WebFetch1851 WebFetch
1844</h5>1852</h5>
1845 1853
1846获取和处理网络内容。1854获取并处理网页内容。
1847 1855
1848| 字段 | 类型 | 示例 | 描述 |1856| 字段 | 类型 | 示例 | 描述 |
1849| :- | :- | :- | :- |1857| :- | :- | :- | :- |
1850| `url` | string | `"https://example.com/api"` | 要从中获取内容的 URL |1858| `url` | string | `"https://example.com/api"` | 要获取内容的 URL |
1851| `prompt` | string | `"Extract the API endpoints"` | 在获取的内容上运行的提示 |1859| `prompt` | string | `"Extract the API endpoints"` | 在获取的内容上运行的提示词 |
1852 1860
1853<h5 id="websearch">1861<h5 id="websearch">
1854 WebSearch1862 WebSearch
1855</h5>1863</h5>
1856 1864
1857搜索网络。1865搜索网页。
1858 1866
1859| 字段 | 类型 | 示例 | 描述 |1867| 字段 | 类型 | 示例 | 描述 |
1860| :- | :- | :- | :- |1868| :- | :- | :- | :- |
1861| `query` | string | `"react hooks best practices"` | 搜索查询 |1869| `query` | string | `"react hooks best practices"` | 搜索查询 |
1862| `allowed_domains` | array | `["docs.example.com"]` | 可选:仅包含来自这些域的结果 |1870| `allowed_domains` | array | `["docs.example.com"]` | 可选:仅包含来自这些域名的结果 |
1863| `blocked_domains` | array | `["spam.example.com"]` | 可选:排除来自这些域的结果 |1871| `blocked_domains` | array | `["spam.example.com"]` | 可选:排除来自这些域名的结果 |
1864 1872
1865<h5 id="agent">1873<h5 id="agent">
1866 Agent1874 Agent
1867</h5>1875</h5>
1868 1876
1869生成 [子 agent](/docs/zh-CN/sub-agents)。1877生成一个[子代理](/docs/zh-CN/sub-agents)。
1870 1878
1871| 字段 | 类型 | 示例 | 描述 |1879| 字段 | 类型 | 示例 | 描述 |
1872| :- | :- | :- | :- |1880| :- | :- | :- | :- |
1873| `prompt` | string | `"Find all API endpoints"` | agent 要执行的任务 |1881| `prompt` | string | `"Find all API endpoints"` | Agent 要执行的任务 |
1874| `description` | string | `"Find API endpoints"` | 任务的简短描述 |1882| `description` | string | `"Find API endpoints"` | 任务的简短描述 |
1875| `subagent_type` | string | `"Explore"` | 要使用的专门 agent 类型 |1883| `subagent_type` | string | `"Explore"` | 要使用的专用 Agent 类型 |
1876| `model` | string | `"sonnet"` | 可选模型别名以覆盖默认值 |1884| `model` | string | `"sonnet"` | 可选的模型别名,用于覆盖默认值 |
1877 1885
1878当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 在 `tool_response` 中接收子 agent 的结果和运行遥测。读取这些字段以检查运行;对于跨子 agents 的令牌和成本汇总,使用 [令牌和成本计数器](/docs/zh-CN/monitoring-usage#token-counter) 过滤到 `query_source` `"subagent"`,因为 `totalTokens` 和 `usage` 仅涵盖最终请求:1886当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 会在 `tool_response` 中接收子代理的结果和运行遥测数据。读取这些字段以检查运行情况;对于跨子代理的 token 和成本汇总,请使用按 `query_source` `"subagent"` 过滤的 [token 和成本计数器](/docs/zh-CN/monitoring-usage#token-counter),因为 `totalTokens` 和 `usage` 仅涵盖最终请求:
1879 1887
1880| 字段 | 类型 | 示例 | 描述 |1888| 字段 | 类型 | 示例 | 描述 |
1881| :- | :- | :- | :- |1889| :- | :- | :- | :- |
1882| `status` | string | `"completed"` | 前台子代理为 `"completed"`,后台子代理为 `"async_launched"`。子代理默认在后台运行,因此省略 `run_in_background` 的 Agent 调用也会产生 `"async_launched"` |1890| `status` | string | `"completed"` | 前台子代理为 `"completed"`,后台子代理为 `"async_launched"`。子代理默认在后台运行,因此省略 `run_in_background` 的 Agent 调用也会产生 `"async_launched"` |
1883| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子 agent 运行的标识符 |1891| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子代理运行的标识符 |
1884| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子 agent 的最终文本块,或对于其报告通过 `SubagentHandback` 的子 agent,关于该交接的简短说明代替 |1892| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子代理的最终文本块;对于通过 `SubagentHandback` 提交报告的子代理,则改为一条关于该交回的简短说明 |
1885| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子 agent 启动的模型,可能与请求的模型不同 |1893| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子代理启动时使用的模型,可能与请求的模型不同 |
1886| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复折叠;仅在模型在运行中交换时设置。需要 Claude Code v2.1.212 或更高版本 |1894| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复项会被合并;仅在运行中途切换了模型时设置。需要 Claude Code v2.1.212 或更高版本 |
1887| `totalTokens` | number | `12450` | 子 agent 最终 API 请求的令牌计数:输入、输出和缓存令牌合并。这不是整个运行的总计 |1895| `totalTokens` | number | `12450` | 子代理最终 API 请求的 token 数:输入、输出和缓存 token 的总和。这不是整个运行的总数 |
1888| `totalDurationMs` | number | `48211` | 子 agent 运行的挂钟持续时间 |1896| `totalDurationMs` | number | `48211` | 子代理运行的实际耗时 |
1889| `totalToolUseCount` | number | `7` | 子 agent 进行的工具调用计数 |1897| `totalToolUseCount` | number | `7` | 子代理进行的工具调用次数 |
1890| `usage` | object | `{"input_tokens": 8320, ...}` | 最终 API 请求的每类型令牌分解:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |1898| `usage` | object | `{"input_tokens": 8320, ...}` | 最终 API 请求按类型划分的 token 明细:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |
1891 1899
1892在 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`。1900在 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`。
1893 1901
1894对于后台子 agents,工具在任务移到后台时返回,因此 `tool_response` 不携带使用字段:后台启动立即返回,前台任务在 Claude Code 在运行中将其后台化时返回。它有 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。1902对于后台子代理,工具会在任务移至后台时返回,因此 `tool_response` 不携带用量字段:后台启动会立即返回,而被 Claude Code 在运行中途移至后台的前台任务会在该转换时返回。它包含 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。
1895 1903
1896在 `completed` 响应上,`resolvedModel` 命名子 agent 启动的模型,可能与 `tool_input` 中的 `model` 值不同,如当 `availableModels` 或另一个覆盖适用时。在 `async_launched` 响应上,`resolvedModel` 命名 agent 移到后台时使用的模型,因此在后台化之前发生的交换反映在那里。`modelsUsed` 和后台化时间 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。1904在 `completed` 响应中,`resolvedModel` 指子代理启动时使用的模型,它可能与 `tool_input` 中的 `model` 值不同,例如在 `availableModels` 或其他覆盖生效时。在 `async_launched` 响应中,`resolvedModel` 指 Agent 移至后台时正在使用的模型,因此在移至后台之前发生的切换会反映在其中。`modelsUsed` 以及移至后台时的 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。
1897 1905
1898<a id="askuserquestion" />1906<a id="askuserquestion" />
1899 1907
1901 AskUserQuestion1909 AskUserQuestion
1902</h5>1910</h5>
1903 1911
1904向用户提出一到四个多选问题。1912向用户提出一到四个多项选择题。
1905 1913
1906| 字段 | 类型 | 示例 | 描述 |1914| 字段 | 类型 | 示例 | 描述 |
1907| :- | :- | :- | :- |1915| :- | :- | :- | :- |
1908| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | 要呈现的问题,每个都有 `question` 字符串、简短 `header`、`options` 数组和可选 `multiSelect` 标志 |1916| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | 要呈现的问题,每个问题包含一个 `question` 字符串、简短的 `header`、`options` 数组以及可选的 `multiSelect` 标志 |
1909| `answers` | object | `{"Which framework?": "React"}` | 可选。将问题文本映射到选定的选项标签。多选答案用逗号连接标签。Claude 不设置此字段;通过 `updatedInput` 提供它以以编程方式回答 |1917| `answers` | object | `{"Which framework?": "React"}` | 可选。将问题文本映射到所选选项的标签。多选答案以逗号连接标签。Claude 不会设置此字段;可通过 `updatedInput` 提供它以编程方式作答 |
1910 1918
1911<h5 id="exitplanmode">1919<h5 id="exitplanmode">
1912 ExitPlanMode1920 ExitPlanMode
1913</h5>1921</h5>
1914 1922
1915呈现计划并要求用户在 Claude 离开 [plan mode](/docs/zh-CN/permission-modes#analyze-before-you-edit-with-plan-mode) 之前批准它。Claude 在调用工具之前将计划写入磁盘上的文件,因此来自模型的字面 `tool_input` 通常为空。Claude Code 在将输入传递给 hooks 之前注入计划内容和文件路径。1923在 Claude 离开[计划模式](/docs/zh-CN/permission-modes#analyze-before-you-edit-with-plan-mode)之前呈现计划并请求用户批准。Claude 会在调用该工具之前将计划写入磁盘上的文件,因此模型给出的原始 `tool_input` 通常为空。Claude Code 会在将输入传递给 hook 之前注入计划内容和文件路径。
1916 1924
1917| 字段 | 类型 | 示例 | 描述 |1925| 字段 | 类型 | 示例 | 描述 |
1918| :- | :- | :- | :- |1926| :- | :- | :- | :- |
1919| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 中的计划内容。从磁盘上的计划文件注入 |1927| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 格式的计划内容。从磁盘上的计划文件注入 |
1920| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |1928| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |
1921| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已弃用。Claude Code 接受该字段但忽略它。在 v2.1.205 之前,它携带 Claude 请求以实现计划的基于提示的权限 |1929| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已弃用。Claude Code 接受该字段但会忽略它。在 v2.1.205 之前,它携带 Claude 为实施计划而请求的基于提示词的权限 |
1922 1930
1923在 `PostToolUse` 中,`tool_response` 是一个包含 `plan` 和 `filePath` 字段的对象,保持批准的计划,加上内部状态标志。读取 `tool_response.plan` 以获取计划内容,而不是从磁盘重新读取文件。1931在 `PostToolUse` 中,`tool_response` 是一个对象,其中 `plan` 和 `filePath` 字段保存已批准的计划,另外还有内部状态标志。请读取 `tool_response.plan` 获取计划内容,而不要从磁盘重新读取文件。
1924 1932
1925<h4 id="pretooluse-decision-control">1933<h4 id="pretooluse-decision-control">
1926 PreToolUse 决策控制1934 PreToolUse 决策控制
1927</h4>1935</h4>
1928 1936
1929`PreToolUse` hooks 可以控制工具调用是否继续。与使用顶级 `decision` 字段的其他 hooks 不同,PreToolUse 在 `hookSpecificOutput` 对象内返回其决策。这给了它更丰富的控制:四个结果(允许、拒绝、询问或延迟)加上在执行前修改工具输入的能力。1937`PreToolUse` hook 可以控制工具调用是否继续。与使用顶层 `decision` 字段的其他 hook 不同,PreToolUse 在 `hookSpecificOutput` 对象中返回其决策。这为其提供了更丰富的控制:四种结果(allow、deny、ask 或 defer),以及在执行前修改工具输入的能力。
1930 1938
1931| 字段 | 描述 |1939| 字段 | 描述 |
1932| :- | :- |1940| :- | :- |
1933| `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 返回什么 |1941| `permissionDecision` | `"allow"` 会跳过权限提示,但[任何模式都不会自动批准的操作](/docs/zh-CN/permission-modes#actions-no-mode-auto-approves)以及 `AskUserQuestion` 和 `ExitPlanMode` 除外,后两者需要[与 `updatedInput` 搭配使用](#allow-with-updatedinput)。`"deny"` 会阻止工具调用。`"ask"` 会提示用户确认。`"defer"` 会正常退出,以便稍后恢复该工具。无论 hook 返回什么,[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)仍会被评估 |
1934| `permissionDecisionReason` | 对于 `"ask"`,显示给用户但不显示给 Claude。对于 `"deny"`,显示给 Claude。对于 `"allow"` 和 `"defer"`,仅写入 [调试日志](#debug-hooks) |1942| `permissionDecisionReason` | 对于 `"ask"`,在权限提示中显示给用户。在无人能回答该提示的 `-p` 运行中,当 Claude Code [拒绝该调用](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)时,Claude 会改为在工具结果中读到该原因。对于 `"deny"`,显示给 Claude。对于 `"allow"` 和 `"defer"`,仅写入[调试日志](#debug-hooks) |
1935| `updatedInput` | 在执行前修改工具的输入参数。替换整个输入对象,因此在修改的输入旁边包含未更改的字段。Claude Code 根据您的 hook 返回的输入而不是 Claude 发送的输入评估权限规则和 Bash 命令的 [自动后台资格](/docs/zh-CN/tools-reference#background-commands)。与 `"allow"` 结合以自动批准,或与 `"ask"` 结合以向用户显示修改的输入。对于 `"defer"`,被忽略 |1943| `updatedInput` | 在执行前修改工具的输入参数。会替换整个输入对象,因此请将未更改的字段与修改后的字段一并包含。Claude Code 会针对您的 hook 返回的输入(而不是 Claude 发送的输入)评估权限规则以及 Bash 命令的[自动移至后台资格](/docs/zh-CN/tools-reference#foreground-commands-that-move-to-the-background)。与 `"allow"` 组合可自动批准,与 `"ask"` 组合可向用户显示修改后的输入。对于 `"defer"`,该字段被忽略 |
1936| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。当 `permissionDecision` 为 `"defer"` 时被忽略。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |1944| `additionalContext` | 与工具结果一起添加到 Claude 上下文中的字符串。当 `permissionDecision` 为 `"defer"` 时被忽略。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1937 1945
1938当多个 PreToolUse hooks 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。1946当多个 PreToolUse hook 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。
1939 1947
1940通过退出 2 阻止的 hook 路由方式与 `"deny"` 相同:Claude 看到 stderr 消息作为拒绝原因。1948通过以退出码 2 退出来阻止的 hook,其处理方式与 `"deny"` 相同:Claude 会将 stderr 消息视为拒绝原因。
1941 1949
1942当 hook 返回 `"ask"` 时,显示给用户的权限提示包含一个标签,标识 hook 来自何处:`[settings]` 对于来自任何设置文件或 agent frontmatter 的 hook,`[plugin:<name>]` 对于插件的 hook,或 `[skill]` 对于来自 skill frontmatter 的 hook。这帮助用户理解哪个配置源请求确认。1950当 hook 返回 `"ask"` 时,显示给用户的权限提示会包含一个标签,标明该 hook 的来源:来自任何设置文件或 Agent frontmatter 的 hook 标记为 `[settings]`,插件的 hook 标记为 `[plugin:<name>]`,来自 skill frontmatter 的 hook 标记为 `[skill]`。这有助于用户了解是哪个配置来源在请求确认。
1943 1951
1944hook 的 `"ask"` 也在 [自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode) 中强制权限提示:分类器仍然可以拒绝工具调用,但它无法静默批准调用。在 v2.1.211 之前,分类器可以批准在 [沙箱](/docs/zh-CN/sandboxing) 外运行的 Bash 命令而不显示 hook 请求的提示;分类器仍然对该命令应用了自己的安全规则,hook `"deny"` 总是被尊重。1952hook 的 `"ask"` 在[自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode)中也会强制显示权限提示:分类器仍然可以拒绝该工具调用,但无法静默批准该调用。在 v2.1.211 之前,分类器可以批准在[沙箱](/docs/zh-CN/sandboxing)外运行的 Bash 命令,而不显示 hook 所请求的提示;分类器仍会对该命令应用其自身的安全规则,并且 hook 的 `"deny"` 始终会被遵守。
1945 1953
1946```json theme={null}1954```json theme={null}
1947{1955{
1959 1967
1960<span id="allow-with-updatedinput" />1968<span id="allow-with-updatedinput" />
1961 1969
1962在 [非交互模式](/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) 对象,将每个问题的文本映射到选定的答案。1970在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下,只有当运行具有接收提示的[权限宿主](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)(例如 Agent SDK 的 `canUseTool` 回调)时,Claude Code 才会提供 `AskUserQuestion` 和 `ExitPlanMode`。这些工具需要用户交互。同时返回 `permissionDecision: "allow"` 和 `updatedInput` 即可满足这一要求:hook 从 stdin 读取工具的输入,通过您自己的 UI 收集答案,并在 `updatedInput` 中返回,使工具无需提示即可运行。对于这些工具,仅返回 `"allow"` 是不够的。对于 `AskUserQuestion`,请回传原始的 `questions` 数组,并添加一个 [`answers`](#askuserquestion) 对象,将每个问题的文本映射到所选答案。
1963 1971
1964从 v2.1.199 起,一个 MCP 工具,其服务器用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记它,更严格:hook 无法用 `"allow"` 跳过其批准提示,无论是否有 `updatedInput`,因为 Claude Code 无法确认 hook 收集了工具需要的交互。1972对于其服务器使用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记的 MCP 工具,要求更为严格:hook 无法通过 `"allow"` 跳过其批准提示,无论是否带有 `updatedInput`,因为 Claude Code 无法确认 hook 是否收集了该工具所需的交互。
1965 1973
1966<Note>1974<Note>
1967 PreToolUse 以前使用顶级 `decision` 和 `reason` 字段,但这些对此事件已弃用。改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已弃用的值 `"approve"` 和 `"block"` 映射到 `"allow"` 和 `"deny"` 分别。PostToolUse 和 Stop 等其他事件继续使用顶级 `decision` 和 `reason` 作为其当前格式。1975 PreToolUse 之前使用顶层 `decision` 和 `reason` 字段,但这些字段在此事件中已弃用。请改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已弃用的值 `"approve"` 和 `"block"` 分别映射到 `"allow"` 和 `"deny"`。PostToolUse 和 Stop 等其他事件继续使用顶层 `decision` 和 `reason` 作为其当前格式。
1968</Note>1976</Note>
1969 1977
1970<h4 id="defer-a-tool-call-for-later">1978<h4 id="defer-a-tool-call-for-later">
1971 延迟工具调用以供稍后使用1979 延迟工具调用以便稍后处理
1972</h4>1980</h4>
1973 1981
1974`"defer"` 用于运行 `claude -p` 作为子进程并读取其 JSON 输出的集成,如 Agent SDK 应用或构建在 Claude Code 之上的自定义 UI。它让该调用进程在工具调用处暂停 Claude,通过其自己的界面收集输入,并从中断处恢复。Claude Code 仅在 [非交互模式](/docs/zh-CN/headless) 中使用 `-p` 标志时尊重此值。在交互式会话中,它记录警告并忽略 hook 结果。1982`"defer"` 适用于将 `claude -p` 作为子进程运行并读取其 JSON 输出的集成,例如 Agent SDK 应用或基于 Claude Code 构建的自定义 UI。它允许调用进程在工具调用处暂停 Claude,通过自己的界面收集输入,然后从中断处恢复。Claude Code 仅在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下遵守此值。在交互式会话中,它会记录一条警告并忽略该 hook 结果。
1975 1983
1976`AskUserQuestion` 工具是典型情况:Claude 想问用户什么,但没有终端来回答。`-p` 运行仅当它有 [权限主机](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs) 时提供 `AskUserQuestion`,如您使用 `--permission-prompt-tool` 传递的 MCP 工具,因此使用一个启动运行。往返工作如下:1984`AskUserQuestion` 工具是典型场景:Claude 想向用户提问,但没有可以作答的终端。`-p` 运行只有在具有[权限宿主](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)(例如通过 `--permission-prompt-tool` 传入的 MCP 工具)时才会提供 `AskUserQuestion`,因此请使用权限宿主启动运行。完整的往返流程如下:
1977 1985
19781. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。19861. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。
19792. hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在成绩单中。19872. hook 返回 `permissionDecision: "defer"`。工具不会执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在会话记录中。
19803. 调用进程从 SDK 结果读取 `deferred_tool_use`,在其自己的 UI 中呈现问题,并等待答案。19883. 调用进程从 SDK 结果中读取 `deferred_tool_use`,在自己的 UI 中呈现问题,并等待答案。
19814. 调用进程运行 `claude -p --resume <session-id>`,带有相同的权限主机。相同的工具调用再次触发 `PreToolUse`。19894. 调用进程使用相同的权限宿主运行 `claude -p --resume <session-id>`。同一个工具调用会再次触发 `PreToolUse`。
19825. hook 返回 `permissionDecision: "allow"`,答案在 `updatedInput` 中。工具执行,Claude 继续。19905. hook 返回 `permissionDecision: "allow"`,并在 `updatedInput` 中提供答案。工具执行,Claude 继续。
1983 1991
1984`deferred_tool_use` 字段携带工具的 `id`、`name` 和 `input`。`input` 是 Claude 为工具调用生成的参数,在执行前捕获:1992`deferred_tool_use` 字段携带工具的 `id`、`name` 和 `input`。`input` 是 Claude 为该工具调用生成的参数,在执行之前捕获:
1985 1993
1986```json theme={null}1994```json theme={null}
1987{1995{
1997}2005}
1998```2006```
1999 2007
2000没有超时或重试限制。会话保留在磁盘上直到您恢复它,受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留扫描的约束,默认情况下在 30 天后删除会话文件,遵循 [保留扫描规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果恢复时答案还没准备好,hook 可以再次返回 `"defer"`,进程以相同方式退出。调用进程通过最终从 hook 返回 `"allow"` 或 `"deny"` 来控制何时打破循环。2008没有超时或重试次数限制。会话会保留在磁盘上直到您恢复它,但受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留期清理的约束,该清理默认在 30 天后删除会话文件,遵循[保留期清理规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果恢复时答案尚未就绪,hook 可以再次返回 `"defer"`,进程会以相同方式退出。调用进程通过最终从 hook 返回 `"allow"` 或 `"deny"` 来控制何时跳出该循环。
2001 2009
2002`"defer"` 仅在 Claude 在回合中进行单个工具调用时有效。如果 Claude 一次进行多个工具调用,`"defer"` 被忽略并带有警告,工具通过正常权限流程进行。约束存在是因为恢复只能重新运行一个工具:没有办法从批次中延迟一个调用而不留下其他未解决的。2010`"defer"` 仅在 Claude 在该轮次中只进行单个工具调用时有效。如果 Claude 同时进行多个工具调用,`"defer"` 会被忽略并发出警告,工具将按正常权限流程继续。存在此限制是因为恢复时只能重新运行一个工具:无法在不让其他调用悬而未决的情况下延迟一批调用中的某一个。
2003 2011
2004如果恢复时延迟的工具不再可用,进程以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出,hook 触发前。这发生在为恢复的会话未连接提供工具的 MCP 服务器时。`deferred_tool_use` 有效负载仍然包含,以便您可以识别哪个工具丢失。2012如果恢复时被延迟的工具已不可用,进程会在 hook 触发之前以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出。当提供该工具的 MCP 服务器在恢复的会话中未连接时,就会发生这种情况。`deferred_tool_use` 数据仍会包含在内,以便您识别是哪个工具缺失了。
2005 2013
2006<Note>2014<Note>
2007 要在 plan mode 中恢复延迟会话,请与 `--resume` 一起传递 [`--permission-prompt-tool`](/docs/zh-CN/cli-reference#cli-flags),以便 Claude Code 可以呈现计划以供批准。如果您传递某些其他启动标志,恢复的运行不会返回到 plan mode;请参阅 [使用 `-p` 在 plan mode 中恢复](/docs/zh-CN/sessions#resume-in-plan-mode-with-p)。需要 Claude Code v2.1.246 或更高版本。2015 要在计划模式下恢复被延迟的会话,请将 [`--permission-prompt-tool`](/docs/zh-CN/cli-reference#cli-flags) 与 `--resume` 一起传入,以便 Claude Code 可以呈现计划供批准。如果您传入某些其他启动标志,恢复的运行不会返回计划模式;请参阅[使用 `-p` 在计划模式下恢复](/docs/zh-CN/sessions#resume-in-plan-mode-with-p)。需要 Claude Code v2.1.246 或更高版本。
2008 2016
2009 当您使用 `-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) 中列出的例外。2017 当您使用 `-p` 恢复时,Claude Code 不会还原任何其他已存储的权限模式。它会以新的 `claude -p` 运行所使用的权限模式启动,因此如果被延迟的会话使用了 `--permission-mode` 或 `--dangerously-skip-permissions`,请再次传入。当您不带 `-p` 使用 `claude --resume <session-id>` 恢复时,Claude Code 会还原已存储的权限模式,但[恢复时的权限模式](/docs/zh-CN/sessions#permission-mode-on-resume)中列出的例外情况除外。
2010</Note>2018</Note>
2011 2019
2012<h3 id="permissionrequest">2020<h3 id="permissionrequest">
2013 PermissionRequest2021 PermissionRequest
2014</h3>2022</h3>
2015 2023
2016在 Claude Code 即将向您请求使用某个工具的权限时运行。在无法显示提示的会话中,例如[非交互模式](/docs/zh-CN/headless)下的后台子代理,Claude Code 仍会运行这些 hook,如果没有 hook 返回决策,则会拒绝该工具调用。对于到达 `--permission-prompt-tool` 或 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/permissions)的调用,hook 会与您的宿主并行运行,以先做出决策的一方为准。2024在 Claude Code 即将请求您授予使用某个工具的权限时运行。在无法显示提示的会话中,例如[非交互模式](/docs/zh-CN/headless)下的后台子代理,Claude Code 仍会运行这些 hook,如果没有 hook 返回决策,它会拒绝该工具调用。对于到达 `--permission-prompt-tool` 或 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/permissions)的调用,hook 会与您的宿主并行运行,以先做出决策者为准。
2017使用 [PermissionRequest 决策控制](#permissionrequest-decision-control)代表用户允许或拒绝。2025使用 [PermissionRequest 决策控制](#permissionrequest-decision-control)代表用户允许或拒绝。
2018 2026
2019当您需要 Claude 要求许可使用工具的时刻的信号时使用此事件。Claude Code 仅在提示等待约六秒后才运行 [Notification](#notification) hook,带有 `permission_prompt` 类型。2027当您需要在 Claude 请求使用工具的权限时立即获得信号,请使用此事件。Claude Code 仅在提示等待约六秒后才会运行 `permission_prompt` 类型的 [Notification](#notification) hook。
2020 2028
2021Claude Code 不为沙箱命令的 [网络请求](/docs/zh-CN/sandboxing#network-isolation) 运行 PermissionRequest hooks。要获得该提示的信号,请使用 `permission_prompt` 通知类型。2029对于沙箱中命令的[网络请求](/docs/zh-CN/sandboxing#network-isolation),Claude Code 不会运行 PermissionRequest hook。要获得该提示的信号,请使用 `permission_prompt` 通知类型。
2022 2030
2023在工具名称上匹配,与 PreToolUse 相同的值。2031针对工具名称进行匹配,取值与 PreToolUse 相同。
2024 2032
2025<h4 id="permissionrequest-input">2033<h4 id="permissionrequest-input">
2026 PermissionRequest 输入2034 PermissionRequest 输入
2027</h4>2035</h4>
2028 2036
2029PermissionRequest hooks 接收 `tool_name` 和 `tool_input` 字段,如 PreToolUse hooks,但没有 `tool_use_id`。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 为此请求建议的 [权限更新](#permission-update-entries),如添加允许规则或更改权限模式。2037PermissionRequest hook 会像 PreToolUse hook 一样接收 `tool_name` 和 `tool_input` 字段,但没有 `tool_use_id`。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 针对此请求建议的[权限更新](#permission-update-entries),例如添加允许规则或更改权限模式。
2030 2038
2031`permission_suggestions` 数组不是您看到的选项的精确列表,因为每个权限对话构建自己的选项。某些对话(如文件编辑的对话)根本不读取数组,并从请求本身派生其选项。读取它的对话仍然可以保留一个选项,其建议保留在数组中,例如当 [`allowManagedPermissionRulesOnly`](/docs/zh-CN/settings-reference#allowmanagedpermissionrulesonly) 隐藏规则保存选项时。它也可以提供没有建议条目的选项,如 [**Yes, and switch to auto mode**](/docs/zh-CN/permission-modes#switch-permission-modes),它直接更改权限模式而不是通过权限更新。2039`permission_suggestions` 数组并不是您所看到选项的精确列表,因为每个权限对话框都会构建自己的选项。有些对话框(例如用于文件编辑的对话框)根本不读取该数组,而是从请求本身派生其选项。读取该数组的对话框仍可能隐藏某个建议仍保留在数组中的选项,例如当 [`allowManagedPermissionRulesOnly`](/docs/zh-CN/settings-reference#allowmanagedpermissionrulesonly) 隐藏保存规则的选项时。它也可能提供没有对应建议条目的选项,例如 [**Yes, and switch to auto mode**](/docs/zh-CN/permission-modes#switch-permission-modes),它直接更改权限模式,而不是通过权限更新。
2032 2040
2033PreToolUse hooks 在每个工具调用之前运行,无论它是否需要权限。PermissionRequest hooks 仅在 Claude Code 即将要求您许可时运行,或当它会以其他方式自动拒绝无法提示的调用时。两个事件都不为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。2041PreToolUse hook 在每次工具调用之前运行,无论是否需要权限。PermissionRequest hook 仅在 Claude Code 即将向您请求权限时运行,或在它原本会自动拒绝无法提示的调用时运行。这两个事件都不会为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
2034 2042
2035```json theme={null}2043```json theme={null}
2036{2044{
2059 PermissionRequest 决策控制2067 PermissionRequest 决策控制
2060</h4>2068</h4>
2061 2069
2062`PermissionRequest` hooks 可以允许或拒绝权限请求。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回一个 `decision` 对象,带有这些事件特定的字段:2070`PermissionRequest` hook 可以允许或拒绝权限请求。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回一个包含以下特定于事件字段的 `decision` 对象:
2063 2071
2064| 字段 | 描述 |2072| 字段 | 描述 |
2065| :- | :- |2073| :- | :- |
2066| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝它。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions) 仍然被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |2074| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝权限。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)仍会被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |
2067| `updatedInput` | 仅对 `"allow"`:在执行前修改工具的输入参数。替换整个输入对象,因此在修改的输入旁边包含未更改的字段。修改的输入针对拒绝和询问规则重新评估 |2075| `updatedInput` | 仅适用于 `"allow"`:在执行前修改工具的输入参数。会替换整个输入对象,因此请将未更改的字段与修改后的字段一并包含。修改后的输入会根据拒绝和询问规则重新评估 |
2068| `updatedPermissions` | 仅对 `"allow"`:[权限更新条目](#permission-update-entries) 数组以应用,如添加允许规则或更改会话权限模式 |2076| `updatedPermissions` | 仅适用于 `"allow"`:要应用的[权限更新条目](#permission-update-entries)数组,例如添加允许规则或更改会话权限模式 |
2069| `message` | 仅对 `"deny"`:告诉 Claude 为什么权限被拒绝 |2077| `message` | 仅适用于 `"deny"`:告诉 Claude 权限被拒绝的原因 |
2070| `interrupt` | 仅对 `"deny"`:如果 `true`,停止 Claude |2078| `interrupt` | 仅适用于 `"deny"`:如果为 `true`,则停止 Claude |
2071 2079
2072不带 `decision` 对象退出 2 的 hook 保持权限流程不变,其 stderr 被丢弃。仅 `decision` 对象可以授予或拒绝请求。2080以退出码 2 退出但没有 `decision` 对象的 hook 不会改变权限流程,其 stderr 会被丢弃。只有 `decision` 对象才能授予或拒绝请求。
2073 2081
2074```json theme={null}2082```json theme={null}
2075{2083{
2089 权限更新条目2097 权限更新条目
2090</h4>2098</h4>
2091 2099
2092`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input) 都使用相同的条目对象数组。每个条目有一个 `type` 来确定其他字段,以及一个 `destination` 来控制更改写入的位置。2100`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input)都使用相同的条目对象数组。每个条目都有一个决定其其他字段的 `type`,以及一个控制更改写入位置的 `destination`。
2093 2101
2094| `type` | 字段 | 效果 |2102| `type` | 字段 | 效果 |
2095| :- | :- | :- |2103| :- | :- | :- |
2096| `addRules` | `rules`、`behavior`、`destination` | 添加权限规则。`rules` 是 `{toolName, ruleContent?}` 对象的数组。省略 `ruleContent` 以匹配整个工具。`behavior` 是 `"allow"`、`"deny"` 或 `"ask"` |2104| `addRules` | `rules`、`behavior`、`destination` | 添加权限规则。`rules` 是 `{toolName, ruleContent?}` 对象的数组。省略 `ruleContent` 可匹配整个工具。`behavior` 为 `"allow"`、`"deny"` 或 `"ask"` |
2097| `replaceRules` | `rules`、`behavior`、`destination` | 用提供的 `rules` 替换 `destination` 处给定 `behavior` 的所有规则 |2105| `replaceRules` | `rules`、`behavior`、`destination` | 用提供的 `rules` 替换 `destination` 处给定 `behavior` 的所有规则 |
2098| `removeRules` | `rules`、`behavior`、`destination` | 删除给定 `behavior` 的匹配规则 |2106| `removeRules` | `rules`、`behavior`、`destination` | 删除给定 `behavior` 的匹配规则 |
2099| `setMode` | `mode`、`destination` | 更改权限模式。有效模式为 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan` 和 `manual` 作为 `default` 的别名。`manual` 别名需要 Claude Code v2.1.200 或更高版本 |2107| `setMode` | `mode`、`destination` | 更改权限模式。有效模式为 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan`,以及作为 `default` 别名的 `manual`。`manual` 别名需要 Claude Code v2.1.200 或更高版本 |
2100| `addDirectories` | `directories`、`destination` | 添加工作目录。`directories` 是路径字符串的数组 |2108| `addDirectories` | `directories`、`destination` | 添加工作目录。`directories` 是路径字符串数组 |
2101| `removeDirectories` | `directories`、`destination` | 删除工作目录 |2109| `removeDirectories` | `directories`、`destination` | 移除工作目录 |
2102 2110
2103<Note>2111<Note>
2104 `setMode` 与 `bypassPermissions` 仅在您使用已可用的绕过模式启动会话时生效:`--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) 中启动时,更新也是无操作。2112 只有当您启动会话时已经可以使用绕过模式,`setMode` 配合 `bypassPermissions` 才会生效:即使用了 `--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)启动时,该更新同样不产生任何效果。
2105 2113
2106 `bypassPermissions` 永远不会作为 `defaultMode` 持久化,无论 `destination` 如何。2114 无论 `destination` 为何值,`bypassPermissions` 都不会被持久化为 `defaultMode`。
2107</Note>2115</Note>
2108 2116
2109每个条目上的 `destination` 字段确定更改是保留在内存中还是持久化到设置文件。2117每个条目上的 `destination` 字段决定该更改是仅保留在内存中,还是持久化到设置文件。
2110 2118
2111| `destination` | 写入 |2119| `destination` | 写入位置 |
2112| :- | :- |2120| :- | :- |
2113| `session` | 仅在内存中,会话结束时丢弃 |2121| `session` | 仅在内存中,会话结束时丢弃 |
2114| `localSettings` | `.claude/settings.local.json` |2122| `localSettings` | `.claude/settings.local.json` |
2115| `projectSettings` | `.claude/settings.json` |2123| `projectSettings` | `.claude/settings.json` |
2116| `userSettings` | `~/.claude/settings.json` |2124| `userSettings` | `~/.claude/settings.json` |
2117 2125
2118hook 可以回显它接收的 `permission_suggestions` 之一作为其自己的 `updatedPermissions` 输出。2126hook 可以将其收到的某个 `permission_suggestions` 原样作为自己的 `updatedPermissions` 输出返回。
2119 2127
2120<h3 id="posttooluse">2128<h3 id="posttooluse">
2121 PostToolUse2129 PostToolUse
2123 2131
2124在工具成功完成后立即运行。2132在工具成功完成后立即运行。
2125 2133
2126在工具名称上匹配,与 PreToolUse 相同的值。2134按工具名称匹配,取值与 PreToolUse 相同。
2127 2135
2128当工具名称不是正确的过滤器时更广泛地匹配:2136当工具名称不是合适的过滤条件时,可以进行更宽泛的匹配:
2129 2137
2130* 要在任何工具成功完成后运行 hook,省略 `matcher` 或将其设置为 `"*"`。您的 hook 然后可以自己发现更改了什么,例如通过运行 `git status --porcelain`,它也列出 `git diff` 错过的未跟踪文件。对于失败的工具调用,在 [PostToolUseFailure](#posttoolusefailure) 下添加相同的 hook。2138* 要在任意工具成功完成后运行 hook,请省略 `matcher` 或将其设为 `"*"`。然后您的 hook 可以自行发现发生了哪些更改,例如运行 `git status --porcelain`,它还会列出 `git diff` 遗漏的未跟踪文件。对于失败的工具调用,请在 [PostToolUseFailure](#posttoolusefailure) 下添加相同的 hook。
2131* 要在特定文件更改时运行 hook,无论什么写入它,请使用 [FileChanged](#filechanged)。当 `Bash` 命令或 Claude Code 外的进程重写同一文件时,Claude Code 不运行匹配 `Edit|Write` 的 `PostToolUse` hook。2139* 要在特定文件在磁盘上发生更改时运行 hook(无论是由什么写入的),请使用 [FileChanged](#filechanged)。当 `Bash` 命令或 Claude Code 之外的进程重写同一文件时,Claude Code 不会运行匹配 `Edit|Write` 的 `PostToolUse` hook。
2132 2140
2133<h4 id="posttooluse-input">2141<h4 id="posttooluse-input">
2134 PostToolUse 输入2142 PostToolUse 输入
2135</h4>2143</h4>
2136 2144
2137`PostToolUse` hooks 在工具已经成功执行后触发。输入包括 `tool_input`(发送给工具的参数)和 `tool_response`(它返回的结果)。两者的确切模式取决于工具。文件工具 `tool_input` 路径以与 [PreToolUse](#pretooluse-input) 相同的格式到达:始终绝对,带有平台的本机分隔符,因此 Windows 上的反斜杠。对于 MCP 工具,输入也携带 [`mcp_server`](#pretooluse-input) 对象。2145`PostToolUse` hook 在工具已成功执行后触发。输入同时包含 `tool_input`(发送给工具的参数)和 `tool_response`(工具返回的结果)。两者的确切 schema 取决于具体工具。文件工具的 `tool_input` 路径格式与 [PreToolUse](#pretooluse-input) 相同:始终为绝对路径,使用平台原生分隔符,因此在 Windows 上为反斜杠。对于 MCP 工具,输入还会携带 [`mcp_server`](#pretooluse-input) 对象。
2138 2146
2139```json theme={null}2147```json theme={null}
2140{2148{
2159 2167
2160| 字段 | 描述 |2168| 字段 | 描述 |
2161| :- | :- |2169| :- | :- |
2162| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |2170| `duration_ms` | 可选。工具执行时间,以毫秒为单位。不包括在权限提示和 PreToolUse hook 中花费的时间 |
2163 2171
2164<h4 id="posttooluse-decision-control">2172<h4 id="posttooluse-decision-control">
2165 PostToolUse 决策控制2173 PostToolUse 决策控制
2166</h4>2174</h4>
2167 2175
2168`PostToolUse` hooks 可以在工具执行后提供反馈给 Claude。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2176`PostToolUse` hook 可以在工具执行后向 Claude 提供反馈。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下特定于事件的字段:
2169 2177
2170| 字段 | 描述 |2178| 字段 | 描述 |
2171| :- | :- |2179| :- | :- |
2172| `decision` | `"block"` 在工具结果旁边添加 `reason`。Claude 仍然看到原始输出;要替换它,使用 `updatedToolOutput` |2180| `decision` | `"block"` 会在工具结果旁边添加 `reason`。Claude 仍会看到原始输出;要替换它,请使用 `updatedToolOutput` |
2173| `reason` | 当 `decision` 为 `"block"` 时显示给 Claude 的解释 |2181| `reason` | 当 `decision` 为 `"block"` 时向 Claude 显示的说明 |
2174| `additionalContext` | 与工具结果一起添加到 Claude 上下文的字符串。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2182| `additionalContext` | 与工具结果一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2175| `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 或更高版本 |2183| `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 或更高版本 |
2176| `updatedToolOutput` | 在将工具的输出发送给 Claude 之前用提供的值替换它。该值必须与工具的输出形状匹配 |2184| `updatedToolOutput` | 在工具输出发送给 Claude 之前,用提供的值替换它。该值必须与工具的输出结构相匹配 |
2177| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools) 的输出。优先使用 `updatedToolOutput`,它适用于所有工具 |2185| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools)的输出。建议优先使用适用于所有工具的 `updatedToolOutput` |
2178 2186
2179下面的示例替换 `Bash` 调用的输出。替换值与 `Bash` 工具的输出形状匹配:2187以下示例替换了一次 `Bash` 调用的输出。替换值与 `Bash` 工具的输出结构相匹配:
2180 2188
2181```json theme={null}2189```json theme={null}
2182{2190{
2194```2202```
2195 2203
2196<Warning>2204<Warning>
2197 `updatedToolOutput` 仅更改 Claude 看到的内容。工具已经在 hook 触发时运行,因此任何写入的文件、执行的命令或发送的网络请求已经生效。遥测如 OpenTelemetry 工具跨度和分析事件也在 hook 运行之前捕获原始输出。要在运行前防止或修改工具调用,请改用 [PreToolUse](#pretooluse) hook。2205 `updatedToolOutput` 只会改变 Claude 看到的内容。hook 触发时工具已经运行,因此任何已写入的文件、已执行的命令或已发送的网络请求都已生效。OpenTelemetry 工具 span 和分析事件等遥测数据也会在 hook 运行之前捕获原始输出。要在工具调用运行之前阻止或修改它,请改用 [PreToolUse](#pretooluse) hook。
2198 2206
2199 替换值必须与工具的输出形状匹配。内置工具返回结构化对象而不是纯字符串。例如,`Bash` 返回一个带有 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,不与工具的输出模式匹配的值被忽略,使用原始输出。MCP 工具输出通过而不进行模式验证。剥离 Claude 需要的错误详情可能导致它在错误的假设下继续。2207 替换值必须与工具的输出结构相匹配。内置工具返回的是结构化对象,而不是纯字符串。例如,`Bash` 返回一个包含 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,与工具输出 schema 不匹配的值会被忽略,并使用原始输出。MCP 工具的输出会直接传递,不进行 schema 验证。删除 Claude 需要的错误详细信息可能会导致它基于错误的假设继续执行。
2200</Warning>2208</Warning>
2201 2209
2202<h4 id="annotate-a-result-for-the-auto-mode-classifier">2210<h4 id="annotate-a-result-for-the-auto-mode-classifier">
2203 为自动模式分类器注释结果2211 为自动模式分类器注释结果
2204</h4>2212</h4>
2205 2213
2206返回 `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 或更高版本。2214返回 `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 或更高版本。
2207 2215
2208下面的示例告诉分类器查询的输出来自何处:2216以下示例告诉分类器某次查询的输出来自何处:
2209 2217
2210```json theme={null}2218```json theme={null}
2211{2219{
2216}2224}
2217```2225```
2218 2226
2219分类器给予说明的权重取决于您配置 hook 的位置:2227分类器对该说明的重视程度取决于您在何处配置了该 hook:
2220 2228
2221* **在 Claude Code 中配置的 Hooks**:对于来自设置文件、插件、skills 和 agent frontmatter 的 hooks,分类器将说明视为未验证的、应用程序提供的上下文。说明永远不会建立用户意图,如果它声称您批准或请求了什么,分类器会根据您在对话中的自己的消息检查该声明2229* **在 Claude Code 中配置的 hook**:对于来自设置文件、插件、skill 和 Agent frontmatter 的 hook,分类器将该说明视为未经验证的、由应用程序提供的上下文。该说明永远不能确立用户意图;如果它声称您批准或请求了某事,分类器会将该声明与您在对话中发送的消息进行核对
2222* **进程内 Agent SDK 回调**:当应用程序嵌入 Claude Code 将 hook 注册为 [TypeScript SDK 回调](/docs/zh-CN/agent-sdk/hooks) 并在实时会话期间返回说明时,分类器可能会将用户语句(在说明中中继)视为用户意图。这样的语句可以满足分类器会接受来自您发送的消息的同意要求,但它永远不会解除您自己的消息也无法解除的阻止。会话恢复后,Claude Code 将恢复的说明视为未验证的上下文。当两个组的 hooks 注释同一调用时,分类器将组合说明视为未验证2230* **进程内 Agent SDK 回调**:当嵌入 Claude Code 的应用程序将该 hook 注册为 [TypeScript SDK 回调](/docs/zh-CN/agent-sdk/hooks)并在实时会话期间返回该说明时,分类器可能会将说明中转述的用户陈述视为用户意图。此类陈述可以满足分类器原本会从您发送的消息中接受的同意要求,但它永远不能解除您自己的消息也无法解除的阻止。会话恢复后,Claude Code 会将恢复的说明视为未经验证的上下文。当两类 hook 都对同一调用添加注释时,分类器会将合并后的说明视为未经验证的内容
2223 2231
2224Claude Code 在传递说明时应用这些限制:2232Claude Code 在传递说明时会应用以下限制:
2225 2233
2226* **长度**:Claude Code 将一个工具调用的说明上限为 2,000 个字符,并截断其余部分。上限在响应该调用的每个 hook 中共享2234* **长度**:Claude Code 将单次工具调用的说明上限设为 2,000 个字符,并截断其余部分。该上限由响应该调用的所有 hook 共享
2227* **仅同步响应**:Claude Code 忽略 [在后台运行](#run-hooks-in-the-background) 的 hook 响应中的字段,因为该响应在 Claude Code 记录工具结果后到达2235* **仅限同步响应**:对于[在后台运行](#run-hooks-in-the-background)的 hook,Claude Code 会忽略其响应中的该字段,因为该响应在 Claude Code 记录工具结果之后才到达
2228* **分类器不记录的调用**:分类器的成绩单省略只读查找,如文件读取和搜索。Claude Code 丢弃附加到其中一个调用的说明2236* **分类器不记录的调用**:分类器的会话记录会省略只读查找,例如文件读取和搜索。附加到这些调用上的说明会被 Claude Code 丢弃
2229* **与重写的交互**:当说明描述您用 `updatedToolOutput` 替换的输出时,在同一 hook 响应中返回两个字段。如果该重写被拒绝或另一个 hook 的重写替换它,Claude Code 丢弃说明。Claude Code 传递您返回的说明而不重写,即使另一个 hook 重写输出2237* **与重写的交互**:当说明描述的是您正在用 `updatedToolOutput` 替换的输出时,请在同一个 hook 响应中同时返回这两个字段。如果该重写被拒绝或被另一个 hook 的重写替换,Claude Code 会丢弃该说明。即使另一个 hook 重写了输出,Claude Code 仍会传递您在没有重写的情况下返回的说明
2230 2238
2231<Warning>2239<Warning>
2232 分类器读取您放入 `classifierContext` 的内容作为来自托管会话的应用程序的信息,因此不要将不受信任的工具输出或第三方文本复制到其中。将说明保持为关于此一个调用的简短断言,如关于其来源的事实或关于它的用户语句;不要使用该字段传递不相关的消息或事件流。2240 分类器会将您放入 `classifierContext` 的内容视为来自托管该会话的应用程序的信息,因此请勿将不受信任的工具输出或第三方文本复制到其中。请将说明限定为关于这一次调用的简短断言,例如关于其来源的事实或用户对它的陈述;不要使用该字段传递无关消息或事件流。
2233</Warning>2241</Warning>
2234 2242
2235<h3 id="posttoolusefailure">2243<h3 id="posttoolusefailure">
2236 PostToolUseFailure2244 PostToolUseFailure
2237</h3>2245</h3>
2238 2246
2239在启动执行的工具失败时运行:工具抛出错误或 MCP 工具返回错误结果。使用此来记录失败、发送警报或向 Claude 提供纠正反馈。2247当已开始执行的工具失败时运行:工具抛出了错误,或 MCP 工具返回了错误结果。可用于记录失败、发送警报或向 Claude 提供纠正性反馈。
2240 2248
2241在工具名称上匹配,与 PreToolUse 相同的值。2249按工具名称匹配,取值与 PreToolUse 相同。
2242 2250
2243<Note>2251<Note>
2244 此事件不为执行前被拒绝的工具调用触发:未知工具名称、失败模式或工具特定验证的输入,或权限拒绝。验证拒绝作为 `tool_use_error` 结果返回,发生在 hooks 运行之前,因此它们既不触发 `PreToolUse` 也不触发此事件。权限拒绝触发 `PreToolUse` 但不触发此事件;请参阅 [PermissionDenied](#permissiondenied)。2252 对于在执行前被拒绝的工具调用,此事件不会触发:包括未知的工具名称、未通过 schema 或工具特定验证的输入,以及权限拒绝。验证拒绝会以 `tool_use_error` 结果返回,并且发生在 hook 运行之前,因此既不会触发 `PreToolUse`,也不会触发 `PostToolUseFailure`。权限拒绝会触发 `PreToolUse`,但不会触发此事件;请参阅 [PermissionDenied](#permissiondenied)。
2245</Note>2253</Note>
2246 2254
2247<h4 id="posttoolusefailure-input">2255<h4 id="posttoolusefailure-input">
2248 PostToolUseFailure 输入2256 PostToolUseFailure 输入
2249</h4>2257</h4>
2250 2258
2251PostToolUseFailure hooks 接收与 PostToolUse 相同的 `tool_name` 和 `tool_input` 字段,以及错误信息作为顶级字段。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。例如,失败的 `npm test` 命令可能传递:2259PostToolUseFailure hook 接收与 PostToolUse 相同的 `tool_name` 和 `tool_input` 字段,以及作为顶层字段的错误信息。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。例如,一次失败的 `npm test` 命令可能会传递:
2252 2260
2253```json theme={null}2261```json theme={null}
2254{2262{
2271 2279
2272| 字段 | 描述 |2280| 字段 | 描述 |
2273| :- | :- |2281| :- | :- |
2274| `error` | 描述出错内容的字符串。格式取决于失败的工具 |2282| `error` | 描述出错内容的字符串。其格式取决于失败的工具 |
2275| `is_interrupt` | 可选布尔值。当失败作为中止到达 Claude Code 而不是工具报告的错误时为 True。取消运行的工具不触发此 hook;工具结果携带中断消息 |2283| `is_interrupt` | 可选布尔值。当失败以中止而非工具报告的错误形式到达 Claude Code 时为 true。取消正在运行的工具不会触发此 hook;此时工具结果会携带中断消息 |
2276| `duration_ms` | 可选。工具执行时间(毫秒)。不包括权限提示和 PreToolUse hooks 中花费的时间 |2284| `duration_ms` | 可选。工具执行时间,以毫秒为单位。不包括在权限提示和 PreToolUse hook 中花费的时间 |
2277 2285
2278`error` 字符串通常与 Claude 接收的失败工具结果相同的文本。其格式因工具和失败而异。在 `tool_name`、`is_interrupt` 和第一行 `Exit code N` 上键入您的 hook;将字符串的其余部分视为显示文本,而不是稳定格式。2286`error` 字符串通常与 Claude 作为失败工具结果收到的文本相同。其格式因工具和失败类型而异。请让您的 hook 基于 `tool_name`、`is_interrupt` 以及第一行的 `Exit code N` 进行判断;将字符串的其余部分视为显示文本,而非稳定的格式。
2279 2287
2280* 对于 Bash 和 PowerShell,运行并退出的命令产生第一行 `Exit code N`,然后是命令产生的任何输出作为一个块,stdout 和 stderr 交错2288* 对于 Bash 和 PowerShell,已运行并退出的命令会生成第一行 `Exit code N`,随后是命令产生的所有输出,作为一个整体块,其中 stdout 和 stderr 交错排列
2281* 有效负载也可能携带裸失败消息,没有退出代码行,当 Claude Code 无法启动 shell 进程本身时2289* 当 Claude Code 无法启动 shell 进程本身时,负载也可能只携带一条没有退出码行的失败消息
2282* Claude Code 中间截断长字符串,围绕 `... [N characters truncated] ...` 标记,并可以插入自己的行,如 `Command timed out after 2m 0s`2290* Claude Code 会对长字符串进行中间截断,并插入 `... [N characters truncated] ...` 标记,还可能插入自己的行,例如 `Command timed out after 2m 0s`
2283 2291
2284<h4 id="posttoolusefailure-decision-control">2292<h4 id="posttoolusefailure-decision-control">
2285 PostToolUseFailure 决策控制2293 PostToolUseFailure 决策控制
2286</h4>2294</h4>
2287 2295
2288`PostToolUseFailure` hooks 可以在工具失败后向 Claude 提供上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2296`PostToolUseFailure` hook 可以在工具失败后向 Claude 提供上下文。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下特定于事件的字段:
2289 2297
2290| 字段 | 描述 |2298| 字段 | 描述 |
2291| :- | :- |2299| :- | :- |
2292| `additionalContext` | 与错误一起添加到 Claude 上下文的字符串。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2300| `additionalContext` | 与错误一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2293 2301
2294```json theme={null}2302```json theme={null}
2295{2303{
2304 PostToolBatch2312 PostToolBatch
2305</h3>2313</h3>
2306 2314
2307在批次中的每个工具调用都已解决后运行一次,在 Claude Code 向模型发送下一个请求之前。`PostToolUse` 每个工具触发一次,这意味着当 Claude 进行并行工具调用时它并发触发。`PostToolBatch` 恰好触发一次,带有完整批次,因此它是注入取决于运行的工具集而不是任何单个工具的上下文的正确位置。此事件没有匹配器。2315在一批中的每个工具调用都已完成后、Claude Code 向模型发送下一个请求之前运行一次。`PostToolUse` 对每个工具触发一次,这意味着当 Claude 进行并行工具调用时它会并发触发。`PostToolBatch` 针对整个批次只触发一次,因此适合注入依赖于已运行工具集合而非单个工具的上下文。此事件没有匹配器。
2308 2316
2309<h4 id="posttoolbatch-input">2317<h4 id="posttoolbatch-input">
2310 PostToolBatch 输入2318 PostToolBatch 输入
2311</h4>2319</h4>
2312 2320
2313除了 [常见输入字段](#common-input-fields) 外,PostToolBatch hooks 接收 `tool_calls`,一个描述批次中每个工具调用的数组:2321除了[通用输入字段](#common-input-fields)之外,PostToolBatch hook 还会接收 `tool_calls`,这是一个描述批次中每个工具调用的数组:
2314 2322
2315```json theme={null}2323```json theme={null}
2316{2324{
2336}2344}
2337```2345```
2338 2346
2339`tool_response` 包含模型在相应 `tool_result` 块中接收的相同内容。该值是序列化字符串或内容块数组,完全如工具发出的那样。对于 `Read`,这意味着行号前缀文本而不是原始文件内容。响应可能很大,因此仅解析您需要的字段。2347`tool_response` 包含的内容与模型在对应 `tool_result` 块中收到的内容相同。该值是序列化字符串或内容块数组,与工具发出的完全一致。对于 `Read`,这意味着是带行号前缀的文本,而不是原始文件内容。响应可能很大,因此请只解析您需要的字段。
2340 2348
2341<Note>2349<Note>
2342 `tool_response` 形状与 `PostToolUse` 的不同。`PostToolUse` 传递工具的结构化 `Output` 对象,如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递模型看到的序列化 `tool_result` 内容。2350 `tool_response` 的结构与 `PostToolUse` 的不同。`PostToolUse` 传递的是工具的结构化 `Output` 对象,例如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递的是模型看到的序列化 `tool_result` 内容。
2343</Note>2351</Note>
2344 2352
2345<h4 id="posttoolbatch-decision-control">2353<h4 id="posttoolbatch-decision-control">
2346 PostToolBatch 决策控制2354 PostToolBatch 决策控制
2347</h4>2355</h4>
2348 2356
2349`PostToolBatch` hooks 可以为 Claude 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2357`PostToolBatch` hook 可以为 Claude 注入上下文。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下特定于事件的字段:
2350 2358
2351| 字段 | 描述 |2359| 字段 | 描述 |
2352| :- | :- |2360| :- | :- |
2353| `additionalContext` | 在下一个模型调用之前注入一次的上下文字符串。有关传递详情、放入其中的内容以及恢复的会话如何处理过去的值,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2361| `additionalContext` | 在下一次模型调用之前注入一次的上下文字符串。有关传递细节、应放入的内容以及恢复的会话如何处理以往的值,请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2354 2362
2355```json theme={null}2363```json theme={null}
2356{2364{
2361}2369}
2362```2370```
2363 2371
2364返回 `decision: "block"` 或 `continue: false` 在下一个模型调用之前停止 agentic 循环。阻止消息来自 JSON `reason` 或 `stopReason`,或来自退出 2 的 stderr。您在成绩单中看到它作为警告,它保留在对话中,因此当对话继续时 Claude 看到它。2372返回 `decision: "block"` 或 `continue: false` 会在下一次模型调用之前停止智能体循环。阻止消息来自 JSON 中的 `reason` 或 `stopReason`,或退出码 2 时的 stderr。您会在会话记录中看到它显示为警告,并且它会保留在对话中,因此当对话继续时 Claude 会看到它。
2365 2373
2366<h3 id="permissiondenied">2374<h3 id="permissiondenied">
2367 PermissionDenied2375 PermissionDenied
2368</h3>2376</h3>
2369 2377
2370在 [自动模式](/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` 规则匹配时不运行。使用它来记录拒绝、调整配置或告诉模型它可能重试工具调用。2378当[自动模式](/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` 规则匹配时,它不会运行。可用于记录拒绝、调整配置,或告诉模型它可以重试该工具调用。
2371 2379
2372在工具名称上匹配,与 PreToolUse 相同的值。2380按工具名称匹配,取值与 PreToolUse 相同。
2373 2381
2374<h4 id="permissiondenied-input">2382<h4 id="permissiondenied-input">
2375 PermissionDenied 输入2383 PermissionDenied 输入
2376</h4>2384</h4>
2377 2385
2378除了 [常见输入字段](#common-input-fields) 外,PermissionDenied hooks 接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。对于 MCP 工具,它们也接收 [`mcp_server`](#pretooluse-input) 对象。2386除了[通用输入字段](#common-input-fields)之外,PermissionDenied hook 还会接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。
2379 2387
2380```json theme={null}2388```json theme={null}
2381{2389{
2396 2404
2397| 字段 | 描述 |2405| 字段 | 描述 |
2398| :- | :- |2406| :- | :- |
2399| `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` |2407| `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` |
2400 2408
2401<h4 id="permissiondenied-decision-control">2409<h4 id="permissiondenied-decision-control">
2402 PermissionDenied 决策控制2410 PermissionDenied 决策控制
2403</h4>2411</h4>
2404 2412
2405PermissionDenied hooks 可以告诉模型它可能重试被拒绝的工具调用。返回一个 JSON 对象,其中 `hookSpecificOutput.retry` 设置为 `true`:2413PermissionDenied hook 可以告诉模型它可以重试被拒绝的工具调用。返回一个 `hookSpecificOutput.retry` 设为 `true` 的 JSON 对象:
2406 2414
2407```json theme={null}2415```json theme={null}
2408{2416{
2413}2421}
2414```2422```
2415 2423
2416当 `retry` 为 `true` 时,Claude Code 向对话添加一条消息,告诉模型它可能重试工具调用。Claude Code 不反转拒绝本身。如果您的 hook 不返回 JSON 或返回 `retry: false`,拒绝成立,模型接收原始拒绝消息。2424当 `retry` 为 `true` 时,Claude Code 会向对话中添加一条消息,告诉模型它可以重试该工具调用。Claude Code 本身不会撤销该拒绝。如果您的 hook 没有返回 JSON,或返回 `retry: false`,拒绝将保持有效,模型会收到原始的拒绝消息。
2417 2425
2418当分类器对操作产生 [无判决](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action) 时,Claude Code 忽略 `retry: true`:其响应没有解析,或与自动模式分开的安全检查拒绝了分类器自己的请求。对于这些拒绝,Claude Code 已经在拒绝消息中告诉模型是否稍后重试或继续。2426当分类器[未对该操作作出判定](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action)时(其响应无法解析,或独立于自动模式的安全检查拒绝了分类器自身的请求),Claude Code 会忽略 `retry: true`。对于这些拒绝,Claude Code 已经在拒绝消息中告诉模型是稍后重试还是继续其他工作。
2419 2427
2420<h3 id="notification">2428<h3 id="notification">
2421 Notification2429 Notification
2422</h3>2430</h3>
2423 2431
2424在 Claude Code 发送通知时运行。在通知类型上匹配。省略匹配器以对所有通知类型运行 hooks。2432当 Claude Code 发送通知时运行。按通知类型匹配。省略匹配器即可为所有通知类型运行 hook。
2425 2433
2426您即使关闭桌面通知也接收这些 hook 事件:`preferredNotifChannel` 设置,包括 `notifications_disabled`,仅更改您如何被警报,而不是您的 hook 是否运行。2434即使关闭了桌面通知,您也会收到这些 hook 事件:`preferredNotifChannel` 设置(包括 `notifications_disabled`)只改变提醒您的方式,而不影响您的 hook 是否运行。
2427 2435
2428| 匹配器 | 何时触发 |2436| 匹配器 | 触发时机 |
2429| :- | :- |2437| :- | :- |
2430| `permission_prompt` | Claude 需要您批准工具使用或沙箱命令的 [网络请求](/docs/zh-CN/sandboxing#network-isolation),提示已等待约六秒 |2438| `permission_prompt` | Claude 需要您批准一次工具使用或沙箱化命令的[网络请求](/docs/zh-CN/sandboxing#network-isolation),且该提示已等待约六秒 |
2431| `idle_prompt` | Claude 约 60 秒前完成响应,您自那以后没有输入 |2439| `idle_prompt` | Claude 大约在 60 秒前完成回复,且您此后未输入任何内容 |
2432| `auth_success` | 身份验证完成 |2440| `auth_success` | 身份验证完成 |
2433| `elicitation_dialog` | MCP 服务器打开引出表单,您约六秒没有输入 |2441| `elicitation_dialog` | MCP 服务器打开了一个 elicitation 表单,且您约六秒未输入任何内容 |
2434| `elicitation_url_dialog` | MCP 服务器要求您打开浏览器 URL,您约六秒没有输入 |2442| `elicitation_url_dialog` | MCP 服务器要求您打开一个浏览器 URL,且您约六秒未输入任何内容 |
2435| `elicitation_complete` | MCP 服务器报告 [URL 模式引出](#elicitation-input) 完成 |2443| `elicitation_complete` | MCP 服务器报告 [URL 模式 elicitation](#elicitation-input) 已完成 |
2436| `elicitation_response` | MCP 引出响应被发送回服务器 |2444| `elicitation_response` | MCP elicitation 响应被发回服务器 |
2437| `agent_needs_input` | 后台会话在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时开始等待您的输入,或当前会话要求您一个 [agent team 队友的终端设置问题](/docs/zh-CN/agent-teams#choose-a-display-mode) 或自动模式的 [分类器请求费用](/docs/zh-CN/auto-mode-classifier-billing) 通知,您约六秒没有输入 |2445| `agent_needs_input` | 当 [agent view](/docs/zh-CN/agent-view) 在终端中打开时,某个后台会话开始等待您的输入。当终端会话向您显示 [agent team 队友的终端设置问题](/docs/zh-CN/agent-teams#choose-a-display-mode)或自动模式关于[分类器请求费用](/docs/zh-CN/auto-mode-classifier-billing)的提示,且您约六秒未输入任何内容时,也会触发 |
2438| `agent_completed` | 后台会话完成或失败。仅在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时触发 |2446| `agent_completed` | 某个后台会话完成或失败。仅在 [agent view](/docs/zh-CN/agent-view) 在终端中打开时触发 |
2439| `quota_auto_resume_fired` | Claude Code 在 claude.ai 使用限制暂停它后继续您的任务:在重置时,或更早当您在 Claude Code 中做的某事(如添加使用信用、升级您的计划或切换模型)在等待期间使使用可用时,带有 [模型设置异常](/docs/zh-CN/interactive-mode#wait-for-a-usage-limit-to-reset) |2447| `quota_auto_resume_fired` | 在 claude.ai 用量限制暂停您的任务后,Claude Code 继续执行该任务:在限制重置时,或者在等待期间您在 Claude Code 中执行的某些操作(例如添加使用额度、升级套餐或切换模型)使用量再次可用时提前继续,但存在[模型设置例外](/docs/zh-CN/interactive-mode#wait-for-a-usage-limit-to-reset) |
2440| `quota_auto_resume_stale` | claude.ai 使用限制在您的计算机睡眠超过约 30 分钟时重置。Claude Code 等待您按 `Enter` 而不是继续。在更短的睡眠后它继续并改为触发 `quota_auto_resume_fired` |2448| `quota_auto_resume_stale` | claude.ai 用量限制在您的计算机休眠超过约 30 分钟期间重置。Claude Code 会等待您按 `Enter`,而不是继续执行。如果休眠时间较短,它会继续执行并改为触发 `quota_auto_resume_fired` |
2441| `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** 时不触发 |2449| `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** 时不会触发 |
2442 2450
2443`quota_auto_resume_fired`、`quota_auto_resume_stale` 和 `quota_auto_resume_disabled` 类型需要 Claude Code v2.1.234 或更高版本。2451`quota_auto_resume_fired`、`quota_auto_resume_stale` 和 `quota_auto_resume_disabled` 类型需要 Claude Code v2.1.234 或更高版本。
2444 2452
2445在终端会话中,沙箱命令的网络请求的 `permission_prompt` 需要 Claude Code v2.1.246 或更高版本。2453在终端会话中,针对沙箱化命令网络请求的 `permission_prompt` 需要 Claude Code v2.1.246 或更高版本。
2446 2454
2447队友的终端设置问题的 `agent_needs_input` 需要 Claude Code v2.1.248 或更高版本。2455针对队友终端设置问题的 `agent_needs_input` 需要 Claude Code v2.1.248 或更高版本。
2448 2456
2449<Note>2457<Note>
2450 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享其时序,因此在终端会话中您仅在您似乎远离终端时看到它们:2458 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享计时方式,因此在终端会话中,只有当您看起来已离开终端时才会看到它们:
2451 2459
2452 * 期望 `permission_prompt` 一旦您约六秒没有输入。计时器在权限提示出现时启动,每次按键推迟它。要在 Claude 要求许可使用工具时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。2460 * 当您约六秒未输入任何内容时,预期会出现 `permission_prompt`。计时器在权限提示出现时开始,每次按键都会推迟它。要在 Claude 请求使用工具的权限时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。
2453 * 期望 `idle_prompt` 约 60 秒后 Claude 完成响应,仅当您自那以后没有输入时。Claude Code 在等待 claude.ai 使用限制重置时不发送 `idle_prompt`。当等待自己结束时,其中一个 `quota_auto_resume_*` 类型触发。2461 * 预期 `idle_prompt` 会在 Claude 完成回复约 60 秒后出现,并且仅当您此后未输入任何内容且没有后台 Agent(例如后台[子代理](/docs/zh-CN/sub-agents))仍在运行时才会出现。在等待 claude.ai 用量限制重置期间,Claude Code 不会发送 `idle_prompt`。当等待自行结束时,会改为触发某个 `quota_auto_resume_*` 类型。
2454 * 期望 `elicitation_dialog` 对于引出表单或 `elicitation_url_dialog` 对于浏览器 URL 请求,一旦您约六秒没有输入。两者共享与 `permission_prompt` 相同的六秒门:计时器在对话出现时启动,每次按键推迟它。2462 * 对于 elicitation 表单预期会出现 `elicitation_dialog`,对于浏览器 URL 请求预期会出现 `elicitation_url_dialog`,前提是您约六秒未输入任何内容。两者与 `permission_prompt` 共享相同的六秒门槛:计时器在对话框出现时开始,每次按键都会推迟它。
2455 2463
2456 权限请求或引出在另一个对话在屏幕上时到达保持相同的六秒门,从请求到达时计时。其通知可以在请求仍在等待打开的对话后面时到达您。2464 在另一个对话框显示在屏幕上时到达的权限请求或 elicitation 同样适用六秒门槛,从请求到达时开始计时。其通知可能会在请求仍排在已打开对话框之后等待时就送达您。
2457</Note>2465</Note>
2458 2466
2459Claude Code 在会话中以不同方式计时 `permission_prompt`,其中它向 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input) 发送权限请求,这是 Claude Desktop 和 VS Code 扩展如何托管 Claude Code 的方式:2467在 Claude Code 将权限请求发送给 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input)的会话中(Claude Desktop 和 VS Code 扩展就是以这种方式托管 Claude Code 的),Claude Code 对 `permission_prompt` 的计时方式有所不同:
2460 2468
2461* 期望 `permission_prompt` 约六秒后 Claude 要求权限。Claude Code 在您输入时不推迟它。2469* 预期 `permission_prompt` 会在 Claude 请求权限约六秒后出现。在您输入时,Claude Code 不会推迟它。
2462* 如果您或 [PermissionRequest](#permissionrequest) hook 更早回答,Claude Code 不运行 `permission_prompt`。2470* 如果您或 [PermissionRequest](#permissionrequest) hook 提前作出回应,Claude Code 不会运行 `permission_prompt`。
2463* 设置 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 为 `1` 以在这些会话中关闭 `permission_prompt`。2471* 将 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 设为 `1`,即可在这些会话中关闭 `permission_prompt`。
2464 2472
2465在 v2.1.233 之前,`permission_prompt` 在这些会话中不触发。2473在 v2.1.233 之前,`permission_prompt` 不会在这些会话中触发。
2466 2474
2467使用单独的匹配器根据通知类型运行不同的处理程序。此配置在 Claude 需要权限批准时触发权限特定的警报脚本,在 Claude 空闲时触发不同的通知:2475使用不同的匹配器,可以根据通知类型运行不同的处理程序。以下配置会在 Claude 需要权限批准时触发一个专门用于权限的警报脚本,在 Claude 处于空闲状态时触发另一个通知:
2468 2476
2469```json theme={null}2477```json theme={null}
2470{2478{
2497 Notification 输入2505 Notification 输入
2498</h4>2506</h4>
2499 2507
2500除了 [常见输入字段](#common-input-fields) 外,Notification hooks 接收 `message` 与通知文本、可选 `title` 和 `notification_type` 指示哪个类型触发。2508除了[通用输入字段](#common-input-fields)之外,Notification hook 还会接收包含通知文本的 `message`、可选的 `title`,以及指示触发了哪种类型的 `notification_type`。
2501 2509
2502```json theme={null}2510```json theme={null}
2503{2511{
2511}2519}
2512```2520```
2513 2521
2514Notification hooks 无法阻止或修改通知。Claude Code 丢弃它们的 `systemMessage` 和 `continue` 字段,但仍然发出 [`terminalSequence`](#emit-terminal-notifications),这是桌面通知示例所依赖的。Notification hooks 用于副作用,如将通知转发到外部服务。2522Notification hook 无法阻止或修改通知。Claude Code 会丢弃它们的 `systemMessage` 和 `continue` 字段,但仍会发出 [`terminalSequence`](#emit-terminal-notifications),桌面通知示例正是依赖于此。Notification hook 旨在用于副作用,例如将通知转发到外部服务。
2515 2523
2516<h3 id="subagentstart">2524<h3 id="subagentstart">
2517 SubagentStart2525 SubagentStart
2518</h3>2526</h3>
2519 2527
2520在 Claude 使用 Agent 工具生成子 agent 时运行,当 Claude [恢复子 agent](/docs/zh-CN/sub-agents#resume-subagents) 时,以及每次进程内 [agent team](/docs/zh-CN/agent-teams) 队友处理新消息时。支持匹配器以按 agent 类型名称过滤。对于内置 agents,这是 agent 名称如 `general-purpose`、`Explore` 或 `Plan`。对于 [自定义子 agents](/docs/zh-CN/sub-agents),这是 agent 的 frontmatter 中的 `name` 字段,而不是文件名。2528当 Claude 使用 Agent 工具生成子代理、当 Claude [恢复子代理](/docs/zh-CN/sub-agents#resume-subagents),以及每次进程内 [agent team](/docs/zh-CN/agent-teams) 队友处理新消息时运行。支持使用匹配器按 Agent 类型名称进行过滤。对于内置 Agent,这是 Agent 名称,例如 `general-purpose`、`Explore` 或 `Plan`。对于[自定义子代理](/docs/zh-CN/sub-agents),这是 Agent frontmatter 中的 `name` 字段,而不是文件名。
2521 2529
2522对于由 [插件](/docs/zh-CN/plugins/overview) 提供的子 agents,agent 类型是插件范围的标识符,如 `my-plugin:reviewer`,而不是裸 frontmatter 名称。冒号将插件范围的名称放在正则表达式路径上,因此用 `^` 和 `$` 锚定匹配器以获得精确匹配:`^my-plugin:reviewer$`。2530对于由[插件](/docs/zh-CN/plugins/overview)提供的子代理,Agent 类型是插件范围的标识符,例如 `my-plugin:reviewer`,而不是单纯的 frontmatter 名称。冒号会使插件范围的名称走正则表达式匹配路径,因此请用 `^` 和 `$` 锚定匹配器以进行精确匹配:`^my-plugin:reviewer$`。
2523 2531
2524<h4 id="subagentstart-input">2532<h4 id="subagentstart-input">
2525 SubagentStart 输入2533 SubagentStart 输入
2526</h4>2534</h4>
2527 2535
2528除了 [常见输入字段](#common-input-fields) 外,SubagentStart hooks 接收 `agent_id` 与子 agent 的唯一标识符和 `agent_type` 与匹配器过滤的 agent 名称。2536除了[通用输入字段](#common-input-fields)之外,SubagentStart hook 还会接收包含子代理唯一标识符的 `agent_id`,以及包含匹配器所过滤的 Agent 名称的 `agent_type`。
2529 2537
2530```json theme={null}2538```json theme={null}
2531{2539{
2538}2546}
2539```2547```
2540 2548
2541SubagentStart hooks 无法阻止子 agent 创建,但它们可以向子 agent 注入上下文。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:2549SubagentStart hook 无法阻止子代理的创建,但可以向子代理注入上下文。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您还可以返回:
2542 2550
2543| 字段 | 描述 |2551| 字段 | 描述 |
2544| :- | :- |2552| :- | :- |
2545| `additionalContext` | 在子 agent 对话开始时添加到子 agent 上下文的字符串,在其第一个提示之前。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |2553| `additionalContext` | 在子代理对话开始时、其第一个提示词之前添加到子代理上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2546 2554
2547```json theme={null}2555```json theme={null}
2548{2556{
2553}2561}
2554```2562```
2555 2563
2556当 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 再次注入下一个运行的上下文。2564当 hook 针对同一子代理再次运行时,仅当子代理的上下文中尚未包含先前运行注入的副本时,Claude Code 才会注入返回的上下文。启动时注入的副本会保留在原位,从而使子代理的[提示缓存](/docs/zh-CN/prompt-caching#subagents-and-the-cache)保持完整。在[自动压缩](/docs/zh-CN/sub-agents#auto-compaction)丢弃该副本后,Claude Code 会再次注入下一次运行的上下文。
2557 2565
2558<h3 id="subagentstop">2566<h3 id="subagentstop">
2559 SubagentStop2567 SubagentStop
2560</h3>2568</h3>
2561 2569
2562在 Claude Code 子 agent 完成响应时运行。在 agent 类型上匹配,与 SubagentStart 相同的值。2570当 Claude Code 子代理完成回复时运行。按 Agent 类型匹配,取值与 SubagentStart 相同。
2563 2571
2564<h4 id="subagentstop-input">2572<h4 id="subagentstop-input">
2565 SubagentStop 输入2573 SubagentStop 输入
2566</h4>2574</h4>
2567 2575
2568除了 [常见输入字段](#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 可以访问它而不解析成绩单文件。2576除了[通用输入字段](#common-input-fields)之外,SubagentStop hook 还会接收 `stop_hook_active`、`agent_id`、`agent_type`、`agent_transcript_path` 和 `last_assistant_message`。`agent_type` 字段是用于匹配器过滤的值。`transcript_path` 是主会话的会话记录,而 `agent_transcript_path` 是存储在嵌套 `subagents/` 文件夹中的子代理自身的会话记录。`last_assistant_message` 字段包含子代理最终回复的文本内容,因此 hook 无需解析会话记录文件即可访问它。
2569 2577
2570不是每个 SubagentStop 事件都来自 Claude 生成的子 agent。Claude Code 也为其自己的某些功能运行内部 agents,如 [提示建议](/docs/zh-CN/interactive-mode#prompt-suggestions) 和 [`/btw` 侧问题](/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) 设置的,当会话运行而不带一个时为空字符串。2578并非每个 SubagentStop 事件都来自 Claude 生成的子代理。Claude Code 还会为其自身的某些功能运行内部 Agent,例如[提示词建议](/docs/zh-CN/interactive-mode#prompt-suggestions)和 [`/btw` 旁支问题](/docs/zh-CN/interactive-mode#side-questions-with-%2Fbtw),当这些 Agent 之一完成时,SubagentStop 也会触发。对于这些事件,`agent_type` 是会话本身运行所用的 Agent 名称,例如通过 [`--agent`](/docs/zh-CN/cli-reference#cli-flags) 或 [`agent` 设置](/docs/zh-CN/settings-reference#agent)设定的名称;当会话未使用 Agent 运行时则为空字符串。
2571 2579
2572命名 agent 类型的 `matcher` 不匹配空 `agent_type`。一个 matcher 被省略、`""`、`"*"` 或是匹配空字符串的正则表达式的 hook 也为带有空 `agent_type` 的事件运行。2580指定了 Agent 类型的 `matcher` 不会匹配空的 `agent_type`。匹配器被省略、为 `""` 或 `"*"`,或者是能匹配空字符串的正则表达式的 hook,也会针对 `agent_type` 为空的事件运行。
2573 2581
2574在 Claude Code v2.1.271 或更高版本上,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子 agent 在它停止之前通过该工具传递其报告。`last_assistant_message` 字段然后保持子 agent 的结束文本(如果有),这不是传递的报告。报告是该调用的 `message` 输入,`PreToolUse` 或 `PostToolUse` hook 匹配 `SubagentHandback` 接收作为 `tool_input.message`。2582在 Claude Code v2.1.271 或更高版本中,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子代理会在停止之前通过该工具传递其报告。此时 `last_assistant_message` 字段保存的是子代理的结束文本(如果有),而不是所传递的报告。报告是该调用的 `message` 输入,匹配 `SubagentHandback` 的 `PreToolUse` 或 `PostToolUse` hook 会以 `tool_input.message` 的形式收到它。
2575 2583
2576SubagentStop hooks 也接收 [Stop 输入](#stop-input) 下描述的 `background_tasks` 和 `session_crons` 数组。两个数组都限定于父会话,而不是子 agent。2584SubagentStop hook 还会接收 [Stop 输入](#stop-input)中描述的 `background_tasks` 和 `session_crons` 数组。这两个数组的范围是父会话,而不是子代理。
2577 2585
2578```json theme={null}2586```json theme={null}
2579{2587{
2592}2600}
2593```2601```
2594 2602
2595SubagentStop 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。2603SubagentStop hook 使用与 [Stop hook](#stop-decision-control) 相同的决策控制格式,包括将 `hookEventName` 设为 `"SubagentStop"` 的 `hookSpecificOutput.additionalContext`,用于提供让子代理继续运行的非错误反馈。返回带有 `reason` 的 `decision: "block"` 会让子代理继续运行,并将 `reason` 作为下一条指令传递给子代理。通过退出码 2 进行阻止的 hook 会以同样方式传递其 stderr 消息。要在子代理返回后向父会话注入上下文,请改为在 `Agent` 工具上使用 [`PostToolUse`](#posttooluse) hook。
2596 2604
2597<h3 id="taskcreated">2605<h3 id="taskcreated">
2598 TaskCreated2606 TaskCreated
2599</h3>2607</h3>
2600 2608
2601在通过 `TaskCreate` 工具创建任务时运行。使用此来强制命名约定、要求任务描述或防止某些任务被创建。在 [没有 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability) 中,此事件不触发。2609当通过 `TaskCreate` 工具创建任务时运行。可用于强制执行命名约定、要求提供任务描述或阻止创建某些任务。在[没有 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability)中,此事件不会触发。
2602 2610
2603TaskCreated hooks 不支持匹配器,对每个出现触发。2611TaskCreated hook 不支持匹配器,每次发生时都会触发。
2604 2612
2605<h4 id="taskcreated-input">2613<h4 id="taskcreated-input">
2606 TaskCreated 输入2614 TaskCreated 输入
2607</h4>2615</h4>
2608 2616
2609除了 [常见输入字段](#common-input-fields) 外,TaskCreated hooks 接收 `task_id`、`task_subject` 和可选的 `task_description`、`teammate_name` 和 `team_name`。2617除了[通用输入字段](#common-input-fields)之外,TaskCreated hook 还会接收 `task_id`、`task_subject`,以及可选的 `task_description`、`teammate_name` 和 `team_name`。
2610 2618
2611```json theme={null}2619```json theme={null}
2612{2620{
2625| 字段 | 描述 |2633| 字段 | 描述 |
2626| :- | :- |2634| :- | :- |
2627| `task_id` | 正在创建的任务的标识符 |2635| `task_id` | 正在创建的任务的标识符 |
2628| `task_subject` | 任务的标题 |2636| `task_subject` | 任务标题 |
2629| `task_description` | 任务的详细描述。可能不存在 |2637| `task_description` | 任务的详细描述。可能不存在 |
2630| `teammate_name` | 创建任务的队友的名称。可能不存在 |2638| `teammate_name` | 创建该任务的队友名称。可能不存在 |
2631| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |2639| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |
2632 2640
2633<h4 id="taskcreated-decision-control">2641<h4 id="taskcreated-decision-control">
2634 TaskCreated 决策控制2642 TaskCreated 决策控制
2635</h4>2643</h4>
2636 2644
2637TaskCreated hook 可以以两种方式阻止创建。任一方式,Claude Code 删除任务并将您的消息返回给 Claude 作为工具的错误。Claude Code 忽略此事件的 `continue: false`,Claude 继续工作。2645TaskCreated hook 可以通过两种方式阻止创建。无论哪种方式,Claude Code 都会删除该任务,并将您的消息作为工具错误返回给 Claude。Claude Code 会忽略此事件中的 `continue: false`,Claude 会继续工作。
2638 2646
2639* **退出代码 2**:Claude Code 将 stderr 文本作为消息返回。2647* **退出码 2**:Claude Code 将 stderr 文本作为消息返回。
2640* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。2648* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。
2641 2649
2642此示例阻止主题不遵循所需格式的任务:2650以下示例会阻止主题不符合所需格式的任务:
2643 2651
2644```bash theme={null}2652```bash theme={null}
2645#!/bin/bash2653#!/bin/bash
2658 TaskCompleted2666 TaskCompleted
2659</h3>2667</h3>
2660 2668
2661在任务被标记为完成时运行。这在两种情况下触发:当任何 agent 通过 TaskUpdate 工具显式标记任务为完成时,或当 [agent team](/docs/zh-CN/agent-teams) 队友完成其回合与进行中的任务时。使用此来强制完成标准,如通过测试或 lint 检查,然后任务才能关闭。2669当任务被标记为已完成时运行。它会在两种情况下触发:任何 Agent 通过 TaskUpdate 工具显式将任务标记为已完成时,或 [agent team](/docs/zh-CN/agent-teams) 队友在仍有进行中任务的情况下结束其轮次时。可用于在任务关闭之前强制执行完成标准,例如测试通过或 lint 检查通过。
2662 2670
2663TaskCompleted hooks 不支持匹配器,对每个出现触发。2671TaskCompleted hook 不支持匹配器,每次发生时都会触发。
2664 2672
2665<h4 id="taskcompleted-input">2673<h4 id="taskcompleted-input">
2666 TaskCompleted 输入2674 TaskCompleted 输入
2667</h4>2675</h4>
2668 2676
2669除了 [常见输入字段](#common-input-fields) 外,TaskCompleted hooks 接收 `task_id`、`task_subject` 和可选的 `task_description`、`teammate_name` 和 `team_name`。2677除了[通用输入字段](#common-input-fields)之外,TaskCompleted hook 还会接收 `task_id`、`task_subject`,以及可选的 `task_description`、`teammate_name` 和 `team_name`。
2670 2678
2671```json theme={null}2679```json theme={null}
2672{2680{
2686| 字段 | 描述 |2694| 字段 | 描述 |
2687| :- | :- |2695| :- | :- |
2688| `task_id` | 正在完成的任务的标识符 |2696| `task_id` | 正在完成的任务的标识符 |
2689| `task_subject` | 任务的标题 |2697| `task_subject` | 任务标题 |
2690| `task_description` | 任务的详细描述。可能不存在 |2698| `task_description` | 任务的详细描述。可能不存在 |
2691| `teammate_name` | 完成任务的队友的名称。可能不存在 |2699| `teammate_name` | 完成该任务的队友名称。可能不存在 |
2692| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |2700| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |
2693 2701
2694<h4 id="taskcompleted-decision-control">2702<h4 id="taskcompleted-decision-control">
2695 TaskCompleted 决策控制2703 TaskCompleted 决策控制
2696</h4>2704</h4>
2697 2705
2698TaskCompleted hooks 支持两种方式来控制任务完成:2706TaskCompleted hook 支持两种控制任务完成的方式:
2699 2707
2700* **退出代码 2**:任务不被标记为完成,stderr 消息被反馈给模型作为反馈。2708* **退出码 2**:任务不会被标记为已完成,stderr 消息会作为反馈传回给模型。
2701* **JSON `{"continue": false, "stopReason": "..."}`**:当队友完成其回合触发事件时,完全停止队友,匹配 `Stop` hook 行为。`stopReason` 显示给用户。当 `TaskUpdate` 工具触发事件时,Claude Code 忽略 `continue: false`;退出代码 2 仍然阻止完成。2709* **JSON `{"continue": false, "stopReason": "..."}`**:当事件由队友结束其轮次触发时,完全停止该队友,与 `Stop` hook 的行为一致。`stopReason` 会显示给用户。当事件由 `TaskUpdate` 工具触发时,Claude Code 会忽略 `continue: false`;退出码 2 仍会阻止完成。
2702 2710
2703此示例运行测试并在它们失败时阻止任务完成:2711以下示例运行测试,如果测试失败则阻止任务完成:
2704 2712
2705```bash theme={null}2713```bash theme={null}
2706#!/bin/bash2714#!/bin/bash
2720 Stop2728 Stop
2721</h3>2729</h3>
2722 2730
2723在主 Claude Code agent 完成响应时运行。如果停止由于用户中断而发生,不运行。API 错误触发 [StopFailure](#stopfailure)。2731当主 Claude Code Agent 完成回复时运行。如果停止是由用户中断导致的,则不会运行。API 错误会改为触发
2732[StopFailure](#stopfailure)。
2724 2733
2725<Tip>2734<Tip>
2726 [`/goal`](/docs/zh-CN/goal) 命令是会话范围的基于提示的 Stop hook 的内置快捷方式。当您想让 Claude 在不编写 hook 配置的情况下继续朝着条件工作时使用它。2735 [`/goal`](/docs/zh-CN/goal) 命令是会话范围内基于提示词的 Stop hook 的内置快捷方式。当您希望 Claude 朝着某个条件持续工作而无需编写 hook 配置时,请使用它。
2727</Tip>2736</Tip>
2728 2737
2729<h4 id="stop-input">2738<h4 id="stop-input">
2730 Stop 输入2739 Stop 输入
2731</h4>2740</h4>
2732 2741
2733除了 [常见输入字段](#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 连续继续上限:在 stop hooks 连续继续回合 8 次后,Claude Code 覆盖下一个阻止并结束回合。要提高上限,设置 [`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`](/docs/zh-CN/env-vars)。2742除了[通用输入字段](#common-input-fields)之外,Stop hook 还会接收 `stop_hook_active`、`last_assistant_message`、`background_tasks` 和 `session_crons`。当 Claude Code 已经因 stop hook 而继续执行时,`stop_hook_active` 字段为 `true`。请检查此值或处理会话记录,以避免因一个永远无法满足的条件而持续阻止。Claude Code 设有 8 次连续继续的上限:在 stop hook 连续八次让轮次继续之后,Claude Code 会覆盖下一次阻止并结束该轮次。要提高此上限,请设置 [`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`](/docs/zh-CN/env-vars)。
2734 2743
2735`last_assistant_message` 字段包含 Claude 最终响应的文本内容,因此 hooks 可以访问它而不解析成绩单文件。对于作用于刚完成的回合的 hooks,如朗读或通知 hooks,使用此字段而不是读取 `transcript_path`:成绩单文件不保证在所有版本的 Stop 时包含最终消息。2744`last_assistant_message` 字段包含 Claude 最终回复的文本内容,因此 hook 无需解析会话记录文件即可访问它。对于需要处理刚完成的轮次的 hook(例如朗读或通知 hook),请使用此字段,而不是读取 `transcript_path`:在所有版本中,并不能保证会话记录文件在 Stop 时已包含最终消息。
2736 2745
2737`background_tasks` 和 `session_crons` 数组让 hooks 区分"会话完成"与"会话暂停等待后台工作唤醒它"。当任务注册表可达时两个数组都出现,当没有任何东西在飞行或计划时为空。2746`background_tasks` 和 `session_crons` 数组让 hook 能够区分"会话已完成"和"会话已暂停,正在等待后台工作将其重新唤醒"。当任务注册表可访问时,这两个数组都会存在;当没有正在进行或已计划的内容时,它们为空。
2738 2747
2739`background_tasks` 中的每个条目描述一个进行中的任务,并使用这些字段:2748`background_tasks` 中的每个条目描述一个正在进行的任务,并使用以下字段:
2740 2749
2741| 字段 | 描述 |2750| 字段 | 描述 |
2742| :- | :- |2751| :- | :- |
2743| `id` | 任务标识符 |2752| `id` | 任务标识符 |
2744| `type` | 友好的任务类型标签,如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识哪个 Claude Code 功能创建了任务。对于无法识别的类型回退到原始判别式 |2753| `type` | 易读的任务类型标签,例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识了创建该任务的 Claude Code 功能。对于无法识别的类型,回退为原始判别值 |
2745| `status` | 当前任务状态 |2754| `status` | 当前任务状态 |
2746| `description` | 自由文本描述,上限为 1000 个字符,当剪裁时在字符串中带有 `… [+N chars]` 标记 |2755| `description` | 自由文本描述,上限为 1000 个字符,被截断时在字符串中带有 `… [+N chars]` 标记 |
2747| `command` | Shell 命令行,上限为 1000 个字符。仅对 `shell` 任务出现 |2756| `command` | shell 命令行,上限为 1000 个字符。仅存在于 `shell` 任务中 |
2748| `agent_type` | 子 agent 类型名称。仅对 `subagent` 任务出现 |2757| `agent_type` | 子代理类型名称。仅存在于 `subagent` 任务中 |
2749| `server` | MCP 服务器名称。仅对 `monitor` 和 `MCP task` 任务出现 |2758| `server` | MCP 服务器名称。仅存在于 `monitor` 和 `MCP task` 任务中 |
2750| `tool` | MCP 工具名称。仅对 `monitor` 和 `MCP task` 任务出现 |2759| `tool` | MCP 工具名称。仅存在于 `monitor` 和 `MCP task` 任务中 |
2751| `name` | 工作流名称。仅对 `workflow` 任务出现 |2760| `name` | 工作流名称。仅存在于 `workflow` 任务中 |
2752 2761
2753`session_crons` 中的每个条目描述一个会话范围的计划唤醒,来自 `CronCreate`、`ScheduleWakeup` 和 `/loop`:2762`session_crons` 中的每个条目描述一个会话范围内的计划唤醒,来源于 `CronCreate`、`ScheduleWakeup` 和 `/loop`:
2754 2763
2755| 字段 | 描述 |2764| 字段 | 描述 |
2756| :- | :- |2765| :- | :- |
2757| `id` | Cron 任务标识符 |2766| `id` | Cron 任务标识符 |
2758| `schedule` | Cron 表达式,例如 `0 9 * * 1-5` |2767| `schedule` | Cron 表达式,例如 `0 9 * * 1-5` |
2759| `recurring` | 对于一次性唤醒(其计划编码单个触发时间)为 `false`,对于在每个匹配上重新触发的任务为 `true` |2768| `recurring` | 对于计划中只编码了单个触发时间的一次性唤醒为 `false`,对于每次匹配都会重新触发的任务为 `true` |
2760| `prompt` | 当 cron 触发时提交的提示,上限为 1000 个字符,带有相同的 `… [+N chars]` 标记 |2769| `prompt` | cron 触发时提交的提示词,上限为 1000 个字符,带有相同的 `… [+N chars]` 标记 |
2761 2770
2762此示例显示了一个 Stop 输入,带有一个进行中的 shell 任务和一个循环 cron:2771以下示例展示了一个包含一个正在进行的 shell 任务和一个周期性 cron 的 Stop 输入:
2763 2772
2764```json theme={null}2773```json theme={null}
2765{2774{
2794 Stop 决策控制2803 Stop 决策控制
2795</h4>2804</h4>
2796 2805
2797`Stop` 和 `SubagentStop` hooks 可以控制 Claude 是否继续。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您的 hook 脚本可以返回这些事件特定的字段:2806`Stop` 和 `SubagentStop` hook 可以控制 Claude 是否继续。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下特定于事件的字段:
2798 2807
2799| 字段 | 描述 |2808| 字段 | 描述 |
2800| :- | :- |2809| :- | :- |
2801| `decision` | `"block"` 防止 Claude 停止。省略以允许 Claude 停止 |2810| `decision` | `"block"` 会阻止 Claude 停止。省略则允许 Claude 停止 |
2802| `reason` | 当 `decision` 为 `"block"` 时需要。告诉 Claude 为什么它应该继续 |2811| `reason` | 当 `decision` 为 `"block"` 时必填。告诉 Claude 为什么应该继续 |
2803| `hookSpecificOutput.additionalContext` | Claude 的非错误反馈。对话继续,以便 Claude 可以作用于它,但与 `decision: "block"` 不同,它在成绩单中显示为 hook 反馈而不是 hook 错误 |2812| `hookSpecificOutput.additionalContext` | 给 Claude 的非错误反馈。对话会继续,以便 Claude 据此采取行动,但与 `decision: "block"` 不同,它在会话记录中显示为 hook 反馈,而不是 hook 错误 |
2804 2813
2805通过退出 2 阻止的 hook 路由方式与 `reason` 相同:Claude 接收 stderr 消息作为为什么它应该继续的解释。2814通过退出码 2 进行阻止的 hook 与 `reason` 的传递方式相同:Claude 会收到 stderr 消息,作为它应该继续的原因说明。
2806 2815
2807```json theme={null}2816```json theme={null}
2808{2817{
2811}2820}
2812```2821```
2813 2822
2814当 hook 按设计工作并给 Claude 指导时使用 `additionalContext`,如"在完成前运行测试套件"。它通过与 `decision: "block"` 相同的循环保护保持对话进行,即 `stop_hook_active` 输入和 8 连续继续上限,但成绩单将其标记为 `Stop hook feedback`,不显示 hook 错误通知:2823当 hook 按设计正常工作并为 Claude 提供指导时(例如"完成前运行测试套件"),请使用 `additionalContext`。它通过与 `decision: "block"` 相同的循环保护机制(即 `stop_hook_active` 输入和 8 次连续继续上限)让对话继续,但会话记录会将其标记为 `Stop hook feedback`,并且不会显示 hook 错误通知:
2815 2824
2816```json theme={null}2825```json theme={null}
2817{2826{
2826 StopFailure2835 StopFailure
2827</h3>2836</h3>
2828 2837
2829在回合由于 API 错误而结束时运行,而不是 [Stop](#stop)。Claude Code 忽略 hook 的输出和退出代码,除了 [`terminalSequence`](#emit-terminal-notifications)。使用此来记录失败、发送警报或当 Claude 由于速率限制、身份验证问题或其他 API 错误无法完成响应时采取恢复操作。2838当轮次因 API 错误而结束时,代替 [Stop](#stop) 运行。除 [`terminalSequence`](#emit-terminal-notifications) 外,Claude Code 会忽略该 hook 的输出和退出码。当 Claude 由于速率限制、身份验证问题或其他 API 错误而无法完成回复时,可用于记录失败、发送警报或采取恢复措施。
2830 2839
2831<h4 id="stopfailure-input">2840<h4 id="stopfailure-input">
2832 StopFailure 输入2841 StopFailure 输入
2833</h4>2842</h4>
2834 2843
2835除了 [常见输入字段](#common-input-fields) 外,StopFailure hooks 接收 `error`、可选的 `error_details` 和可选的 `last_assistant_message`。`error` 字段标识错误类型,用于匹配器过滤。2844除了[通用输入字段](#common-input-fields)之外,StopFailure hook 还会接收 `error`、可选的 `error_details` 和可选的 `last_assistant_message`。`error` 字段标识错误类型,并用于匹配器过滤。
2836 2845
2837| 字段 | 描述 |2846| 字段 | 描述 |
2838| :- | :- |2847| :- | :- |
2839| `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` |2848| `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` |
2840| `error_details` | 关于错误的额外详情,当可用时 |2849| `error_details` | 关于该错误的其他详细信息(如有) |
2841| `last_assistant_message` | 在对话中显示的渲染错误文本。与 `Stop` 和 `SubagentStop` 不同,其中此字段保持 Claude 的对话输出,对于 `StopFailure` 它包含 API 错误字符串本身,如 `"API Error: Rate limit reached"` |2850| `last_assistant_message` | 在对话中显示的渲染后错误文本。与 `Stop` 和 `SubagentStop` 中该字段保存 Claude 的对话输出不同,对于 `StopFailure`,它包含 API 错误字符串本身,例如 `"API Error: Rate limit reached"` |
2842 2851
2843```json theme={null}2852```json theme={null}
2844{2853{
2852}2861}
2853```2862```
2854 2863
2855StopFailure hooks 没有决策控制。它们仅为通知和日志目的运行。2864StopFailure hook 没有决策控制。它们仅用于通知和日志记录目的。
2856 2865
2857<h3 id="teammateidle">2866<h3 id="teammateidle">
2858 TeammateIdle2867 TeammateIdle
2859</h3>2868</h3>
2860 2869
2861在 [agent team](/docs/zh-CN/agent-teams) 队友在完成其回合后即将空闲时运行。使用此来强制质量门,如在队友停止工作前要求通过 lint 检查或验证输出文件存在。2870当 [agent team](/docs/zh-CN/agent-teams) 队友在结束其轮次后即将进入空闲状态时运行。可用于在队友停止工作之前强制执行质量关卡,例如要求 lint 检查通过或验证输出文件是否存在。
2862 2871
2863TeammateIdle hooks 不支持匹配器,对每个出现触发。2872TeammateIdle hook 不支持匹配器,每次发生时都会触发。
2864 2873
2865<h4 id="teammateidle-input">2874<h4 id="teammateidle-input">
2866 TeammateIdle 输入2875 TeammateIdle 输入
2867</h4>2876</h4>
2868 2877
2869除了 [常见输入字段](#common-input-fields) 外,TeammateIdle hooks 接收 `teammate_name` 和 `team_name`。2878除了[通用输入字段](#common-input-fields)之外,TeammateIdle hook 还会接收 `teammate_name` 和 `team_name`。
2870 2879
2871```json theme={null}2880```json theme={null}
2872{2881{
2882 2891
2883| 字段 | 描述 |2892| 字段 | 描述 |
2884| :- | :- |2893| :- | :- |
2885| `teammate_name` | 即将空闲的队友的名称 |2894| `teammate_name` | 即将进入空闲状态的队友名称 |
2886| `team_name` | 已弃用。会话派生的团队名称;将在未来版本中删除 |2895| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |
2887 2896
2888<h4 id="teammateidle-decision-control">2897<h4 id="teammateidle-decision-control">
2889 TeammateIdle 决策控制2898 TeammateIdle 决策控制
2890</h4>2899</h4>
2891 2900
2892TeammateIdle hooks 支持两种方式来控制队友行为:2901TeammateIdle hook 支持两种控制队友行为的方式:
2893 2902
2894* **退出代码 2**:队友接收 stderr 消息作为反馈并继续工作而不是空闲。2903* **退出码 2**:队友会收到 stderr 消息作为反馈,并继续工作而不是进入空闲状态。
2895* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止队友,匹配 `Stop` hook 行为。`stopReason` 显示给用户。2904* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止该队友,与 `Stop` hook 的行为一致。`stopReason` 会显示给用户。
2896 2905
2897此示例检查构建工件存在,然后允许队友空闲:2906以下示例在允许队友进入空闲状态之前检查构建产物是否存在:
2898 2907
2899```bash theme={null}2908```bash theme={null}
2900#!/bin/bash2909#!/bin/bash
2911 ConfigChange2920 ConfigChange
2912</h3>2921</h3>
2913 2922
2914在会话期间配置文件更改时运行。使用此来审计设置更改、强制安全策略或阻止对配置文件的未授权修改。2923当会话期间配置文件发生更改时运行。可用于审计设置更改、强制执行安全策略,或阻止对配置文件的未经授权的修改。
2915 2924
2916Claude 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 端托管设置文件而不运行它们。2925当设置文件、托管策略文件或 skill 文件发生更改时,Claude Code 会运行 ConfigChange hook。对于托管策略,仅当 `managed-settings.json` 或 `managed-settings.d/` 中的文件发生更改时才会运行。对于[服务器托管设置](/docs/zh-CN/server-managed-settings)以及 macOS 托管偏好设置或 Windows 注册表策略的更改,Claude Code 会直接应用而不运行这些 hook。在启用了 [`wslInheritsWindowsSettings`](/docs/zh-CN/settings-reference#wslinheritswindowssettings) 的 WSL 上,它在策略轮询时也会直接应用已更改的 Windows 端托管设置文件,而不运行这些 hook。
2917 2926
2918匹配器在配置源上过滤:2927匹配器按配置来源进行过滤:
2919 2928
2920| 匹配器 | 何时触发 |2929| 匹配器 | 触发时机 |
2921| :- | :- |2930| :- | :- |
2922| `user_settings` | `~/.claude/settings.json` 更改 |2931| `user_settings` | `~/.claude/settings.json` 发生更改 |
2923| `project_settings` | `.claude/settings.json` 更改 |2932| `project_settings` | `.claude/settings.json` 发生更改 |
2924| `local_settings` | `.claude/settings.local.json` 更改 |2933| `local_settings` | `.claude/settings.local.json` 发生更改 |
2925| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的文件更改 |2934| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的文件发生更改 |
2926| `skills` | `.claude/skills/` 中的 skill 文件更改 |2935| `skills` | `.claude/skills/` 中的 skill 文件发生更改 |
2927 2936
2928此示例记录所有配置更改以进行安全审计:2937以下示例记录所有配置更改以进行安全审计:
2929 2938
2930```json theme={null}2939```json theme={null}
2931{2940{
2949 ConfigChange 输入2958 ConfigChange 输入
2950</h4>2959</h4>
2951 2960
2952除了 [常见输入字段](#common-input-fields) 外,ConfigChange hooks 接收 `source` 和可选的 `file_path`。`source` 字段指示哪个配置类型更改,`file_path` 提供被修改的特定文件的路径。2961除了[通用输入字段](#common-input-fields)之外,ConfigChange hook 还会接收 `source` 和可选的 `file_path`。`source` 字段指示哪种配置类型发生了更改,`file_path` 提供被修改的具体文件的路径。
2953 2962
2954```json theme={null}2963```json theme={null}
2955{2964{
2966 ConfigChange 决策控制2975 ConfigChange 决策控制
2967</h4>2976</h4>
2968 2977
2969ConfigChange hooks 可以阻止配置更改生效。使用退出代码 2 或 JSON `decision` 来防止更改。当被阻止时,新设置不应用于运行的会话。2978ConfigChange hook 可以阻止配置更改生效。使用退出码 2 或 JSON `decision` 来阻止更改。被阻止时,新设置不会应用到正在运行的会话。
2970 2979
2971| 字段 | 描述 |2980| 字段 | 描述 |
2972| :- | :- |2981| :- | :- |
2973| `decision` | `"block"` 防止配置更改被应用。省略以允许更改 |2982| `decision` | `"block"` 会阻止应用该配置更改。省略则允许更改 |
2974| `reason` | 被接受但永远不显示 |2983| `reason` | 可接受但永远不会显示 |
2975 2984
2976```json theme={null}2985```json theme={null}
2977{2986{
2980}2989}
2981```2990```
2982 2991
2983`policy_settings` 更改无法被阻止。当机器上的托管设置文件更改时,hooks 仍然为 `policy_settings` 源触发,因此您可以使用它们来记录这些编辑,但任何阻止决策都被忽略。这确保企业托管设置始终生效。当 [服务器托管设置](/docs/zh-CN/server-managed-settings) 到达或刷新时,Claude Code 不运行 `ConfigChange` hooks。2992`policy_settings` 更改无法被阻止。当机器上的托管设置文件发生更改时,hook 仍会针对 `policy_settings` 来源触发,因此您可以使用它们记录这些编辑,但任何阻止决策都会被忽略。这确保了企业托管设置始终生效。当[服务器托管设置](/docs/zh-CN/server-managed-settings)到达或刷新时,Claude Code 不会运行 `ConfigChange` hook。
2984 2993
2985Claude Code 作用于 ConfigChange hook 的 JSON 输出中的阻止决策,并丢弃 `systemMessage` 和 `continue`。被阻止的更改不向您或 Claude 呈现任何消息,无论您是用 `reason` 还是退出 2 的 stderr 阻止。Claude Code 仅向调试日志写入一行。2994Claude Code 会根据 ConfigChange hook JSON 输出中的阻止决策采取行动,并丢弃 `systemMessage` 和 `continue`。无论您是通过 `reason` 还是通过退出码 2 时的 stderr 进行阻止,被阻止的更改都不会向您或 Claude 显示任何消息。Claude Code 只会在调试日志中写入一行。
2986 2995
2987<h3 id="cwdchanged">2996<h3 id="cwdchanged">
2988 CwdChanged2997 CwdChanged
2989</h3>2998</h3>
2990 2999
2991在主对话中的 shell 命令更改工作目录时运行,例如当 Claude 执行 `cd` 命令时。使用此来对目录更改做出反应:重新加载环境变量、激活项目特定的工具链或自动运行设置脚本。与 [FileChanged](#filechanged) 配对,用于像 [direnv](https://direnv.net/) 这样管理每个目录环境的工具。3000当主对话中的 shell 命令更改了工作目录时运行,例如 Claude 执行 `cd` 命令时。可用于响应目录更改:重新加载环境变量、激活特定于项目的工具链,或自动运行设置脚本。可与 [FileChanged](#filechanged) 配合使用,以支持 [direnv](https://direnv.net/) 等管理每目录环境的工具。
2992 3001
2993CwdChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 CwdChanged 事件,当 Claude Code 清除它们时。3002CwdChanged hook 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量会在后续 Bash 命令中持续有效,直到下一个 CwdChanged 事件时由 Claude Code 清除。
2994 3003
2995CwdChanged 不支持匹配器,对每个出现触发。3004CwdChanged 不支持匹配器,每次发生时都会触发。
2996 3005
2997<h4 id="cwdchanged-input">3006<h4 id="cwdchanged-input">
2998 CwdChanged 输入3007 CwdChanged 输入
2999</h4>3008</h4>
3000 3009
3001除了 [常见输入字段](#common-input-fields) 外,CwdChanged hooks 接收 `old_cwd` 和 `new_cwd`。3010除了[通用输入字段](#common-input-fields)之外,CwdChanged hook 还会接收 `old_cwd` 和 `new_cwd`。
3002 3011
3003```json theme={null}3012```json theme={null}
3004{3013{
3015 CwdChanged 输出3024 CwdChanged 输出
3016</h4>3025</h4>
3017 3026
3018除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,CwdChanged hooks 可以返回 `watchPaths` 来动态设置 [FileChanged](#filechanged) 监视哪些文件路径:3027除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,CwdChanged hook 还可以返回 `watchPaths`,以动态设置 [FileChanged](#filechanged) 监视哪些文件路径:
3019 3028
3020| 字段 | 描述 |3029| 字段 | 描述 |
3021| :- | :- |3030| :- | :- |
3022| `watchPaths` | 绝对路径数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。返回空数组清除动态列表,这在进入新目录时是典型的 |3031| `watchPaths` | 绝对路径数组。替换当前的动态监视列表。您的 `matcher` 配置中的路径始终会被监视。返回空数组会清除动态列表,这在进入新目录时很常见 |
3023 3032
3024CwdChanged hooks 没有决策控制。它们无法阻止目录更改。3033CwdChanged hook 没有决策控制。它们无法阻止目录更改。
3025 3034
3026Claude Code 从它们的 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。3035Claude Code 会从其 JSON 输出中读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它会将 `systemMessage` 显示为简短的终端通知。该消息不会进入 SDK 消息流。
3027 3036
3028<h3 id="directoryadded">3037<h3 id="directoryadded">
3029 DirectoryAdded3038 DirectoryAdded
3030</h3>3039</h3>
3031 3040
3032在您使用 `/add-dir` 命令在会话中添加工作目录后运行,或在 SDK 客户端使用 `register_repo_root` 控制请求添加一个后运行。使用此来准备新添加的存储库,例如安装其依赖。3041在您于会话中途使用 `/add-dir` 命令添加工作目录之后,或在 SDK 客户端通过 `register_repo_root` 控制请求添加工作目录之后运行。可用于准备新添加的仓库,例如安装其依赖。
3033 3042
3034Claude Code 在以下情况下不触发此事件:3043在以下情况下,Claude Code 不会触发此事件:
3035 3044
3036* 您使用 `--add-dir` 启动标志传递目录;[SessionStart](#sessionstart) 涵盖这些目录3045* 您通过 `--add-dir` 启动标志传入目录;这些目录由 [SessionStart](#sessionstart) 覆盖
3037* 您在 `/permissions` Workspace 标签上添加目录3046* 您在 `/permissions` 的 Workspace 选项卡上添加目录
3038* 您添加已经是工作目录或在一个内部的目录3047* 您添加的目录已经是工作目录或位于某个工作目录内
3039 3048
3040Claude Code 在刷新沙箱和权限状态后触发 DirectoryAdded,因此沙箱工具已经在您的 hook 运行时看到新目录。Hook 命令本身运行未沙箱化。3049Claude Code 会在刷新沙箱和权限状态之后触发 DirectoryAdded,因此当您的 hook 运行时,沙箱化工具已经能看到新目录。hook 命令本身在沙箱之外运行。
3041 3050
3042Claude Code 不等待 hook:添加立即完成,hook 在后台以 600 秒默认超时运行。3051Claude Code 不会等待该 hook:添加操作会立即完成,hook 在后台运行,使用 600 秒的默认超时时间。
3043 3052
3044匹配器在目录添加方式上过滤:3053匹配器按目录的添加方式进行过滤:
3045 3054
3046| 匹配器 | 何时触发 |3055| 匹配器 | 触发时机 |
3047| :- | :- |3056| :- | :- |
3048| `slash_command` | 您使用 `/add-dir` 添加目录 |3057| `slash_command` | 您使用 `/add-dir` 添加目录 |
3049| `register_repo_root` | SDK 客户端使用 `register_repo_root` 控制请求添加目录 |3058| `register_repo_root` | SDK 客户端通过 `register_repo_root` 控制请求添加目录 |
3050 3059
3051<h4 id="directoryadded-input">3060<h4 id="directoryadded-input">
3052 DirectoryAdded 输入3061 DirectoryAdded 输入
3053</h4>3062</h4>
3054 3063
3055除了 [常见输入字段](#common-input-fields) 外,DirectoryAdded hooks 接收 `directory` 和 `source`。3064除了[通用输入字段](#common-input-fields)之外,DirectoryAdded hook 还会接收 `directory` 和 `source`。
3056 3065
3057| 字段 | 描述 |3066| 字段 | 描述 |
3058| :- | :- |3067| :- | :- |
3059| `directory` | 添加的目录的绝对路径 |3068| `directory` | 所添加目录的绝对路径 |
3060| `source` | 目录如何添加,`/add-dir` 为 `"slash_command"` 或 SDK 控制请求为 `"register_repo_root"` |3069| `source` | 目录的添加方式:`/add-dir` 对应 `"slash_command"`,SDK 控制请求对应 `"register_repo_root"` |
3061 3070
3062```json theme={null}3071```json theme={null}
3063{3072{
3070}3079}
3071```3080```
3072 3081
3073DirectoryAdded hooks 没有决策控制。它们无法阻止添加,这在 hook 运行时已经完成。Claude Code 从它们的 JSON 输出丢弃 `continue` 字段,并根据源以不同方式呈现其余部分:3082DirectoryAdded hook 没有决策控制。它们无法阻止添加操作,因为 hook 运行时添加已经完成。Claude Code 会丢弃其 JSON 输出中的 `continue` 字段,并根据来源以不同方式呈现其余内容:
3074 3083
3075* `slash_command`:Claude Code 将 hook 的 `systemMessage` 作为上下文传递给 Claude,在下一个对话回合上,而不是向您显示。失败 hooks 的计数出现在成绩单中。完整失败输出进入调试日志3084* `slash_command`:Claude Code 会在下一个对话轮次中将 hook 的 `systemMessage` 作为上下文传递给 Claude,而不是向您显示。失败 hook 的数量会显示在会话记录中。完整的失败输出会写入调试日志
3076* `register_repo_root`:Claude Code 仅将 `systemMessage` 输出和失败输出写入调试日志3085* `register_repo_root`:Claude Code 仅将 `systemMessage` 输出和失败输出写入调试日志
3077 3086
3078<h3 id="filechanged">3087<h3 id="filechanged">
3079 FileChanged3088 FileChanged
3080</h3>3089</h3>
3081 3090
3082在监视的文件在磁盘上更改时运行。Claude Code 使用文件系统监视器检测更改,而不是通过检查工具调用,因此它运行 hook,无论什么更改了文件:`Edit` 或 `Write` 工具调用、Claude 使用 `Bash` 运行的脚本或 Claude Code 外的进程。常见用途是在项目配置文件更改时重新加载环境变量。3091当被监视的文件在磁盘上发生更改时运行。Claude Code 通过文件系统监视器而非检查工具调用来检测更改,因此无论是什么更改了文件,它都会运行该 hook:`Edit` 或 `Write` 工具调用、Claude 通过 `Bash` 运行的脚本,或完全在 Claude Code 之外的进程。一个常见用途是在项目配置文件更改时重新加载环境变量。
3083 3092
3084此事件的 `matcher` 有两个角色:3093此事件的 `matcher` 有两个作用:
3085 3094
3086* **构建监视列表**:值在 `|` 上分割,每个段注册为工作目录中的字面文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里不有用:像 `^\.env` 这样的值会监视字面名为 `^\.env` 的文件。3095* **构建监视列表**:该值按 `|` 拆分,每个片段都被注册为工作目录中的字面文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里没有用处:像 `^\.env` 这样的值会监视一个字面名为 `^\.env` 的文件。
3087* **过滤哪些 hooks 运行**:当监视的文件更改时,相同的值使用标准 [匹配器规则](#matcher-patterns) 针对更改文件的基名过滤哪个 hook 组运行。3096* **过滤运行哪些 hook**:当被监视的文件发生更改时,同一个值会按照标准[匹配器规则](#matcher-patterns),针对已更改文件的基本名称过滤运行哪些 hook 组。
3088 3097
3089此示例在任何更改后规范化 `data.csv` 中的行结尾,包括 `Bash` 命令或外部脚本重写文件:3098以下示例会在 `data.csv` 发生任何更改后(包括 `Bash` 命令或外部脚本重写该文件)规范化其行尾:
3090 3099
3091```json theme={null}3100```json theme={null}
3092{3101{
3106}3115}
3107```3116```
3108 3117
3109hook 从 stdin 上的 [JSON 输入](#filechanged-input) 的 `file_path` 字段读取更改文件的绝对路径。其 `grep` 守卫测试与 `perl` 删除的相同内容,行末的 CR,因此规范化后的运行退出而不触及文件。更松散的守卫循环永远,因为 `perl -i` 重写文件,即使它替换了什么,Claude Code 在每次重写后运行 hook。将此脚本保存在 `/path/to/normalize-line-endings.sh` 并使其可执行:3118该 hook 从 stdin 上 [JSON 输入](#filechanged-input)的 `file_path` 字段读取已更改文件的绝对路径。它的 `grep` 守卫检查的正是 `perl` 要删除的内容,即行尾的 CR,因此规范化之后的那次运行会直接退出而不触碰文件。较宽松的守卫会导致无限循环,因为即使没有替换任何内容,`perl -i` 也会重写文件,而 Claude Code 在每次重写后都会再次运行该 hook。请将此脚本保存到 `/path/to/normalize-line-endings.sh` 并使其可执行:
3110 3119
3111```bash theme={null}3120```bash theme={null}
3112#!/bin/bash3121#!/bin/bash
3116fi3125fi
3117```3126```
3118 3127
3119要确认 hook 有效,要求 Claude 使用 `Bash` 命令将 CRLF 行附加到 `data.csv`。Claude Code 运行 hook,文件最终以 LF 结尾。3128要确认 hook 是否正常工作,请让 Claude 使用 `Bash` 命令向 `data.csv` 追加一行 CRLF。Claude Code 会运行该 hook,文件最终将使用 LF 行尾。
3120 3129
3121要监视您无法提前命名的文件,从 hook 返回 [`watchPaths`](#filechanged-output) 来动态更新监视列表。Claude Code 仅在某个东西命名要监视的文件时启动监视器,因此使用命名至少一个文件的 FileChanged 组为列表播种,或使用 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 返回 `watchPaths`。匹配器仍然过滤当监视的文件更改时哪个 hook 组运行,因此给处理动态路径的组一个省略的匹配器,它匹配每个监视的文件并不向监视列表添加任何内容。`"*"` 匹配器也匹配每个文件,但 Claude Code 像任何其他值一样在监视列表中注册它,作为字面名为 `*` 的文件。3130要监视无法预先命名的文件,请从 hook 返回 [`watchPaths`](#filechanged-output) 以动态更新监视列表。只有当有内容指定了要监视的文件时,Claude Code 才会启动监视器,因此请用一个匹配器至少指定了一个文件的 FileChanged 组,或一个返回 `watchPaths` 的 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 来初始化该列表。当被监视的文件发生更改时,匹配器仍会过滤运行哪些 hook 组,因此请为处理动态路径的组省略匹配器,这样它会匹配每个被监视的文件,且不会向监视列表添加任何内容。`"*"` 匹配器同样匹配每个文件,但 Claude Code 会像处理其他值一样将其注册到监视列表中,作为一个字面名为 `*` 的文件。
3122 3131
3123FileChanged hooks 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量持久化到后续 Bash 命令,直到下一个 [CwdChanged](#cwdchanged) 事件,当 Claude Code 清除它们时。3132FileChanged hook 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量会在后续 Bash 命令中持续有效,直到下一个 [CwdChanged](#cwdchanged) 事件时由 Claude Code 清除。
3124 3133
3125<h4 id="filechanged-input">3134<h4 id="filechanged-input">
3126 FileChanged 输入3135 FileChanged 输入
3127</h4>3136</h4>
3128 3137
3129除了 [常见输入字段](#common-input-fields) 外,FileChanged hooks 接收 `file_path` 和 `event`。3138除了[通用输入字段](#common-input-fields)之外,FileChanged hook 还会接收 `file_path` 和 `event`。
3130 3139
3131| 字段 | 描述 |3140| 字段 | 描述 |
3132| :- | :- |3141| :- | :- |
3133| `file_path` | 更改的文件的绝对路径 |3142| `file_path` | 已更改文件的绝对路径 |
3134| `event` | 发生了什么:修改文件为 `"change"`、创建的文件为 `"add"` 或删除的文件为 `"unlink"` |3143| `event` | 发生了什么:`"change"` 表示文件被修改,`"add"` 表示文件被创建,`"unlink"` 表示文件被删除 |
3135 3144
3136```json theme={null}3145```json theme={null}
3137{3146{
3148 FileChanged 输出3157 FileChanged 输出
3149</h4>3158</h4>
3150 3159
3151除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,FileChanged hooks 可以返回 `watchPaths` 来动态更新监视的文件路径:3160除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,FileChanged hook 还可以返回 `watchPaths`,以动态更新监视哪些文件路径:
3152 3161
3153| 字段 | 描述 |3162| 字段 | 描述 |
3154| :- | :- |3163| :- | :- |
3155| `watchPaths` | 绝对路径数组。替换当前动态监视列表。来自您 `matcher` 配置的路径始终被监视。当您的 hook 脚本根据更改的文件发现要监视的额外文件时使用此 |3164| `watchPaths` | 绝对路径数组。替换当前的动态监视列表。您的 `matcher` 配置中的路径始终会被监视。当您的 hook 脚本根据已更改的文件发现需要额外监视的文件时,请使用此字段 |
3156 3165
3157FileChanged hooks 没有决策控制。它们无法阻止文件更改发生。3166FileChanged hook 没有决策控制。它们无法阻止文件更改的发生。
3158 3167
3159Claude Code 从它们的 JSON 输出读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它显示 `systemMessage` 作为简短的终端通知。消息不到达 SDK 消息流。3168Claude Code 会从其 JSON 输出中读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它会将 `systemMessage` 显示为简短的终端通知。该消息不会进入 SDK 消息流。
3160 3169
3161<h3 id="worktreecreate">3170<h3 id="worktreecreate">
3162 WorktreeCreate3171 WorktreeCreate
3163</h3>3172</h3>
3164 3173
3165在创建 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。3174在创建 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 等其他版本控制系统。
3166 3175
3167因为 hook 完全替换默认行为,[`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees) 不被处理。如果您需要将本地配置文件(如 `.env`)复制到新 worktree,请在您的 hook 脚本内执行。3176由于该 hook 完全替换了默认行为,因此不会处理 [`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees)。如果您需要将 `.env` 等本地配置文件复制到新的 worktree 中,请在您的 hook 脚本中完成。
3168 3177
3169hook 必须返回创建的 worktree 目录的路径。Claude Code 使用此路径作为隔离会话的工作目录。有关每个 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。3178该 hook 必须返回所创建 worktree 目录的路径。Claude Code 将此路径用作隔离会话的工作目录。有关每种 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。
3170 3179
3171Claude Code 作用于 hook 的成功和返回的路径,并丢弃 `systemMessage` 和 `continue`。3180Claude Code 会根据 hook 的成功状态和返回的路径采取行动,并丢弃 `systemMessage` 和 `continue`。
3172 3181
3173此示例创建 SVN 工作副本并打印路径供 Claude Code 使用。将存储库 URL 替换为您自己的:3182以下示例创建一个 SVN 工作副本,并打印路径供 Claude Code 使用。请将仓库 URL 替换为您自己的 URL:
3174 3183
3175```json theme={null}3184```json theme={null}
3176{3185{
3189}3198}
3190```3199```
3191 3200
3192hook 从 stdin 上的 JSON 输入读取 worktree `name`,检出一个新副本到新目录,并打印目录路径。最后一行的 `echo` 是 Claude Code 读取为 worktree 路径的内容。将任何其他输出重定向到 stderr,以便它不干扰路径。3201该 hook 从 stdin 上的 JSON 输入中读取 worktree 的 `name`,将全新副本检出到新目录中,并打印目录路径。最后一行的 `echo` 就是 Claude Code 读取为 worktree 路径的内容。请将任何其他输出重定向到 stderr,以免干扰该路径。
3193 3202
3194<h4 id="worktreecreate-input">3203<h4 id="worktreecreate-input">
3195 WorktreeCreate 输入3204 WorktreeCreate 输入
3196</h4>3205</h4>
3197 3206
3198除了 [常见输入字段](#common-input-fields) 外,WorktreeCreate hooks 接收 `name` 字段。这是新 worktree 的 slug 标识符,由用户指定或自动生成,例如 `bold-oak-a3f2`。3207除了[通用输入字段](#common-input-fields)之外,WorktreeCreate hook 还会接收 `name` 字段。这是新 worktree 的 slug 标识符,由用户指定或自动生成,例如 `bold-oak-a3f2`。
3199 3208
3200```json theme={null}3209```json theme={null}
3201{3210{
3211 WorktreeCreate 输出3220 WorktreeCreate 输出
3212</h4>3221</h4>
3213 3222
3214WorktreeCreate hooks 不使用标准允许/阻止决策模型。相反,hook 的成功或失败确定结果。hook 必须返回创建的 worktree 目录的路径:3223WorktreeCreate hook 不使用标准的允许/阻止决策模型,而是由 hook 的成功或失败决定结果。hook 必须返回所创建的 worktree 目录的路径:
3215 3224
3216* **命令 hooks** (`type: "command"`):将路径打印为 stdout 的最后一个非空行。Claude Code 在读取该行之前剥离 ANSI 转义代码,因此在您的 `echo` 之前打印的 shell 启动横幅被忽略。将任何其他 hook 输出重定向到 stderr。3225* **命令 hook**(`type: "command"`):将路径作为 stdout 的最后一个非空行打印。Claude Code 在读取该行之前会去除 ANSI 转义码,因此在您的 `echo` 之前打印的 shell 启动横幅会被忽略。请将其他任何 hook 输出重定向到 stderr。
3217* **HTTP hooks** (`type: "http"`):在响应体中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。3226* **HTTP hook**(`type: "http"`):在响应体中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。
3218 3227
3219如果 hook 失败或产生无路径,worktree 创建失败并出现错误。3228如果 hook 失败或未生成路径,worktree 创建将失败并报错。
3220 3229
3221Claude Code 根据 hook 运行的目录解析相对路径,折叠其中的任何 `.` 或 `..` 段。如果结果路径不是 Claude Code 可以进入的目录,会话打印命名路径的错误并以代码 1 退出。3230Claude Code 会相对于 hook 运行所在的目录解析相对路径,并折叠其中的任何 `.` 或 `..` 段。如果解析得到的路径不是 Claude Code 可以进入的目录,会话会打印一条指明该路径的错误,并以代码 1 退出。
3222 3231
3223Claude Code 拒绝包含 `.` 或 `..` 段的绝对路径,以及通过存储库根下的符号链接的任何路径,因为提交到存储库的符号链接可能将 worktree 重定向到其外。错误命名被拒绝的组件。返回不通过存储库内符号链接的规范化路径。在 v2.1.216 之前,worktree 创建遵循 hook 的路径而不进行此筛选。3232Claude Code 会拒绝包含 `.` 或 `..` 段的绝对路径,以及任何经过仓库根目录下符号链接的路径,因为提交到仓库中的符号链接可能会将 worktree 重定向到仓库之外。错误信息会指明被拒绝的路径组成部分。请返回一个规范化的、不经过仓库内符号链接的路径。在 v2.1.216 之前,worktree 创建会直接采用 hook 返回的路径,不进行此项检查。
3224 3233
3225<h3 id="worktreeremove">3234<h3 id="worktreeremove">
3226 WorktreeRemove3235 WorktreeRemove
3227</h3>3236</h3>
3228 3237
3229在删除 worktree 时运行。这是 [WorktreeCreate](#worktreecreate) 的清理对应物。事件在以下情况下触发:3238在移除 worktree 时运行。这是 [WorktreeCreate](#worktreecreate) 对应的清理事件。该事件在以下情况下触发:
3230 3239
3231* 您退出 `--worktree` 会话并选择删除它3240* 您退出 `--worktree` 会话并选择将其移除
3232* 带有 `isolation: "worktree"` 的子 agent 完成3241* 设置了 `isolation: "worktree"` 的子代理完成
3233* 您删除 [后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes),其 worktree hook 创建3242* 您删除了一个[后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes),且其 worktree 由该 hook 创建
3234 3243
3235对于基于 git 的 worktrees,Claude Code 使用 `git worktree remove` 自动处理清理。如果您配置了 WorktreeCreate hook,将其与 WorktreeRemove hook 配对来控制它创建的 worktrees 的清理:3244对于基于 git 的 worktree,Claude Code 会使用 `git worktree remove` 自动处理清理。如果您配置了 WorktreeCreate hook,请搭配一个 WorktreeRemove hook,以控制其所创建的 worktree 的清理:
3236 3245
3237* **无 WorktreeRemove hook**:当您退出 `--worktree` 会话并选择删除时,Claude Code 回退到您的 WorktreeCreate hook 返回的路径上的 `git worktree remove --force`,因此 git 识别的 worktree 被删除。git 不识别的 worktree,例如您的 hook 使用非 git 版本控制系统创建的,保留在磁盘上。对于删除 [后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 对 hook 创建的 worktree 做什么,请参阅 agent view 的删除规则。3246* **没有 WorktreeRemove hook**:当您退出 `--worktree` 会话并选择移除时,Claude Code 会回退为对 WorktreeCreate hook 返回的路径执行 `git worktree remove --force`,因此 git 能识别的 worktree 会被移除。git 无法识别的 worktree(例如您的 hook 使用非 git 版本控制系统创建的 worktree)会保留在磁盘上。关于删除[后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes)时如何处理由 hook 创建的 worktree,请参阅 Agent 视图的删除规则。
3238* **Hook 退出 0**:worktree 计为已删除。Claude Code 从 hook 读取其他任何内容,因此确保您的 hook 删除了目录。3247* **Hook 以 0 退出**:该 worktree 视为已移除。Claude Code 不会从 hook 读取其他任何内容,因此请确保您的 hook 已删除该目录。
3239* **Hook 退出非零**:如果 `worktree_path` 处的目录在之后仍然存在,删除失败,worktree 保留在磁盘上,没有 git 回退。在退出非零前删除目录的 hook 计为已删除。对于失败如何报告,请参阅 [WorktreeRemove 输入](#worktreeremove-input)。3248* **Hook 以非零值退出**:如果 `worktree_path` 处的目录在之后仍然存在,则移除失败,worktree 保留在磁盘上,且不会回退到 git。在以非零值退出之前已删除目录的 hook 视为已移除。关于失败的报告方式,请参阅 [WorktreeRemove 输入](#worktreeremove-input)。
3240 3249
3241Claude Code 永远不删除属于 hook 创建的 worktree 的分支,因为它仅知道您的 WorktreeCreate hook 返回的路径。如果您的 WorktreeCreate hook 创建分支,在您的 WorktreeRemove hook 中删除它。3250Claude Code 从不删除属于 hook 创建的 worktree 的分支,因为它只知道您的 WorktreeCreate hook 返回的路径。如果您的 WorktreeCreate hook 创建了分支,请在 WorktreeRemove hook 中删除该分支。
3242 3251
3243Claude Code 丢弃 WorktreeRemove hook 的 [JSON 输出字段](#json-output),如 `systemMessage` 和 `continue`。3252Claude Code 会丢弃 WorktreeRemove hook 的 [JSON 输出字段](#json-output),例如 `systemMessage` 和 `continue`。
3244 3253
3245对于后台会话删除,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 在存储的路径上运行而不进行这些检查。3254对于后台会话的删除,Claude Code 会在运行 hook 之前验证存储的 worktree 路径,并拒绝本身是符号链接或经过仓库根目录下符号链接的路径。对于仍包含文件的 worktree,只有当您在 [Agent 视图](/docs/zh-CN/agent-view#what-deleting-a-session-removes)中确认删除时,hook 才会运行;对于这类 worktree,[`claude rm`](/docs/zh-CN/agent-view#manage-sessions-from-the-shell) 会保留会话和 worktree。在 v2.1.216 之前,hook 会直接在存储的路径上运行,不进行这些检查。
3246 3255
3247Claude Code 将 WorktreeCreate 返回的路径作为 `worktree_path` 在 hook 输入中传递。此示例读取该路径并删除目录:3256Claude Code 会将 WorktreeCreate 返回的路径作为 hook 输入中的 `worktree_path` 传入。以下示例读取该路径并删除该目录:
3248 3257
3249```json theme={null}3258```json theme={null}
3250{3259{
3267 WorktreeRemove 输入3276 WorktreeRemove 输入
3268</h4>3277</h4>
3269 3278
3270除了 [常见输入字段](#common-input-fields) 外,WorktreeRemove hooks 接收 `worktree_path` 字段,这是被删除的 worktree 的绝对路径。3279除[通用输入字段](#common-input-fields)外,WorktreeRemove hook 还会接收 `worktree_path` 字段,即正在移除的 worktree 的绝对路径。
3271 3280
3272```json theme={null}3281```json theme={null}
3273{3282{
3279}3288}
3280```3289```
3281 3290
3282WorktreeRemove hook 的退出代码决定结果。当 hook 退出非零且 `worktree_path` 处的目录在之后仍然存在时,删除失败:3291WorktreeRemove hook 的退出码决定结果。当 hook 以非零值退出且 `worktree_path` 处的目录之后仍然存在时,移除失败:
3283 3292
3284* worktree 保留在磁盘上,hook 的命令和 stderr 进入 [调试日志](#debug-hooks)。3293* worktree 保留在磁盘上,hook 的命令和 stderr 会写入[调试日志](#debug-hooks)。
3285* 如果您删除后台会话,会话也保留。[agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中的拒绝消息报告 hook 如何结束,如 `exited 1`,引用其 stderr 的开头,并说删除会话是否再次删除目录。3294* 如果您正在删除后台会话,该会话也会保留。[Agent 视图](/docs/zh-CN/agent-view#what-deleting-a-session-removes)中的拒绝消息会报告 hook 的结束方式(例如 `exited 1`),引用其 stderr 的开头部分,并说明再次删除该会话是否仍会移除该目录。
3286 3295
3287<h3 id="precompact">3296<h3 id="precompact">
3288 PreCompact3297 PreCompact
3289</h3>3298</h3>
3290 3299
3291在 Claude Code 即将运行压缩操作之前运行。3300在 Claude Code 即将执行压缩操作之前运行。
3292 3301
3293匹配器值指示压缩是手动还是自动触发:3302匹配器值表示压缩是手动触发还是自动触发:
3294 3303
3295| 匹配器 | 何时触发 |3304| 匹配器 | 触发时机 |
3296| :- | :- |3305| :- | :- |
3297| `manual` | `/compact` |3306| `manual` | `/compact` |
3298| `auto` | 当对话到达 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) 时自动压缩 |3307| `auto` | 对话达到[自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window)时的自动压缩 |
3299 3308
3300使用代码 2 退出以阻止压缩。对于手动 `/compact`,stderr 消息显示给用户。您也可以通过返回带有 `"decision": "block"` 的 JSON 来阻止。3309以代码 2 退出可阻止压缩。对于手动 `/compact`,stderr 消息会显示给用户。您也可以通过返回带有 `"decision": "block"` 的 JSON 来阻止。
3301 3310
3302阻止自动压缩有不同的效果,取决于它何时触发。如果压缩在上下文限制之前主动触发,Claude Code 跳过它,对话继续未压缩。如果压缩被触发以从 API 已经返回的上下文限制错误恢复,底层错误浮出并且当前请求失败。3311阻止自动压缩的效果取决于其触发时机。如果压缩是在达到上下文限制之前主动触发的,Claude Code 会跳过压缩,对话在未压缩的情况下继续。如果压缩是为了从 API 已返回的上下文限制错误中恢复而触发的,底层错误会显示出来,当前请求失败。
3303 3312
3304Claude Code 丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。3313Claude Code 会丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。
3305 3314
3306<h4 id="precompact-input">3315<h4 id="precompact-input">
3307 PreCompact 输入3316 PreCompact 输入
3308</h4>3317</h4>
3309 3318
3310除了 [常见输入字段](#common-input-fields) 外,PreCompact hooks 接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传递到 `/compact` 的内容,当他们不传递任何内容时为 `null`。对于 `auto`,`custom_instructions` 为 `null`。3319除[通用输入字段](#common-input-fields)外,PreCompact hook 还会接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传给 `/compact` 的内容,用户未传入任何内容时为 `null`。对于 `auto`,`custom_instructions` 为 `null`。
3311 3320
3312```json theme={null}3321```json theme={null}
3313{3322{
3324 PostCompact3333 PostCompact
3325</h3>3334</h3>
3326 3335
3327在 Claude Code 完成压缩操作后运行。使用此事件对新压缩状态做出反应,例如记录生成的摘要或更新外部状态。Claude Code 丢弃 PostCompact hook 的 `systemMessage` 和 `continue` 字段。3336在 Claude Code 完成压缩操作后运行。使用此事件对压缩后的新状态作出响应,例如记录生成的摘要或更新外部状态。Claude Code 会丢弃 PostCompact hook 的 `systemMessage` 和 `continue` 字段。
3328 3337
3329与 `PreCompact` 相同的匹配器值适用:3338适用与 `PreCompact` 相同的匹配器值:
3330 3339
3331| 匹配器 | 何时触发 |3340| 匹配器 | 触发时机 |
3332| :- | :- |3341| :- | :- |
3333| `manual` | 在 `/compact` 后 |3342| `manual` | `/compact` 之后 |
3334| `auto` | 当对话到达 [自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window) 时自动压缩后 |3343| `auto` | 对话达到[自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window)时的自动压缩之后 |
3335 3344
3336<h4 id="postcompact-input">3345<h4 id="postcompact-input">
3337 PostCompact 输入3346 PostCompact 输入
3338</h4>3347</h4>
3339 3348
3340除了 [常见输入字段](#common-input-fields) 外,PostCompact hooks 接收 `trigger` 和 `compact_summary`。`compact_summary` 字段包含压缩操作生成的对话摘要。3349除[通用输入字段](#common-input-fields)外,PostCompact hook 还会接收 `trigger` 和 `compact_summary`。`compact_summary` 字段包含压缩操作生成的对话摘要。
3341 3350
3342```json theme={null}3351```json theme={null}
3343{3352{
3350}3359}
3351```3360```
3352 3361
3353PostCompact hooks 没有决策控制。它们无法影响压缩结果,但可以执行后续任务。3362PostCompact hook 没有决策控制。它们无法影响压缩结果,但可以执行后续任务。
3354 3363
3355<h3 id="premodelswitch">3364<h3 id="premodelswitch">
3356 PreModelSwitch3365 PreModelSwitch
3357</h3>3366</h3>
3358 3367
3359在 Claude Code 应用您或客户端请求的模型切换之前运行。使用它来阻止切换、要求确认或在切换发生前显示成本。3368在 Claude Code 应用您或客户端请求的模型切换之前运行。可用于阻止切换、要求确认,或在切换发生前显示切换的成本。
3360 3369
3361PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 为这些请求运行它:3370PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 会针对以下请求运行它:
3362 3371
3363* `/model <name>` 和 `/model` 选择器3372* `/model <name>` 和 `/model` 选择器
3364* `Option+P` 或 `Alt+P` 模型选择器3373* `Option+P` 或 `Alt+P` 模型选择器
3365* `/config` 中的 Model 设置3374* `/config` 中的 Model 设置
3366* 当那改变会话的模型时打开 [fast mode](/docs/zh-CN/fast-mode)3375* 启用[快速模式](/docs/zh-CN/fast-mode)且这会改变会话的模型时
3367* 来自 [Agent SDK](/docs/zh-CN/agent-sdk/typescript#query-object) 主机或 [Remote Control](/docs/zh-CN/remote-control) 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改3376* 来自 [Agent SDK](/docs/zh-CN/agent-sdk/typescript#query-object) 宿主或 [Remote Control](/docs/zh-CN/remote-control) 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改
3368 3377
3369Claude Code 不为它自己进行的切换运行 PreModelSwitch hooks,如 [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback) 或恢复会话时恢复模型。这些更改仅到达 [PostModelSwitch](#postmodelswitch)。3378对于 Claude Code 自行进行的切换,例如[自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback)或在您恢复会话时恢复模型,Claude Code 不会运行 PreModelSwitch hook。这些更改只会触发 [PostModelSwitch](#postmodelswitch)。
3370 3379
3371Claude Code 根据会话切换到的模型的规范名称比较匹配器,忽略任何 `[1m]` 后缀。别名如 `opus`、日期模型 ID 和提供商特定 ID(如 Amazon Bedrock 模型 ID)都匹配它们解析到的一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的每个拼写。3380Claude Code 会将匹配器与会话要切换到的模型的规范名称进行比较,忽略任何 `[1m]` 后缀。别名(如 `opus`)、带日期的模型 ID 以及特定于提供商的 ID(如 Amazon Bedrock 模型 ID)都会匹配它们所解析到的同一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的所有写法。
3372 3381
3373当 Claude Code 无法确定目标的规范名称时,例如仅您的 [LLM gateway](/docs/zh-CN/llm-gateway) 知道的自定义模型 ID,它运行每个 PreModelSwitch hook,无论匹配器如何。阻止的 hook 应该从其输入检查 `to_model` 而不是仅依赖匹配器。3382当 Claude Code 无法确定目标的规范名称时,例如只有您的 [LLM 网关](/docs/zh-CN/llm-gateway)才知道的自定义模型 ID,它会运行所有 PreModelSwitch hook,无论匹配器如何。因此,执行阻止的 hook 应检查其输入中的 `to_model`,而不是仅依赖匹配器。
3374 3383
3375将匹配器写为精确名称、`|` 分隔列表如 `claude-opus-4-6|claude-opus-5` 或正则表达式如 `.*opus.*`。此示例使用精确名称匹配器并也从 hook 输入检查 `to_model`,因此它拒绝切换到 Opus 4.6,通过退出代码 2,并让任何其他目标通过:3384匹配器可以写为确切名称、以 `|` 分隔的列表(如 `claude-opus-4-6|claude-opus-5`),或正则表达式(如 `.*opus.*`)。以下示例使用确切名称匹配器,同时检查 hook 输入中的 `to_model`,因此它会通过以代码 2 退出来拒绝切换到 Opus 4.6,并允许切换到任何其他目标:
3376 3385
3377<Tabs>3386<Tabs>
3378 <Tab title="macOS/Linux">3387 <Tab title="macOS/Linux">
3379 命令使用 `jq` 检查 `to_model`:3388 该命令使用 `jq` 检查 `to_model`:
3380 3389
3381 ```json theme={null}3390 ```json theme={null}
3382 {3391 {
3398 </Tab>3407 </Tab>
3399 3408
3400 <Tab title="Windows (PowerShell)">3409 <Tab title="Windows (PowerShell)">
3401 注册一个命令 hook,通过 PowerShell 运行脚本:3410 注册一个通过 PowerShell 运行脚本的命令 hook:
3402 3411
3403 ```json theme={null}3412 ```json theme={null}
3404 {3413 {
3425 }3434 }
3426 ```3435 ```
3427 3436
3428 将此脚本保存到项目中的 `.claude/hooks/block-opus-46.ps1`:3437 将以下脚本保存到项目中的 `.claude/hooks/block-opus-46.ps1`:
3429 3438
3430 ```powershell theme={null}3439 ```powershell theme={null}
3431 $hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json3440 $hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
3438 </Tab>3447 </Tab>
3439</Tabs>3448</Tabs>
3440 3449
3441要确认 hook 有效,从运行不同模型的会话运行 `/model claude-opus-4-6`。Claude Code 保持当前模型并报告 PreModelSwitch hook 阻止了切换,以您的消息作为原因。3450要确认 hook 是否生效,请在运行其他模型的会话中运行 `/model claude-opus-4-6`。Claude Code 会保留当前模型,并报告 PreModelSwitch hook 阻止了切换,同时将您的消息作为原因。
3442 3451
3443<h4 id="premodelswitch-input">3452<h4 id="premodelswitch-input">
3444 PreModelSwitch 输入3453 PreModelSwitch 输入
3445</h4>3454</h4>
3446 3455
3447除了 [常见输入字段](#common-input-fields) 外,PreModelSwitch hooks 接收此表中的字段。最后五个描述重新发送对话到新模型的成本,因此 hook 可以在切换发生前显示该数字。3456除[通用输入字段](#common-input-fields)外,PreModelSwitch hook 还会接收下表中的字段。最后五个字段描述将对话重新发送给新模型的成本,以便 hook 在切换发生之前显示该数值。
3448 3457
3449| 字段 | 类型 | 描述 |3458| 字段 | 类型 | 描述 |
3450| :- | :- | :- |3459| :- | :- | :- |
3451| `from_model` | string | 切换改变的模型 ID |3460| `from_model` | string | 切换前的模型 ID |
3452| `to_model` | string | 切换改变到的模型 ID。匹配器根据此模型的规范名称比较 |3461| `to_model` | string | 切换后的模型 ID。匹配器与该模型的规范名称进行比较 |
3453| `requested_model` | string or `null` | 请求命名的模型:别名如 `opus`、完整模型 ID 或当请求是默认模型时为 `null` |3462| `requested_model` | string 或 `null` | 请求中指定的模型:别名(如 `opus`)、完整模型 ID,或在请求默认模型时为 `null` |
3454| `source` | string | 请求来自何处:`/model <name>`、`/config` 中的 Model 设置或打开 fast mode 的 `"command"`;模型选择器的 `"picker"`;来自 Agent SDK 主机或 Remote Control 的 `set_model` 请求或 `apply_flag_settings` 请求中的模型更改的 `"sdk"` |3463| `source` | string | 请求的来源:`"command"` 表示 `/model <name>`、`/config` 中的 Model 设置或启用快速模式;`"picker"` 表示模型选择器;`"sdk"` 表示来自 Agent SDK 宿主或 Remote Control 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改 |
3455| `context_tokens` | number | 下一个请求重新发送作为其提示的令牌:主对话中最后响应的输入、缓存读取、缓存创建和输出令牌,合并。第一个响应前为 `0` |3464| `context_tokens` | number | 下一个请求作为提示词重新发送的 token 数:主对话中最后一个响应的输入、缓存读取、缓存创建和输出 token 之和。在第一个响应之前为 `0` |
3456| `prompt_cache_warm` | boolean | 当前模型的 prompt cache 是否可能仍然温暖,意味着切换放弃它 |3465| `prompt_cache_warm` | boolean | 当前模型的提示缓存是否可能仍处于预热状态,即切换会使其失效 |
3457| `cache_ttl` | string | [Prompt cache 生命周期](/docs/zh-CN/prompt-caching#cache-lifetime) Claude Code 为此会话请求:`"5m"` 或 `"1h"` |3466| `cache_ttl` | string | Claude Code 为此会话请求的[提示缓存生命周期](/docs/zh-CN/prompt-caching#cache-lifetime):`"5m"` 或 `"1h"` |
3458| `estimated_cache_write_usd` | number | 在 `to_model` 上以 `cache_ttl` 速率将 `context_tokens` 写入 prompt cache 的估计成本(美元),不包括下一个响应。服务器可能不需要重新缓存整个上下文,因此将其视为估计 |3467| `estimated_cache_write_usd` | number | 以 `cache_ttl` 费率在 `to_model` 上将 `context_tokens` 写入提示缓存的估计成本(美元),不包括下一个响应。服务器可能无需重新缓存整个上下文,因此请将其视为估计值 |
3459| `pricing` | string | Claude Code 如何定价 `estimated_cache_write_usd`:当您的组织配置了自己的速率时为 `"configured"`,列表价格为 `"catalog"`,或当 `to_model` 没有已知价格且 Claude Code 假设默认速率时为 `"default"` |3468| `pricing` | string | Claude Code 为 `estimated_cache_write_usd` 定价的方式:`"configured"` 表示按您的组织已配置的自有费率,`"catalog"` 表示按标价,`"default"` 表示 `to_model` 没有已知价格,Claude Code 采用了默认费率 |
3460 3469
3461此示例显示了在运行 Sonnet 5 的会话中 `/model opus` 的输入:3470以下示例展示在运行 Sonnet 5 的会话中执行 `/model opus` 时的输入:
3462 3471
3463```json theme={null}3472```json theme={null}
3464{3473{
3482 PreModelSwitch 决策控制3491 PreModelSwitch 决策控制
3483</h4>3492</h4>
3484 3493
3485`PreModelSwitch` hooks 可以取消切换、要求用户确认或让它继续。退出代码 2 或顶级 `decision: "block"` 取消切换。3494`PreModelSwitch` hook 可以取消切换、请用户确认切换,或允许切换继续。退出码 2 或顶层的 `decision: "block"` 会取消切换。
3486 3495
3487为了更精细的控制,在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,如 [PreToolUse](#pretooluse-decision-control)。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述两个字段:3496如需更精细的控制,请在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,与 [PreToolUse](#pretooluse-decision-control) 相同。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述这两个字段:
3488 3497
3489| 字段 | 描述 |3498| 字段 | 描述 |
3490| :- | :- |3499| :- | :- |
3491| `permissionDecision` | `"allow"` 继续并跳过 [Claude Code 在 prompt cache 温暖时显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户确认它 |3500| `permissionDecision` | `"allow"` 继续切换,并跳过[提示缓存处于预热状态时 Claude Code 显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户进行确认 |
3492| `permissionDecisionReason` | 对于 `"deny"`,显示给用户作为切换被阻止的原因,或作为 `set_model` 请求的错误返回。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 被忽略 |3501| `permissionDecisionReason` | 对于 `"deny"`,作为切换被阻止的原因显示给用户,或作为 `set_model` 请求的错误返回。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 则被忽略 |
3493 3502
3494仅交互式会话中的 `/model` 可以显示 `"ask"` 提示。在每个其他表面,包括带有 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 将 `"ask"` 视为拒绝。3503只有交互式会话中的 `/model` 才能显示 `"ask"` 提示。在其他所有使用入口上,包括使用 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 都会将 `"ask"` 视为拒绝。
3495 3504
3496此示例要求用户确认并引用来自 `context_tokens` 的令牌计数:3505以下示例请用户确认,并引用 `context_tokens` 中的 token 数:
3497 3506
3498```json theme={null}3507```json theme={null}
3499{3508{
3505}3514}
3506```3515```
3507 3516
3508当多个 PreModelSwitch hooks 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。3517当多个 PreModelSwitch hook 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。
3509 3518
3510Claude Code 显示用户您的 hook 返回的任何 `systemMessage`,无论决策如何,因此成本报告 hook 可以返回 `{"systemMessage": "..."}` 并退出 0。3519无论决策如何,Claude Code 都会向用户显示 hook 返回的任何 `systemMessage`,因此成本报告 hook 可以返回 `{"systemMessage": "..."}` 并以 0 退出。
3511 3520
3512在其超时前不响应的 PreModelSwitch hook 阻止切换。在 [PreToolUse](#timeouts) 上,相比之下,超时的命令 hook 让工具调用继续。此事件的默认超时为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hooks,因此 `prompt` 和 `agent` 默认不适用。3521在超时前未响应的 PreModelSwitch hook 会阻止切换。相比之下,在 [PreToolUse](#timeouts) 上,超时的命令 hook 会让工具调用继续。此事件的默认超时时间为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hook,因此 `prompt` 和 `agent` 的默认值不适用。
3513 3522
3514退出代码不是 0 或 2 且打印无 JSON 决策的 hook 不阻止:Claude Code 显示其 stderr 并应用切换,如 [其他退出代码](#other-exit-codes) 下所述。3523以 0 或 2 以外的代码退出且未打印 JSON 决策的 hook 不会阻止切换:Claude Code 会显示其 stderr 并应用切换,如[其他退出码](#other-exit-codes)中所述。
3515 3524
3516<h3 id="postmodelswitch">3525<h3 id="postmodelswitch">
3517 PostModelSwitch3526 PostModelSwitch
3518</h3>3527</h3>
3519 3528
3520在会话的模型更改后运行。使用它来给 Claude 模型特定的指导,而不编辑每个 CLAUDE.md,例如仅在某些模型上适用的组织范围指令。3529在会话的模型更改后运行。可用于向 Claude 提供特定于模型的指导,而无需编辑每个 CLAUDE.md,例如适用于某些模型的组织级指令。
3521 3530
3522PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。Claude Code 在这些更改后运行 PostModelSwitch hooks:3531PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。Claude Code 会在以下任何更改后运行 PostModelSwitch hook:
3523 3532
3524* 您或客户端请求的切换3533* 您或客户端请求的切换
3525* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),改变会话的模型3534* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),它会更改会话的模型
3526* 设置如 [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting) 进入或离开 plan mode3535* [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting) 等设置在进入或退出计划模式时
3527* Claude Code 恢复会话时恢复模型3536* 您恢复会话时 Claude Code 恢复模型
3528 3537
3529当 [回退模型链](/docs/zh-CN/model-config#fallback-model-chains) 中的模型服务回合时,Claude Code 不运行 PostModelSwitch hooks,因为该替换持续一个回合并保持会话的模型不变。3538当[备用模型链](/docs/zh-CN/model-config#fallback-model-chains)中的模型为某一轮次提供服务时,Claude Code 不会运行 PostModelSwitch hook,因为这种替换只持续一轮,会话的模型保持不变。
3530 3539
3531匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 根据会话切换到的模型的规范名称比较它。3540匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 将其与会话所切换到的模型的规范名称进行比较。
3532 3541
3533此示例在会话的模型更改为任何 Opus 模型时添加指导:3542以下示例在会话的模型更改为任何 Opus 模型时添加指导:
3534 3543
3535```json theme={null}3544```json theme={null}
3536{3545{
3550}3559}
3551```3560```
3552 3561
3553要确认 hook 有效,从运行不同模型的会话切换到 Opus 模型,例如从 Sonnet 会话运行 `/model opus`,然后要求 Claude 关于当前模型的指导。3562要确认 hook 是否生效,请在运行其他模型的会话中切换到 Opus 模型,例如在 Sonnet 会话中运行 `/model opus`,然后询问 Claude 它对当前模型有哪些指导。
3554 3563
3555<h4 id="postmodelswitch-input">3564<h4 id="postmodelswitch-input">
3556 PostModelSwitch 输入3565 PostModelSwitch 输入
3557</h4>3566</h4>
3558 3567
3559PostModelSwitch hooks 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,`hook_event_name` 设置为 `"PostModelSwitch"` 和两个更多 `source` 值:`"auto"` 对于自动回退或 Claude Code 自己进行的其他更改,`"resume"` 对于恢复会话时恢复的模型。3568PostModelSwitch hook 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,其中 `hook_event_name` 设置为 `"PostModelSwitch"`,并增加两个 `source` 值:`"auto"` 表示自动回退或 Claude Code 自行进行的其他更改,`"resume"` 表示您恢复会话时恢复的模型。
3560 3569
3561当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 恢复的保存模型设置。3570当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 恢复的已保存模型设置。
3562 3571
3563<h4 id="postmodelswitch-decision-control">3572<h4 id="postmodelswitch-decision-control">
3564 PostModelSwitch 决策控制3573 PostModelSwitch 决策控制
3565</h4>3574</h4>
3566 3575
3567Claude Code 获取您的 hook 在退出 0 时的 [纯文本 stdout](#exit-code-0),或来自 JSON 输出的 `additionalContext`,并在切换后的下一个请求中将其传递给 Claude。除了所有 hooks 可用的 [JSON 输出字段](#json-output) 外,您可以返回:3576Claude Code 会在退出码为 0 时获取 hook 的[纯文本 stdout](#exit-code-0),或获取 JSON 输出中的 `additionalContext`,并在切换后随下一个请求将其传递给 Claude。除所有 hook 均可用的 [JSON 输出字段](#json-output)外,您还可以返回:
3568 3577
3569| 字段 | 描述 |3578| 字段 | 描述 |
3570| :- | :- |3579| :- | :- |
3571| `additionalContext` | 与下一个请求一起添加到 Claude 上下文的字符串。有关如何传递文本以及放入其中的内容,请参阅 [为 Claude 添加上下文](#add-context-for-claude) |3580| `additionalContext` | 随下一个请求添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
3572 3581
3573如果 hook 在您发送下一个提示后五秒内未完成,Claude Code 发送该请求而不输出,并将其附加到以下请求。如果模型在下一个请求之前更改多次,Claude Code 仅传递最后一个切换目标模型的输出。3582如果在您发送下一个提示词后五秒内 hook 仍未完成,Claude Code 会在不含该输出的情况下发送该请求,并改为将输出附加到再下一个请求。如果模型在下一个请求之前更改了多次,Claude Code 只会传递最后一次切换的目标模型对应的输出。
3574 3583
3575<h3 id="sessionend">3584<h3 id="sessionend">
3576 SessionEnd3585 SessionEnd
3577</h3>3586</h3>
3578 3587
3579在 Claude Code 会话结束时运行。对于清理任务、记录会话统计或保存会话状态很有用。支持匹配器以按退出原因过滤。3588在 Claude Code 会话结束时运行。适用于清理任务、记录会话
3589统计信息或保存会话状态。支持使用匹配器按退出原因进行筛选。
3580 3590
3581`reason` 字段在 hook 输入中指示会话为什么结束:3591hook 输入中的 `reason` 字段表示会话结束的原因:
3582 3592
3583| 原因 | 描述 |3593| 原因 | 描述 |
3584| :- | :- |3594| :- | :- |
3585| `clear` | 会话使用 `/clear` 命令清除 |3595| `clear` | 使用 `/clear` 命令清除了会话 |
3586| `resume` | 会话通过交互式 `/resume` 切换 |3596| `resume` | 通过交互式 `/resume` 切换了会话 |
3587| `logout` | 用户登出 |3597| `logout` | 用户已注销 |
3588| `prompt_input_exit` | 用户在提示输入可见时退出 |3598| `prompt_input_exit` | 用户在输入框可见时退出 |
3589| `other` | 其他退出原因 |3599| `other` | 其他退出原因 |
3590| `bypass_permissions_disabled` | 在 v2.1.234 中删除;Claude Code 不发送它。从您的 `SessionEnd` 匹配器中删除它 |3600| `bypass_permissions_disabled` | 已在 v2.1.234 中移除;Claude Code 不再发送此值。请将其从您的 `SessionEnd` 匹配器中删除 |
3591 3601
3592<h4 id="sessionend-input">3602<h4 id="sessionend-input">
3593 SessionEnd 输入3603 SessionEnd 输入
3594</h4>3604</h4>
3595 3605
3596除了 [常见输入字段](#common-input-fields) 外,SessionEnd hooks 接收指示会话为什么结束的 `reason` 字段。有关所有值,请参阅上面的 [原因表](#sessionend)。3606除[通用输入字段](#common-input-fields)外,SessionEnd hook 还会接收表示会话结束原因的 `reason` 字段。有关所有取值,请参阅上方的[原因表](#sessionend)。
3597 3607
3598```json theme={null}3608```json theme={null}
3599{3609{
3605}3615}
3606```3616```
3607 3617
3608SessionEnd hooks 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 丢弃它们的 [JSON 输出字段](#json-output),如 `systemMessage`。3618SessionEnd hook 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 会丢弃它们的 [JSON 输出字段](#json-output),例如 `systemMessage`。
3609 3619
3610SessionEnd hooks 的默认超时为 1.5 秒。它在您退出、运行 `/clear` 或使用交互式 `/resume` 切换会话时适用。您可以通过两种方式给 hook 更多时间:3620SessionEnd hook 的默认超时时间为 1.5 秒。它适用于您退出、运行 `/clear` 或通过交互式 `/resume` 切换会话时。您可以通过两种方式为 hook 提供更多时间:
3611 3621
3612* **每个 hook `timeout`**:在该 hook 的配置中设置 `timeout`。总体预算自动上升以匹配您的设置文件中最高的每个 hook `timeout`,最多 60 秒。如果您以这种方式提高预算,没有自己的 `timeout` 的 hook 仍然保持默认。在插件提供的 hooks 上设置的超时不提高预算。3622* **单个 hook 的 `timeout`**:在该 hook 的配置中设置 `timeout`。总体时间预算会自动提高,以匹配您的设置文件中最大的单个 hook `timeout`,最长 60 秒。如果以这种方式提高预算,未设置自身 `timeout` 的 hook 仍保持默认值。在插件提供的 hook 上设置的超时时间不会提高预算。
3613* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:设置此环境变量(毫秒)以显式覆盖预算。您设置的值也成为每个没有自己的 `timeout` 的 hook 的超时。3623* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:以毫秒为单位设置此环境变量,以显式覆盖预算。您设置的值也会成为每个未设置自身 `timeout` 的 hook 的超时时间。
3614 3624
3615此示例将预算设置为 5 秒:3625以下示例将预算设置为 5 秒:
3616 3626
3617```bash theme={null}3627```bash theme={null}
3618CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude3628CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
3619```3629```
3620 3630
3621在 v2.1.268 之前,`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 仅提高总体预算,没有自己的 `timeout` 的 hook 仍然在 1.5 秒后被取消。3631在 v2.1.268 之前,`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 只会提高总体预算,未设置自身 `timeout` 的 hook 仍会在 1.5 秒后被取消。
3622 3632
3623<h3 id="elicitation">3633<h3 id="elicitation">
3624 Elicitation3634 Elicitation
3625</h3>3635</h3>
3626 3636
3627在 MCP 服务器请求用户输入中任务时运行。默认情况下,Claude Code 显示交互式对话供用户响应。Hooks 可以拦截此请求并以编程方式响应,完全跳过对话。3637在 MCP 服务器于任务执行过程中请求用户输入时运行。默认情况下,Claude Code 会显示一个交互式对话框供用户响应。hook 可以拦截此请求并以编程方式响应,完全跳过对话框。
3628 3638
3629匹配器字段根据 MCP 服务器名称匹配。3639matcher 字段与 MCP 服务器名称进行匹配。
3630 3640
3631<h4 id="elicitation-input">3641<h4 id="elicitation-input">
3632 Elicitation 输入3642 Elicitation 输入
3633</h4>3643</h4>
3634 3644
3635除了 [常见输入字段](#common-input-fields) 外,Elicitation hooks 接收 `mcp_server_name`、`message` 和可选的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 字段。3645除[通用输入字段](#common-input-fields)外,Elicitation hook 还会接收 `mcp_server_name`、`message`,以及可选的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 字段。
3636 3646
3637对于表单模式引出,最常见的情况:3647对于表单模式的 elicitation(最常见的情况):
3638 3648
3639```json theme={null}3649```json theme={null}
3640{3650{
3654}3664}
3655```3665```
3656 3666
3657对于 URL 模式引出,用于基于浏览器的身份验证:3667对于 URL 模式的 elicitation(用于基于浏览器的身份验证):
3658 3668
3659```json theme={null}3669```json theme={null}
3660{3670{
3673 Elicitation 输出3683 Elicitation 输出
3674</h4>3684</h4>
3675 3685
3676要以编程方式响应而不显示对话,返回一个带有 `hookSpecificOutput` 的 JSON 对象:3686要在不显示对话框的情况下以编程方式响应,请返回带有 `hookSpecificOutput` 的 JSON 对象:
3677 3687
3678```json theme={null}3688```json theme={null}
3679{3689{
3687}3697}
3688```3698```
3689 3699
3690| 字段 | 值 | 描述 |3700| 字段 | 取值 | 描述 |
3691| :- | :- | :- |3701| :- | :- | :- |
3692| `action` | `accept`、`decline`、`cancel` | 是否接受、拒绝或取消请求 |3702| `action` | `accept`、`decline`、`cancel` | 接受、拒绝还是取消该请求 |
3693| `content` | object | 要提交的表单字段值。仅在 `action` 为 `accept` 时使用 |3703| `content` | object | 要提交的表单字段值。仅在 `action` 为 `accept` 时使用 |
3694 3704
3695退出代码 2 拒绝引出。Claude Code 不在任何地方显示您的 stderr 消息。3705退出码 2 会拒绝该 elicitation。Claude Code 不会在任何地方显示您的 stderr 消息。
3696 3706
3697Claude Code 作用于 Elicitation hook 的 JSON 输出中的 `hookSpecificOutput` 并丢弃 `systemMessage` 和 `continue`。3707Claude Code 会处理 Elicitation hook JSON 输出中的 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。
3698 3708
3699<h3 id="elicitationresult">3709<h3 id="elicitationresult">
3700 ElicitationResult3710 ElicitationResult
3701</h3>3711</h3>
3702 3712
3703在用户响应 MCP 引出后运行。Hooks 可以观察、修改或阻止响应,然后将其发送回 MCP 服务器。3713在用户响应 MCP elicitation 后运行。hook 可以在响应发回 MCP 服务器之前观察、修改或阻止该响应。
3704 3714
3705匹配器字段根据 MCP 服务器名称匹配。3715matcher 字段与 MCP 服务器名称进行匹配。
3706 3716
3707<h4 id="elicitationresult-input">3717<h4 id="elicitationresult-input">
3708 ElicitationResult 输入3718 ElicitationResult 输入
3709</h4>3719</h4>
3710 3720
3711除了 [常见输入字段](#common-input-fields) 外,ElicitationResult hooks 接收 `mcp_server_name`、`action` 和可选的 `mode`、`elicitation_id` 和 `content` 字段。3721除[通用输入字段](#common-input-fields)外,ElicitationResult hook 还会接收 `mcp_server_name`、`action`,以及可选的 `mode`、`elicitation_id` 和 `content` 字段。
3712 3722
3713```json theme={null}3723```json theme={null}
3714{3724{
3728 ElicitationResult 输出3738 ElicitationResult 输出
3729</h4>3739</h4>
3730 3740
3731要覆盖用户的响应,返回一个带有 `hookSpecificOutput` 的 JSON 对象:3741要覆盖用户的响应,请返回带有 `hookSpecificOutput` 的 JSON 对象:
3732 3742
3733```json theme={null}3743```json theme={null}
3734{3744{
3740}3750}
3741```3751```
3742 3752
3743| 字段 | 值 | 描述 |3753| 字段 | 取值 | 描述 |
3744| :- | :- | :- |3754| :- | :- | :- |
3745| `action` | `accept`、`decline`、`cancel` | 覆盖用户的操作 |3755| `action` | `accept`、`decline`、`cancel` | 覆盖用户的操作 |
3746| `content` | object | 覆盖表单字段值。仅在 `action` 为 `accept` 时有意义 |3756| `content` | object | 覆盖表单字段值。仅在 `action` 为 `accept` 时有意义 |
3747 3757
3748退出代码 2 阻止响应,将有效操作更改为 `decline`。Claude Code 不在任何地方显示您的 stderr 消息。3758退出码 2 会阻止该响应,将实际生效的操作更改为 `decline`。Claude Code 不会在任何地方显示您的 stderr 消息。
3749 3759
3750Claude Code 作用于 ElicitationResult hook 的 JSON 输出中的 `hookSpecificOutput` 并丢弃 `systemMessage` 和 `continue`。3760Claude Code 会处理 ElicitationResult hook JSON 输出中的 `hookSpecificOutput`,并丢弃 `systemMessage` 和 `continue`。
3751 3761
3752<h2 id="prompt-based-hooks">3762<h2 id="prompt-based-hooks">
3753 基于提示的 hooks3763 基于提示的 hooks