827 827
828hook 的退出码告诉 Claude Code 是否继续执行触发该 hook 的操作,例如工具调用或提示词。运行结束时有以下三种结果之一:828hook 的退出码告诉 Claude Code 是否继续执行触发该 hook 的操作,例如工具调用或提示词。运行结束时有以下三种结果之一:
829 829
830* **成功**:hook 以 0 退出。Claude Code 应用 hook 打印的任何 [JSON 输出](#json-output)字段,除非这些字段阻止或拒绝该操作,否则操作继续进行。830* **成功**:hook 以 0 退出。Claude Code 应用 hook 打印的任何 [JSON 输出](#json-output)字段,除非这些字段阻止或拒绝该操作,否则操作继续进行。[启动后台进程的 hook](#hooks-that-start-a-background-process) 介绍了例外情况。
831* **阻止错误**:hook 以 2 退出。在[可以阻止的事件](#exit-code-2-behavior-per-event)上,Claude Code 停止该操作。831* **阻止错误**:hook 以 2 退出。在[可以阻止的事件](#exit-code-2-behavior-per-event)上,Claude Code 停止该操作。
832* **非阻止错误**:hook 以任何其他代码退出,或以其他方式失败,例如无法启动或打印无效 JSON。操作继续进行,在 `PreToolUse` 等事件上,您会在会话记录中看到 `<hook name> hook error` 通知。如果希望失败的 hook 阻止操作,请设置 [`onFailure: "block"`](#block-the-action-when-a-hook-fails)。832* **非阻止错误**:hook 以任何其他代码退出,或以其他方式失败,例如无法启动或打印无效 JSON。操作继续进行,在 `PreToolUse` 等事件上,您会在会话记录中看到 `<hook name> hook error` 通知。如果希望失败的 hook 阻止操作,请设置 [`onFailure: "block"`](#block-the-action-when-a-hook-fails)。
833 833
932* 超时的 `command`、`http` 或 `mcp_tool` hook 不阻止工具调用。调用通过正常[权限流程](/docs/zh-CN/permissions)继续,因此不要指望停滞的 hook 充当关卡。要在 `command` 或 `http` hook 超时时阻止调用,请设置 [`onFailure: "block"`](#block-the-action-when-a-hook-fails)。932* 超时的 `command`、`http` 或 `mcp_tool` hook 不阻止工具调用。调用通过正常[权限流程](/docs/zh-CN/permissions)继续,因此不要指望停滞的 hook 充当关卡。要在 `command` 或 `http` hook 超时时阻止调用,请设置 [`onFailure: "block"`](#block-the-action-when-a-hook-fails)。
933* 超过其超时时间的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 会[阻止工具调用](#pretooluse)。933* 超过其超时时间的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 会[阻止工具调用](#pretooluse)。
934 934
935<h4 id="hooks-that-start-a-background-process">
936 启动后台进程的 hook
937</h4>
938
939如果您的命令 hook 在后台进程中做出决策然后退出,那么该进程在 Claude Code 停止读取之后打印的拒绝决策不会阻止工具调用。对于非[异步](#run-hooks-in-the-background)的 hook,Claude Code 会在 hook 自身进程退出后不久完成对 hook 输出的读取。
940
941请在启动后台进程之前打印决策,并重定向该进程的 stdout 和 stderr。如果您的脚本打印了允许决策,然后启动后台进程且未重定向该进程的 stdout 和 stderr,Claude Code 会阻止该工具调用。hook 错误中包含 `refusing to honor the suspect capture`。
942
943此 `PreToolUse` hook 脚本通过 `policy-check.sh` 打印决策,然后在后台上传指标:
944
945```bash theme={null}
946#!/bin/bash
947"$CLAUDE_PROJECT_DIR"/.claude/hooks/policy-check.sh || exit $?
948"$CLAUDE_PROJECT_DIR"/.claude/hooks/upload-metrics.sh >/dev/null 2>&1 &
949```
950
951脚本的其余部分作用如下:
952
953* **`|| exit $?`**:使检查的退出码成为 hook 自身的退出码,因此以 2 退出以表示拒绝的检查仍会阻止。否则 hook 会以最后一行的退出码退出,即 0。
954* **`>/dev/null 2>&1 &`**:在后台运行 `upload-metrics.sh` 并重定向其输出,使其不会让 hook 的输出保持打开状态。
955
956要测试该脚本,请让 `policy-check.sh` 以 2 退出,然后触发一个与该 hook 匹配的工具调用。该工具调用会被阻止。
957
935<h4 id="block-the-action-when-a-hook-fails">958<h4 id="block-the-action-when-a-hook-fails">
936 hook 失败时阻止操作959 hook 失败时阻止操作
937</h4>960</h4>
1245 Hook 事件1268 Hook 事件
1246</h2>1269</h2>
1247 1270
1248每个事件都对应 Claude Code 生命周期中可以运行 hook 的一个时间点。以下各节按照生命周期的顺序排列:从会话设置,到智能体循环,再到会话结束。每一节都会说明事件何时触发、支持哪些匹配器、接收的 JSON 输入,以及如何通过输出控制行为。1271每个事件对应 Claude Code 生命周期中可以运行 hook 的一个时间点。以下各节按生命周期顺序排列:从会话设置,经过智能体循环,直到会话结束。每节说明事件何时触发、支持哪些匹配器、接收的 JSON 输入,以及如何通过输出控制行为。
1249 1272
1250<h3 id="sessionstart">1273<h3 id="sessionstart">
1251 SessionStart1274 SessionStart
1252</h3>1275</h3>
1253 1276
1254在 Claude Code 启动新会话或恢复现有会话时运行。适用于加载开发上下文(例如现有问题或代码库的最近更改),或设置环境变量。对于不需要脚本的静态上下文,请改用 [CLAUDE.md](/docs/zh-CN/memory)。1277在 Claude Code 启动新会话或恢复现有会话时运行。适用于加载开发上下文,例如现有 issue 或代码库的近期变更,或者设置环境变量。对于不需要脚本的静态上下文,请改用 [CLAUDE.md](/docs/zh-CN/memory)。
1255 1278
1256SessionStart 在每个会话中都会运行,因此请确保这些 hook 运行迅速。仅支持 `type: "command"` 和 `type: "mcp_tool"` hook。关于 `mcp_tool` hook 何时运行,请参阅 [MCP 工具 hook 字段](#mcp-tool-hook-fields)。1279SessionStart 在每个会话中都会运行,因此请让这些 hook 保持快速。仅支持 `type: "command"` 和 `type: "mcp_tool"` hook。有关 `mcp_tool` hook 何时运行,请参阅 [MCP 工具 hook 字段](#mcp-tool-hook-fields)。
1257 1280
1258匹配器的值对应会话的启动方式:1281匹配器的值对应会话的启动方式:
1259 1282
1263| `resume` | `--resume`、`--continue` 或 `/resume` |1286| `resume` | `--resume`、`--continue` 或 `/resume` |
1264| `clear` | `/clear` |1287| `clear` | `/clear` |
1265| `compact` | 自动或手动压缩 |1288| `compact` | 自动或手动压缩 |
1266| `fork` | 从现有会话分叉出的新会话:与 `--resume` 或 `--continue` 一起使用的 `--fork-session`、`/fork` 后台副本、`/branch`,或您[移至后台](/docs/zh-CN/agent-view#from-inside-a-session)的对话 |1289| `fork` | 从现有会话派生出的新会话:`--fork-session` 与 `--resume` 或 `--continue` 一起使用、`/fork` 后台副本、`/branch`,或您[移到后台](/docs/zh-CN/agent-view#from-inside-a-session)的对话 |
1267 1290
1268在 v2.1.214 之前,分叉的会话报告的 source 为 `"resume"`。1291在 v2.1.214 之前,派生的会话报告的 source 为 `"resume"`。
1269 1292
1270当您启动交互式会话、在启动时使用 `--continue` 或 `--resume` 恢复对话,或运行 `/clear` 时,SessionStart hook 会在后台运行。您可以立即开始输入,恢复的对话也会直接显示,无需等待 hook。Claude 的第一次回复仍会等待 hook 完成,以便其上下文能传达给 Claude。1293当您启动交互式会话、在启动时使用 `--continue` 或 `--resume` 恢复对话,或运行 `/clear` 时,SessionStart hook 会在后台运行。您可以立即输入,恢复的对话也会直接显示,无需等待 hook。Claude 的第一次回复仍会等待 hook 完成,以便它们的上下文能够传达给 Claude。
1271 1294
1272当您在会话内使用 `/resume` 切换对话时,切换操作则会等待 hook 完成。如果您在后台 hook 仍在运行时运行 `/clear` 或切换到另一个对话,它们返回的任何内容都不会应用到该会话。1295当您在会话中使用 `/resume` 切换对话时,切换操作则会等待 hook 完成。如果您在后台 hook 仍在运行时运行 `/clear` 或切换到其他对话,它们返回的任何内容都不会应用到该会话。
1273 1296
1274启动时(包括恢复的会话)也存在同样的等待:在 SessionStart hook 仍在运行时发送的提示词,要等它们完成后才会传达给 Claude。1297启动时(包括恢复的会话)也有同样的等待:在 SessionStart hook 仍在运行时发送的提示词,要等它们完成后才会传达给 Claude。
1275 1298
1276在任一种等待期间,按 `Esc` 可将提示词收回输入框而不发送。hook 会继续运行。1299在任一等待期间,按 `Esc` 可将提示词取回到输入框而不发送。hook 会继续运行。
1277 1300
1278<h4 id="sessionstart-input">1301<h4 id="sessionstart-input">
1279 SessionStart 输入1302 SessionStart 输入
1281 1304
1282除[通用输入字段](#common-input-fields)外,SessionStart hook 还会接收 `source`,以及可选的 `model`、`agent_type` 和 `session_title`:1305除[通用输入字段](#common-input-fields)外,SessionStart hook 还会接收 `source`,以及可选的 `model`、`agent_type` 和 `session_title`:
1283 1306
1284| 字段 | 描述 |1307| 字段 | 说明 |
1285| :- | :- |1308| :- | :- |
1286| `source` | 会话的启动方式:新会话为 `"startup"`,恢复的会话为 `"resume"`,`/clear` 之后为 `"clear"`,压缩之后为 `"compact"`,从现有会话分叉出的新会话为 `"fork"` |1309| `source` | 会话的启动方式:新会话为 `"startup"`,恢复的会话为 `"resume"`,`/clear` 之后为 `"clear"`,压缩之后为 `"compact"`,从现有会话派生出的新会话为 `"fork"` |
1287| `model` | 当前活动模型的标识符。该字段可能缺失,例如在 `/clear` 之后或通过对话恢复还原会话时,因此请在读取前检查该字段是否存在 |1310| `model` | 当前模型标识符。该字段可能被省略,例如在 `/clear` 之后,或通过对话恢复还原会话时,因此读取前请先检查该字段是否存在 |
1288| `agent_type` | Agent 名称,当您使用 `claude --agent <name>` 启动 Claude Code 时存在 |1311| `agent_type` | Agent 名称,当您使用 `claude --agent <name>` 启动 Claude Code 时存在 |
1289| `session_title` | 会话的自定义标题,在已设置时存在,例如通过 `--name`、`/rename`、hook 的 `sessionTitle` 输出或 Agent SDK 的 `renameSession()` 设置。输出 `sessionTitle` 的 hook 可以先检查此字段,以避免覆盖现有的自定义标题 |1312| `session_title` | 会话的自定义标题,在已设置时存在,例如通过 `--name`、`/rename`、hook 的 `sessionTitle` 输出或 Agent SDK 的 `renameSession()` 设置。输出 `sessionTitle` 的 hook 可以先检查此字段,以避免覆盖已有的自定义标题 |
1290 1313
1291未命名的会话仍可能有一个[自动生成的标题](/docs/zh-CN/sessions#name-your-sessions)。该标题不是自定义标题,不会出现在 `session_title` 中。1314未命名的会话仍可能有[自动生成的标题](/docs/zh-CN/sessions#name-your-sessions)。该标题不是自定义标题,不会出现在 `session_title` 中。
1292 1315
1293当 `source` 为 `"resume"` 或 `"fork"`,且会话记录中至少包含一条 Claude 的回复时,SessionStart hook 还会接收下面四个字段。您的 hook 可以利用它们在第一个请求之前报告恢复一个陈旧对话的成本,例如通过 [`systemMessage`](#json-output)。这些字段需要 Claude Code v2.1.251 或更高版本。1316当 `source` 为 `"resume"` 或 `"fork"` 且会话记录中至少包含一条 Claude 的回复时,SessionStart hook 还会接收以下四个字段。您的 hook 可以使用它们在第一次请求之前报告恢复一个陈旧对话的成本,例如通过 [`systemMessage`](#json-output)。这些字段需要 Claude Code v2.1.251 或更高版本。
1294 1317
1295| 字段 | 描述 |1318| 字段 | 说明 |
1296| :- | :- |1319| :- | :- |
1297| `seconds_since_last_response` | 自恢复的会话记录中最后一条回复以来经过的实际秒数 |1320| `seconds_since_last_response` | 自恢复的会话记录中最后一条回复以来经过的实际秒数 |
1298| `context_tokens` | 恢复后会话的第一个请求作为提示词重新发送的 token 数 |1321| `context_tokens` | 恢复的会话的第一次请求作为提示词重新发送的 token 数 |
1299| `prompt_cache_likely_expired` | 当最后一条回复早于会话的[提示缓存有效期](/docs/zh-CN/prompt-caching#cache-lifetime),或之后的压缩替换了已缓存的对话时为 `true` |1322| `prompt_cache_likely_expired` | 当最后一条回复早于会话的[提示缓存生命周期](/docs/zh-CN/prompt-caching#cache-lifetime),或之后的压缩替换了缓存的对话时为 `true` |
1300| `estimated_cache_write_usd` | 在会话所用模型上将 `context_tokens` 写入提示缓存的估计成本(美元),不包括回复 |1323| `estimated_cache_write_usd` | 在会话的模型上将 `context_tokens` 写入提示缓存的估计成本(美元),不包括回复 |
1301 1324
1302此示例展示了一个在最后一条回复 90 分钟后恢复的会话的输入:1325此示例显示了在最后一条回复 90 分钟后恢复的会话的输入:
1303 1326
1304```json theme={null}1327```json theme={null}
1305{1328{
1322 1345
1323SessionStart hook 可以为 Claude 添加上下文、提供第一条用户消息、设置会话标题、监视文件以及重新加载 skill。除所有 hook 都可用的 [JSON 输出字段](#json-output)外,为每项功能返回相应字段:1346SessionStart hook 可以为 Claude 添加上下文、提供第一条用户消息、设置会话标题、监视文件以及重新加载 skill。除所有 hook 都可用的 [JSON 输出字段](#json-output)外,为每项功能返回相应字段:
1324 1347
1325| 字段 | 描述 |1348| 字段 | 说明 |
1326| :- | :- |1349| :- | :- |
1327| `additionalContext` | 在对话开始时、第一个提示词之前添加到 Claude 上下文中的字符串。关于文本的传递方式以及应放入的内容,请参阅[为 Claude 添加上下文](#add-context-for-claude) |1350| `additionalContext` | 在对话开始时、第一个提示词之前添加到 Claude 上下文中的字符串。有关文本的传递方式以及应放入的内容,请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1328| `initialUserMessage` | 在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下,用作会话第一条用户消息的字符串。即使您未传入提示词,它也会成为第一轮。您传入的提示词会作为下一轮紧随其后 |1351| `initialUserMessage` | 在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下用作会话第一条用户消息的字符串。即使您未传入提示词,它也会成为第一轮。您传入的提示词会作为下一轮跟随其后 |
1329| `sessionTitle` | 设置会话标题,效果与 `/rename` 相同。在 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时生效 |1352| `sessionTitle` | 设置会话标题,效果与 `/rename` 相同。当 `source` 为 `"startup"`、`"resume"` 或 `"fork"` 时生效 |
1330| `watchPaths` | 在此会话期间监视 [FileChanged](#filechanged) 事件的绝对路径数组 |1353| `watchPaths` | 在本会话期间要监视 [FileChanged](#filechanged) 事件的绝对路径数组 |
1331| `reloadSkills` | 布尔值。为 `true` 时,Claude Code 会在 SessionStart hook 完成后重新扫描 [skill](/docs/zh-CN/skills) 和命令目录。请参阅[重新加载 hook 安装的 skill](#reload-skills-that-a-hook-installs) |1354| `reloadSkills` | 布尔值。为 `true` 时,Claude Code 会在 SessionStart hook 完成后重新扫描 [skill](/docs/zh-CN/skills) 和命令目录。请参阅[重新加载 hook 安装的 skill](#reload-skills-that-a-hook-installs) |
1332 1355
1333以下输出添加上下文并为会话命名:1356此输出添加上下文并为会话命名:
1334 1357
1335```json theme={null}1358```json theme={null}
1336{1359{
1342}1365}
1343```1366```
1344 1367
1345仅添加上下文的 hook 可以直接打印内容而无需构建 JSON,因为 Claude Code 会将 SessionStart hook 的[纯文本 stdout](#exit-code-0) 添加到 Claude 的上下文中。1368仅添加上下文的 hook 可以直接打印内容而无需构造 JSON,因为 Claude Code 会将 SessionStart hook 的[纯文本 stdout](#exit-code-0) 添加到 Claude 的上下文中。
1346 1369
1347如果您的插件的 SessionStart hook 提供 `initialUserMessage` 或 `sessionTitle`,请在会话开始前安装该插件。对于在 SessionStart hook 运行之后才完成安装的插件,Claude Code 会忽略这两个字段。1370如果您插件的 SessionStart hook 提供了 `initialUserMessage` 或 `sessionTitle`,请在会话开始之前安装该插件。对于在 SessionStart hook 运行之后才完成安装的插件,Claude Code 会忽略这两个字段。
1348 1371
1349<h4 id="reload-skills-that-a-hook-installs">1372<h4 id="reload-skills-that-a-hook-installs">
1350 重新加载 hook 安装的 skill1373 重新加载 hook 安装的 skill
1351</h4>1374</h4>
1352 1375
1353要使 SessionStart hook 安装的 skill 在同一会话中可用,请返回 `reloadSkills`。skill 发现通常在 SessionStart hook 完成之前运行,因此如果不这样做,hook 写入 `~/.claude/skills/` 或 `.claude/skills/` 的文件在第一个提示词运行时可能缺失。1376要让 SessionStart hook 安装的 skill 在同一会话中可用,请返回 `reloadSkills`。skill 发现通常在 SessionStart hook 完成之前运行,因此如果不使用它,hook 写入 `~/.claude/skills/` 或 `.claude/skills/` 的文件在第一个提示词运行时可能尚不可用。
1354 1377
1355此示例同步共享的 skill 仓库并请求重新扫描:1378此示例同步一个共享的 skill 仓库并请求重新扫描:
1356 1379
1357```bash theme={null}1380```bash theme={null}
1358#!/bin/bash1381#!/bin/bash
1363echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'1386echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'
1364```1387```
1365 1388
1366仓库 URL 是占位符。请将其替换为您自己的 skill 仓库。1389仓库 URL 是一个占位符。请将其替换为您自己的 skill 仓库。
1367 1390
1368<h4 id="persist-environment-variables">1391<h4 id="persist-environment-variables">
1369 持久化环境变量1392 持久化环境变量
1370</h4>1393</h4>
1371 1394
1372SessionStart hook 可以访问 `CLAUDE_ENV_FILE` 环境变量,它提供一个文件路径,您可以在其中为 Claude 在会话后续运行的 shell 命令持久化环境变量。1395SessionStart hook 可以访问 `CLAUDE_ENV_FILE` 环境变量,该变量提供一个文件路径,您可以在其中为 Claude 在会话后续运行的 shell 命令持久化环境变量。
1373 1396
1374要设置单个环境变量,请将 `export` 语句写入 `CLAUDE_ENV_FILE`。使用追加(`>>`)以保留其他 hook 设置的变量:1397要设置单个环境变量,请将 `export` 语句写入 `CLAUDE_ENV_FILE`。使用追加(`>>`)以保留其他 hook 设置的变量:
1375 1398
1385exit 01408exit 0
1386```1409```
1387 1410
1388要捕获设置命令带来的所有环境更改,请比较执行前后导出的变量:1411要捕获设置命令带来的所有环境变更,请比较前后导出的变量:
1389 1412
1390```bash theme={null}1413```bash theme={null}
1391#!/bin/bash1414#!/bin/bash
1404exit 01427exit 0
1405```1428```
1406 1429
1407每个 Bash 命令在执行命令本身之前,都会将该文件的内容作为 shell 代码运行,因此其中的行可以使用 Bash 能求值的任何内容,例如 `export PATH="$PATH:./node_modules/.bin"` 中的 `$PATH` 引用。1430每个 Bash 命令都会在命令本身之前将该文件的内容作为 shell 代码运行,因此其中的一行可以使用 Bash 能求值的任何内容,例如 `export PATH="$PATH:./node_modules/.bin"` 中的 `$PATH` 引用。
1408 1431
1409<a id="persisted-variables-in-powershell-commands" />1432<a id="persisted-variables-in-powershell-commands" />
1410 1433
1412 PowerShell 命令中的持久化变量1435 PowerShell 命令中的持久化变量
1413</h5>1436</h5>
1414 1437
1415在 Claude Code v2.1.296 或更高版本中,[PowerShell](/docs/zh-CN/tools-reference#powershell-tool) 命令也会接收来自 `CLAUDE_ENV_FILE` 的变量,但 PowerShell 从不运行该文件。Claude Code 会从中读取赋值语句,并将其复制到 PowerShell 命令的环境中。只有当本会话中每个 hook 写入的内容,以及您在启动前[将 `CLAUDE_ENV_FILE` 设置为](/docs/zh-CN/env-vars)的任何脚本中,每一行都属于以下类型之一时,它才会这样做:1438在 Claude Code v2.1.296 或更高版本中,[PowerShell](/docs/zh-CN/tools-reference#powershell-tool) 命令也会接收来自 `CLAUDE_ENV_FILE` 的变量,但 PowerShell 从不运行该文件。Claude Code 会从中读出赋值,并将其复制到 PowerShell 命令的环境中。只有当本会话中每个 hook 写入的内容,以及您在启动前[将 `CLAUDE_ENV_FILE` 设置为](/docs/zh-CN/env-vars)的任何脚本中,每一行都属于以下类型之一时,才会这样做:
1416 1439
1417* 空行或 `#` 注释1440* 空行或 `#` 注释
1418* 位于行首的一条赋值语句,写作 `export NAME=value`、`declare -x NAME=value` 或 `NAME=value`,其值必须是 Bash 会按原样使用的值,由以下部分任意组合而成:仅使用字母、数字和字符 `_ @ % + = : , . / -` 的无引号文本、单引号内的文本,以及双引号内的文本(其中的任何 `$`、反引号或 `"` 都用反斜杠转义)1441* 行首的一个赋值,写作 `export NAME=value`、`declare -x NAME=value` 或 `NAME=value`,其值是 Bash 会原样使用的值,由以下部分任意组合而成:仅使用字母、数字和字符 `_ @ % + = : , . / -` 的未加引号文本、单引号中的文本,以及其中所有 `$`、反引号或 `"` 都用反斜杠转义的双引号文本
1419 1442
1420如果任何一行属于其他类型,例如带有未转义 `$PATH` 的 `export PATH="$PATH:./node_modules/.bin"`、`source` 命令,或 `direnv export bash` 打印的 `$'...'` 字符串,则 PowerShell 命令不会接收任何变量,并且 `claude --debug` 会记录 `Session environment is not all plain assignments`。Bash 命令仍会接收所有变量。在 Windows 上,PowerShell 命令也不会接收值中包含 `/` 或 `\` 的变量,因为 Git Bash 和 Windows 的路径写法不同。[沙箱化](/docs/zh-CN/sandboxing)的 PowerShell 命令不会接收任何变量。1443如果有任何一行属于其他类型,例如带有未转义 `$PATH` 的 `export PATH="$PATH:./node_modules/.bin"`、`source` 命令,或 `direnv export bash` 打印的 `$'...'` 字符串,PowerShell 命令将不会接收任何变量,并且 `claude --debug` 会记录 `Session environment is not all plain assignments`。Bash 命令仍会接收所有变量。在 Windows 上,PowerShell 命令也不会接收值中包含 `/` 或 `\` 的变量,因为 Git Bash 和 Windows 的路径写法不同。[沙箱化](/docs/zh-CN/sandboxing)的 PowerShell 命令不会接收任何变量。
1421 1444
1422<Note>1445<Note>
1423 `CLAUDE_ENV_FILE` 可用于 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hook。其他 hook 事件无法访问此变量,在 PowerShell 中运行的 hook 也无法访问,无论是通过 [`"shell": "powershell"`](#command-hook-fields) 还是在没有 Git Bash 的 Windows 上默认如此。1446 `CLAUDE_ENV_FILE` 可用于 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hook。其他 hook 事件无法访问此变量,在 PowerShell 中运行的 hook 也无法访问,无论是通过 [`"shell": "powershell"`](#command-hook-fields) 还是在没有 Git Bash 的 Windows 上默认运行。
1424</Note>1447</Note>
1425 1448
1426<h3 id="setup">1449<h3 id="setup">
1427 Setup1450 Setup
1428</h3>1451</h3>
1429 1452
1430仅当您使用 `--init-only` 启动 Claude Code,或在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)中使用 `--init` 或 `--maintenance` 启动时才会触发。正常启动时不会触发。可将其用于您从 CI 或脚本中显式触发的一次性依赖安装或定期清理,与正常的会话启动分开。对于每个会话的初始化,请改用 [SessionStart](#sessionstart)。1453仅在您使用 `--init-only` 启动 Claude Code,或在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下使用 `--init` 或 `--maintenance` 启动时触发。正常启动时不会触发。将其用于您从 CI 或脚本中显式触发的一次性依赖安装或定期清理,与正常的会话启动分开。对于每个会话的初始化,请改用 [SessionStart](#sessionstart)。
1431 1454
1432匹配器的值对应触发该 hook 的 CLI 标志:1455匹配器的值对应触发该 hook 的 CLI 标志:
1433 1456
1436| `init` | `claude --init-only` 或 `claude -p --init` |1459| `init` | `claude --init-only` 或 `claude -p --init` |
1437| `maintenance` | `claude -p --maintenance` |1460| `maintenance` | `claude -p --maintenance` |
1438 1461
1439当您运行 `claude --init-only` 时,Claude Code 会运行 Setup hook 和带有 `startup` 匹配器的 `SessionStart` hook,然后在不开始对话的情况下退出。1462当您运行 `claude --init-only` 时,Claude Code 会运行 Setup hook 和使用 `startup` 匹配器的 `SessionStart` hook,然后退出而不开始对话。
1440 1463
1441当您使用 `-p` 开始或继续对话时,还需要提供一个提示词,作为参数或通过 stdin 管道传入。当 `SessionStart` hook 提供了 [`initialUserMessage`](#sessionstart-decision-control),或者您恢复一个带有[推迟的工具调用](#defer-a-tool-call-for-later)的会话时,可以省略提示词。1464当您使用 `-p` 开始或继续对话时,还需要提供一个提示词,作为参数或通过 stdin 管道传入。当 `SessionStart` hook 提供了 [`initialUserMessage`](#sessionstart-decision-control),或者您恢复一个带有[延迟工具调用](#defer-a-tool-call-for-later)的会话时,可以省略提示词。
1442 1465
1443成功时,`--init-only` 不会向终端打印任何内容。要确认 hook 已运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,然后在日志中查看 Setup 和 SessionStart hook 的条目。1466成功时,`--init-only` 不会向终端打印任何内容。要确认 hook 已运行,请使用 `claude --debug-file <path> --init-only` 启动,将 `<path>` 替换为日志文件位置,然后在日志中检查 Setup 和 SessionStart hook 条目。
1444 1467
1445由于 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)。1468由于 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)。
1446 1469
1447<h4 id="setup-input">1470<h4 id="setup-input">
1448 Setup 输入1471 Setup 输入
1464 Setup 决策控制1487 Setup 决策控制
1465</h4>1488</h4>
1466 1489
1467Setup 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)的形式出现在运行输出中。1490Setup 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)出现在运行输出中。
1468 1491
1469Setup hook 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量会在会话的后续 Bash 命令中持久存在,与 [SessionStart hook](#persist-environment-variables) 相同。`Setup` 上只运行 `type: "command"` hook。`Setup` 上的 `type: "mcp_tool"` hook 始终会被跳过,详见 [MCP 工具 hook 字段](#mcp-tool-hook-fields)。1492Setup hook 可以访问 `CLAUDE_ENV_FILE`。写入该文件的变量会持久化到会话后续的 Bash 命令中,与 [SessionStart hook](#persist-environment-variables) 相同。`Setup` 上只运行 `type: "command"` hook。`Setup` 上的 `type: "mcp_tool"` hook 始终会被跳过,如 [MCP 工具 hook 字段](#mcp-tool-hook-fields)中所述。
1470 1493
1471<h3 id="instructionsloaded">1494<h3 id="instructionsloaded">
1472 InstructionsLoaded1495 InstructionsLoaded
1473</h3>1496</h3>
1474 1497
1475当 `CLAUDE.md` 或 `.claude/rules/*.md` 文件被加载到上下文中时触发。此事件在会话开始时针对立即加载的文件触发,之后在文件被延迟加载时再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录时,或当带有 `paths:` frontmatter 的条件规则匹配时。该 hook 不支持阻止或决策控制。它以异步方式运行,用于可观测性目的。1498在 `CLAUDE.md` 或 `.claude/rules/*.md` 文件被加载到上下文中时触发。对于预先加载的文件,此事件在会话开始时触发;之后在文件被延迟加载时会再次触发,例如当 Claude 访问包含嵌套 `CLAUDE.md` 的子目录时,或当带有 `paths:` frontmatter 的条件规则匹配时。该 hook 不支持阻止或决策控制。它出于可观测性目的异步运行。
1476 1499
1477当 Claude 通过 **Project instructions** 设置[直接读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不会触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时,它会触发,`load_reason` 设置为 `include`,与任何其他被导入的文件相同;当 `CLAUDE.md` 是指向它的符号链接时,它也会作为一次普通的 `CLAUDE.md` 加载触发。1500当 Claude 通过 **Project instructions** 设置[直接读取 `AGENTS.md`](/docs/zh-CN/memory#agents-md) 时,此事件不会触发。当 `CLAUDE.md` 导入您的 `AGENTS.md` 时,此事件会触发,`load_reason` 设置为 `include`,与任何其他导入的文件相同;当 `CLAUDE.md` 是指向它的符号链接时,也会作为一次正常的 `CLAUDE.md` 加载而触发。
1478 1501
1479匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅针对会话开始时加载的文件触发,或使用 `"matcher": "path_glob_match|nested_traversal"` 仅针对延迟加载触发。1502匹配器针对 `load_reason` 运行。例如,使用 `"matcher": "session_start"` 仅对会话开始时加载的文件触发,或使用 `"matcher": "path_glob_match|nested_traversal"` 仅对延迟加载触发。
1480 1503
1481<h4 id="instructionsloaded-input">1504<h4 id="instructionsloaded-input">
1482 InstructionsLoaded 输入1505 InstructionsLoaded 输入
1484 1507
1485除[通用输入字段](#common-input-fields)外,InstructionsLoaded hook 还会接收以下字段:1508除[通用输入字段](#common-input-fields)外,InstructionsLoaded hook 还会接收以下字段:
1486 1509
1487| 字段 | 描述 |1510| 字段 | 说明 |
1488| :- | :- |1511| :- | :- |
1489| `file_path` | 被加载的指令文件的绝对路径 |1512| `file_path` | 已加载的指令文件的绝对路径 |
1490| `memory_type` | 文件的作用域:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |1513| `memory_type` | 文件的作用域:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |
1491| `load_reason` | 文件被加载的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值在压缩事件之后重新加载指令文件时触发 |1514| `load_reason` | 文件被加载的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。当指令文件在压缩事件后被重新加载时,会使用 `"compact"` 值 |
1492| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如有)。仅在 `path_glob_match` 加载时存在 |1515| `globs` | 文件 `paths:` frontmatter 中的路径 glob 模式(如果有)。仅在 `path_glob_match` 加载时存在 |
1493| `trigger_file_path` | 对于延迟加载,其访问触发了此次加载的文件的路径 |1516| `trigger_file_path` | 对于延迟加载,其访问触发了此次加载的文件路径 |
1494| `parent_file_path` | 对于 `include` 加载,包含此文件的父指令文件的路径 |1517| `parent_file_path` | 对于 `include` 加载,包含此文件的父指令文件路径 |
1495 1518
1496```json theme={null}1519```json theme={null}
1497{1520{
1509 InstructionsLoaded 决策控制1532 InstructionsLoaded 决策控制
1510</h4>1533</h4>
1511 1534
1512InstructionsLoaded hook 没有决策控制。它们无法阻止或修改指令的加载。Claude Code 会丢弃它们的 [JSON 输出字段](#json-output),例如 `systemMessage` 和 `continue`。可将此事件用于审计日志、合规跟踪或可观测性。1535InstructionsLoaded hook 没有决策控制。它们无法阻止或修改指令加载。Claude Code 会丢弃它们的 [JSON 输出字段](#json-output),例如 `systemMessage` 和 `continue`。将此事件用于审计日志、合规跟踪或可观测性。
1513 1536
1514<h3 id="userpromptsubmit">1537<h3 id="userpromptsubmit">
1515 UserPromptSubmit1538 UserPromptSubmit
1516</h3>1539</h3>
1517 1540
1518在提交提示词后、Claude 处理之前运行。这使您能够1541在提交提示词时、Claude 处理之前运行。这使您可以
1519根据提示词/对话添加额外的上下文、验证提示词,或1542根据提示词/对话添加额外的上下文、验证提示词,或
1520阻止某些类型的提示词。1543阻止某些类型的提示词。
1521 1544
1523 1546
1524* [定时任务](/docs/zh-CN/scheduled-tasks)触发时,包括 `/loop` 的一次迭代1547* [定时任务](/docs/zh-CN/scheduled-tasks)触发时,包括 `/loop` 的一次迭代
1525* [后台子代理](/docs/zh-CN/sub-agents#run-subagents-in-foreground-or-background)向启动它的会话回报时1548* [后台子代理](/docs/zh-CN/sub-agents#run-subagents-in-foreground-or-background)向启动它的会话回报时
1526* [另一个会话发送消息](/docs/zh-CN/cross-session-messaging)到您的主对话时1549* [另一个会话向](/docs/zh-CN/cross-session-messaging)您的主对话发送消息时
1527 1550
1528对于 `command`、`http` 和 `mcp_tool` 类型,`UserPromptSubmit` hook 的默认超时时间为 30 秒,短于这些类型在大多数其他事件上 600 秒的默认值。由于此 hook 在每个提示词之前运行,并且在完成前会阻塞模型处理,卡住的 hook 会使会话停滞。如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。1551对于 `command`、`http` 和 `mcp_tool` 类型,`UserPromptSubmit` hook 的默认超时时间为 30 秒,短于这些类型在大多数其他事件上 600 秒的默认值。由于此 hook 在每个提示词之前运行,并在完成之前阻塞模型处理,卡住的 hook 会使会话停滞。如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1529 1552
1530除了使用 [`async: true`](#run-hooks-in-the-background) 运行的 command hook 之外,达到超时的 `UserPromptSubmit` command、HTTP 或 MCP 工具 hook 都会被取消,其输出(包括任何 `additionalContext`)会被丢弃。提示词仍会在没有该上下文的情况下传达给 Claude。若要改为阻止该提示词,请在 command 或 HTTP hook 上设置 [`onFailure: "block"`](#block-the-action-when-a-hook-fails)。会话记录中会显示一条通知,指明该 hook、触发的超时以及输出已被丢弃。1553除使用 [`async: true`](#run-hooks-in-the-background) 运行的命令 hook 外,达到超时的 `UserPromptSubmit` 命令、HTTP 或 MCP 工具 hook 会被取消,其输出(包括任何 `additionalContext`)会被丢弃。提示词仍会传达给 Claude,但不带该上下文。若要改为阻止提示词,请在命令或 HTTP hook 上设置 [`onFailure: "block"`](#block-the-action-when-a-hook-fails)。会话记录会显示一条通知,指明该 hook、触发的超时,以及输出已被丢弃。
1531 1554
1532`UserPromptSubmit` 上的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 达到超时时,会阻止该提示词,并显示一条指明该 hook 和超时时间的消息,因为此处的回调可能充当不能失败放行的策略关卡。会话会继续。在 v2.1.208 之前,该事件上的回调超时会以执行错误结束该轮次。1555`UserPromptSubmit` 上的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 达到超时时,会阻止该提示词,并显示一条指明该 hook 和超时的消息,因为此处的回调可能充当不能以失败放行方式处理的策略关卡。会话会继续。在 v2.1.208 之前,该事件上的回调超时会以执行错误结束该轮次。
1533 1556
1534<h4 id="userpromptsubmit-input">1557<h4 id="userpromptsubmit-input">
1535 UserPromptSubmit 输入1558 UserPromptSubmit 输入
1536</h4>1559</h4>
1537 1560
1538除[通用输入字段](#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 需要解析提示词,请考虑这些行。1561除[通用输入字段](#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 解析提示词,请考虑这些行。
1539 1562
1540当会话有自定义标题时,UserPromptSubmit hook 还会接收 `session_title`,其含义与 [SessionStart 的 `session_title` 字段](#sessionstart-input)相同。1563当会话具有自定义标题时,UserPromptSubmit hook 还会接收 `session_title`,其含义与 [SessionStart 的 `session_title` 字段](#sessionstart-input)相同。
1541 1564
1542```json theme={null}1565```json theme={null}
1543{1566{
1554 UserPromptSubmit 决策控制1577 UserPromptSubmit 决策控制
1555</h4>1578</h4>
1556 1579
1557`UserPromptSubmit` hook 可以控制是否处理提交的提示词,并添加上下文。所有 [JSON 输出字段](#json-output)均可用。1580`UserPromptSubmit` hook 可以控制是否处理所提交的提示词,并添加上下文。所有 [JSON 输出字段](#json-output)均可用。
1558 1581
1559在退出码为 0 时,有两种方式可以向对话添加上下文:1582在退出码为 0 时,有两种方式向对话添加上下文:
1560 1583
1561* **纯文本 stdout**:Claude Code 会将其[视为纯文本](#exit-code-0)的 stdout 添加到 Claude 的上下文中1584* **纯文本 stdout**:Claude Code 会将其[视为纯文本](#exit-code-0)的 stdout 添加到 Claude 的上下文中
1562* **带有 `additionalContext` 的 JSON**:使用下面的 JSON 格式以获得更多控制。`additionalContext` 字段会作为上下文添加1585* **带 `additionalContext` 的 JSON**:使用下面的 JSON 格式进行更多控制。`additionalContext` 字段会作为上下文添加
1563 1586
1564两种方式都不会在会话记录中生成可见条目。纯 stdout 和 `additionalContext` 的值都会各自作为以 hook 名称开头的系统提醒注入;Claude 会读取两者。要确认已送达,请查看[调试日志](#debug-hooks)。1587这两种方式都不会产生可见的会话记录条目。纯 stdout 和 `additionalContext` 的值各自作为以 hook 名称开头的系统提醒注入;Claude 会读取两者。要确认已传递,请查看[调试日志](#debug-hooks)。
1565 1588
1566要阻止提示词,请返回一个 `decision` 设置为 `"block"` 的 JSON 对象:1589要阻止提示词,请返回一个 `decision` 设置为 `"block"` 的 JSON 对象:
1567 1590
1568| 字段 | 描述 |1591| 字段 | 说明 |
1569| :- | :- |1592| :- | :- |
1570| `decision` | `"block"` 会在提示词到达 Claude 之前将其拦截。省略则允许提示词继续 |1593| `decision` | `"block"` 会在提示词传达给 Claude 之前将其拦下。省略则允许提示词继续 |
1571| `reason` | 当 `decision` 为 `"block"` 时向用户显示。不会添加到上下文中 |1594| `reason` | 当 `decision` 为 `"block"` 时显示给用户。不会添加到上下文中 |
1572| `additionalContext` | 与所提交的提示词一同添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |1595| `additionalContext` | 与所提交的提示词一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1573| `sessionTitle` | 设置会话标题。可用于根据提示词内容自动命名会话 |1596| `sessionTitle` | 设置会话标题。用于根据提示词内容自动命名会话 |
1574| `suppressOriginalPrompt` | 如果在 hook 阻止提示词时为 `true`,则阻止消息中不包含提示词文本。请参阅[被阻止的提示词会留下什么](#what-a-blocked-prompt-leaves-behind) |1597| `suppressOriginalPrompt` | 如果在 hook 阻止提示词时为 `true`,则在阻止消息中省略提示词文本。请参阅[被阻止的提示词会留下什么](#what-a-blocked-prompt-leaves-behind) |
1575 1598
1576通过以 2 退出来阻止的 hook,其处理方式与 `reason` 相同:阻止消息会向用户显示 stderr 文本,且不会添加到上下文中。1599通过以退出码 2 退出来阻止的 hook,其处理方式与 `reason` 相同:阻止消息会向用户显示 stderr 文本,且不会添加到上下文中。
1577 1600
1578```json theme={null}1601```json theme={null}
1579{1602{
1592 被阻止的提示词会留下什么1615 被阻止的提示词会留下什么
1593</h4>1616</h4>
1594 1617
1595被阻止的提示词永远不会到达 Claude,但其文本并不会在所有地方被删除。默认情况下,向用户显示的阻止消息以 `Original prompt:` 结尾,后接所提交的文本,并且 Claude Code 会将该消息写入磁盘上会话的会话记录文件。要在消息中省略该文本,请在 `hookSpecificOutput` 中打印带有 `"suppressOriginalPrompt": true` 的 JSON。无论 hook 是通过 `decision: "block"` 还是通过以 2 退出来阻止,此方法均有效。1618被阻止的提示词永远不会传达给 Claude,但其文本并不会在所有地方被移除。默认情况下,显示给用户的阻止消息以 `Original prompt:` 结尾,后跟所提交的文本,并且 Claude Code 会将该消息写入磁盘上的会话记录文件。要在消息中省略该文本,请在 `hookSpecificOutput` 中打印带有 `"suppressOriginalPrompt": true` 的 JSON。无论 hook 是通过 `decision: "block"` 还是以退出码 2 退出来阻止,此方法都有效。
1596 1619
1597`suppressOriginalPrompt` 只会改变阻止消息。所提交的文本仍可能出现在本地文件中,例如会话记录和您的提示词历史记录,因此阻止型 hook 并不能让机密信息不落盘。要限制或删除这些文件,请参阅[明文存储](/docs/zh-CN/claude-directory#plaintext-storage)和[清除本地数据](/docs/zh-CN/claude-directory#clear-local-data)。1620`suppressOriginalPrompt` 只改变阻止消息。所提交的文本仍可能出现在本地文件中,例如会话记录和您的提示词历史,因此阻止 hook 并不是防止机密写入磁盘的方法。要限制或删除这些文件,请参阅[明文存储](/docs/zh-CN/claude-directory#plaintext-storage)和[清除本地数据](/docs/zh-CN/claude-directory#clear-local-data)。
1598 1621
1599<h3 id="userpromptexpansion">1622<h3 id="userpromptexpansion">
1600 UserPromptExpansion1623 UserPromptExpansion
1601</h3>1624</h3>
1602 1625
1603当用户输入的命令在到达 Claude 之前展开为提示词时运行。可用于阻止直接调用特定命令、为特定 skill 注入上下文,或记录用户调用了哪些命令。例如,匹配 `deploy` 的 hook 可以在不存在批准文件时阻止 `/deploy`,或者匹配某个审查 skill 的 hook 可以将团队的审查清单作为 `additionalContext` 附加。1626在用户输入的命令展开为提示词、传达给 Claude 之前运行。使用它可以阻止直接调用特定命令、为特定 skill 注入上下文,或记录用户调用了哪些命令。例如,匹配 `deploy` 的 hook 可以在不存在批准文件时阻止 `/deploy`,或者匹配某个审查 skill 的 hook 可以将团队的审查清单作为 `additionalContext` 追加。
1604 1627
1605此事件覆盖了 `PreToolUse` 无法覆盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 只在 Claude 调用该工具时触发,但直接输入 `/skillname` 会绕过 `PreToolUse`。`UserPromptExpansion` 会在这条直接路径上触发。1628此事件覆盖了 `PreToolUse` 无法覆盖的路径:匹配 `Skill` 工具的 `PreToolUse` hook 仅在 Claude 调用该工具时触发,而直接输入 `/skillname` 会绕过 `PreToolUse`。`UserPromptExpansion` 会在这条直接路径上触发。
1606 1629
1607匹配 `command_name`。将匹配器留空可在每个提示词类型的命令上触发。1630针对 `command_name` 进行匹配。将匹配器留空可在每个提示词类命令上触发。
1608 1631
1609<h4 id="userpromptexpansion-input">1632<h4 id="userpromptexpansion-input">
1610 UserPromptExpansion 输入1633 UserPromptExpansion 输入
1633 1656
1634`UserPromptExpansion` hook 可以阻止展开或添加上下文。所有 [JSON 输出字段](#json-output)均可用。1657`UserPromptExpansion` hook 可以阻止展开或添加上下文。所有 [JSON 输出字段](#json-output)均可用。
1635 1658
1636| 字段 | 描述 |1659| 字段 | 说明 |
1637| :- | :- |1660| :- | :- |
1638| `decision` | `"block"` 会阻止命令展开。省略则允许其继续 |1661| `decision` | `"block"` 会阻止命令展开。省略则允许其继续 |
1639| `reason` | 当 `decision` 为 `"block"` 时向用户显示 |1662| `reason` | 当 `decision` 为 `"block"` 时显示给用户 |
1640| `additionalContext` | 与展开后的提示词一同添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |1663| `additionalContext` | 与展开后的提示词一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
1641 1664
1642通过以 2 退出来阻止的 hook,其处理方式与 `reason` 相同:阻止消息会向用户显示 stderr 文本。1665通过以退出码 2 退出来阻止的 hook,其处理方式与 `reason` 相同:阻止消息会向用户显示 stderr 文本。
1643 1666
1644```json theme={null}1667```json theme={null}
1645{1668{
1656 MessageDisplay1679 MessageDisplay
1657</h3>1680</h3>
1658 1681
1659在助手消息流式显示到屏幕上时运行。Claude Code 会分批显示消息:每当一批新完成的行准备好渲染时,hook 会使用这些行运行一次,Claude Code 会在原位置渲染 hook 返回的替换文本。长消息会产生多次调用;短消息可能只产生一次。1682在助手消息流式显示到屏幕上时运行。Claude Code 以增量方式显示消息:每当一批新完成的行准备好渲染时,hook 就会用这些行运行一次,Claude Code 会在其位置渲染 hook 返回的替换文本。长消息会产生多次调用;短消息可能只产生一次。
1660 1683
1661使用 MessageDisplay 可以:1684使用 MessageDisplay 可以:
1662 1685
1663* 去除 markdown 以获得极简显示1686* 去除 markdown 以实现简洁显示
1664* 转换 Agent SDK 应用向其用户显示的文本1687* 转换 Agent SDK 应用程序向其用户显示的文本
1665* 从 Claude 的回复中隐去 API 密钥或内部主机名1688* 从 Claude 的回复中隐去 API 密钥或内部主机名
1666 1689
1667Claude Code 会保留每一批内容,直到您的 hook 返回,因此请确保 hook 运行迅速。如果 hook 失败或超时,Claude Code 会显示原始文本。此事件的默认超时时间为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。1690Claude Code 会保留每一批内容,直到您的 hook 返回,因此请让 hook 保持快速。如果 hook 失败或超时,Claude Code 会显示原始文本。此事件的默认超时时间为 10 秒;如果您的 hook 需要更多时间,请在 hook 条目中设置 `timeout` 字段。
1668 1691
1669MessageDisplay 仅作用于显示:替换文本只会改变屏幕上渲染的内容。会话记录以及 Claude 看到的内容都保持原始文本,因此 Claude 永远看不到替换内容,详细模式也会显示原始文本。该 hook 只接收助手消息文本,因此工具结果和您输入的文本会原样渲染。1692MessageDisplay 仅影响显示:替换文本只改变屏幕上渲染的内容。会话记录和 Claude 看到的内容保留原始文本,因此 Claude 永远不会看到替换内容,详细模式也会显示原始文本。该 hook 仅接收助手消息文本,因此工具结果和您输入的文本会原样渲染。
1670 1693
1671MessageDisplay 不支持匹配器,并会针对每条流式输出文本的助手消息触发;不含文本的消息(例如仅包含工具调用的响应)不会触发它。1694MessageDisplay 不支持匹配器,会对每条流式输出文本的助手消息触发;不含文本的消息(例如仅包含工具调用的回复)不会触发它。
1672 1695
1673在非交互式运行中(包括 Agent SDK 查询和 `claude -p`),MessageDisplay 对每条助手消息只运行一次,而不是每批行运行一次。这唯一的一次调用在消息完成后到达,并携带完整的消息文本:`index` 为 `0`,`final` 为 `true`,`delta` 包含整条消息。收集每条消息 `delta` 文本的 hook 在两种模式下接收到的总文本相同。1696在非交互运行中(包括 Agent SDK 查询和 `claude -p`),MessageDisplay 对每条助手消息运行一次,而不是对每批行运行一次。这一次调用在消息完成后到达,并携带完整的消息文本:`index` 为 `0`,`final` 为 `true`,`delta` 包含整条消息。收集每条消息 `delta` 文本的 hook 在两种模式下接收到的总文本相同。
1674 1697
1675<h4 id="messagedisplay-input">1698<h4 id="messagedisplay-input">
1676 MessageDisplay 输入1699 MessageDisplay 输入
1677</h4>1700</h4>
1678 1701
1679除[通用输入字段](#common-input-fields)外,MessageDisplay hook 还会接收轮次和消息的标识符、此次调用在消息中的位置,以及 `delta` 中的新文本。批次边界取决于文本的流式传输方式,因此请使用 `index` 和 `final` 来跟踪消息的进度,而不要假定各行会以特定方式分组。1702除[通用输入字段](#common-input-fields)外,MessageDisplay hook 还会接收轮次和消息的标识符、本次调用在消息中的位置,以及 `delta` 中的新文本。批次边界取决于文本的流式传输方式,因此请使用 `index` 和 `final` 跟踪消息的进度,而不要期望行以特定方式分组。
1680 1703
1681| 字段 | 描述 |1704| 字段 | 说明 |
1682| :- | :- |1705| :- | :- |
1683| `turn_id` | 当前轮次的 UUID |1706| `turn_id` | 当前轮次的 UUID |
1684| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每一批中保持不变。这不是 API 的 `msg_…` id,因此无法与会话记录中的消息 id 关联 |1707| `message_id` | 正在显示的助手消息的 UUID。在同一消息的每个批次中保持不变。这不是 API 的 `msg_…` id,因此无法与会话记录中的消息 id 关联 |
1685| `index` | 此批次在消息中的从零开始的索引 |1708| `index` | 本批次在消息中从零开始的索引 |
1686| `final` | 在消息的最后一批上为 `true`。每条消息恰好有一个最终批次 |1709| `final` | 在消息的最后一批时为 `true`。每条消息恰好有一个最终批次 |
1687| `delta` | 自上一批次以来新完成的行,包括结尾的换行符。始终是完整的行,但最终批次可能在行中间结束。在交互式运行中,当消息以换行符结尾时,最终批次的 delta 为空,因此请将 `final`(而不是非空的 delta)作为消息结束的信号。在 Agent SDK 和 `claude -p` 运行中,这唯一的一次调用携带整条消息 |1710| `delta` | 自上一批次以来新完成的行,包括行尾换行符。始终为完整的行,但最终批次可能在行中间结束。在交互运行中,当消息以换行符结尾时,最终批次的 delta 为空,因此请将 `final`(而非非空的 delta)作为消息结束的信号。在 Agent SDK 和 `claude -p` 运行中,这一次调用携带整条消息 |
1688 1711
1689```json theme={null}1712```json theme={null}
1690{1713{
1704 MessageDisplay 输出1727 MessageDisplay 输出
1705</h4>1728</h4>
1706 1729
1707除所有 hook 都可用的 [JSON 输出字段](#json-output)外,MessageDisplay hook 还可以返回 `displayContent`,以在屏幕上替换 delta:1730除所有 hook 都可用的 [JSON 输出字段](#json-output)外,MessageDisplay hook 还可以返回 `displayContent` 以在屏幕上替换 delta:
1708 1731
1709| 字段 | 描述 |1732| 字段 | 说明 |
1710| :- | :- |1733| :- | :- |
1711| `displayContent` | 代替 delta 显示的文本。省略则显示原始文本 |1734| `displayContent` | 代替 delta 显示的文本。省略则显示原始内容 |
1712 1735
1713MessageDisplay hook 没有决策控制。它们无法阻止消息,也无法更改存储在会话记录中或发送给 Claude 的内容。Claude Code 会处理其 JSON 输出中的 `displayContent`,并丢弃 `systemMessage` 和 `continue`。1736MessageDisplay hook 没有决策控制。它们无法阻止消息,也无法更改存储在会话记录中或发送给 Claude 的内容。Claude Code 会处理其 JSON 输出中的 `displayContent`,并丢弃 `systemMessage` 和 `continue`。
1714 1737
1715此示例从 Claude 的回复中去除 markdown 格式,以实现纯文本显示。该脚本从 stdin 读取每一批内容,从 `delta` 中移除粗体标记和行内代码反引号,并将结果作为 `displayContent` 返回。1738此示例从 Claude 的回复中去除 markdown 格式,以进行纯文本显示。该脚本从 stdin 读取每一批,从 `delta` 中移除粗体标记和行内代码反引号,并将结果作为 `displayContent` 返回。
1716 1739
1717<Tabs>1740<Tabs>
1718 <Tab title="macOS/Linux">1741 <Tab title="macOS/Linux">
1719 在您的设置文件中为该事件注册一个 command hook:1742 在您的设置文件中为该事件注册一个命令 hook:
1720 1743
1721 ```json theme={null}1744 ```json theme={null}
1722 {1745 {
1745 </Tab>1768 </Tab>
1746 1769
1747 <Tab title="Windows (PowerShell)">1770 <Tab title="Windows (PowerShell)">
1748 注册一个通过 PowerShell 运行脚本的 command hook:1771 注册一个通过 PowerShell 运行脚本的命令 hook:
1749 1772
1750 ```json theme={null}1773 ```json theme={null}
1751 {1774 {
1771 }1794 }
1772 ```1795 ```
1773 1796
1774 `-NoProfile` 标志会跳过加载您的 PowerShell 配置文件,使 hook 快速启动,`-ExecutionPolicy Bypass` 则允许 PowerShell 运行本地脚本文件。1797 `-NoProfile` 标志会跳过加载您的 PowerShell 配置文件,使 hook 快速启动;`-ExecutionPolicy Bypass` 则允许 PowerShell 运行本地脚本文件。
1775 1798
1776 将此脚本保存到项目中的 `.claude/hooks/plain-display.ps1`:1799 将此脚本保存到项目中的 `.claude/hooks/plain-display.ps1`:
1777 1800
1794 PreToolUse1817 PreToolUse
1795</h3>1818</h3>
1796 1819
1797在 Claude 创建工具参数之后、处理工具调用之前运行。可匹配除 `EndConversation` 之外的任何工具名称:包括 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 和 `ExitPlanMode` 等内置工具,以及任何 [MCP 工具名称](#match-mcp-tools)。1820在 Claude 创建工具参数之后、处理工具调用之前运行。匹配除 `EndConversation` 之外的任何工具名称:内置工具,如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 和 `ExitPlanMode`,以及任何 [MCP 工具名称](#match-mcp-tools)。
1798 1821
1799要在磁盘上某个特定文件发生变化时运行 hook(无论是谁写入的),请使用 [FileChanged](#filechanged),而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在更改发生后运行 FileChanged hook,并且它们没有决策控制,因此无法阻止写入。1822要在特定文件在磁盘上发生变化时运行 hook(无论由谁写入),请使用 [FileChanged](#filechanged),而不是按名称匹配文件编辑工具。与 PreToolUse 不同,Claude Code 在变更之后运行 FileChanged hook,且它们没有决策控制,因此无法阻止写入。
1800 1823
1801<Warning>1824<Warning>
1802 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)。1825 PreToolUse 仅在 Claude 调用工具时运行。默认情况下,您[在提示词中用 `@` 引用](/docs/zh-CN/common-workflows#reference-files-and-directories)的文件会在没有任何工具调用的情况下添加。Claude Code 在构建提示词时插入其内容,因此不会为它们触发任何 PreToolUse hook,包括匹配 `Read` 的 hook。PreToolUse 也不会为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
1803 1826
1804 PreToolUse 也不会为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。1827 您可以阻止 `@` 引用特定路径,或关闭插入功能:
1828
1829 * **阻止特定路径**:为这些路径添加 [`Read` 拒绝规则](/docs/zh-CN/permissions#read-and-edit)
1830 * **关闭插入功能**:在您的 shell、用户设置或托管设置中设置 [`CLAUDE_CODE_DISABLE_FILE_MENTIONS=1`](/docs/zh-CN/env-vars#variables)。这样 Claude 会获得所提及的路径以及一条说明,提示其使用文件工具读取这些路径。如果 Claude 这样做,您匹配的 PreToolUse hook 就会运行。该变量需要 Claude Code v2.1.299 或更高版本,且 Claude Code 会在项目设置和本地设置中忽略它。
1805</Warning>1831</Warning>
1806 1832
1807使用 [PreToolUse 决策控制](#pretooluse-decision-control)来允许、拒绝、询问或推迟工具调用。1833使用 [PreToolUse 决策控制](#pretooluse-decision-control)来允许、拒绝、询问或延迟工具调用。
1808 1834
1809`PreToolUse` 上的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 超过其超时时间时,会阻止该工具调用,Claude 会收到一个指明超时的错误结果。其他 hook 返回的显式拒绝仍然优先。1835`PreToolUse` 上的 [Agent SDK 回调 hook](/docs/zh-CN/agent-sdk/hooks) 超过其超时时间时,会阻止该工具调用,Claude 会收到一个指明该超时的错误结果。另一个 hook 返回的显式拒绝仍然优先。
1810 1836
1811<h4 id="pretooluse-input">1837<h4 id="pretooluse-input">
1812 PreToolUse 输入1838 PreToolUse 输入
1814 1840
1815除[通用输入字段](#common-input-fields)外,PreToolUse hook 还会接收 `tool_name`、`tool_input` 和 `tool_use_id`。1841除[通用输入字段](#common-input-fields)外,PreToolUse hook 还会接收 `tool_name`、`tool_input` 和 `tool_use_id`。
1816 1842
1817对于 [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 或更高版本。1843对于 [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 或更高版本。
1818 1844
1819对于文件工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 始终是绝对路径:1845对于文件工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 始终是绝对路径:
1820 1846
1821* Claude Code 会在 hook 运行前展开 `~` 和相对路径,因此基于路径匹配的 hook 无法通过 `~` 或同一路径的相对写法被绕过1847* Claude Code 在 hook 运行之前会展开 `~` 和相对路径,因此基于路径匹配的 hook 无法通过 `~` 或同一路径的相对写法被绕过
1822* 在 Windows 上,路径以反斜杠分隔符传入,即使您的 hook 在 Git Bash 下运行(其中 `$PWD` 看起来像 `/c/project`)也是如此1848* 在 Windows 上,路径以反斜杠分隔符传入,即使您的 hook 在 `$PWD` 看起来像 `/c/project` 的 Git Bash 下运行也是如此
1823* 使用正斜杠编写的比较(例如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用会像 hook 没有任何需要阻止的内容一样继续进行1849* 使用正斜杠编写的比较(例如 `/src/` 检查)永远不会匹配反斜杠路径,工具调用会如同 hook 没有任何需要阻止的内容一样继续进行
1824* 比较之前请先规范化分隔符:在 Bash 中使用 `FILE_PATH="${FILE_PATH//\\//}"`,在 Python 中使用 `file_path.replace("\\", "/")`,然后匹配诸如 `/src/` 这样的路径片段,而不要用 `^` 锚定,因为路径是绝对路径1850* 比较之前请规范化分隔符:在 Bash 中使用 `FILE_PATH="${FILE_PATH//\\//}"`,在 Python 中使用 `file_path.replace("\\", "/")`,然后匹配路径片段(如 `/src/`),而不是用 `^` 锚定,因为路径是绝对路径
1825 1851
1826Windows 上的 `Write` 调用会传入:1852Windows 上的 `Write` 调用会传递:
1827 1853
1828```json theme={null}1854```json theme={null}
1829{1855{
1837}1863}
1838```1864```
1839 1865
1840`tool_input` 字段取决于具体工具:1866`tool_input` 字段取决于工具:
1841 1867
1842<a id="bash" />1868<a id="bash" />
1843 1869
1847 1873
1848执行 shell 命令。1874执行 shell 命令。
1849 1875
1850| 字段 | 类型 | 示例 | 描述 |1876| 字段 | 类型 | 示例 | 说明 |
1851| :- | :- | :- | :- |1877| :- | :- | :- | :- |
1852| `command` | string | `"npm test"` | 要执行的 shell 命令 |1878| `command` | string | `"npm test"` | 要执行的 shell 命令 |
1853| `description` | string | `"Run test suite"` | 可选,描述该命令的作用 |1879| `description` | string | `"Run test suite"` | 可选,描述该命令的作用 |
1854| `timeout` | number | `120000` | 可选,以毫秒为单位的超时时间。超过[最大值](/docs/zh-CN/tools-reference#bash-tool-behavior)的值会被降至最大值,而不会被拒绝 |1880| `timeout` | number | `120000` | 可选,以毫秒为单位的超时时间。超过[最大值](/docs/zh-CN/tools-reference#bash-tool-behavior)的值会被降至最大值,而不是被拒绝 |
1855| `run_in_background` | boolean | `false` | 是否在后台运行该命令 |1881| `run_in_background` | boolean | `false` | 是否在后台运行该命令 |
1856 1882
1857当 Bash 命令更改 Git 仓库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置启用记录时,它会在所有权限模式下记录更改;该设置的条目说明了哪些文件可以设置它。否则,它仅在自动模式和 `bypassPermissions` 模式下记录,并且仅在 Claude Code 指示 Claude 通过 Bash 编辑文件时记录。将 `bashEditDiffEnabled` 设置为 `false` 可关闭记录。后台命令和只读命令不携带 diff。1883当 Bash 命令更改 Git 仓库中的文件时,Claude Code 可以记录更改的内容。当 [`bashEditDiffEnabled`](/docs/zh-CN/settings-reference#basheditdiffenabled) 设置开启记录时,它会在所有权限模式下记录更改;该设置的条目说明了哪些文件可以设置它。否则,它仅在自动模式和 `bypassPermissions` 模式下记录,且仅当 Claude Code 指示 Claude 通过 Bash 编辑文件时才记录。将 `bashEditDiffEnabled` 设置为 `false` 可关闭记录。后台命令和只读命令不带 diff。
1858 1884
1859随后,您的 [PostToolUse hook](#posttooluse) 会在 `tool_response.bashEditDiff` 中接收到已更改的文件。该列表涵盖命令运行期间仓库下发生的更改。Git 忽略的文件和子模块中的文件不会列出。需要 Claude Code v2.1.269 或更高版本。1885然后,您的 [PostToolUse hook](#posttooluse) 会在 `tool_response.bashEditDiff` 中接收更改的文件。该列表涵盖命令运行期间仓库下发生更改的内容。Git 忽略的文件和子模块中的文件不会列出。需要 Claude Code v2.1.269 或更高版本。
1860 1886
1861<Note>1887<Note>
1862 该列表为尽力而为,目前处于公测阶段。Claude Code 可能会遗漏更改、包含同一时间被其他进程更改的文件,或在达到其大小限制时停止。字段结构可能会变化。请使用该列表来确定需要审查的内容,而不要用它来强制执行策略。1888 该列表是尽力而为的,目前处于公测阶段。Claude Code 可能遗漏某个更改、包含另一个进程同时更改的文件,或在达到其大小限制时停止。字段结构可能会更改。请使用该列表来确定需要审查的内容,而不是用来执行策略。
1863</Note>1889</Note>
1864 1890
1865`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整程度和可靠程度。1891`changedFiles` 和 `files` 列出命令更改的内容;其余字段说明该列表的完整程度和可靠程度。
1866 1892
1867| 字段 | 类型 | 示例 | 描述 |1893| 字段 | 类型 | 示例 | 说明 |
1868| :- | :- | :- | :- |1894| :- | :- | :- | :- |
1869| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令更改的文件的绝对路径,最多 200 个。只要 `files` 中包含 diff 或 `moreFiles` 大于零,该字段就会存在 |1895| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令更改的文件的绝对路径,最多 200 个。只要 `files` 包含 diff 或 `moreFiles` 大于零就会存在 |
1870| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 个已更改文件的 diff,用于显示。对于命令新增或删除的文件,`created` 或 `deleted` 为 `true` |1896| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 个已更改文件的 diff,用于显示。对于命令添加或删除的文件,`created` 或 `deleted` 为 `true` |
1871| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的已更改文件数量 |1897| `moreFiles` | number | `2` | 在 `files` 中没有 diff 的已更改文件数量 |
1872| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |1898| `unavailable` | boolean | `true` | 当 diff 不完整或无法获取时设置 |
1873| `skipped` | boolean | `true` | 针对会移动工作树的 Git 命令(例如 `git checkout` 或 `git stash`)设置,此时 Claude Code 不获取 diff |1899| `skipped` | boolean | `true` | 对于移动工作树的 Git 命令(如 `git checkout` 或 `git stash`)设置,此时 Claude Code 不获取 diff |
1874| `shared` | boolean | `true` | 当另一个 Bash 工具调用(例如子代理的调用)同时在同一仓库中运行时设置,因此列出的某些更改可能来自该命令 |1900| `shared` | boolean | `true` | 当另一个 Bash 工具调用(例如子代理的调用)同时在同一仓库中运行时设置,因此列出的部分更改可能来自该命令 |
1875 1901
1876<a id="powershell" />1902<a id="powershell" />
1877 1903
1879 PowerShell1905 PowerShell
1880</h5>1906</h5>
1881 1907
1882执行 PowerShell 命令。关于各平台的可用性,请参阅 [PowerShell 工具](/docs/zh-CN/tools-reference#powershell-tool)。1908执行 PowerShell 命令。有关各平台的可用性,请参阅 [PowerShell 工具](/docs/zh-CN/tools-reference#powershell-tool)。
1883 1909
1884字段与 Bash 工具相同,命令字符串位于 `command` 中:1910字段与 Bash 工具相同,命令字符串位于 `command` 中:
1885 1911
1886| 字段 | 类型 | 示例 | 描述 |1912| 字段 | 类型 | 示例 | 说明 |
1887| :- | :- | :- | :- |1913| :- | :- | :- | :- |
1888| `command` | string | `"Get-ChildItem -Recurse"` | 要执行的 PowerShell 命令 |1914| `command` | string | `"Get-ChildItem -Recurse"` | 要执行的 PowerShell 命令 |
1889| `description` | string | `"List files recursively"` | 可选,描述该命令的作用 |1915| `description` | string | `"List files recursively"` | 可选,描述该命令的作用 |
1892 1918
1893在检查 shell 命令的 hook 中匹配 `Bash|PowerShell`,以便同时覆盖这两个工具:1919在检查 shell 命令的 hook 中匹配 `Bash|PowerShell`,以便同时覆盖这两个工具:
1894 1920
1895* 在 Windows 上,只要启用了 PowerShell 工具,Claude 就会将 PowerShell 视为主 shell,并通过它路由 shell 命令。1921* 在 Windows 上,只要启用了 PowerShell 工具,Claude 就会将 PowerShell 视为主 shell,并通过它执行 shell 命令。
1896* 在没有 Git Bash 的 Windows 上,该工具会自动启用,Claude Code 根本不会注册 Bash 工具。1922* 在没有 Git Bash 的 Windows 上,该工具会自动启用,而 Claude Code 根本不会注册 Bash 工具。
1897* 仅匹配 `Bash` 的 hook 在那里永远不会触发。1923* 仅匹配 `Bash` 的 hook 在那里永远不会触发。
1898 1924
1899<h5 id="write">1925<h5 id="write">
1902 1928
1903创建或覆盖文件。1929创建或覆盖文件。
1904 1930
1905| 字段 | 类型 | 示例 | 描述 |1931| 字段 | 类型 | 示例 | 说明 |
1906| :- | :- | :- | :- |1932| :- | :- | :- | :- |
1907| `file_path` | string | `"/path/to/file.txt"` | 要写入的文件的绝对路径 |1933| `file_path` | string | `"/path/to/file.txt"` | 要写入的文件的绝对路径 |
1908| `content` | string | `"file content"` | 要写入文件的内容 |1934| `content` | string | `"file content"` | 要写入文件的内容 |
1913 1939
1914替换现有文件中的字符串。1940替换现有文件中的字符串。
1915 1941
1916| 字段 | 类型 | 示例 | 描述 |1942| 字段 | 类型 | 示例 | 说明 |
1917| :- | :- | :- | :- |1943| :- | :- | :- | :- |
1918| `file_path` | string | `"/path/to/file.txt"` | 要编辑的文件的绝对路径 |1944| `file_path` | string | `"/path/to/file.txt"` | 要编辑的文件的绝对路径 |
1919| `old_string` | string | `"original text"` | 要查找并替换的文本 |1945| `old_string` | string | `"original text"` | 要查找并替换的文本 |
1920| `new_string` | string | `"replacement text"` | 替换文本 |1946| `new_string` | string | `"replacement text"` | 替换文本 |
1921| `replace_all` | boolean | `false` | 是否替换所有出现之处 |1947| `replace_all` | boolean | `false` | 是否替换所有匹配项 |
1922 1948
1923<h5 id="read">1949<h5 id="read">
1924 Read1950 Read
1926 1952
1927读取文件内容。1953读取文件内容。
1928 1954
1929| 字段 | 类型 | 示例 | 描述 |1955| 字段 | 类型 | 示例 | 说明 |
1930| :- | :- | :- | :- |1956| :- | :- | :- | :- |
1931| `file_path` | string | `"/path/to/file.txt"` | 要读取的文件的绝对路径 |1957| `file_path` | string | `"/path/to/file.txt"` | 要读取的文件的绝对路径 |
1932| `offset` | number | `10` | 可选,开始读取的行号 |1958| `offset` | number | `10` | 可选,开始读取的行号 |
1938 1964
1939查找与 glob 模式匹配的文件。1965查找与 glob 模式匹配的文件。
1940 1966
1941| 字段 | 类型 | 示例 | 描述 |1967| 字段 | 类型 | 示例 | 说明 |
1942| :- | :- | :- | :- |1968| :- | :- | :- | :- |
1943| `pattern` | string | `"**/*.ts"` | 用于匹配文件的 glob 模式 |1969| `pattern` | string | `"**/*.ts"` | 用于匹配文件的 glob 模式 |
1944| `path` | string | `"/path/to/dir"` | 可选,要搜索的目录。默认为当前工作目录 |1970| `path` | string | `"/path/to/dir"` | 可选,要搜索的目录。默认为当前工作目录 |
1949 1975
1950使用正则表达式搜索文件内容。1976使用正则表达式搜索文件内容。
1951 1977
1952| 字段 | 类型 | 示例 | 描述 |1978| 字段 | 类型 | 示例 | 说明 |
1953| :- | :- | :- | :- |1979| :- | :- | :- | :- |
1954| `pattern` | string | `"TODO.*fix"` | 要搜索的正则表达式模式 |1980| `pattern` | string | `"TODO.*fix"` | 要搜索的正则表达式模式 |
1955| `path` | string | `"/path/to/dir"` | 可选,要搜索的文件或目录 |1981| `path` | string | `"/path/to/dir"` | 可选,要搜索的文件或目录 |
1964 1990
1965获取并处理网页内容。1991获取并处理网页内容。
1966 1992
1967| 字段 | 类型 | 示例 | 描述 |1993| 字段 | 类型 | 示例 | 说明 |
1968| :- | :- | :- | :- |1994| :- | :- | :- | :- |
1969| `url` | string | `"https://example.com/api"` | 要获取内容的 URL |1995| `url` | string | `"https://example.com/api"` | 要获取内容的 URL |
1970| `prompt` | string | `"Extract the API endpoints"` | 对获取到的内容运行的提示词 |1996| `prompt` | string | `"Extract the API endpoints"` | 对获取的内容运行的提示词 |
1971| `offset` | number | `100000` | 可选,从页面开头跳过的字符数。Claude 会设置它以继续读取较长的页面。需要 Claude Code v2.1.290 或更高版本 |1997| `offset` | number | `100000` | 可选,从页面开头跳过的字符数。Claude 设置它以继续阅读长页面。需要 Claude Code v2.1.290 或更高版本 |
1972 1998
1973<h5 id="websearch">1999<h5 id="websearch">
1974 WebSearch2000 WebSearch
1976 2002
1977搜索网络。2003搜索网络。
1978 2004
1979| 字段 | 类型 | 示例 | 描述 |2005| 字段 | 类型 | 示例 | 说明 |
1980| :- | :- | :- | :- |2006| :- | :- | :- | :- |
1981| `query` | string | `"react hooks best practices"` | 搜索查询 |2007| `query` | string | `"react hooks best practices"` | 搜索查询 |
1982| `allowed_domains` | array | `["docs.example.com"]` | 可选:仅包含来自这些域的结果 |2008| `allowed_domains` | array | `["docs.example.com"]` | 可选:仅包含来自这些域名的结果 |
1983| `blocked_domains` | array | `["spam.example.com"]` | 可选:排除来自这些域的结果 |2009| `blocked_domains` | array | `["spam.example.com"]` | 可选:排除来自这些域名的结果 |
1984 2010
1985<h5 id="agent">2011<h5 id="agent">
1986 Agent2012 Agent
1988 2014
1989生成一个[子代理](/docs/zh-CN/sub-agents)。2015生成一个[子代理](/docs/zh-CN/sub-agents)。
1990 2016
1991| 字段 | 类型 | 示例 | 描述 |2017| 字段 | 类型 | 示例 | 说明 |
1992| :- | :- | :- | :- |2018| :- | :- | :- | :- |
1993| `prompt` | string | `"Find all API endpoints"` | Agent 要执行的任务 |2019| `prompt` | string | `"Find all API endpoints"` | Agent 要执行的任务 |
1994| `description` | string | `"Find API endpoints"` | 任务的简短描述 |2020| `description` | string | `"Find API endpoints"` | 任务的简短说明 |
1995| `subagent_type` | string | `"Explore"` | 要使用的专用 Agent 类型 |2021| `subagent_type` | string | `"Explore"` | 要使用的专用 Agent 类型 |
1996| `model` | string | `"sonnet"` | 可选,用于覆盖默认值的模型别名 |2022| `model` | string | `"sonnet"` | 可选,用于覆盖默认值的模型别名 |
1997 2023
1998当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 会在 `tool_response` 中接收到子代理的结果和运行遥测数据。读取这些字段即可检查该次运行;如需汇总各子代理的 token 和成本,请使用按 `query_source` `"subagent"` 过滤的 [token 和成本计数器](/docs/zh-CN/monitoring-usage#token-counter),因为 `totalTokens` 和 `usage` 只涵盖最后一个请求:2024当前台 Agent 调用完成时,您的 [PostToolUse hook](#posttooluse) 会在 `tool_response` 中接收子代理的结果和运行遥测数据。读取这些字段以检查运行情况;要汇总各子代理的 token 和成本,请使用按 `query_source` `"subagent"` 过滤的 [token 和成本计数器](/docs/zh-CN/monitoring-usage#token-counter),因为 `totalTokens` 和 `usage` 仅涵盖最后一次请求:
1999 2025
2000| 字段 | 类型 | 示例 | 描述 |2026| 字段 | 类型 | 示例 | 说明 |
2001| :- | :- | :- | :- |2027| :- | :- | :- | :- |
2002| `status` | string | `"completed"` | 前台子代理为 `"completed"`,后台子代理为 `"async_launched"`。子代理默认在后台运行,因此省略 `run_in_background` 的 Agent 调用也会产生 `"async_launched"` |2028| `status` | string | `"completed"` | 前台子代理为 `"completed"`,后台子代理为 `"async_launched"`。子代理默认在后台运行,因此省略 `run_in_background` 的 Agent 调用也会产生 `"async_launched"` |
2003| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子代理运行的标识符 |2029| `agentId` | string | `"a4d2c8f1e0b3a297"` | 子代理运行的标识符 |
2004| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子代理的最终文本块;对于通过 `SubagentHandback` 提交报告的子代理,则以一条关于该交回的简短说明代替 |2030| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | 子代理的最终文本块;对于通过 `SubagentHandback` 提交报告的子代理,则代之以一条关于该移交的简短说明 |
2005| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子代理启动时使用的模型,可能与请求的模型不同 |2031| `resolvedModel` | string | `"claude-sonnet-4-5"` | 子代理启动时使用的模型,可能与请求的模型不同 |
2006| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复项会被合并;仅在运行中途更换模型时设置。需要 Claude Code v2.1.212 或更高版本 |2032| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 按顺序使用的模型,连续重复项会合并;仅当运行中途切换了模型时设置。需要 Claude Code v2.1.212 或更高版本 |
2007| `totalTokens` | number | `12450` | 子代理最后一次 API 请求的 token 数:输入、输出和缓存 token 之和。这不是整个运行的总数 |2033| `totalTokens` | number | `12450` | 子代理最后一次 API 请求的 token 数:输入、输出和缓存 token 的总和。这不是整个运行的总数 |
2008| `totalDurationMs` | number | `48211` | 子代理运行的实际时长 |2034| `totalDurationMs` | number | `48211` | 子代理运行的实际耗时 |
2009| `totalToolUseCount` | number | `7` | 子代理进行的工具调用次数 |2035| `totalToolUseCount` | number | `7` | 子代理进行的工具调用次数 |
2010| `usage` | object | `{"input_tokens": 8320, ...}` | 最后一次 API 请求按类型划分的 token 明细:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |2036| `usage` | object | `{"input_tokens": 8320, ...}` | 最后一次 API 请求按类型划分的 token 明细:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |
2011 2037
2012在 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`。2038在 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` 字段携带的是关于该移交的简短说明,而不是报告本身。要读取报告,请在 `SubagentHandback` 上匹配 `PreToolUse` 或 `PostToolUse` hook,并读取 `tool_input.message`。
2013 2039
2014对于后台子代理,工具会在任务转入后台时返回,因此 `tool_response` 不携带任何用量字段:后台启动会立即返回,而 Claude Code 在运行中途转入后台的前台任务会在转换时返回。它包含 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。2040对于后台子代理,工具会在任务移到后台时返回,因此 `tool_response` 不携带用量字段:后台启动会立即返回,而 Claude Code 在运行中途移到后台的前台任务会在该转换时返回。它包含 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。
2015 2041
2016在 `completed` 响应中,`resolvedModel` 表示子代理启动时使用的模型,它可能与 `tool_input` 中的 `model` 值不同,例如当 `availableModels` 或其他覆盖生效时。在 `async_launched` 响应中,`resolvedModel` 表示 Agent 转入后台时正在使用的模型,因此转入后台之前发生的模型更换会反映在其中。`modelsUsed` 以及转入后台时的 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。2042在 `completed` 响应中,`resolvedModel` 指明子代理启动时使用的模型,它可能与 `tool_input` 中的 `model` 值不同,例如当 `availableModels` 或其他覆盖生效时。在 `async_launched` 响应中,`resolvedModel` 指明 Agent 移到后台时正在使用的模型,因此在移到后台之前发生的切换会反映在其中。`modelsUsed` 以及移到后台时的 `resolvedModel` 行为需要 Claude Code v2.1.212 或更高版本。
2017 2043
2018<a id="askuserquestion" />2044<a id="askuserquestion" />
2019 2045
2021 AskUserQuestion2047 AskUserQuestion
2022</h5>2048</h5>
2023 2049
2024向用户提出一到四个多选题。2050向用户提出一到四个多项选择问题。
2025 2051
2026| 字段 | 类型 | 示例 | 描述 |2052| 字段 | 类型 | 示例 | 说明 |
2027| :- | :- | :- | :- |2053| :- | :- | :- | :- |
2028| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React", "description": "Component library"}, {"label": "Vue", "description": "Progressive framework"}], "multiSelect": false}]` | 要呈现的问题,每个问题包含 `question` 字符串、简短的 `header`、`options` 数组以及可选的 `multiSelect` 标志 |2054| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React", "description": "Component library"}, {"label": "Vue", "description": "Progressive framework"}], "multiSelect": false}]` | 要呈现的问题,每个问题包含一个 `question` 字符串、简短的 `header`、`options` 数组和可选的 `multiSelect` 标志 |
2029| `answers` | object | `{"Which framework?": "React"}` | 可选。将问题文本映射到所选选项的标签。多选答案用逗号连接各标签。Claude 不会设置此字段;如需以编程方式作答,请通过 `updatedInput` 提供 |2055| `answers` | object | `{"Which framework?": "React"}` | 可选。将问题文本映射到所选选项的标签。多选答案用逗号连接标签。Claude 不会设置此字段;通过 `updatedInput` 提供它以编程方式作答 |
2030 2056
2031<h5 id="exitplanmode">2057<h5 id="exitplanmode">
2032 ExitPlanMode2058 ExitPlanMode
2033</h5>2059</h5>
2034 2060
2035呈现一个计划,并在 Claude 离开[计划模式](/docs/zh-CN/permission-modes#analyze-before-you-edit-with-plan-mode)之前请求用户批准。Claude 在调用该工具之前会将计划写入磁盘上的文件,因此模型给出的原始 `tool_input` 通常为空。Claude Code 会在将输入传递给 hook 之前注入计划内容和文件路径。2061呈现一个计划,并在 Claude 离开[计划模式](/docs/zh-CN/permission-modes#analyze-before-you-edit-with-plan-mode)之前请求用户批准。Claude 在调用该工具之前将计划写入磁盘上的文件,因此模型给出的原始 `tool_input` 通常为空。Claude Code 会在将输入传递给 hook 之前注入计划内容和文件路径。
2036 2062
2037| 字段 | 类型 | 示例 | 描述 |2063| 字段 | 类型 | 示例 | 说明 |
2038| :- | :- | :- | :- |2064| :- | :- | :- | :- |
2039| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 格式的计划内容。从磁盘上的计划文件注入 |2065| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 格式的计划内容。从磁盘上的计划文件注入 |
2040| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。由注入得到 |2066| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 计划文件的路径。注入 |
2041| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已弃用。Claude Code 接受该字段但会忽略它。在 v2.1.205 之前,它携带 Claude 为实施计划而请求的基于提示词的权限 |2067| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已弃用。Claude Code 接受该字段但会忽略它。在 v2.1.205 之前,它携带 Claude 为实施计划而请求的基于提示词的权限 |
2042 2068
2043在 `PostToolUse` 中,`tool_response` 是一个对象,其 `plan` 和 `filePath` 字段包含已批准的计划,另外还有一些内部状态标志。请读取 `tool_response.plan` 获取计划内容,而不要从磁盘重新读取文件。2069在 `PostToolUse` 中,`tool_response` 是一个对象,其 `plan` 和 `filePath` 字段包含已批准的计划,此外还有内部状态标志。请读取 `tool_response.plan` 获取计划内容,而不是从磁盘重新读取文件。
2044 2070
2045<h4 id="pretooluse-decision-control">2071<h4 id="pretooluse-decision-control">
2046 PreToolUse 决策控制2072 PreToolUse 决策控制
2047</h4>2073</h4>
2048 2074
2049`PreToolUse` hook 可以控制工具调用是否继续。与使用顶层 `decision` 字段的其他 hook 不同,PreToolUse 在 `hookSpecificOutput` 对象中返回其决策。这为其提供了更丰富的控制能力:四种结果(允许、拒绝、询问或推迟),以及在执行前修改工具输入的能力。2075`PreToolUse` hook 可以控制工具调用是否继续。与使用顶层 `decision` 字段的其他 hook 不同,PreToolUse 在 `hookSpecificOutput` 对象中返回其决策。这为其提供了更丰富的控制:四种结果(允许、拒绝、询问或延迟),以及在执行前修改工具输入的能力。
2050 2076
2051| 字段 | 描述 |2077| 字段 | 说明 |
2052| :- | :- |2078| :- | :- |
2053| `permissionDecision` | `"allow"` 跳过权限提示,但以下情况除外:[任何模式都不会自动批准的操作](/docs/zh-CN/permission-modes#actions-no-mode-auto-approves)、[从网络路径读取](/docs/zh-CN/permissions#network-paths),以及需要[与 `updatedInput` 搭配使用](#allow-with-updatedinput)的 `AskUserQuestion` 和 `ExitPlanMode`。`"deny"` 阻止工具调用。`"ask"` 提示用户确认。`"defer"` 正常退出,以便稍后恢复该工具。无论 hook 返回什么,[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)仍会被评估 |2079| `permissionDecision` | `"allow"` 会跳过权限提示,但以下情况除外:[任何模式都不会自动批准的操作](/docs/zh-CN/permission-modes#actions-no-mode-auto-approves)、[从网络路径读取](/docs/zh-CN/permissions#network-paths),以及 `AskUserQuestion` 和 `ExitPlanMode`(它们需要[与 `updatedInput` 配合使用](#allow-with-updatedinput))。`"deny"` 会阻止工具调用。`"ask"` 会提示用户确认。`"defer"` 会正常退出,以便稍后恢复该工具。无论 hook 返回什么,[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)仍会被评估 |
2054| `permissionDecisionReason` | 对于 `"ask"`,在权限提示中向用户显示。当 Claude Code 在无人能响应该提示的 `-p` 运行中[拒绝调用](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)时,Claude 会改为在工具结果中读取该原因。对于 `"deny"`,向 Claude 显示。对于 `"allow"` 和 `"defer"`,仅写入[调试日志](#debug-hooks) |2080| `permissionDecisionReason` | 对于 `"ask"`,在权限提示中显示给用户。当 Claude Code 在无人能回应该提示的 `-p` 运行中[拒绝该调用](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)时,Claude 会在工具结果中读取该原因。对于 `"deny"`,显示给 Claude。对于 `"allow"` 和 `"defer"`,仅写入[调试日志](#debug-hooks) |
2055| `updatedInput` | 在执行前修改工具的输入参数。会替换整个输入对象,因此请将未更改的字段与修改后的字段一并包含在内。Claude Code 会针对您的 hook 返回的输入(而不是 Claude 发送的输入)评估权限规则以及 Bash 命令的[自动转入后台资格](/docs/zh-CN/tools-reference#foreground-commands-that-move-to-the-background)。与 `"allow"` 结合可自动批准,与 `"ask"` 结合可向用户显示修改后的输入。对于 `"defer"` 会被忽略 |2081| `updatedInput` | 在执行前修改工具的输入参数。会替换整个输入对象,因此请将未更改的字段与修改后的字段一起包含。Claude Code 会针对您的 hook 返回的输入(而非 Claude 发送的输入)评估权限规则以及 Bash 命令的[自动转入后台资格](/docs/zh-CN/tools-reference#foreground-commands-that-move-to-the-background)。与 `"allow"` 结合可自动批准,与 `"ask"` 结合可向用户显示修改后的输入。对于 `"defer"`,会被忽略 |
2056| `additionalContext` | 与工具结果一同添加到 Claude 上下文中的字符串。当 `permissionDecision` 为 `"defer"` 时会被忽略。请参阅[为 Claude 添加上下文](#add-context-for-claude) |2082| `additionalContext` | 与工具结果一起添加到 Claude 上下文中的字符串。当 `permissionDecision` 为 `"defer"` 时会被忽略。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2057 2083
2058当多个 PreToolUse hook 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。2084当多个 PreToolUse hook 返回不同的决策时,优先级为 `deny` > `defer` > `ask` > `allow`。
2059 2085
2060通过以 2 退出来阻止的 hook,其处理方式与 `"deny"` 相同:Claude 会将 stderr 消息视为拒绝原因。2086通过以退出码 2 退出来阻止的 hook,其处理方式与 `"deny"` 相同:Claude 会将 stderr 消息视为拒绝原因。
2061 2087
2062当 hook 返回 `"ask"` 时,向用户显示的权限提示中会包含一个标签,标明该 hook 的来源:来自任何设置文件或 Agent frontmatter 的 hook 为 `[settings]`,插件的 hook 为 `[plugin:<name>]`,来自 skill frontmatter 的 hook 为 `[skill]`。这有助于用户了解是哪个配置来源在请求确认。2088当 hook 返回 `"ask"` 时,显示给用户的权限提示会包含一个标签,标明该 hook 的来源:来自任何设置文件或 Agent frontmatter 的 hook 为 `[settings]`,插件的 hook 为 `[plugin:<name>]`,来自 skill frontmatter 的 hook 为 `[skill]`。这有助于用户了解是哪个配置来源在请求确认。
2063 2089
2064hook 的 `"ask"` 在[自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode)中也会强制显示权限提示:分类器仍然可以拒绝该工具调用,但不能在不提示的情况下批准它。在 v2.1.211 之前,分类器可以在不显示 hook 所请求提示的情况下批准在[沙箱](/docs/zh-CN/sandboxing)外运行的 Bash 命令;分类器仍会对该命令应用其自身的安全规则,并且 hook 的 `"deny"` 始终会被遵守。2090hook 的 `"ask"` 在[自动模式](/docs/zh-CN/permission-modes#eliminate-prompts-with-auto-mode)下也会强制显示权限提示:分类器仍可以拒绝该工具调用,但无法静默批准该调用。在 v2.1.211 之前,分类器可以在不显示 hook 所请求提示的情况下,批准在[沙箱](/docs/zh-CN/sandboxing)外运行的 Bash 命令;分类器仍会对该命令应用其自身的安全规则,且 hook 的 `"deny"` 始终会被遵守。
2065 2091
2066```json theme={null}2092```json theme={null}
2067{2093{
2078```2104```
2079 2105
2080<Note>2106<Note>
2081 PreToolUse 以前使用顶层的 `decision` 和 `reason` 字段,但对于此事件,这些字段已弃用。请改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已弃用的值 `"approve"` 和 `"block"` 分别映射到 `"allow"` 和 `"deny"`。PostToolUse 和 Stop 等其他事件仍将顶层的 `decision` 和 `reason` 作为其当前格式使用。2107 PreToolUse 以前使用顶层的 `decision` 和 `reason` 字段,但这些字段在此事件中已弃用。请改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已弃用的值 `"approve"` 和 `"block"` 分别映射到 `"allow"` 和 `"deny"`。PostToolUse 和 Stop 等其他事件继续使用顶层 `decision` 和 `reason` 作为其当前格式。
2082</Note>2108</Note>
2083 2109
2084<h4 id="allow-with-updatedinput">2110<h4 id="allow-with-updatedinput">
2085 需要用户交互的工具2111 需要用户交互的工具
2086</h4>2112</h4>
2087 2113
2088`AskUserQuestion` 和 `ExitPlanMode` 需要用户交互。在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)中,只有当运行具有可接收提示的[权限宿主](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)(例如 Agent SDK 的 `canUseTool` 回调)时,Claude Code 才会提供这些工具。2114`AskUserQuestion` 和 `ExitPlanMode` 需要用户交互。在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下,只有当运行具有接收提示的[权限宿主](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)(例如 Agent SDK 的 `canUseTool` 回调)时,Claude Code 才会提供这些工具。
2089 2115
2090当 `PreToolUse` hook 执行以下操作时,即可满足该要求:2116`PreToolUse` hook 在执行以下操作时即可满足该要求:
2091 2117
20921. 从 stdin 读取工具的输入21181. 从 stdin 读取工具的输入
20932. 通过您自己的 UI 收集答案21192. 通过您自己的 UI 收集答案
2095 2121
2096对于这些工具,仅返回 `"allow"` 是不够的。2122对于这些工具,仅返回 `"allow"` 是不够的。
2097 2123
2098对于 `AskUserQuestion`,请原样回传原始的 `questions` 数组,并添加一个 [`answers`](#askuserquestion) 对象,将每个问题的文本映射到所选答案。以下输出用 `React` 回答了一个问题:2124对于 `AskUserQuestion`,请原样返回原始的 `questions` 数组,并添加一个 [`answers`](#askuserquestion) 对象,将每个问题的文本映射到所选答案。此输出以 `React` 回答了一个问题:
2099 2125
2100```json theme={null}2126```json theme={null}
2101{2127{
2117}2143}
2118```2144```
2119 2145
2120其服务器使用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记的 MCP 工具要求更严格:无论是否带有 `updatedInput`,hook 都无法通过 `"allow"` 跳过其批准提示,因为 Claude Code 无法确认 hook 已完成该工具所需的交互。2146其服务器用 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-CN/mcp#require-approval-for-a-specific-tool) 标记的 MCP 工具要求更严格:hook 无法通过 `"allow"` 跳过其批准提示,无论是否附带 `updatedInput`,因为 Claude Code 无法确认该 hook 已完成该工具所需的交互。
2121 2147
2122<h4 id="defer-a-tool-call-for-later">2148<h4 id="defer-a-tool-call-for-later">
2123 推迟工具调用2149 延迟工具调用
2124</h4>2150</h4>
2125 2151
2126`"defer"` 适用于将 `claude -p` 作为子进程运行并读取其 JSON 输出的集成,例如 Agent SDK 应用或基于 Claude Code 构建的自定义 UI。它让调用进程能够在某个工具调用处暂停 Claude,通过自己的界面收集输入,然后从中断处继续。Claude Code 仅在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)中遵守此值。在交互式会话中,它会记录一条警告并忽略该 hook 结果。2152`"defer"` 适用于将 `claude -p` 作为子进程运行并读取其 JSON 输出的集成,例如 Agent SDK 应用或基于 Claude Code 构建的自定义 UI。它允许调用进程在某个工具调用处暂停 Claude,通过自己的界面收集输入,然后从中断处恢复。Claude Code 仅在使用 `-p` 标志的[非交互模式](/docs/zh-CN/headless)下遵守此值。在交互式会话中,它会记录一条警告并忽略该 hook 结果。
2127 2153
2128`AskUserQuestion` 工具是典型场景:Claude 想向用户提问,但没有终端可供作答。`-p` 运行只有在具有[权限宿主](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)(例如您通过 `--permission-prompt-tool` 传入的 MCP 工具)时才会提供 `AskUserQuestion`,因此请带上一个权限宿主启动运行。整个往返流程如下:2154`AskUserQuestion` 工具是典型场景:Claude 想向用户提问,但没有可供作答的终端。`-p` 运行只有在具有[权限宿主](/docs/zh-CN/headless#turn-off-permission-prompts-in-unattended-runs)(例如您通过 `--permission-prompt-tool` 传入的 MCP 工具)时才会提供 `AskUserQuestion`,因此请在启动运行时提供一个。完整的往返流程如下:
2129 2155
21301. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。21561. Claude 调用 `AskUserQuestion`。`PreToolUse` hook 触发。
21312. hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保留在会话记录中。21572. hook 返回 `permissionDecision: "defer"`。工具不执行。进程以 `stop_reason: "tool_deferred"` 退出,待处理的工具调用保存在会话记录中。
21323. 调用进程从 SDK 结果中读取 `deferred_tool_use`,在自己的 UI 中展示问题,并等待回答。21583. 调用进程从 SDK 结果中读取 `deferred_tool_use`,在其自己的 UI 中呈现问题,并等待答案。
21334. 调用进程使用相同的权限宿主运行 `claude -p --resume <session-id>`。同一个工具调用再次触发 `PreToolUse`。21594. 调用进程使用相同的权限宿主运行 `claude -p --resume <session-id>`。同一工具调用会再次触发 `PreToolUse`。
21345. hook 返回 `permissionDecision: "allow"`,并在 `updatedInput` 中附带答案。工具执行,Claude 继续。21605. hook 返回 `permissionDecision: "allow"`,并在 `updatedInput` 中附带答案。工具执行,Claude 继续。
2135 2161
2136`deferred_tool_use` 字段携带工具的 `id`、`name` 和 `input`。`input` 是 Claude 为该工具调用生成的参数,在执行前捕获:2162`deferred_tool_use` 字段携带工具的 `id`、`name` 和 `input`。`input` 是 Claude 为该工具调用生成的参数,在执行前捕获:
2149}2175}
2150```2176```
2151 2177
2152没有超时或重试次数限制。会话会一直保留在磁盘上,直到您恢复它,但受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留清理的约束,该清理默认会在 30 天后删除会话文件,并遵循[保留清理规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果恢复时答案尚未准备好,hook 可以再次返回 `"defer"`,进程会以相同方式退出。调用进程通过最终让 hook 返回 `"allow"` 或 `"deny"` 来控制何时结束循环。2178没有超时或重试限制。会话会保留在磁盘上直到您恢复它,但受 [`cleanupPeriodDays`](/docs/zh-CN/settings-reference#cleanupperioddays) 保留清理的约束,该清理默认在 30 天后删除会话文件,遵循[保留清理规则](/docs/zh-CN/claude-directory#cleaned-up-automatically)。如果恢复时答案尚未准备好,hook 可以再次返回 `"defer"`,进程会以同样的方式退出。调用进程通过最终从 hook 返回 `"allow"` 或 `"deny"` 来控制何时结束循环。
2153 2179
2154`"defer"` 仅在 Claude 在该轮次中只进行一次工具调用时有效。如果 Claude 同时进行多次工具调用,`"defer"` 会被忽略并发出警告,工具会经过正常的权限流程继续。存在此限制是因为恢复时只能重新运行一个工具:无法在推迟一批调用中的某一个的同时,不让其他调用处于未解决状态。2180`"defer"` 仅在 Claude 在该轮次中进行单个工具调用时有效。如果 Claude 同时进行多个工具调用,`"defer"` 会被忽略并给出警告,工具将通过正常的权限流程继续。存在此限制是因为恢复只能重新运行一个工具:无法在不让其他调用悬而未决的情况下,从一批调用中延迟其中一个。
2155 2181
2156如果恢复时被推迟的工具已不可用,进程会在 hook 触发之前以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出。当提供该工具的 MCP 服务器在恢复的会话中未连接时,就会发生这种情况。`deferred_tool_use` 负载仍会包含在内,以便您确定缺失的是哪个工具。2182如果恢复时延迟的工具已不再可用,进程会在 hook 触发之前以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出。当提供该工具的 MCP 服务器未在恢复的会话中连接时,就会发生这种情况。`deferred_tool_use` 数据仍会包含在内,以便您识别缺失的是哪个工具。
2157 2183
2158<Note>2184<Note>
2159 要在计划模式下恢复被延迟的会话,请将 [`--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 或更高版本。2185 要在计划模式下恢复延迟的会话,请将 [`--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 或更高版本。
2160 2186
2161 当您使用 `-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)中。2187 当您使用 `-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)中列出的例外情况除外。
2162</Note>2188</Note>
2163 2189
2164<h3 id="permissionrequest">2190<h3 id="permissionrequest">
2165 PermissionRequest2191 PermissionRequest
2166</h3>2192</h3>
2167 2193
2168在 Claude Code 即将向您请求使用某个工具的权限时运行。在无法显示提示的会话中,例如[非交互模式](/docs/zh-CN/headless)下的后台子代理,Claude Code 仍会运行这些 hook,如果没有 hook 返回决策,它会拒绝该工具调用。对于到达 `--permission-prompt-tool` 或 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/permissions)的调用,hook 会与您的宿主并行运行,以先做出决策者为准。2194在 Claude Code 即将向您请求使用某个工具的权限时运行。在无法显示提示的会话中,例如[非交互模式](/docs/zh-CN/headless)下的后台子代理,Claude Code 仍会运行这些 hook;如果没有 hook 返回决策,它会拒绝该工具调用。对于到达 `--permission-prompt-tool` 或 Agent SDK [`canUseTool` 回调](/docs/zh-CN/agent-sdk/permissions)的调用,hook 会与您的宿主并行运行,以先做出决策的一方为准。
2169使用 [PermissionRequest 决策控制](#permissionrequest-decision-control)代表用户允许或拒绝。2195使用 [PermissionRequest 决策控制](#permissionrequest-decision-control)代表用户允许或拒绝。
2170 2196
2171当您需要在 Claude 请求使用工具权限的那一刻获得信号时,请使用此事件。Claude Code 只有在提示已等待约六秒后,才会运行 `permission_prompt` 类型的 [Notification](#notification) hook。2197当您需要在 Claude 请求使用工具权限的那一刻获得信号时,请使用此事件。Claude Code 仅在提示等待约六秒后,才会运行 `permission_prompt` 类型的 [Notification](#notification) hook。
2172 2198
2173对于沙箱中命令的[网络请求](/docs/zh-CN/sandboxing#network-isolation),Claude Code 不会运行 PermissionRequest hook。要获取该提示的信号,请使用 `permission_prompt` 通知类型。2199Claude Code 不会为沙箱化命令的[网络请求](/docs/zh-CN/sandboxing#network-isolation)运行 PermissionRequest hook。要获取该提示的信号,请使用 `permission_prompt` 通知类型。
2174 2200
2175按工具名称匹配,取值与 PreToolUse 相同。2201按工具名称匹配,取值与 PreToolUse 相同。
2176 2202
2178 PermissionRequest 输入2204 PermissionRequest 输入
2179</h4>2205</h4>
2180 2206
2181PermissionRequest hook 与 PreToolUse hook 一样接收 `tool_name` 和 `tool_input` 字段,但没有 `tool_use_id`。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 针对此请求建议的[权限更新](#permission-update-entries),例如添加允许规则或更改权限模式。2207PermissionRequest hook 与 PreToolUse hook 一样接收 `tool_name` 和 `tool_input` 字段,但不包含 `tool_use_id`。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。可选的 `permission_suggestions` 数组包含 Claude Code 针对此请求建议的[权限更新](#permission-update-entries),例如添加允许规则或更改权限模式。
2182 2208
2183`permission_suggestions` 数组并不是您所看到选项的精确列表,因为每个权限对话框都会构建自己的选项。某些对话框(例如文件编辑的对话框)根本不读取该数组,而是根据请求本身得出选项。读取该数组的对话框仍可能隐藏某个建议仍保留在数组中的选项,例如当 [`allowManagedPermissionRulesOnly`](/docs/zh-CN/settings-reference#allowmanagedpermissionrulesonly) 隐藏保存规则的选项时。它也可能提供没有对应建议条目的选项,例如 [**Yes, and switch to auto mode**](/docs/zh-CN/permission-modes#switch-permission-modes),该选项直接更改权限模式,而不是通过权限更新。2209`permission_suggestions` 数组并不是您所看到选项的精确列表,因为每个权限对话框都会构建自己的选项。某些对话框(例如用于文件编辑的对话框)根本不读取该数组,而是从请求本身推导出选项。读取该数组的对话框仍可能隐藏某个选项,而其对应建议仍保留在数组中,例如当 [`allowManagedPermissionRulesOnly`](/docs/zh-CN/settings-reference#allowmanagedpermissionrulesonly) 隐藏保存规则的选项时。对话框也可能提供没有对应建议条目的选项,例如 [**Yes, and switch to auto mode**](/docs/zh-CN/permission-modes#switch-permission-modes),它直接更改权限模式,而不是通过权限更新来实现。
2184 2210
2185PreToolUse hook 在每次工具调用之前运行,无论该调用是否需要权限。PermissionRequest hook 仅在 Claude Code 即将向您请求权限时,或者在它原本会自动拒绝一个无法提示的调用时运行。这两个事件都不会为 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。2211PreToolUse hook 在每次工具调用之前运行,无论该调用是否需要权限。PermissionRequest hook 仅在 Claude Code 即将向您请求权限时运行,或者在它原本会自动拒绝一个无法弹出提示的调用时运行。这两个事件都不会针对 [`EndConversation`](/docs/zh-CN/tools-reference#endconversation-tool-behavior) 触发。
2186 2212
2187```json theme={null}2213```json theme={null}
2188{2214{
2211 PermissionRequest 决策控制2237 PermissionRequest 决策控制
2212</h4>2238</h4>
2213 2239
2214`PermissionRequest` hook 可以允许或拒绝权限请求。除所有 hook 都可用的 [JSON 输出字段](#json-output)外,您的 hook 脚本还可以返回一个包含以下事件专属字段的 `decision` 对象:2240`PermissionRequest` hook 可以允许或拒绝权限请求。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回一个包含以下事件特定字段的 `decision` 对象:
2215 2241
2216| 字段 | 描述 |2242| 字段 | 描述 |
2217| :- | :- |2243| :- | :- |
2218| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝权限。[拒绝和询问规则](/docs/zh-CN/permissions#manage-permissions)仍会被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |2244| `behavior` | `"allow"` 授予权限,`"deny"` 拒绝权限。[拒绝规则和询问规则](/docs/zh-CN/permissions#manage-permissions)仍会被评估,因此返回 `"allow"` 的 hook 不会覆盖匹配的拒绝规则 |
2219| `updatedInput` | 仅用于 `"allow"`:在执行前修改工具的输入参数。会替换整个输入对象,因此请将未更改的字段与修改后的字段一并包含在内。修改后的输入会针对拒绝和询问规则重新评估 |2245| `updatedInput` | 仅适用于 `"allow"`:在执行前修改工具的输入参数。它会替换整个输入对象,因此请将未更改的字段与修改后的字段一并包含。修改后的输入会再次根据拒绝规则和询问规则进行评估 |
2220| `updatedPermissions` | 仅用于 `"allow"`:要应用的[权限更新条目](#permission-update-entries)数组,例如添加允许规则或更改会话的权限模式 |2246| `updatedPermissions` | 仅适用于 `"allow"`:要应用的[权限更新条目](#permission-update-entries)数组,例如添加允许规则或更改会话权限模式 |
2221| `message` | 仅用于 `"deny"`:告诉 Claude 权限被拒绝的原因 |2247| `message` | 仅适用于 `"deny"`:告知 Claude 权限被拒绝的原因 |
2222| `interrupt` | 仅用于 `"deny"`:如果为 `true`,则停止 Claude |2248| `interrupt` | 仅适用于 `"deny"`:如果为 `true`,则停止 Claude |
2223 2249
2224以退出码 2 退出但未提供 `decision` 对象的 hook 不会改变权限流程,其 stderr 会被丢弃。要授予或拒绝请求,请返回 `decision` 对象。2250以退出码 2 退出但未返回 `decision` 对象的 hook 不会改变权限流程,其 stderr 会被丢弃。要授予或拒绝请求,请返回 `decision` 对象。
2225 2251
2226```json theme={null}2252```json theme={null}
2227{2253{
2241 权限更新条目2267 权限更新条目
2242</h4>2268</h4>
2243 2269
2244`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input)都使用相同的条目对象数组。每个条目都有一个 `type`,它决定该条目的其他字段;还有一个 `destination`,它控制更改写入的位置。2270`updatedPermissions` 输出字段和 [`permission_suggestions` 输入字段](#permissionrequest-input)都使用相同的条目对象数组。每个条目都有一个决定其其他字段的 `type`,以及一个控制更改写入位置的 `destination`。
2245 2271
2246| `type` | 字段 | 效果 |2272| `type` | 字段 | 效果 |
2247| :- | :- | :- |2273| :- | :- | :- |
2248| `addRules` | `rules`、`behavior`、`destination` | 添加权限规则。`rules` 是由 `{toolName, ruleContent?}` 对象组成的数组。省略 `ruleContent` 即匹配整个工具。`behavior` 为 `"allow"`、`"deny"` 或 `"ask"` |2274| `addRules` | `rules`、`behavior`、`destination` | 添加权限规则。`rules` 是一个由 `{toolName, ruleContent?}` 对象组成的数组。省略 `ruleContent` 可匹配整个工具。`behavior` 为 `"allow"`、`"deny"` 或 `"ask"` |
2249| `replaceRules` | `rules`、`behavior`、`destination` | 用提供的 `rules` 替换 `destination` 中给定 `behavior` 的所有规则 |2275| `replaceRules` | `rules`、`behavior`、`destination` | 用提供的 `rules` 替换 `destination` 处给定 `behavior` 的所有规则 |
2250| `removeRules` | `rules`、`behavior`、`destination` | 移除给定 `behavior` 的匹配规则 |2276| `removeRules` | `rules`、`behavior`、`destination` | 删除给定 `behavior` 的匹配规则 |
2251| `setMode` | `mode`、`destination` | 更改权限模式。有效模式为 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan`,以及作为 `default` 别名的 `manual` |2277| `setMode` | `mode`、`destination` | 更改权限模式。有效模式为 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan`,以及作为 `default` 别名的 `manual` |
2252| `addDirectories` | `directories`、`destination` | 添加工作目录。`directories` 是路径字符串数组 |2278| `addDirectories` | `directories`、`destination` | 添加工作目录。`directories` 是一个路径字符串数组 |
2253| `removeDirectories` | `directories`、`destination` | 移除工作目录 |2279| `removeDirectories` | `directories`、`destination` | 删除工作目录 |
2254 2280
2255<Note>2281<Note>
2256 仅当您启动会话时 bypass 模式已可用,`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)启动时,该更新同样不起作用。2282 仅当您启动会话时 bypass 模式已可用,带有 `bypassPermissions` 的 `setMode` 才会生效:即使用了 `--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)启动时,该更新同样不会产生任何效果。
2257 2283
2258 无论 `destination` 为何值,`bypassPermissions` 都不会被持久化为 `defaultMode`。2284 无论 `destination` 为何值,`bypassPermissions` 都不会被持久化为 `defaultMode`。
2259</Note>2285</Note>
2260 2286
2261每个条目上的 `destination` 字段决定更改是仅保留在内存中,还是持久化到设置文件。2287每个条目上的 `destination` 字段决定更改是仅保留在内存中,还是持久化到设置文件中。
2262 2288
2263| `destination` | 写入位置 |2289| `destination` | 写入位置 |
2264| :- | :- |2290| :- | :- |
2277 2303
2278按工具名称匹配,取值与 PreToolUse 相同。2304按工具名称匹配,取值与 PreToolUse 相同。
2279 2305
2280当工具名称不是合适的过滤条件时,可以更宽泛地匹配:2306当工具名称不是合适的过滤条件时,可以进行更宽泛的匹配:
2281 2307
2282* 要在任何工具成功完成后运行 hook,请省略 `matcher` 或将其设为 `"*"`。然后您的 hook 可以自行发现发生了哪些更改,例如运行 `git status --porcelain`,它还会列出 `git diff` 遗漏的未跟踪文件。对于失败的工具调用,请在 [PostToolUseFailure](#posttoolusefailure) 下添加相同的 hook。2308* 要在任何工具成功完成后运行 hook,请省略 `matcher` 或将其设置为 `"*"`。然后您的 hook 可以自行发现发生了哪些更改,例如运行 `git status --porcelain`,它还会列出 `git diff` 遗漏的未跟踪文件。对于失败的工具调用,请在 [PostToolUseFailure](#posttoolusefailure) 下添加相同的 hook。
2283* 要在特定文件在磁盘上发生更改时运行 hook(无论由谁写入),请使用 [FileChanged](#filechanged)。当 `Bash` 命令或 Claude Code 之外的进程重写同一文件时,Claude Code 不会运行匹配 `Edit|Write` 的 `PostToolUse` hook。2309* 要在特定文件在磁盘上发生更改时运行 hook(无论由谁写入),请使用 [FileChanged](#filechanged)。当 `Bash` 命令或 Claude Code 之外的进程重写同一文件时,Claude Code 不会运行匹配 `Edit|Write` 的 `PostToolUse` hook。
2284 2310
2285<h4 id="posttooluse-input">2311<h4 id="posttooluse-input">
2286 PostToolUse 输入2312 PostToolUse 输入
2287</h4>2313</h4>
2288 2314
2289`PostToolUse` hook 在工具已成功执行后触发。输入同时包含 `tool_input`(发送给工具的参数)和 `tool_response`(工具返回的结果)。两者的确切 schema 取决于具体工具。文件类工具的 `tool_input` 路径格式与 [PreToolUse](#pretooluse-input) 相同:始终为绝对路径,使用平台原生分隔符,因此在 Windows 上为反斜杠。对于 MCP 工具,输入还包含 [`mcp_server`](#pretooluse-input) 对象。2315`PostToolUse` hook 在工具已成功执行后触发。输入同时包含 `tool_input`(发送给工具的参数)和 `tool_response`(工具返回的结果)。两者的确切 schema 取决于具体工具。文件工具的 `tool_input` 路径格式与 [PreToolUse](#pretooluse-input) 相同:始终为绝对路径,并使用平台原生的分隔符,因此在 Windows 上为反斜杠。对于 MCP 工具,输入还会携带 [`mcp_server`](#pretooluse-input) 对象。
2290 2316
2291```json theme={null}2317```json theme={null}
2292{2318{
2317 PostToolUse 决策控制2343 PostToolUse 决策控制
2318</h4>2344</h4>
2319 2345
2320`PostToolUse` hook 可以在工具执行后向 Claude 提供反馈。除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,您的 hook 脚本还可以返回以下事件特定字段:2346`PostToolUse` hook 可以在工具执行后向 Claude 提供反馈。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下事件特定字段:
2321 2347
2322| 字段 | 描述 |2348| 字段 | 描述 |
2323| :- | :- |2349| :- | :- |
2324| `decision` | `"block"` 会在工具结果旁添加 `reason`。Claude 仍会看到原始输出;要替换它,请使用 `updatedToolOutput` |2350| `decision` | `"block"` 会将 `reason` 添加到工具结果旁边。Claude 仍会看到原始输出;要替换它,请使用 `updatedToolOutput` |
2325| `reason` | 当 `decision` 为 `"block"` 时向 Claude 显示的说明 |2351| `reason` | 当 `decision` 为 `"block"` 时向 Claude 显示的说明 |
2326| `additionalContext` | 与工具结果一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |2352| `additionalContext` | 与工具结果一起添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2327| `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 或更高版本 |2353| `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 或更高版本 |
2328| `updatedToolOutput` | 在工具输出发送给 Claude 之前,用提供的值替换它。该值必须与工具的输出结构相匹配 |2354| `updatedToolOutput` | 在工具输出发送给 Claude 之前,用提供的值替换它。该值必须与工具的输出结构相匹配 |
2329| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools)的输出。建议优先使用适用于所有工具的 `updatedToolOutput` |2355| `updatedMCPToolOutput` | 仅替换 [MCP 工具](#match-mcp-tools)的输出。建议优先使用适用于所有工具的 `updatedToolOutput` |
2330 2356
2331以下示例替换了一次 `Bash` 调用的输出。替换值与 `Bash` 工具的输出结构相匹配:2357下面的示例替换了一次 `Bash` 调用的输出。替换值与 `Bash` 工具的输出结构相匹配:
2332 2358
2333```json theme={null}2359```json theme={null}
2334{2360{
2346```2372```
2347 2373
2348<Warning>2374<Warning>
2349 `updatedToolOutput` 只会改变 Claude 看到的内容。hook 触发时工具已经运行完毕,因此任何已写入的文件、已执行的命令或已发送的网络请求都已生效。诸如 OpenTelemetry 工具 span 和分析事件之类的遥测数据也会在 hook 运行之前捕获原始输出。要在工具调用运行之前阻止或修改它,请改用 [PreToolUse](#pretooluse) hook。2375 `updatedToolOutput` 只会改变 Claude 看到的内容。hook 触发时工具已经运行,因此任何已写入的文件、已执行的命令或已发送的网络请求都已生效。诸如 OpenTelemetry 工具 span 和分析事件之类的遥测数据也会在 hook 运行之前捕获原始输出。要在工具调用运行之前阻止或修改它,请改用 [PreToolUse](#pretooluse) hook。
2350 2376
2351 替换值必须与工具的输出结构相匹配。内置工具返回的是结构化对象,而非纯字符串。例如,`Bash` 返回一个包含 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,与工具输出 schema 不匹配的值会被忽略,并使用原始输出。MCP 工具的输出会直接传递,不进行 schema 验证。删除 Claude 所需的错误详情可能会导致它基于错误的假设继续操作。2377 替换值必须与工具的输出结构相匹配。内置工具返回的是结构化对象,而不是纯字符串。例如,`Bash` 返回一个包含 `stdout`、`stderr`、`interrupted` 和 `isImage` 字段的对象。对于内置工具,与工具输出 schema 不匹配的值会被忽略,并使用原始输出。MCP 工具输出会直接传递,不进行 schema 验证。删除 Claude 需要的错误详细信息可能会导致它基于错误的假设继续执行。
2352</Warning>2378</Warning>
2353 2379
2354<h4 id="annotate-a-result-for-the-auto-mode-classifier">2380<h4 id="annotate-a-result-for-the-auto-mode-classifier">
2355 为自动模式分类器注释结果2381 为自动模式分类器注释结果
2356</h4>2382</h4>
2357 2383
2358返回 `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 或更高版本。2384返回 `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 或更高版本。
2359 2385
2360以下示例告知分类器某个查询输出的来源:2386下面的示例告知分类器某次查询输出的来源:
2361 2387
2362```json theme={null}2388```json theme={null}
2363{2389{
2368}2394}
2369```2395```
2370 2396
2371分类器对该说明的重视程度取决于您配置 hook 的位置:2397分类器对该说明的重视程度取决于您在何处配置该 hook:
2372 2398
2373* **在 Claude Code 中配置的 hook**:对于来自设置文件、插件、skill 和 Agent frontmatter 的 hook,分类器将该说明视为未经验证的、由应用程序提供的上下文。该说明永远不能确立用户意图;如果它声称您批准或请求了某事,分类器会将该声明与您在对话中发送的消息进行核对2399* **在 Claude Code 中配置的 hook**:对于来自设置文件、插件、skill 和 Agent frontmatter 的 hook,分类器将该说明视为未经验证的、由应用程序提供的上下文。该说明永远不能确立用户意图;如果它声称您批准或请求了某些内容,分类器会将该声明与您在对话中发送的消息进行核对
2374* **进程内 Agent SDK 回调**:当嵌入 Claude Code 的应用程序将 hook 注册为 [TypeScript SDK 回调](/docs/zh-CN/agent-sdk/hooks),并在实时会话期间返回该说明时,分类器可能会将说明中转述的用户陈述视为用户意图。这样的陈述可以满足分类器本会从您发送的消息中接受的同意要求,但它永远不能解除您自己的消息也无法解除的阻止。会话恢复后,Claude Code 会将恢复的说明视为未经验证的上下文。当两组中的 hook 都对同一调用进行注释时,分类器会将合并后的说明视为未经验证的内容2400* **进程内 Agent SDK 回调**:当嵌入 Claude Code 的应用程序将 hook 注册为 [TypeScript SDK 回调](/docs/zh-CN/agent-sdk/hooks)并在实时会话期间返回该说明时,分类器可能会将说明中转述的用户陈述视为用户意图。这样的陈述可以满足分类器原本会从您发送的消息中接受的同意要求,但它永远无法解除您自己的消息同样无法解除的阻止。会话恢复后,Claude Code 会将恢复的说明视为未经验证的上下文。当来自两类的 hook 为同一调用添加注释时,分类器会将合并后的说明视为未经验证
2375 2401
2376Claude Code 在传递该说明时会应用以下限制:2402Claude Code 在传递该说明时会施加以下限制:
2377 2403
2378* **长度**:Claude Code 将单次工具调用的说明上限设为 2,000 个字符,并截断其余部分。该上限由响应该调用的所有 hook 共享2404* **长度**:Claude Code 将单次工具调用的说明上限设为 2,000 个字符,并截断其余部分。该上限由响应该调用的所有 hook 共享
2379* **仅限同步响应**:对于[在后台运行](#run-hooks-in-the-background)的 hook,Claude Code 会忽略其响应中的该字段,因为该响应在 Claude Code 记录工具结果之后才到达2405* **仅限同步响应**:对于[在后台运行](#run-hooks-in-the-background)的 hook,Claude Code 会忽略其响应中的该字段,因为该响应在 Claude Code 记录工具结果之后才到达
2380* **分类器不记录的调用**:分类器的会话记录会省略只读查找,例如文件读取和搜索。Claude Code 会丢弃附加在这类调用上的说明2406* **分类器不记录的调用**:分类器的会话记录会省略只读查找,例如文件读取和搜索。Claude Code 会丢弃附加到这类调用上的说明
2381* **与重写的交互**:当说明描述的是您要用 `updatedToolOutput` 替换的输出时,请在同一个 hook 响应中返回这两个字段。如果该重写被拒绝,或被另一个 hook 的重写替换,Claude Code 会丢弃该说明。即使另一个 hook 重写了输出,Claude Code 仍会传递您在没有重写的情况下返回的说明2407* **与重写的交互**:当说明描述的是您正在用 `updatedToolOutput` 替换的输出时,请在同一个 hook 响应中同时返回这两个字段。如果该重写被拒绝,或被另一个 hook 的重写替换,Claude Code 会丢弃该说明。即使另一个 hook 重写了输出,Claude Code 仍会传递您在未进行重写的情况下返回的说明
2382 2408
2383<Warning>2409<Warning>
2384 分类器会将您放入 `classifierContext` 的内容视为来自托管该会话的应用程序的信息,因此不要将不受信任的工具输出或第三方文本复制到其中。请将说明保持为关于这一次调用的简短断言,例如关于其来源的事实或用户对其的陈述;不要使用该字段传递无关消息或事件流。2410 分类器会将您放入 `classifierContext` 的内容视为来自托管该会话的应用程序的信息,因此请勿将不受信任的工具输出或第三方文本复制到其中。请将说明限定为关于这一次调用的简短断言,例如关于其来源的事实或用户对其所作的陈述;不要使用该字段传递无关消息或一系列事件。
2385</Warning>2411</Warning>
2386 2412
2387<h3 id="posttoolusefailure">2413<h3 id="posttoolusefailure">
2388 PostToolUseFailure2414 PostToolUseFailure
2389</h3>2415</h3>
2390 2416
2391当已开始执行的工具失败时运行:工具抛出错误,或 MCP 工具返回错误结果。可用于记录失败、发送警报或向 Claude 提供纠正性反馈。2417当已开始执行的工具失败时运行:工具抛出了错误,或 MCP 工具返回了错误结果。可用于记录失败日志、发送警报或向 Claude 提供纠正性反馈。
2392 2418
2393按工具名称匹配,取值与 PreToolUse 相同。2419按工具名称匹配,取值与 PreToolUse 相同。
2394 2420
2395<Note>2421<Note>
2396 对于在执行前被拒绝的工具调用,此事件不会触发:未知的工具名称、未通过 schema 或工具特定验证的输入,或权限拒绝。验证拒绝会作为 `tool_use_error` 结果返回,且发生在 hook 运行之前,因此既不会触发 `PreToolUse`,也不会触发 `PostToolUseFailure`。权限拒绝会触发 `PreToolUse`,但不会触发此事件;请参阅 [PermissionDenied](#permissiondenied)。2422 对于在执行前被拒绝的工具调用,此事件不会触发:例如未知的工具名称、未通过 schema 或工具特定验证的输入,或权限拒绝。验证拒绝会以 `tool_use_error` 结果返回,且发生在 hook 运行之前,因此既不会触发 `PreToolUse`,也不会触发 `PostToolUseFailure`。权限拒绝会触发 `PreToolUse`,但不会触发此事件;请参阅 [PermissionDenied](#permissiondenied)。
2397</Note>2423</Note>
2398 2424
2399<h4 id="posttoolusefailure-input">2425<h4 id="posttoolusefailure-input">
2400 PostToolUseFailure 输入2426 PostToolUseFailure 输入
2401</h4>2427</h4>
2402 2428
2403PostToolUseFailure hook 接收与 PostToolUse 相同的 `tool_name` 和 `tool_input` 字段,以及作为顶层字段的错误信息。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。例如,一个失败的 `npm test` 命令可能会传递:2429PostToolUseFailure hook 接收与 PostToolUse 相同的 `tool_name` 和 `tool_input` 字段,以及作为顶层字段的错误信息。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。例如,一条失败的 `npm test` 命令可能会传递:
2404 2430
2405```json theme={null}2431```json theme={null}
2406{2432{
2424| 字段 | 描述 |2450| 字段 | 描述 |
2425| :- | :- |2451| :- | :- |
2426| `error` | 描述出错原因的字符串。格式取决于失败的工具 |2452| `error` | 描述出错原因的字符串。格式取决于失败的工具 |
2427| `is_interrupt` | 可选布尔值。当失败是以中止形式而非工具报告的错误到达 Claude Code 时为 true。取消正在运行的工具不会触发此 hook;工具结果中会改为携带中断消息 |2453| `is_interrupt` | 可选布尔值。当失败以中止(而非工具报告的错误)的形式到达 Claude Code 时为 true。取消正在运行的工具不会触发此 hook;此时工具结果会携带中断消息 |
2428| `duration_ms` | 可选。工具执行时间(毫秒)。不包括在权限提示和 PreToolUse hook 中花费的时间 |2454| `duration_ms` | 可选。工具执行时间(毫秒)。不包括在权限提示和 PreToolUse hook 中花费的时间 |
2429 2455
2430`error` 字符串通常与 Claude 作为失败工具结果收到的文本相同。其格式因工具和失败情况而异。请让您的 hook 依据 `tool_name`、`is_interrupt` 以及 `Exit code N` 首行进行判断;将字符串的其余部分视为显示文本,而非稳定格式。2456`error` 字符串通常与 Claude 收到的失败工具结果文本相同。其格式因工具和失败类型而异。请根据 `tool_name`、`is_interrupt` 以及首行 `Exit code N` 来编写 hook 逻辑;将字符串的其余部分视为显示文本,而不是稳定的格式。
2431 2457
2432* 对于 Bash 和 PowerShell,已运行并退出的命令会产生首行 `Exit code N`,随后是命令产生的所有输出,stdout 和 stderr 交错合并为一个块2458* 对于 Bash 和 PowerShell,已运行并退出的命令会生成首行 `Exit code N`,随后是命令产生的所有输出,stdout 和 stderr 交错合并为一个块
2433* 当 Claude Code 无法启动 shell 进程本身时,数据中也可能只携带一条不含退出码行的失败消息2459* 当 Claude Code 无法启动 shell 进程本身时,负载也可能只携带一条不含退出码行的失败消息
2434* Claude Code 会在 `... [N characters truncated] ...` 标记周围对长字符串进行中间截断,并可能插入其自身的行,例如 `Command timed out after 2m 0s`2460* Claude Code 会在 `... [N characters truncated] ...` 标记处对长字符串进行中间截断,并且可能插入自己的行,例如 `Command timed out after 2m 0s`
2435 2461
2436<h4 id="posttoolusefailure-decision-control">2462<h4 id="posttoolusefailure-decision-control">
2437 PostToolUseFailure 决策控制2463 PostToolUseFailure 决策控制
2438</h4>2464</h4>
2439 2465
2440`PostToolUseFailure` hook 可以在工具失败后向 Claude 提供上下文。除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,您的 hook 脚本还可以返回以下事件特定字段:2466`PostToolUseFailure` hook 可以在工具失败后向 Claude 提供上下文。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下事件特定字段:
2441 2467
2442| 字段 | 描述 |2468| 字段 | 描述 |
2443| :- | :- |2469| :- | :- |
2456 PostToolBatch2482 PostToolBatch
2457</h3>2483</h3>
2458 2484
2459在一批工具调用全部完成后运行一次,时机在 Claude Code 向模型发送下一个请求之前。`PostToolUse` 对每个工具触发一次,这意味着当 Claude 进行并行工具调用时它会并发触发。`PostToolBatch` 针对整批调用恰好触发一次,因此适合注入依赖于所运行工具集合(而非任何单个工具)的上下文。此事件没有匹配器。2485在一批中的所有工具调用都已完成之后、Claude Code 向模型发送下一个请求之前运行一次。`PostToolUse` 对每个工具触发一次,这意味着当 Claude 进行并行工具调用时,它会并发触发。`PostToolBatch` 针对整批调用恰好触发一次,因此适合注入依赖于所运行工具集合(而非任何单个工具)的上下文。此事件没有匹配器。
2460 2486
2461<h4 id="posttoolbatch-input">2487<h4 id="posttoolbatch-input">
2462 PostToolBatch 输入2488 PostToolBatch 输入
2463</h4>2489</h4>
2464 2490
2465除了[通用输入字段](#common-input-fields)外,PostToolBatch hook 还会接收 `tool_calls`,这是一个描述该批次中每个工具调用的数组:2491除了[通用输入字段](#common-input-fields)之外,PostToolBatch hook 还会接收 `tool_calls`,这是一个描述批次中每个工具调用的数组:
2466 2492
2467```json theme={null}2493```json theme={null}
2468{2494{
2488}2514}
2489```2515```
2490 2516
2491`tool_response` 包含模型在对应 `tool_result` 块中收到的相同内容。该值是序列化字符串或内容块数组,与工具发出的完全一致。对于 `Read`,这意味着它是带行号前缀的文本,而不是原始文件内容。响应可能很大,因此只解析您需要的字段。2517`tool_response` 包含与模型在对应 `tool_result` 块中收到的相同内容。该值是序列化字符串或内容块数组,与工具发出时完全一致。对于 `Read`,这意味着是带行号前缀的文本,而不是原始文件内容。响应可能很大,因此只解析您需要的字段。
2492 2518
2493<Note>2519<Note>
2494 `tool_response` 的结构与 `PostToolUse` 的不同。`PostToolUse` 传递的是工具的结构化 `Output` 对象,例如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递的是模型看到的序列化 `tool_result` 内容。2520 `tool_response` 的结构与 `PostToolUse` 的不同。`PostToolUse` 传递的是工具的结构化 `Output` 对象,例如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 传递的是模型看到的序列化 `tool_result` 内容。
2498 PostToolBatch 决策控制2524 PostToolBatch 决策控制
2499</h4>2525</h4>
2500 2526
2501`PostToolBatch` hook 可以为 Claude 注入上下文。除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,您的 hook 脚本还可以返回以下事件特定字段:2527`PostToolBatch` hook 可以为 Claude 注入上下文。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下事件特定字段:
2502 2528
2503| 字段 | 描述 |2529| 字段 | 描述 |
2504| :- | :- |2530| :- | :- |
2513}2539}
2514```2540```
2515 2541
2516返回 `decision: "block"` 或 `continue: false` 会在下一次模型调用之前停止智能体循环。阻止消息来自 JSON 中的 `reason` 或 `stopReason`,或在退出码为 2 时来自 stderr。您会在会话记录中看到一条警告,并且它会保留在对话中,因此对话继续时 Claude 也能看到它。2542返回 `decision: "block"` 或 `continue: false` 会在下一次模型调用之前停止智能体循环。阻止消息来自 JSON 的 `reason` 或 `stopReason`,或者来自以退出码 2 退出时的 stderr。您会在会话记录中看到它显示为警告,并且它会保留在对话中,因此当对话继续时 Claude 也会看到它。
2517 2543
2518<h3 id="permissiondenied">2544<h3 id="permissiondenied">
2519 PermissionDenied2545 PermissionDenied
2520</h3>2546</h3>
2521 2547
2522当[自动模式](/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` 规则匹配时,它不会运行。可用于记录拒绝情况、调整配置,或告知模型可以重试该工具调用。2548当[自动模式](/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` 规则匹配时,它不会运行。可用于记录拒绝日志、调整配置,或告知模型可以重试该工具调用。
2523 2549
2524按工具名称匹配,取值与 PreToolUse 相同。2550按工具名称匹配,取值与 PreToolUse 相同。
2525 2551
2527 PermissionDenied 输入2553 PermissionDenied 输入
2528</h4>2554</h4>
2529 2555
2530除了[通用输入字段](#common-input-fields)外,PermissionDenied hook 还会接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。2556除了[通用输入字段](#common-input-fields)之外,PermissionDenied hook 还会接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。对于 MCP 工具,它们还会接收 [`mcp_server`](#pretooluse-input) 对象。
2531 2557
2532```json theme={null}2558```json theme={null}
2533{2559{
2548 2574
2549| 字段 | 描述 |2575| 字段 | 描述 |
2550| :- | :- |2576| :- | :- |
2551| `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` |2577| `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` |
2552 2578
2553<h4 id="permissiondenied-decision-control">2579<h4 id="permissiondenied-decision-control">
2554 PermissionDenied 决策控制2580 PermissionDenied 决策控制
2555</h4>2581</h4>
2556 2582
2557PermissionDenied hook 可以告知模型可以重试被拒绝的工具调用。返回一个将 `hookSpecificOutput.retry` 设为 `true` 的 JSON 对象:2583PermissionDenied hook 可以告知模型可以重试被拒绝的工具调用。返回一个将 `hookSpecificOutput.retry` 设置为 `true` 的 JSON 对象:
2558 2584
2559```json theme={null}2585```json theme={null}
2560{2586{
2565}2591}
2566```2592```
2567 2593
2568当 `retry` 为 `true` 时,Claude Code 会在对话中添加一条消息,告知模型可以重试该工具调用。Claude Code 本身不会撤销拒绝。如果您的 hook 不返回 JSON,或返回 `retry: false`,则拒绝保持有效,模型会收到原始的拒绝消息。2594当 `retry` 为 `true` 时,Claude Code 会在对话中添加一条消息,告知模型可以重试该工具调用。Claude Code 本身不会撤销该拒绝。如果您的 hook 不返回 JSON,或返回 `retry: false`,则拒绝维持不变,模型会收到原始的拒绝消息。
2569 2595
2570当分类器[未对该操作作出裁定](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action)时(其响应无法解析,或独立于自动模式的安全检查拒绝了分类器自身的请求),Claude Code 会忽略 `retry: true`。对于这类拒绝,Claude Code 已在拒绝消息中告知模型是稍后重试还是继续其他工作。2596当分类器[未对该操作作出判定](/docs/zh-CN/errors#auto-mode-cannot-determine-the-safety-of-an-action)时(其响应无法解析,或独立于自动模式的安全检查拒绝了分类器自身的请求),Claude Code 会忽略 `retry: true`。对于这些拒绝,Claude Code 已经在拒绝消息中告知模型是稍后重试还是继续其他工作。
2571 2597
2572<h3 id="notification">2598<h3 id="notification">
2573 Notification2599 Notification
2574</h3>2600</h3>
2575 2601
2576在 Claude Code 发送通知时运行。按通知类型匹配。省略匹配器即可为所有通知类型运行 hook。2602在 Claude Code 发送通知时运行。按通知类型匹配。省略匹配器可为所有通知类型运行 hook。
2577 2603
2578即使关闭了桌面通知,您仍会收到这些 hook 事件:`preferredNotifChannel` 设置(包括 `notifications_disabled`)只会改变提醒您的方式,而不会影响您的 hook 是否运行。2604即使关闭了桌面通知,您也会收到这些 hook 事件:`preferredNotifChannel` 设置(包括 `notifications_disabled`)只改变您接收提醒的方式,而不影响您的 hook 是否运行。
2579 2605
2580| 匹配器 | 触发时机 |2606| 匹配器 | 触发时机 |
2581| :- | :- |2607| :- | :- |
2582| `permission_prompt` | Claude 需要您批准某次工具使用或某个沙箱命令的[网络请求](/docs/zh-CN/sandboxing#network-isolation),且该提示已等待约六秒 |2608| `permission_prompt` | Claude 需要您批准工具使用或沙箱中命令的[网络请求](/docs/zh-CN/sandboxing#network-isolation),且该提示已等待约六秒 |
2583| `idle_prompt` | Claude 在约 60 秒前完成回复,且此后您没有输入 |2609| `idle_prompt` | Claude 大约 60 秒前完成回复,且此后您未进行输入 |
2584| `auth_success` | 身份验证完成 |2610| `auth_success` | 身份验证完成 |
2585| `elicitation_dialog` | MCP 服务器打开了一个信息征询表单,且您约六秒没有输入 |2611| `elicitation_dialog` | MCP 服务器打开 elicitation 表单,且您约六秒未进行输入 |
2586| `elicitation_url_dialog` | MCP 服务器请求您打开一个浏览器 URL,且您约六秒没有输入 |2612| `elicitation_url_dialog` | MCP 服务器要求您打开浏览器 URL,且您约六秒未进行输入 |
2587| `elicitation_complete` | MCP 服务器报告某个 [URL 模式信息征询](#elicitation-input)已完成 |2613| `elicitation_complete` | MCP 服务器报告 [URL 模式 elicitation](#elicitation-input) 已完成 |
2588| `elicitation_response` | MCP 信息征询响应被发送回服务器 |2614| `elicitation_response` | MCP elicitation 响应被发回服务器 |
2589| `agent_needs_input` | 在终端中打开 [Agent 视图](/docs/zh-CN/agent-view)期间,某个后台会话开始等待您的输入。当终端会话向您显示 [agent team 队友的终端设置问题](/docs/zh-CN/agent-teams#choose-a-display-mode)或自动模式关于[分类器请求费用](/docs/zh-CN/auto-mode-classifier-billing)的通知,且您约六秒没有输入时,也会触发 |2615| `agent_needs_input` | 在终端中打开 [Agent 视图](/docs/zh-CN/agent-view)时,某个后台会话开始等待您的输入。当终端会话向您显示 [agent team 队友的终端设置问题](/docs/zh-CN/agent-teams#choose-a-display-mode)或自动模式关于[分类器请求费用](/docs/zh-CN/auto-mode-classifier-billing)的通知,且您约六秒未进行输入时,也会触发 |
2590| `agent_completed` | 某个后台会话完成或失败。仅在终端中打开 [Agent 视图](/docs/zh-CN/agent-view)时触发 |2616| `agent_completed` | 后台会话完成或失败。仅在终端中打开 [Agent 视图](/docs/zh-CN/agent-view)时触发 |
2591| `quota_auto_resume_fired` | 在 claude.ai 用量限制暂停您的任务后,Claude Code 继续执行该任务:在重置时,或者当您在等待期间在 Claude Code 中执行的某些操作(例如添加使用额度、升级套餐或切换模型)使用量再次可用时提前继续,[模型设置例外](/docs/zh-CN/interactive-mode#wait-for-a-usage-limit-to-reset)除外 |2617| `quota_auto_resume_fired` | 在 claude.ai 用量限制暂停您的任务后,Claude Code 继续执行该任务:在限制重置时,或在等待期间您在 Claude Code 中的某些操作(例如添加使用额度、升级套餐或切换模型)使用量重新可用时提前继续,但存在[模型设置例外](/docs/zh-CN/interactive-mode#wait-for-a-usage-limit-to-reset) |
2592| `quota_auto_resume_stale` | 在您的计算机休眠超过约 30 分钟期间,claude.ai 用量限制已重置。Claude Code 会等待您按 `Enter`,而不是继续执行。休眠时间较短时,它会继续执行并改为触发 `quota_auto_resume_fired` |2618| `quota_auto_resume_stale` | claude.ai 用量限制在您的计算机休眠超过约 30 分钟期间重置。Claude Code 会等待您按下 `Enter`,而不是继续执行。如果休眠时间较短,它会继续执行并改为触发 `quota_auto_resume_fired` |
2593| `quota_auto_resume_disabled` | Claude Code 结束对 claude.ai 用量限制的等待而未继续您的任务:在 Claude Code 自行发起的等待期间,[`autoContinueAtUsageLimit`](/docs/zh-CN/settings-reference#autocontinueatusagelimit) 被关闭或重置时间推迟到 24 小时以后;继续执行的任务不断触及限制;或继续执行在到达模型之前被阻止。当您按 `Esc` 或 `Ctrl+C`,或选择 **Don't continue automatically** 时不会触发 |2619| `quota_auto_resume_disabled` | Claude Code 结束对 claude.ai 用量限制的等待,但未继续您的任务:在 Claude Code 自行开始的等待期间,[`autoContinueAtUsageLimit`](/docs/zh-CN/settings-reference#autocontinueatusagelimit) 被关闭或重置时间推迟到 24 小时以后;继续执行的任务不断触及限制;或继续执行在到达模型之前被阻止。当您按下 `Esc` 或 `Ctrl+C`,或选择 **Don't continue automatically** 时不会触发 |
2594 2620
2595`quota_auto_resume_fired`、`quota_auto_resume_stale` 和 `quota_auto_resume_disabled` 类型需要 Claude Code v2.1.234 或更高版本。2621`quota_auto_resume_fired`、`quota_auto_resume_stale` 和 `quota_auto_resume_disabled` 类型需要 Claude Code v2.1.234 或更高版本。
2596 2622
2597在终端会话中,针对沙箱命令网络请求的 `permission_prompt` 需要 Claude Code v2.1.246 或更高版本。2623在终端会话中,针对沙箱中命令网络请求的 `permission_prompt` 需要 Claude Code v2.1.246 或更高版本。
2598 2624
2599针对队友终端设置问题的 `agent_needs_input` 需要 Claude Code v2.1.248 或更高版本。2625针对队友终端设置问题的 `agent_needs_input` 需要 Claude Code v2.1.248 或更高版本。
2600 2626
2601<Note>2627<Note>
2602 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享计时方式,因此在终端会话中,只有当您看起来已离开终端时才会看到它们:2628 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 和 `elicitation_url_dialog` 类型与桌面通知共享计时方式,因此在终端会话中,只有当您看起来已离开终端时才会看到它们:
2603 2629
2604 * 在您约六秒没有输入后,预计会触发 `permission_prompt`。计时器在权限提示出现时开始,每次按键都会推迟它。要在 Claude 请求使用工具的权限时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。2630 * `permission_prompt` 会在您约六秒未进行输入后出现。计时器在权限提示出现时开始,每次按键都会推迟它。要在 Claude 请求使用工具的权限时立即运行 hook,请改用 [PermissionRequest](#permissionrequest)。
2605 * 在 Claude 完成回复约 60 秒后,预计会触发 `idle_prompt`,前提是此后您没有输入,且没有后台 Agent(例如后台[子代理](/docs/zh-CN/sub-agents))仍在运行。Claude Code 在等待 claude.ai 用量限制重置期间不会发送 `idle_prompt`。当等待自行结束时,会改为触发某个 `quota_auto_resume_*` 类型。2631 * `idle_prompt` 会在 Claude 完成回复约 60 秒后出现,且仅当此后您未进行输入,并且没有后台 Agent(例如后台[子代理](/docs/zh-CN/sub-agents))仍在运行时。Claude Code 在等待 claude.ai 用量限制重置期间不会发送 `idle_prompt`。当等待自行结束时,会改为触发某个 `quota_auto_resume_*` 类型。
2606 * 对于信息征询表单,预计会触发 `elicitation_dialog`;对于浏览器 URL 请求,预计会触发 `elicitation_url_dialog`,二者都在您约六秒没有输入后触发。两者与 `permission_prompt` 共享相同的六秒门槛:计时器在对话框出现时开始,每次按键都会推迟它。2632 * 对于 elicitation 表单会出现 `elicitation_dialog`,对于浏览器 URL 请求会出现 `elicitation_url_dialog`,两者均在您约六秒未进行输入后出现。两者与 `permission_prompt` 共享相同的六秒门槛:计时器在对话框出现时开始,每次按键都会推迟它。
2607 2633
2608 在另一个对话框显示期间到达的权限请求或信息征询,仍适用相同的六秒门槛,从请求到达时开始计时。即使该请求仍在已打开的对话框后面等待,它的通知也可能已经送达您。2634 如果权限请求或 elicitation 在另一个对话框显示于屏幕上时到达,同样适用六秒门槛,从请求到达时开始计时。其通知可能在该请求仍排在已打开对话框之后等待时就送达您。
2609</Note>2635</Note>
2610 2636
2611在 Claude Code 将权限请求发送到 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input)的会话中(Claude Desktop 和 VS Code 扩展就是以这种方式托管 Claude Code 的),Claude Code 对 `permission_prompt` 的计时方式不同:2637在 Claude Code 将权限请求发送到 Agent SDK 的 [`canUseTool` 回调](/docs/zh-CN/agent-sdk/user-input)的会话中(Claude Desktop 和 VS Code 扩展就是以这种方式托管 Claude Code 的),Claude Code 对 `permission_prompt` 的计时有所不同:
2612 2638
2613* 预计在 Claude 请求权限约六秒后触发 `permission_prompt`。Claude Code 不会因您输入而推迟它。2639* `permission_prompt` 会在 Claude 请求权限约六秒后出现。您输入时 Claude Code 不会推迟它。
2614* 如果您或 [PermissionRequest](#permissionrequest) hook 更早作出回应,Claude Code 不会运行 `permission_prompt`。2640* 如果您或 [PermissionRequest](#permissionrequest) hook 更早作出回应,Claude Code 不会运行 `permission_prompt`。
2615* 将 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 设为 `1`,即可在这些会话中关闭 `permission_prompt`。2641* 将 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-CN/env-vars) 设置为 `1` 可在这些会话中关闭 `permission_prompt`。
2616 2642
2617在 v2.1.233 之前,`permission_prompt` 在这些会话中不会触发。2643在 v2.1.233 之前,`permission_prompt` 不会在这些会话中触发。
2618 2644
2619使用不同的匹配器,可根据通知类型运行不同的处理程序。以下配置在 Claude 需要权限批准时触发一个专用于权限的提醒脚本,在 Claude 空闲时触发另一个通知:2645使用单独的匹配器,可根据通知类型运行不同的处理程序。以下配置会在 Claude 需要权限批准时触发特定于权限的警报脚本,并在 Claude 处于空闲状态时触发另一种通知:
2620 2646
2621```json theme={null}2647```json theme={null}
2622{2648{
2649 Notification 输入2675 Notification 输入
2650</h4>2676</h4>
2651 2677
2652除了[通用输入字段](#common-input-fields)外,Notification hook 还会接收包含通知文本的 `message`、可选的 `title`,以及指示触发类型的 `notification_type`。2678除了[通用输入字段](#common-input-fields)之外,Notification hook 还会接收包含通知文本的 `message`、可选的 `title`,以及指示触发类型的 `notification_type`。
2653 2679
2654```json theme={null}2680```json theme={null}
2655{2681{
2663}2689}
2664```2690```
2665 2691
2666Notification hook 无法阻止或修改通知。Claude Code 会丢弃它们的 `systemMessage` 和 `continue` 字段,但仍会发出 [`terminalSequence`](#emit-terminal-notifications),桌面通知示例正是依赖于此。Notification hook 适用于产生副作用,例如将通知转发到外部服务。2692Notification hook 无法阻止或修改通知。Claude Code 会丢弃它们的 `systemMessage` 和 `continue` 字段,但仍会发出 [`terminalSequence`](#emit-terminal-notifications),桌面通知示例正依赖于此。Notification hook 旨在用于副作用,例如将通知转发到外部服务。
2667 2693
2668<h3 id="subagentstart">2694<h3 id="subagentstart">
2669 SubagentStart2695 SubagentStart
2670</h3>2696</h3>
2671 2697
2672当 Claude 使用 Agent 工具生成子代理、当 Claude [恢复子代理](/docs/zh-CN/sub-agents#resume-subagents),以及每次进程内 [agent team](/docs/zh-CN/agent-teams) 队友处理新消息时运行。支持使用匹配器按 Agent 类型名称过滤。对于内置 Agent,这是诸如 `general-purpose`、`Explore` 或 `Plan` 之类的 Agent 名称。对于[自定义子代理](/docs/zh-CN/sub-agents),这是 Agent frontmatter 中的 `name` 字段,而非文件名。2698在 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` 字段,而不是文件名。
2673 2699
2674对于由[插件](/docs/zh-CN/plugins/overview)提供的子代理,Agent 类型是插件作用域的标识符,例如 `my-plugin:reviewer`,而不是单纯的 frontmatter 名称。冒号会使插件作用域的名称走正则表达式路径,因此请用 `^` 和 `$` 锚定匹配器以实现精确匹配:`^my-plugin:reviewer$`。2700对于由[插件](/docs/zh-CN/plugins/overview)提供的子代理,Agent 类型是插件作用域的标识符,例如 `my-plugin:reviewer`,而不是单纯的 frontmatter 名称。冒号会使插件作用域名称走正则表达式匹配路径,因此请用 `^` 和 `$` 锚定匹配器以实现精确匹配:`^my-plugin:reviewer$`。
2675 2701
2676<h4 id="subagentstart-input">2702<h4 id="subagentstart-input">
2677 SubagentStart 输入2703 SubagentStart 输入
2678</h4>2704</h4>
2679 2705
2680除了[通用输入字段](#common-input-fields)外,SubagentStart hook 还会接收包含子代理唯一标识符的 `agent_id`,以及包含匹配器所过滤的 Agent 名称的 `agent_type`。2706除了[通用输入字段](#common-input-fields)之外,SubagentStart hook 还会接收包含子代理唯一标识符的 `agent_id`,以及包含匹配器所过滤 Agent 名称的 `agent_type`。
2681 2707
2682```json theme={null}2708```json theme={null}
2683{2709{
2690}2716}
2691```2717```
2692 2718
2693SubagentStart hook 无法阻止子代理的创建,但可以向子代理注入上下文。除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,您还可以返回:2719SubagentStart hook 无法阻止子代理的创建,但可以向子代理注入上下文。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您还可以返回:
2694 2720
2695| 字段 | 描述 |2721| 字段 | 描述 |
2696| :- | :- |2722| :- | :- |
2697| `additionalContext` | 在子代理对话开始时、其第一个提示词之前添加到子代理上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |2723| `additionalContext` | 在子代理对话开始时、第一个提示词之前添加到其上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
2698 2724
2699```json theme={null}2725```json theme={null}
2700{2726{
2705}2731}
2706```2732```
2707 2733
2708当 hook 针对同一子代理再次运行时,仅当子代理的上下文中尚未包含先前运行注入的副本时,Claude Code 才会注入返回的上下文。启动时注入的副本会保留在原位,从而保持子代理的[提示缓存](/docs/zh-CN/prompt-caching#subagents-and-the-cache)不变。在[自动压缩](/docs/zh-CN/sub-agents#auto-compaction)丢弃该副本后,Claude Code 会再次注入下一次运行的上下文。2734当 hook 针对同一子代理再次运行时,只有当子代理的上下文中尚未包含之前运行的副本时,Claude Code 才会注入返回的上下文。启动时注入的副本会保留在原处,从而保持子代理的[提示缓存](/docs/zh-CN/prompt-caching#subagents-and-the-cache)不变。在[自动压缩](/docs/zh-CN/sub-agents#auto-compaction)丢弃该副本之后,Claude Code 会再次注入下一次运行的上下文。
2709 2735
2710<h3 id="subagentstop">2736<h3 id="subagentstop">
2711 SubagentStop2737 SubagentStop
2717 SubagentStop 输入2743 SubagentStop 输入
2718</h4>2744</h4>
2719 2745
2720除了[通用输入字段](#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 无需解析会话记录文件即可访问它。2746除了[通用输入字段](#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 无需解析会话记录文件即可访问它。
2721 2747
2722并非每个 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 运行时,它为空字符串。2748并非每个 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 运行时,则为空字符串。
2723 2749
2724指定了 Agent 类型的 `matcher` 不会匹配空的 `agent_type`。匹配器被省略、为 `""` 或 `"*"`,或者是能匹配空字符串的正则表达式的 hook,也会针对 `agent_type` 为空的事件运行。2750指定了 Agent 类型的 `matcher` 不会匹配空的 `agent_type`。匹配器被省略、为 `""` 或 `"*"`,或为可匹配空字符串的正则表达式的 hook,也会针对 `agent_type` 为空的事件运行。
2725 2751
2726在 Claude Code v2.1.271 或更高版本中,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子代理会在停止前通过该工具传递其报告。此时 `last_assistant_message` 字段保存的是子代理的结束文本(如有),而不是所传递的报告。报告是该调用的 `message` 输入,匹配 `SubagentHandback` 的 `PreToolUse` 或 `PostToolUse` hook 会以 `tool_input.message` 的形式接收它。2752在 Claude Code v2.1.271 或更高版本中,使用 [`SubagentHandback`](/docs/zh-CN/tools-reference) 工具运行的子代理会在停止之前通过该工具交付其报告。此时 `last_assistant_message` 字段包含子代理的结束文本(如果有),而不是已交付的报告。报告是该调用的 `message` 输入,匹配 `SubagentHandback` 的 `PreToolUse` 或 `PostToolUse` hook 会以 `tool_input.message` 的形式接收它。
2727 2753
2728SubagentStop hook 还会接收 [Stop 输入](#stop-input)中所述的 `background_tasks` 和 `session_crons` 数组。这两个数组的作用域都是父会话,而不是子代理。2754SubagentStop hook 还会接收 [Stop 输入](#stop-input)中所述的 `background_tasks` 和 `session_crons` 数组。这两个数组的作用域都是父会话,而不是子代理。
2729 2755
2744}2770}
2745```2771```
2746 2772
2747SubagentStop hook 使用与 [Stop hook](#stop-decision-control) 相同的决策控制格式,包括将 `hookEventName` 设为 `"SubagentStop"` 的 `hookSpecificOutput.additionalContext`,用于提供让子代理继续运行的非错误反馈。返回带有 `reason` 的 `decision: "block"` 会让子代理继续运行,并将 `reason` 作为下一条指令传递给子代理。通过以退出码 2 退出来阻止的 hook 会以相同方式传递其 stderr 消息。要在子代理返回后向父会话注入上下文,请改为在 `Agent` 工具上使用 [`PostToolUse`](#posttooluse) hook。2773SubagentStop hook 使用与 [Stop hook](#stop-decision-control) 相同的决策控制格式,包括将 `hookEventName` 设置为 `"SubagentStop"` 的 `hookSpecificOutput.additionalContext`,用于提供让子代理继续运行的非错误反馈。返回带有 `reason` 的 `decision: "block"` 会让子代理继续运行,并将 `reason` 作为其下一条指令传递给子代理。通过以退出码 2 退出来进行阻止的 hook 会以相同方式传递其 stderr 消息。要在子代理返回后向父会话注入上下文,请改为在 `Agent` 工具上使用 [`PostToolUse`](#posttooluse) hook。
2748 2774
2749<h3 id="taskcreated">2775<h3 id="taskcreated">
2750 TaskCreated2776 TaskCreated
2751</h3>2777</h3>
2752 2778
2753在通过 `TaskCreate` 工具创建任务时运行。可用于强制执行命名约定、要求提供任务描述,或阻止创建某些任务。在[不含 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability)中,此事件不会触发。2779在通过 `TaskCreate` 工具创建任务时运行。可用于强制执行命名约定、要求提供任务描述,或阻止创建某些任务。在[没有 Task 工具的会话](/docs/zh-CN/tools-reference#task-tool-availability)中,此事件不会触发。
2754 2780
2755TaskCreated hook 不支持匹配器,每次发生时都会触发。2781TaskCreated hook 不支持匹配器,每次发生时都会触发。
2756 2782
2758 TaskCreated 输入2784 TaskCreated 输入
2759</h4>2785</h4>
2760 2786
2761除了[通用输入字段](#common-input-fields)外,TaskCreated hook 还会接收 `task_id`、`task_subject`,以及可选的 `task_description`、`teammate_name` 和 `team_name`。2787除了[通用输入字段](#common-input-fields)之外,TaskCreated hook 还会接收 `task_id`、`task_subject`,以及可选的 `task_description`、`teammate_name` 和 `team_name`。
2762 2788
2763```json theme={null}2789```json theme={null}
2764{2790{
2779| `task_id` | 正在创建的任务的标识符 |2805| `task_id` | 正在创建的任务的标识符 |
2780| `task_subject` | 任务标题 |2806| `task_subject` | 任务标题 |
2781| `task_description` | 任务的详细描述。可能不存在 |2807| `task_description` | 任务的详细描述。可能不存在 |
2782| `teammate_name` | 创建该任务的队友名称。可能不存在 |2808| `teammate_name` | 创建任务的队友名称。可能不存在 |
2783| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |2809| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |
2784| `agent_id` | 在此事件中,该[通用输入字段](#common-input-fields)标识正在创建任务的子代理或[进程内队友](/docs/zh-CN/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更高版本 |2810| `agent_id` | 在此事件中,该[通用输入字段](#common-input-fields)标识创建任务的子代理或[进程内队友](/docs/zh-CN/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更高版本 |
2785 2811
2786<h4 id="taskcreated-decision-control">2812<h4 id="taskcreated-decision-control">
2787 TaskCreated 决策控制2813 TaskCreated 决策控制
2788</h4>2814</h4>
2789 2815
2790TaskCreated hook 可以通过退出码 2 或 JSON 决策来阻止创建。无论哪种方式,Claude Code 都会删除该任务,并将您的消息作为工具的错误返回给 Claude。Claude Code 会忽略来自此事件的 `continue: false`,Claude 会继续工作。2816TaskCreated hook 可以通过退出码 2 或 JSON 决策来阻止创建。无论哪种方式,Claude Code 都会删除该任务,并将您的消息作为工具错误返回给 Claude。Claude Code 会忽略此事件中的 `continue: false`,Claude 会继续工作。
2791 2817
2792* **退出码 2**:Claude Code 将 stderr 文本作为消息返回。2818* **退出码 2**:Claude Code 将 stderr 文本作为消息返回。
2793* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。2819* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 将 `reason` 作为消息返回。
2794 2820
2795以下示例会阻止主题不符合所需格式的任务:2821此示例会阻止主题不符合所需格式的任务:
2796 2822
2797```bash theme={null}2823```bash theme={null}
2798#!/bin/bash2824#!/bin/bash
2811 TaskCompleted2837 TaskCompleted
2812</h3>2838</h3>
2813 2839
2814在任务被标记为已完成时运行。它在两种情况下触发:任何 Agent 通过 TaskUpdate 工具显式将任务标记为已完成时,或 [agent team](/docs/zh-CN/agent-teams) 队友在仍有进行中任务的情况下结束其轮次时。可用于在任务关闭前强制执行完成标准,例如测试通过或 lint 检查通过。2840在任务被标记为已完成时运行。它在两种情况下触发:任何 Agent 通过 TaskUpdate 工具显式将任务标记为已完成时,或者 [agent team](/docs/zh-CN/agent-teams) 队友在仍有进行中任务的情况下结束其轮次时。可用于在任务关闭之前强制执行完成标准,例如通过测试或 lint 检查。
2815 2841
2816TaskCompleted hook 不支持匹配器,每次发生时都会触发。2842TaskCompleted hook 不支持匹配器,每次发生时都会触发。
2817 2843
2819 TaskCompleted 输入2845 TaskCompleted 输入
2820</h4>2846</h4>
2821 2847
2822除了[通用输入字段](#common-input-fields)外,TaskCompleted hook 还会接收 `task_id`、`task_subject`,以及可选的 `task_description`、`teammate_name` 和 `team_name`。2848除了[通用输入字段](#common-input-fields)之外,TaskCompleted hook 还会接收 `task_id`、`task_subject`,以及可选的 `task_description`、`teammate_name` 和 `team_name`。
2823 2849
2824```json theme={null}2850```json theme={null}
2825{2851{
2841| `task_id` | 正在完成的任务的标识符 |2867| `task_id` | 正在完成的任务的标识符 |
2842| `task_subject` | 任务标题 |2868| `task_subject` | 任务标题 |
2843| `task_description` | 任务的详细描述。可能不存在 |2869| `task_description` | 任务的详细描述。可能不存在 |
2844| `teammate_name` | 完成该任务的队友名称。可能不存在 |2870| `teammate_name` | 完成任务的队友名称。可能不存在 |
2845| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |2871| `team_name` | 已弃用。从会话派生的团队名称;将在未来版本中移除 |
2846| `agent_id` | 在此事件中,该[通用输入字段](#common-input-fields)标识正在完成任务的子代理或[进程内队友](/docs/zh-CN/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更高版本 |2872| `agent_id` | 在此事件中,该[通用输入字段](#common-input-fields)标识完成任务的子代理或[进程内队友](/docs/zh-CN/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更高版本 |
2847 2873
2848<h4 id="taskcompleted-decision-control">2874<h4 id="taskcompleted-decision-control">
2849 TaskCompleted 决策控制2875 TaskCompleted 决策控制
2851 2877
2852TaskCompleted hook 支持两种控制任务完成的方式:2878TaskCompleted hook 支持两种控制任务完成的方式:
2853 2879
2854* **退出码 2**:任务不会被标记为已完成,stderr 消息会作为反馈回传给模型。2880* **退出码 2**:任务不会被标记为已完成,stderr 消息会作为反馈传回模型。
2855* **JSON `{"continue": false, "stopReason": "..."}`**:当事件由队友结束其轮次触发时,完全停止该队友,与 `Stop` hook 的行为一致。`stopReason` 会显示给用户。当事件由 `TaskUpdate` 工具触发时,Claude Code 会忽略 `continue: false`;退出码 2 仍会阻止完成。2881* **JSON `{"continue": false, "stopReason": "..."}`**:当事件由队友结束其轮次触发时,完全停止该队友,与 `Stop` hook 的行为一致。`stopReason` 会显示给用户。当事件由 `TaskUpdate` 工具触发时,Claude Code 会忽略 `continue: false`;退出码 2 仍会阻止完成。
2856 2882
2857以下示例运行测试,并在测试失败时阻止任务完成:2883此示例运行测试,如果测试失败则阻止任务完成:
2858 2884
2859```bash theme={null}2885```bash theme={null}
2860#!/bin/bash2886#!/bin/bash
2874 Stop2900 Stop
2875</h3>2901</h3>
2876 2902
2877在主 Claude Code Agent 完成回复时运行。如果停止是由用户中断引起的,则不会运行。API 错误会改为触发2903在 Claude Code 主 Agent 完成回复时运行。如果停止是由用户中断引起的,则不会运行。API 错误会改为触发
2878[StopFailure](#stopfailure)。2904[StopFailure](#stopfailure)。
2879 2905
2880<Tip>2906<Tip>
2881 [`/goal`](/docs/zh-CN/goal) 命令是会话作用域的、基于提示词的 Stop hook 的内置快捷方式。当您希望 Claude 持续朝某个条件努力而无需编写 hook 配置时,可以使用它。2907 [`/goal`](/docs/zh-CN/goal) 命令是会话作用域、基于提示词的 Stop hook 的内置快捷方式。当您希望 Claude 持续朝某个条件工作而无需编写 hook 配置时,可以使用它。
2882</Tip>2908</Tip>
2883 2909
2884<h4 id="stop-input">2910<h4 id="stop-input">
2885 Stop 输入2911 Stop 输入
2886</h4>2912</h4>
2887 2913
2888除了[通用输入字段](#common-input-fields)外,Stop hook 还会接收 `stop_hook_active`、`last_assistant_message`、`background_tasks` 和 `session_crons`。当 Claude Code 已经因 stop hook 而继续运行时,`stop_hook_active` 字段为 `true`。请检查此值或处理会话记录,以避免因一个永远无法满足的条件而持续阻止。2914除了[通用输入字段](#common-input-fields)之外,Stop hook 还会接收 `stop_hook_active`、`last_assistant_message`、`background_tasks` 和 `session_crons`。当 Claude Code 已经因 stop hook 而继续执行时,`stop_hook_active` 字段为 `true`。请检查此值或处理会话记录,以避免因一个永远不会满足的条件而持续阻止。
2889 2915
2890Claude Code 设有连续 8 次继续的上限:在 stop hook 连续八次让轮次继续后,Claude Code 会覆盖下一次阻止并结束该轮次。每次 Claude 调用工具时,连续继续的计数都会重置。要提高该上限,请设置 [`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`](/docs/zh-CN/env-vars)。2916Claude Code 设有连续 8 次继续的上限:在 stop hook 连续八次让轮次继续之后,Claude Code 会覆盖下一次阻止并结束该轮次。每次 Claude 调用工具时,连续继续的计数都会重置。要提高该上限,请设置 [`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`](/docs/zh-CN/env-vars)。
2891 2917
2892`last_assistant_message` 字段包含 Claude 最终回复的文本内容,因此 hook 无需解析会话记录文件即可访问它。对于作用于刚刚完成的轮次的 hook(例如朗读或通知 hook),请使用此字段而不是读取 `transcript_path`:并非所有版本都能保证在 Stop 时会话记录文件中已包含最终消息。2918`last_assistant_message` 字段包含 Claude 最终回复的文本内容,因此 hook 无需解析会话记录文件即可访问它。对于作用于刚完成轮次的 hook(例如朗读或通知 hook),请使用此字段,而不是读取 `transcript_path`:并非所有版本都能保证在 Stop 时会话记录文件中已包含最终消息。
2893 2919
2894`background_tasks` 和 `session_crons` 数组使 hook 能够区分"会话已完成"和"会话已暂停,正在等待后台工作将其唤醒"。当任务注册表可访问时,这两个数组都会存在;当没有正在进行或已计划的内容时,它们为空。2920`background_tasks` 和 `session_crons` 数组让 hook 能够区分“会话已完成”与“会话已暂停,等待后台工作将其重新唤醒”。当任务注册表可访问时,两个数组都会存在;当没有进行中或已计划的内容时,它们为空。
2895 2921
2896`background_tasks` 中的每个条目描述一个正在进行的任务,并使用以下字段:2922`background_tasks` 中的每个条目描述一个进行中的任务,并使用以下字段:
2897 2923
2898| 字段 | 描述 |2924| 字段 | 描述 |
2899| :- | :- |2925| :- | :- |
2900| `id` | 任务标识符 |2926| `id` | 任务标识符 |
2901| `type` | 友好的任务类型标签,例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识创建该任务的 Claude Code 功能。对于无法识别的类型,回退为原始判别值 |2927| `type` | 友好的任务类型标签,例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每个标签标识创建该任务的 Claude Code 功能。对于无法识别的类型,回退为原始判别值 |
2902| `status` | 当前任务状态 |2928| `status` | 当前任务状态 |
2903| `description` | 自由文本描述,上限为 1000 个字符,截断时会在字符串内带有 `… [+N chars]` 标记 |2929| `description` | 自由文本描述,上限为 1000 个字符,被截断时字符串中带有 `… [+N chars]` 标记 |
2904| `command` | Shell 命令行,上限为 1000 个字符。仅对 `shell` 任务存在 |2930| `command` | shell 命令行,上限为 1000 个字符。仅存在于 `shell` 任务中 |
2905| `agent_type` | 子代理类型名称。仅对 `subagent` 任务存在 |2931| `agent_type` | 子代理类型名称。仅存在于 `subagent` 任务中 |
2906| `server` | MCP 服务器名称。仅对 `monitor` 和 `MCP task` 任务存在 |2932| `server` | MCP 服务器名称。仅存在于 `monitor` 和 `MCP task` 任务中 |
2907| `tool` | MCP 工具名称。仅对 `monitor` 和 `MCP task` 任务存在 |2933| `tool` | MCP 工具名称。仅存在于 `monitor` 和 `MCP task` 任务中 |
2908| `name` | 工作流名称。仅对 `workflow` 任务存在 |2934| `name` | 工作流名称。仅存在于 `workflow` 任务中 |
2909 2935
2910`session_crons` 中的每个条目描述一个会话作用域的计划唤醒,来源为 `CronCreate`、`ScheduleWakeup` 和 `/loop`:2936`session_crons` 中的每个条目描述一个会话作用域的计划唤醒,来源于 `CronCreate`、`ScheduleWakeup` 和 `/loop`:
2911 2937
2912| 字段 | 描述 |2938| 字段 | 描述 |
2913| :- | :- |2939| :- | :- |
2914| `id` | Cron 任务标识符 |2940| `id` | Cron 任务标识符 |
2915| `schedule` | Cron 表达式,例如 `0 9 * * 1-5` |2941| `schedule` | Cron 表达式,例如 `0 9 * * 1-5` |
2916| `recurring` | 对于计划只编码单次触发时间的一次性唤醒为 `false`,对于每次匹配都会重新触发的任务为 `true` |2942| `recurring` | 对于计划仅编码单个触发时间的一次性唤醒为 `false`,对于每次匹配时都会重新触发的任务为 `true` |
2917| `prompt` | cron 触发时提交的提示词,上限为 1000 个字符,截断时带有相同的 `… [+N chars]` 标记 |2943| `prompt` | cron 触发时提交的提示词,上限为 1000 个字符,带有相同的 `… [+N chars]` 标记 |
2918 2944
2919以下示例展示了一个包含一个正在进行的 shell 任务和一个周期性 cron 的 Stop 输入:2945此示例展示了一个包含一个进行中 shell 任务和一个周期性 cron 的 Stop 输入:
2920 2946
2921```json theme={null}2947```json theme={null}
2922{2948{
2951 Stop 决策控制2977 Stop 决策控制
2952</h4>2978</h4>
2953 2979
2954`Stop` 和 `SubagentStop` hook 可以控制 Claude 是否继续。除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,您的 hook 脚本还可以返回以下事件特定字段:2980`Stop` 和 `SubagentStop` hook 可以控制 Claude 是否继续。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您的 hook 脚本还可以返回以下事件特定字段:
2955 2981
2956| 字段 | 描述 |2982| 字段 | 描述 |
2957| :- | :- |2983| :- | :- |
2958| `decision` | `"block"` 阻止 Claude 停止。省略则允许 Claude 停止 |2984| `decision` | `"block"` 阻止 Claude 停止。省略则允许 Claude 停止 |
2959| `reason` | 当 `decision` 为 `"block"` 时必填。告知 Claude 为何应继续 |2985| `reason` | 当 `decision` 为 `"block"` 时必填。告知 Claude 为什么应该继续 |
2960| `hookSpecificOutput.additionalContext` | 给 Claude 的非错误反馈。对话会继续,以便 Claude 据此采取行动,但与 `decision: "block"` 不同,它在会话记录中显示为 hook 反馈而非 hook 错误 |2986| `hookSpecificOutput.additionalContext` | 给 Claude 的非错误反馈。对话会继续,以便 Claude 据此采取行动,但与 `decision: "block"` 不同,它在会话记录中显示为 hook 反馈,而不是 hook 错误 |
2961 2987
2962通过以退出码 2 退出来阻止的 hook,其路由方式与 `reason` 相同:Claude 会将 stderr 消息作为它应继续的原因说明接收。2988通过以退出码 2 退出来进行阻止的 hook 与 `reason` 的传递方式相同:Claude 会收到 stderr 消息,作为它应该继续的原因说明。
2963 2989
2964```json theme={null}2990```json theme={null}
2965{2991{
2968}2994}
2969```2995```
2970 2996
2971当 hook 按设计正常工作并为 Claude 提供指导时(例如"在完成之前运行测试套件"),请使用 `additionalContext`。它通过与 `decision: "block"` 相同的循环保护机制(即 `stop_hook_active` 输入和连续 8 次继续的上限)让对话继续进行,但会话记录会将其标记为 `Stop hook feedback`,且不会显示 hook 错误通知:2997当 hook 按设计正常运作并为 Claude 提供指导(例如“在完成之前运行测试套件”)时,请使用 `additionalContext`。它通过与 `decision: "block"` 相同的循环保护机制(即 `stop_hook_active` 输入和连续 8 次继续的上限)让对话继续进行,但会话记录会将其标记为 `Stop hook feedback`,并且不会显示 hook 错误通知:
2972 2998
2973```json theme={null}2999```json theme={null}
2974{3000{
2983 StopFailure3009 StopFailure
2984</h3>3010</h3>
2985 3011
2986当轮次因 API 错误而结束时,代替 [Stop](#stop) 运行。除 [`terminalSequence`](#emit-terminal-notifications) 外,Claude Code 会忽略该 hook 的输出和退出码。当 Claude 因速率限制、身份验证问题或其他 API 错误而无法完成回复时,可用于记录失败、发送警报或执行恢复操作。3012当轮次因 API 错误而结束时,代替 [Stop](#stop) 运行。除 [`terminalSequence`](#emit-terminal-notifications) 之外,Claude Code 会忽略该 hook 的输出和退出码。当 Claude 因速率限制、身份验证问题或其他 API 错误而无法完成回复时,可用于记录失败日志、发送警报或采取恢复操作。
2987 3013
2988<h4 id="stopfailure-input">3014<h4 id="stopfailure-input">
2989 StopFailure 输入3015 StopFailure 输入
2990</h4>3016</h4>
2991 3017
2992除了[通用输入字段](#common-input-fields)外,StopFailure hook 还会接收 `error`、可选的 `error_details` 和可选的 `last_assistant_message`。`error` 字段标识错误类型,并用于匹配器过滤。3018除了[通用输入字段](#common-input-fields)之外,StopFailure hook 还会接收 `error`、可选的 `error_details` 和可选的 `last_assistant_message`。`error` 字段标识错误类型,并用于匹配器过滤。
2993 3019
2994| 字段 | 描述 |3020| 字段 | 描述 |
2995| :- | :- |3021| :- | :- |
2996| `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` |3022| `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` |
2997| `error_details` | 有关错误的其他详细信息(如有) |3023| `error_details` | 关于错误的其他详细信息(如果有) |
2998| `last_assistant_message` | 对话中显示的渲染后错误文本。与 `Stop` 和 `SubagentStop`(此字段保存 Claude 的对话输出)不同,对于 `StopFailure`,它包含 API 错误字符串本身,例如 `"API Error: Rate limit reached"` |3024| `last_assistant_message` | 对话中显示的渲染后错误文本。与 `Stop` 和 `SubagentStop` 中该字段包含 Claude 的对话输出不同,对于 `StopFailure`,它包含 API 错误字符串本身,例如 `"API Error: Rate limit reached"` |
2999 3025
3000```json theme={null}3026```json theme={null}
3001{3027{
3009}3035}
3010```3036```
3011 3037
3012StopFailure hook 没有决策控制。它们仅用于通知和日志记录。3038StopFailure hook 没有决策控制。它们仅用于通知和日志记录目的。
3013 3039
3014<h3 id="teammateidle">3040<h3 id="teammateidle">
3015 TeammateIdle3041 TeammateIdle
3016</h3>3042</h3>
3017 3043
3018当 [agent team](/docs/zh-CN/agent-teams) 队友在结束其轮次后即将进入空闲状态时运行。可用于在队友停止工作前强制执行质量关卡,例如要求 lint 检查通过或验证输出文件是否存在。3044当 [agent team](/docs/zh-CN/agent-teams) 队友在结束其轮次后即将进入空闲状态时运行。可用于在队友停止工作之前强制执行质量关卡,例如要求通过 lint 检查或验证输出文件是否存在。
3019 3045
3020TeammateIdle hook 不支持匹配器,每次发生时都会触发。3046TeammateIdle hook 不支持匹配器,每次发生时都会触发。
3021 3047
3023 TeammateIdle 输入3049 TeammateIdle 输入
3024</h4>3050</h4>
3025 3051
3026除了[通用输入字段](#common-input-fields)外,TeammateIdle hook 还会接收 `teammate_name` 和 `team_name`。3052除了[通用输入字段](#common-input-fields)之外,TeammateIdle hook 还会接收 `teammate_name` 和 `team_name`。
3027 3053
3028```json theme={null}3054```json theme={null}
3029{3055{
3049 3075
3050TeammateIdle hook 支持两种控制队友行为的方式:3076TeammateIdle hook 支持两种控制队友行为的方式:
3051 3077
3052* **退出码 2**:队友会将 stderr 消息作为反馈接收,并继续工作而不是进入空闲状态。3078* **退出码 2**:队友会收到 stderr 消息作为反馈,并继续工作而不是进入空闲状态。
3053* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止该队友,与 `Stop` hook 的行为一致。`stopReason` 会显示给用户。3079* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止该队友,与 `Stop` hook 的行为一致。`stopReason` 会显示给用户。
3054 3080
3055以下示例在允许队友进入空闲状态之前检查构建产物是否存在:3081此示例在允许队友进入空闲状态之前检查构建产物是否存在:
3056 3082
3057```bash theme={null}3083```bash theme={null}
3058#!/bin/bash3084#!/bin/bash
3071 3097
3072在会话期间配置文件发生更改时运行。可用于审计设置更改、强制执行安全策略,或阻止对配置文件的未授权修改。3098在会话期间配置文件发生更改时运行。可用于审计设置更改、强制执行安全策略,或阻止对配置文件的未授权修改。
3073 3099
3074当设置文件、托管策略文件或 skill 文件发生更改时,Claude Code 会运行 ConfigChange hook。对于托管策略,仅当 `managed-settings.json` 或 `managed-settings.d/` 中的文件发生更改时才会运行它们。它会应用[服务器托管设置](/docs/zh-CN/server-managed-settings)以及对 macOS 托管偏好设置或 Windows 注册表策略的更改,而不运行这些 hook。在启用了 [`wslInheritsWindowsSettings`](/docs/zh-CN/settings-reference#wslinheritswindowssettings) 的 WSL 上,它还会在策略轮询时应用已更改的 Windows 端托管设置文件,同样不运行这些 hook。3100当设置文件、托管策略文件或 skill 文件发生更改时,Claude Code 会运行 ConfigChange hook。对于托管策略,仅当 `managed-settings.json` 或 `managed-settings.d/` 中的文件发生更改时才会运行。Claude Code 在应用[服务器托管设置](/docs/zh-CN/server-managed-settings)以及 macOS 托管偏好设置或 Windows 注册表策略的更改时不会运行这些 hook。在启用了 [`wslInheritsWindowsSettings`](/docs/zh-CN/settings-reference#wslinheritswindowssettings) 的 WSL 上,它在策略轮询时应用已更改的 Windows 端托管设置文件,同样不会运行这些 hook。
3075 3101
3076匹配器按配置来源过滤:3102匹配器按配置来源进行过滤:
3077 3103
3078| 匹配器 | 触发时机 |3104| 匹配器 | 触发时机 |
3079| :- | :- |3105| :- | :- |
3083| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的文件发生更改 |3109| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的文件发生更改 |
3084| `skills` | `.claude/skills/` 中的 skill 文件发生更改 |3110| `skills` | `.claude/skills/` 中的 skill 文件发生更改 |
3085 3111
3086以下示例记录所有配置更改以用于安全审计:3112此示例记录所有配置更改,用于安全审计:
3087 3113
3088```json theme={null}3114```json theme={null}
3089{3115{
3107 ConfigChange 输入3133 ConfigChange 输入
3108</h4>3134</h4>
3109 3135
3110除了[通用输入字段](#common-input-fields)外,ConfigChange hook 还会接收 `source` 和可选的 `file_path`。`source` 字段指示哪种配置类型发生了更改,`file_path` 提供被修改的具体文件的路径。3136除了[通用输入字段](#common-input-fields)之外,ConfigChange hook 还会接收 `source` 以及可选的 `file_path`。`source` 字段指示哪种配置类型发生了更改,`file_path` 提供被修改的具体文件的路径。
3111 3137
3112```json theme={null}3138```json theme={null}
3113{3139{
3138}3164}
3139```3165```
3140 3166
3141`policy_settings` 更改无法被阻止。当机器上的托管设置文件发生更改时,hook 仍会针对 `policy_settings` 来源触发,因此您可以用它们记录这些编辑,但任何阻止决策都会被忽略。这可确保企业托管设置始终生效。当[服务器托管设置](/docs/zh-CN/server-managed-settings)到达或刷新时,Claude Code 不会运行 `ConfigChange` hook。3167`policy_settings` 更改无法被阻止。当计算机上的托管设置文件发生更改时,hook 仍会针对 `policy_settings` 来源触发,因此您可以使用它们来记录这些编辑,但任何阻止决策都会被忽略。这可确保企业托管的设置始终生效。当[服务器托管设置](/docs/zh-CN/server-managed-settings)到达或刷新时,Claude Code 不会运行 `ConfigChange` hook。
3142 3168
3143Claude Code 会根据 ConfigChange hook JSON 输出中的阻止决策采取行动,并丢弃 `systemMessage` 和 `continue`。被阻止的更改不会向您或 Claude 显示任何消息,无论您是通过 `reason` 还是通过退出码 2 时的 stderr 进行阻止。Claude Code 只会向调试日志写入一行。3169Claude Code 会根据 ConfigChange hook JSON 输出中的阻止决策采取行动,并丢弃 `systemMessage` 和 `continue`。无论您是通过 `reason` 还是通过退出码 2 时的 stderr 进行阻止,被阻止的更改都不会向您或 Claude 显示任何消息。Claude Code 只会在调试日志中写入一行。
3144 3170
3145<h3 id="cwdchanged">3171<h3 id="cwdchanged">
3146 CwdChanged3172 CwdChanged
3147</h3>3173</h3>
3148 3174
3149当主对话中的 shell 命令更改了工作目录时运行,例如当 Claude 执行 `cd` 命令时。可用于响应目录更改:重新加载环境变量、激活项目特定的工具链,或自动运行设置脚本。可与 [FileChanged](#filechanged) 搭配使用,以支持 [direnv](https://direnv.net/) 等按目录管理环境的工具。3175当主对话中的 shell 命令更改工作目录时运行,例如 Claude 执行 `cd` 命令时。可用于响应目录更改:重新加载环境变量、激活项目特定的工具链,或自动运行设置脚本。可与 [FileChanged](#filechanged) 搭配使用,以支持 [direnv](https://direnv.net/) 等按目录管理环境的工具。
3150 3176
3151CwdChanged hook 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量会持续作用于后续的 Bash 命令,直到下一个 CwdChanged 事件发生,届时 Claude Code 会清除它们。3177CwdChanged hook 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量会持续作用于后续的 Bash 命令,直到下一个 CwdChanged 事件发生时由 Claude Code 清除。
3152 3178
3153CwdChanged 不支持匹配器,每次发生时都会触发。3179CwdChanged 不支持匹配器,每次发生时都会触发。
3154 3180
3156 CwdChanged 输入3182 CwdChanged 输入
3157</h4>3183</h4>
3158 3184
3159除了[通用输入字段](#common-input-fields)外,CwdChanged hook 还会接收 `old_cwd` 和 `new_cwd`。3185除了[通用输入字段](#common-input-fields)之外,CwdChanged hook 还会接收 `old_cwd` 和 `new_cwd`。
3160 3186
3161```json theme={null}3187```json theme={null}
3162{3188{
3173 CwdChanged 输出3199 CwdChanged 输出
3174</h4>3200</h4>
3175 3201
3176除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,CwdChanged hook 还可以返回 `watchPaths`,以动态设置 [FileChanged](#filechanged) 监视的文件路径:3202除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,CwdChanged hook 还可以返回 `watchPaths`,以动态设置 [FileChanged](#filechanged) 监视的文件路径:
3177 3203
3178| 字段 | 描述 |3204| 字段 | 描述 |
3179| :- | :- |3205| :- | :- |
3180| `watchPaths` | 绝对路径数组。替换当前的动态监视列表。来自 `matcher` 配置的路径始终会被监视。返回空数组会清空动态列表,这在进入新目录时很常见 |3206| `watchPaths` | 绝对路径数组。替换当前的动态监视列表。来自您 `matcher` 配置的路径始终会被监视。返回空数组会清除动态列表,这在进入新目录时很常见 |
3181 3207
3182CwdChanged hook 没有决策控制。它们无法阻止目录更改。3208CwdChanged hook 没有决策控制。它们无法阻止目录更改。
3183 3209
3184Claude Code 会从其 JSON 输出中读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它会将 `systemMessage` 显示为简短的终端通知。该消息不会到达 SDK 消息流。3210Claude Code 会读取其 JSON 输出中的 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它会将 `systemMessage` 显示为简短的终端通知。该消息不会进入 SDK 消息流。
3185 3211
3186<h3 id="directoryadded">3212<h3 id="directoryadded">
3187 DirectoryAdded3213 DirectoryAdded
3188</h3>3214</h3>
3189 3215
3190在您于会话中途使用 `/add-dir` 命令添加工作目录后,或 SDK 客户端使用 `register_repo_root` 控制请求添加工作目录后运行。可用于准备新添加的仓库,例如安装其依赖。3216在您于会话中途使用 `/add-dir` 命令添加工作目录之后,或在 SDK 客户端通过 `register_repo_root` 控制请求添加工作目录之后运行。可用于准备新添加的仓库,例如安装其依赖。
3191 3217
3192在以下情况下,Claude Code 不会触发此事件:3218在以下情况下,Claude Code 不会触发此事件:
3193 3219
3194* 您通过 `--add-dir` 启动标志传入目录;这些目录由 [SessionStart](#sessionstart) 处理3220* 您通过 `--add-dir` 启动标志传入目录;这些目录由 [SessionStart](#sessionstart) 覆盖
3195* 您在 `/permissions` 的 Workspace 选项卡上添加目录3221* 您在 `/permissions` 的 Workspace 标签页上添加目录
3196* 您添加的目录已经是工作目录或位于某个工作目录内3222* 您添加的目录已经是工作目录或位于某个工作目录之内
3197 3223
3198Claude Code 会在刷新沙箱和权限状态之后触发 DirectoryAdded,因此当您的 hook 运行时,沙箱中的工具已经可以看到新目录。hook 命令本身在沙箱之外运行。3224Claude Code 在刷新沙箱和权限状态之后触发 DirectoryAdded,因此当您的 hook 运行时,沙箱中的工具已经能看到新目录。hook 命令本身在沙箱之外运行。
3199 3225
3200Claude Code 不会等待该 hook:添加操作会立即完成,hook 在后台运行,默认超时时间为 600 秒。3226Claude Code 不会等待该 hook:添加操作会立即完成,hook 在后台运行,使用默认的 600 秒超时时间。
3201 3227
3202匹配器按目录的添加方式过滤:3228匹配器按目录的添加方式进行过滤:
3203 3229
3204| 匹配器 | 触发时机 |3230| 匹配器 | 触发时机 |
3205| :- | :- |3231| :- | :- |
3206| `slash_command` | 您使用 `/add-dir` 添加目录 |3232| `slash_command` | 您使用 `/add-dir` 添加目录 |
3207| `register_repo_root` | SDK 客户端使用 `register_repo_root` 控制请求添加目录 |3233| `register_repo_root` | SDK 客户端通过 `register_repo_root` 控制请求添加目录 |
3208 3234
3209<h4 id="directoryadded-input">3235<h4 id="directoryadded-input">
3210 DirectoryAdded 输入3236 DirectoryAdded 输入
3211</h4>3237</h4>
3212 3238
3213除了[通用输入字段](#common-input-fields)外,DirectoryAdded hook 还会接收 `directory` 和 `source`。3239除了[通用输入字段](#common-input-fields)之外,DirectoryAdded hook 还会接收 `directory` 和 `source`。
3214 3240
3215| 字段 | 描述 |3241| 字段 | 描述 |
3216| :- | :- |3242| :- | :- |
3237 FileChanged3263 FileChanged
3238</h3>3264</h3>
3239 3265
3240当被监视的文件在磁盘上发生更改时运行。Claude Code 通过文件系统监视器而非检查工具调用来检测更改,因此无论是什么更改了文件,它都会运行该 hook:`Edit` 或 `Write` 工具调用、Claude 通过 `Bash` 运行的脚本,或完全在 Claude Code 之外的进程。一个常见用途是在项目配置文件更改时重新加载环境变量。3266当被监视的文件在磁盘上发生变化时运行。Claude Code 通过文件系统监视器检测变化,而不是通过检查工具调用,因此无论是什么更改了文件,它都会运行该 hook:`Edit` 或 `Write` 工具调用、Claude 通过 `Bash` 运行的脚本,或完全在 Claude Code 之外的进程。一个常见用途是在项目配置文件发生变化时重新加载环境变量。
3241 3267
3242此事件的 `matcher` 承担两个角色:3268此事件的 `matcher` 有两个作用:
3243 3269
3244* **构建监视列表**:该值按 `|` 拆分,每个片段都被注册为工作目录中的一个字面文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里没有用处:像 `^\.env` 这样的值会监视一个字面名为 `^\.env` 的文件。3270* **构建监视列表**:该值按 `|` 拆分,每个片段都会被注册为工作目录中的一个字面文件名,因此 `".envrc|.env"` 恰好监视这两个文件。正则表达式模式在这里没有用处:像 `^\.env` 这样的值会监视一个字面名称为 `^\.env` 的文件。
3245* **过滤要运行的 hook**:当被监视的文件发生更改时,同一个值会按照标准[匹配器规则](#matcher-patterns),针对已更改文件的基本名称过滤要运行的 hook 组。3271* **筛选要运行的 hook**:当被监视的文件发生变化时,同一个值会使用标准的[匹配器规则](#matcher-patterns),针对所更改文件的基本名称来筛选要运行的 hook 组。
3246 3272
3247以下示例会在 `data.csv` 发生任何更改(包括由 `Bash` 命令或外部脚本重写文件)后规范化其行尾:3273此示例会在 `data.csv` 发生任何更改后规范化其行尾,包括 `Bash` 命令或外部脚本重写该文件的情况:
3248 3274
3249```json theme={null}3275```json theme={null}
3250{3276{
3264}3290}
3265```3291```
3266 3292
3267该 hook 从 stdin 上 [JSON 输入](#filechanged-input)的 `file_path` 字段中读取已更改文件的绝对路径。其 `grep` 守卫检测的正是 `perl` 要移除的内容,即行尾的 CR,因此规范化之后的那次运行会直接退出而不触碰文件。更宽松的守卫会导致无限循环,因为即使没有替换任何内容,`perl -i` 也会重写文件,而 Claude Code 在每次重写后都会再次运行该 hook。将此脚本保存到 `/path/to/normalize-line-endings.sh` 并使其可执行:3293该 hook 从 stdin 上 [JSON 输入](#filechanged-input)的 `file_path` 字段读取所更改文件的绝对路径。它的 `grep` 检查所测试的内容与 `perl` 删除的内容相同,即行尾的 CR,因此规范化之后的那次运行会直接退出而不触碰文件。如果检查条件更宽松,则会无限循环,因为即使 `perl -i` 没有替换任何内容也会重写文件,而 Claude Code 在每次重写后都会再次运行该 hook。将此脚本保存到 `/path/to/normalize-line-endings.sh` 并使其可执行:
3268 3294
3269```bash theme={null}3295```bash theme={null}
3270#!/bin/bash3296#!/bin/bash
3274fi3300fi
3275```3301```
3276 3302
3277要确认该 hook 正常工作,请让 Claude 使用 `Bash` 命令向 `data.csv` 追加一行 CRLF。Claude Code 会运行该 hook,文件最终会使用 LF 行尾。3303要确认该 hook 是否正常工作,请让 Claude 使用 `Bash` 命令向 `data.csv` 追加一行 CRLF 行。Claude Code 会运行该 hook,文件最终会使用 LF 行尾。
3278 3304
3279要监视无法预先命名的文件,请从 hook 中返回 [`watchPaths`](#filechanged-output) 以动态更新监视列表。Claude Code 仅在有内容指定了要监视的文件时才会启动监视器,因此请用一个匹配器至少指定一个文件的 FileChanged 组,或用一个返回 `watchPaths` 的 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 来初始化列表。当被监视的文件发生更改时,匹配器仍会过滤要运行的 hook 组,因此请为处理动态路径的组省略匹配器,这样它会匹配所有被监视的文件,且不会向监视列表添加任何内容。`"*"` 匹配器同样匹配所有文件,但 Claude Code 会像对待其他值一样将其注册到监视列表中,作为一个字面名为 `*` 的文件。3305要监视无法预先命名的文件,请从 hook 返回 [`watchPaths`](#filechanged-output) 以动态更新监视列表。只有当有内容指定了要监视的文件时,Claude Code 才会启动监视器,因此请使用一个匹配器至少指定了一个文件的 FileChanged 组,或使用一个返回 `watchPaths` 的 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 来初始化该列表。当被监视的文件发生变化时,匹配器仍会筛选要运行的 hook 组,因此请为处理动态路径的组省略匹配器,这样它会匹配每个被监视的文件,且不会向监视列表添加任何内容。`"*"` 匹配器也会匹配每个文件,但 Claude Code 会像对待其他任何值一样将其注册到监视列表中,作为一个名为 `*` 的字面文件。
3280 3306
3281FileChanged hook 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量会持续作用于后续的 Bash 命令,直到下一个 [CwdChanged](#cwdchanged) 事件发生,届时 Claude Code 会清除它们。3307FileChanged hook 可以访问 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。写入该文件的变量会持续作用于后续的 Bash 命令,直到下一个 [CwdChanged](#cwdchanged) 事件发生时由 Claude Code 清除。
3282 3308
3283<h4 id="filechanged-input">3309<h4 id="filechanged-input">
3284 FileChanged 输入3310 FileChanged 输入
3285</h4>3311</h4>
3286 3312
3287除了[通用输入字段](#common-input-fields)外,FileChanged hook 还会接收 `file_path` 和 `event`。3313除了[通用输入字段](#common-input-fields)之外,FileChanged hook 还会接收 `file_path` 和 `event`。
3288 3314
3289| 字段 | 描述 |3315| 字段 | 描述 |
3290| :- | :- |3316| :- | :- |
3291| `file_path` | 已更改文件的绝对路径 |3317| `file_path` | 发生变化的文件的绝对路径 |
3292| `event` | 发生了什么:`"change"` 表示文件被修改,`"add"` 表示文件被创建,`"unlink"` 表示文件被删除 |3318| `event` | 发生了什么:`"change"` 表示文件被修改,`"add"` 表示文件被创建,`"unlink"` 表示文件被删除 |
3293 3319
3294```json theme={null}3320```json theme={null}
3306 FileChanged 输出3332 FileChanged 输出
3307</h4>3333</h4>
3308 3334
3309除了所有 hook 均可使用的 [JSON 输出字段](#json-output)外,FileChanged hook 还可以返回 `watchPaths`,以动态更新被监视的文件路径:3335除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,FileChanged hook 还可以返回 `watchPaths` 以动态更新要监视的文件路径:
3310 3336
3311| 字段 | 描述 |3337| 字段 | 描述 |
3312| :- | :- |3338| :- | :- |
3313| `watchPaths` | 绝对路径数组。替换当前的动态监视列表。来自 `matcher` 配置的路径始终会被监视。当您的 hook 脚本根据已更改的文件发现需要监视的其他文件时,请使用此字段 |3339| `watchPaths` | 绝对路径数组。替换当前的动态监视列表。来自 `matcher` 配置的路径始终会被监视。当您的 hook 脚本根据所更改的文件发现需要监视的其他文件时,请使用此字段 |
3314 3340
3315FileChanged hook 没有决策控制。它们无法阻止文件更改的发生。3341FileChanged hook 没有决策控制。它们无法阻止文件更改的发生。
3316 3342
3317Claude Code 会从其 JSON 输出中读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它会将 `systemMessage` 显示为简短的终端通知。该消息不会到达 SDK 消息流。3343Claude Code 从其 JSON 输出中读取 `watchPaths` 和 `systemMessage`,并丢弃 `continue`。在交互式会话中,它会将 `systemMessage` 显示为简短的终端通知。该消息不会进入 SDK 消息流。
3318 3344
3319<h3 id="worktreecreate">3345<h3 id="worktreecreate">
3320 WorktreeCreate3346 WorktreeCreate
3321</h3>3347</h3>
3322 3348
3323在 Claude Code 于以下等情况下创建 worktree 时运行:3349在以下情况下,当 Claude Code 创建 worktree 时运行:
3324 3350
3325* 您使用 `claude --worktree` 启动会话3351* 您使用 `claude --worktree` 启动会话
3326* Claude 在会话期间创建 worktree,并通过 [`EnterWorktree`](/docs/zh-CN/tools-reference) 工具切换进去3352* Claude 在会话期间创建 worktree 并通过 [`EnterWorktree`](/docs/zh-CN/tools-reference) 工具切换到其中
3327* [子代理使用 `isolation: "worktree"`](/docs/zh-CN/sub-agents#choose-the-subagent-scope)3353* [子代理使用 `isolation: "worktree"`](/docs/zh-CN/sub-agents#choose-the-subagent-scope)
3328* [工作流](/docs/zh-CN/workflows#migrate-many-files-in-parallel)在其自己的 worktree 中运行 Agent3354* [工作流](/docs/zh-CN/workflows#migrate-many-files-in-parallel)在其自己的 worktree 中运行 Agent
3329* Claude Code 将[后台会话](/docs/zh-CN/agent-view#how-file-edits-are-isolated)隔离在其自己的 worktree 中3355* Claude Code 将[后台会话](/docs/zh-CN/agent-view#how-file-edits-are-isolated)隔离在其自己的 worktree 中
3330* `worktree` 模式下的 [`claude remote-control`](/docs/zh-CN/remote-control#start-a-remote-control-session) 在其自己的 worktree 中启动会话3356* 处于 `worktree` 模式的 [`claude remote-control`](/docs/zh-CN/remote-control#start-a-remote-control-session) 在其自己的 worktree 中启动会话
3331 3357
3332当 Claude 通过 Bash 工具运行 `git worktree add` 而不是调用 `EnterWorktree` 时,您的 WorktreeCreate hook 不会运行。要检查或阻止该命令,请添加一个使用 `Bash` 匹配器的 [`PreToolUse`](#pretooluse) hook。3358当 Claude 通过 Bash 工具运行 `git worktree add` 而不是调用 `EnterWorktree` 时,您的 WorktreeCreate hook 不会运行。要检查或阻止该命令,请添加一个使用 `Bash` 匹配器的 [`PreToolUse`](#pretooluse) hook。
3333 3359
3334默认情况下,Claude Code 使用 `git worktree` 创建隔离的工作副本。配置 WorktreeCreate hook 会替换这种默认的 git 行为,让您可以使用其他版本控制系统,例如 SVN、Perforce 或 Mercurial。3360默认情况下,Claude Code 使用 `git worktree` 创建隔离的工作副本。配置 WorktreeCreate hook 会替换该默认的 git 行为,使您可以使用其他版本控制系统,例如 SVN、Perforce 或 Mercurial。
3335 3361
3336由于该 hook 完全替换了默认行为,因此不会处理 [`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees)。如果需要将 `.env` 等本地配置文件复制到新的 worktree 中,请在 hook 脚本中完成。3362由于该 hook 会完全替换默认行为,因此不会处理 [`.worktreeinclude`](/docs/zh-CN/worktrees#copy-gitignored-files-into-worktrees)。如果您需要将 `.env` 等本地配置文件复制到新的 worktree 中,请在 hook 脚本中执行此操作。
3337 3363
3338该 hook 必须返回所创建 worktree 目录的路径。Claude Code 将此路径用作隔离会话的工作目录。有关每种 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。3364该 hook 必须返回所创建的 worktree 目录的路径。Claude Code 会将此路径用作隔离会话的工作目录。有关每种 hook 类型如何返回路径,请参阅 [WorktreeCreate 输出](#worktreecreate-output)。
3339 3365
3340Claude Code 依据 hook 是否成功以及返回的路径执行操作,并丢弃 `systemMessage` 和 `continue`。3366Claude Code 根据 hook 是否成功以及返回的路径采取行动,并丢弃 `systemMessage` 和 `continue`。
3341 3367
3342此示例创建一个 SVN 工作副本,并打印路径供 Claude Code 使用。请将仓库 URL 替换为您自己的 URL:3368此示例创建一个 SVN 工作副本并打印路径供 Claude Code 使用。请将仓库 URL 替换为您自己的:
3343 3369
3344```json theme={null}3370```json theme={null}
3345{3371{
3358}3384}
3359```3385```
3360 3386
3361该 hook 从 stdin 上的 JSON 输入中读取 worktree 的 `name`,将一个全新副本检出到新目录中,并打印目录路径。最后一行的 `echo` 就是 Claude Code 读取为 worktree 路径的内容。请将其他所有输出重定向到 stderr,以免干扰路径。3387该 hook 从 stdin 上的 JSON 输入读取 worktree 的 `name`,将一份全新副本检出到新目录中,并打印该目录路径。最后一行的 `echo` 就是 Claude Code 读取为 worktree 路径的内容。请将其他所有输出重定向到 stderr,以免干扰路径。
3362 3388
3363<h4 id="worktreecreate-input">3389<h4 id="worktreecreate-input">
3364 WorktreeCreate 输入3390 WorktreeCreate 输入
3365</h4>3391</h4>
3366 3392
3367除[通用输入字段](#common-input-fields)外,WorktreeCreate hook 还会接收 `name` 字段。这是新 worktree 的 slug 标识符,由用户指定或自动生成,例如 `bold-oak-a3f2`。3393除了[通用输入字段](#common-input-fields)之外,WorktreeCreate hook 还会接收 `name` 字段。这是新 worktree 的 slug 标识符,由用户指定或自动生成,例如 `bold-oak-a3f2`。
3368 3394
3369```json theme={null}3395```json theme={null}
3370{3396{
3380 WorktreeCreate 输出3406 WorktreeCreate 输出
3381</h4>3407</h4>
3382 3408
3383WorktreeCreate hook 不使用标准的允许/阻止决策模型,而是由 hook 的成功或失败决定结果。该 hook 必须返回所创建 worktree 目录的路径:3409WorktreeCreate hook 不使用标准的允许/阻止决策模型。相反,由 hook 的成功或失败决定结果。该 hook 必须返回所创建的 worktree 目录的路径:
3384 3410
3385* **命令 hook**(`type: "command"`):将路径作为 stdout 的最后一个非空行打印。Claude Code 在读取该行之前会去除 ANSI 转义码,因此在 `echo` 之前打印的 shell 启动横幅会被忽略。请将 hook 的其他所有输出重定向到 stderr。3411* **命令 hook**(`type: "command"`):将路径作为 stdout 的最后一个非空行打印。Claude Code 在读取该行之前会去除 ANSI 转义码,因此在您的 `echo` 之前打印的 shell 启动横幅会被忽略。请将其他所有 hook 输出重定向到 stderr。
3386* **HTTP hook**(`type: "http"`):在响应正文中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。3412* **HTTP hook**(`type: "http"`):在响应正文中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。
3387 3413
3388如果 hook 失败或未生成路径,worktree 创建将失败并报错。3414如果 hook 失败或未生成路径,worktree 创建将失败并报错。
3389 3415
3390Claude Code 会相对于 hook 运行时所在的目录解析相对路径,并折叠其中的 `.` 或 `..` 段。如果生成的路径不是 Claude Code 可以进入的目录,会话会打印一条指明该路径的错误,并以退出码 1 退出。3416Claude Code 会相对于 hook 运行时所在的目录解析相对路径,并折叠其中的任何 `.` 或 `..` 片段。如果得到的路径不是 Claude Code 可以进入的目录,会话会打印一条指明该路径的错误,并以代码 1 退出。
3391 3417
3392Claude Code 会拒绝包含 `.` 或 `..` 段的绝对路径,以及任何经过仓库根目录下符号链接的路径,因为提交到仓库中的符号链接可能会将 worktree 重定向到仓库之外。错误信息会指明被拒绝的路径组成部分。请返回一个规范化的、不经过仓库内符号链接的路径。在 v2.1.216 之前,worktree 创建会直接使用 hook 返回的路径,不进行此项检查。3418Claude Code 会拒绝包含 `.` 或 `..` 片段的绝对路径,以及任何经过仓库根目录下符号链接的路径,因为提交到仓库中的符号链接可能会将 worktree 重定向到仓库之外。错误会指明被拒绝的组成部分。请返回一个不经过仓库内符号链接的规范化路径。在 v2.1.216 之前,worktree 创建会直接使用 hook 的路径,不进行此项检查。
3393 3419
3394<h3 id="worktreeremove">3420<h3 id="worktreeremove">
3395 WorktreeRemove3421 WorktreeRemove
3396</h3>3422</h3>
3397 3423
3398在 Claude Code 清理由您的 [`WorktreeCreate`](#worktreecreate) hook 创建的 worktree 时运行。该事件在以下情况下触发:3424当 Claude Code 清理由您的 [`WorktreeCreate`](#worktreecreate) hook 创建的 worktree 时运行。该事件在以下情况下触发:
3399 3425
3400* 您退出交互式 [worktree 会话](/docs/zh-CN/worktrees#start-claude-in-a-worktree),并在 Claude Code 提示时选择删除该 worktree3426* 您退出交互式 [worktree 会话](/docs/zh-CN/worktrees#start-claude-in-a-worktree),并在 Claude Code 提示时选择删除 worktree
3401* 您退出一个尚未[命名](/docs/zh-CN/sessions#name-your-sessions)的交互式 worktree 会话,Claude Code 未发现已更改或未跟踪的文件,并在不提示的情况下删除该 worktree3427* 您退出一个尚未[命名](/docs/zh-CN/sessions#name-your-sessions)的交互式 worktree 会话,Claude Code 未发现已更改或未跟踪的文件,并在不提示您的情况下删除 worktree
3402* 您删除一个在该 worktree 中运行的[后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes)3428* 您删除在该 worktree 中运行的[后台会话](/docs/zh-CN/agent-view#what-deleting-a-session-removes)
3403* 您在会话期间要求 Claude 退出并删除 worktree,Claude 使用 [`ExitWorktree`](/docs/zh-CN/tools-reference) 工具将其删除3429* 您在会话期间要求 Claude 退出并删除 worktree,Claude 使用 [`ExitWorktree`](/docs/zh-CN/tools-reference) 工具将其删除
3404* 由 [`claude remote-control`](/docs/zh-CN/remote-control#start-a-remote-control-session) 以 `worktree` 模式启动的会话在未崩溃的情况下结束,且 Claude Code 在其 worktree 中未发现任何已更改或未跟踪的文件,也没有新的提交3430* 由 [`claude remote-control`](/docs/zh-CN/remote-control#start-a-remote-control-session) 以 `worktree` 模式启动的会话在未崩溃的情况下结束,并且 Claude Code 在其 worktree 中未发现已更改或未跟踪的文件,也没有新的提交
3405* 您停止 `claude remote-control` 时,它以 `worktree` 模式启动的会话仍在运行,且 Claude Code 在这些会话的 worktree 中未发现任何已更改或未跟踪的文件,也没有新的提交3431* 您在由 `claude remote-control` 以 `worktree` 模式启动的会话仍在运行时停止 `claude remote-control`,并且 Claude Code 在它们的 worktree 中未发现已更改或未跟踪的文件,也没有新的提交
3406 3432
3407当子代理或工作流 Agent 完成时,Claude Code 会保留您的 WorktreeCreate hook 为其创建的 worktree,并且不会运行您的 WorktreeRemove hook。工作完成后,请自行删除这些 worktree。3433当子代理或工作流 Agent 完成时,Claude Code 会保留您的 WorktreeCreate hook 为其创建的 worktree,并且不会运行您的 WorktreeRemove hook。工作完成后,请自行删除这些 worktree。
3408 3434
3409对于 `ExitWorktree` 调用或 `claude remote-control` 清理,Claude Code 在运行您的 hook 之前不会提示您。除非调用传入 [`discard_changes: true`](/docs/zh-CN/agent-sdk/typescript#exitworktree),否则 `ExitWorktree` 会拒绝删除由 hook 创建的 worktree,这使您的 hook 成为该路径上的最后一道检查。3435对于 `ExitWorktree` 调用或 `claude remote-control` 清理,Claude Code 不会在您的 hook 运行之前提示您。除非调用传递了 [`discard_changes: true`](/docs/zh-CN/agent-sdk/typescript#exitworktree),否则 `ExitWorktree` 会拒绝删除由 hook 创建的 worktree,这使您的 hook 成为该路径上的最后一道检查。
3410 3436
3411Claude Code 使用 git 查找已更改或未跟踪的文件,因此对于不是 git 检出或不位于 git 检出内的 worktree,即使目录中有未提交的工作,它也找不到任何内容。请在 WorktreeRemove hook 删除任何内容之前检查此类工作。3437Claude Code 使用 git 查找已更改或未跟踪的文件,因此对于不是 git 检出或不在 git 检出内的 worktree,即使目录中有未提交的工作,它也找不到任何文件。请在 WorktreeRemove hook 删除任何内容之前检查此类工作。
3412 3438
3413对于基于 git 的 worktree,Claude Code 会使用 `git worktree remove` 自动处理清理。如果您配置了 WorktreeCreate hook,请将其与 WorktreeRemove hook 配对使用以控制清理:3439对于基于 git 的 worktree,Claude Code 会使用 `git worktree remove` 自动处理清理。如果您配置了 WorktreeCreate hook,请将其与 WorktreeRemove hook 搭配使用以控制清理:
3414 3440
3415* **没有 WorktreeRemove hook**:对于退出时或通过 `ExitWorktree` 进行的删除,Claude Code 会回退到 git;当 `claude remote-control` 执行清理时,则保留 worktree:3441* **没有 WorktreeRemove hook**:对于退出时或通过 `ExitWorktree` 进行的删除,Claude Code 会回退到 git;当 `claude remote-control` 进行清理时,则保留 worktree:
3416 * **您退出 worktree 会话,或 Claude 调用 `ExitWorktree`**:Claude Code 会像 `git worktree remove --force` 那样删除您的 WorktreeCreate hook 返回的路径,因此 git 能识别的 worktree 会被删除。git 无法识别的 worktree(例如您的 hook 使用非 git 版本控制系统创建的 worktree)会保留在磁盘上。3442 * **您退出 worktree 会话,或 Claude 调用 `ExitWorktree`**:Claude Code 会像 `git worktree remove --force` 那样删除您的 WorktreeCreate hook 返回的路径,因此 git 能识别的 worktree 会被删除。git 无法识别的 worktree(例如您的 hook 使用非 git 版本控制系统创建的 worktree)会保留在磁盘上。
3417 * **`claude remote-control` 清理会话的 worktree**:worktree 保留在磁盘上,运行 `claude remote-control` 的终端会显示 `worktree removal failed, kept: <path>`。3443 * **`claude remote-control` 清理会话的 worktree**:worktree 保留在磁盘上,运行 `claude remote-control` 的终端会显示 `worktree removal failed, kept: <path>`。
3418 * **您删除后台会话**:请参阅[删除会话会移除哪些内容](/docs/zh-CN/agent-view#what-deleting-a-session-removes)。3444 * **您删除后台会话**:请参阅[删除会话会移除什么](/docs/zh-CN/agent-view#what-deleting-a-session-removes)。
3419* **Hook 以 0 退出**:该 worktree 被视为已删除。Claude Code 不会从 hook 读取其他任何内容,因此请确保您的 hook 已删除该目录。3445* **Hook 以 0 退出**:worktree 被视为已删除。Claude Code 不会从 hook 读取其他任何内容,因此请确保您的 hook 已删除该目录。
3420* **Hook 以非零值退出**:如果之后 `worktree_path` 处的目录仍然存在,则删除失败,worktree 保留在磁盘上,且不会回退到 git。在以非零值退出之前已删除目录的 hook 被视为已删除。有关如何报告失败,请参阅 [WorktreeRemove 输入](#worktreeremove-input)。3446* **Hook 以非零退出**:如果之后 `worktree_path` 处的目录仍然存在,则删除失败,worktree 保留在磁盘上,且不会回退到 git。在以非零退出之前已删除目录的 hook 被视为已删除。有关如何报告该失败,请参阅 [WorktreeRemove 输入](#worktreeremove-input)。
3421 3447
3422Claude Code 永远不会删除属于由 hook 创建的 worktree 的分支,因为它只知道您的 WorktreeCreate hook 返回的路径。如果您的 WorktreeCreate hook 创建了分支,请在 WorktreeRemove hook 中删除它。3448Claude Code 从不删除属于由 hook 创建的 worktree 的分支,因为它只知道您的 WorktreeCreate hook 返回的路径。如果您的 WorktreeCreate hook 创建了分支,请在 WorktreeRemove hook 中将其删除。
3423 3449
3424Claude Code 会丢弃 WorktreeRemove hook 的 [JSON 输出字段](#json-output),例如 `systemMessage` 和 `continue`。3450Claude Code 会丢弃 WorktreeRemove hook 的 [JSON 输出字段](#json-output),例如 `systemMessage` 和 `continue`。
3425 3451
3426对于后台会话删除,Claude Code 会在运行 hook 之前验证存储的 worktree 路径,并拒绝本身是符号链接或经过仓库根目录下符号链接的路径。在这条路径上,只有当您在 [agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中确认删除时,hook 才会针对仍包含文件的 worktree 运行;对于这样的 worktree,[`claude rm`](/docs/zh-CN/agent-view#manage-sessions-from-the-shell) 会改为保留会话和 worktree。在 v2.1.216 之前,hook 会在不进行这些检查的情况下针对存储的路径运行。3452对于删除后台会话的情况,Claude Code 会在运行 hook 之前验证存储的 worktree 路径,并拒绝本身是符号链接或经过仓库根目录下符号链接的路径。在该路径上,只有当您在 [Agent 视图](/docs/zh-CN/agent-view#what-deleting-a-session-removes)中确认删除时,hook 才会针对仍包含文件的 worktree 运行;对于此类 worktree,[`claude rm`](/docs/zh-CN/agent-view#manage-sessions-from-the-shell) 会改为保留会话和 worktree。在 v2.1.216 之前,hook 会在未经这些检查的情况下针对存储的路径运行。
3427 3453
3428Claude Code 会将 WorktreeCreate 返回的路径作为 hook 输入中的 `worktree_path` 传递。此示例读取该路径并删除目录:3454Claude Code 会将 WorktreeCreate 返回的路径作为 hook 输入中的 `worktree_path` 传递。此示例读取该路径并删除目录:
3429 3455
3448 WorktreeRemove 输入3474 WorktreeRemove 输入
3449</h4>3475</h4>
3450 3476
3451除[通用输入字段](#common-input-fields)外,WorktreeRemove hook 还会接收 `worktree_path` 字段,即要删除的 worktree 的绝对路径。3477除了[通用输入字段](#common-input-fields)之外,WorktreeRemove hook 还会接收 `worktree_path` 字段,即正在删除的 worktree 的绝对路径。
3452 3478
3453```json theme={null}3479```json theme={null}
3454{3480{
3460}3486}
3461```3487```
3462 3488
3463WorktreeRemove hook 的退出码决定结果。当 hook 以非零值退出,且之后 `worktree_path` 处的目录仍然存在时,删除失败:3489WorktreeRemove hook 的退出码决定结果。当 hook 以非零退出且之后 `worktree_path` 处的目录仍然存在时,删除失败:
3464 3490
3465* worktree 保留在磁盘上,hook 的命令和 stderr 会写入[调试日志](#debug-hooks)。3491* worktree 保留在磁盘上,hook 的命令和 stderr 会写入[调试日志](#debug-hooks)。
3466* 如果您正在删除后台会话,该会话也会保留。[agent view](/docs/zh-CN/agent-view#what-deleting-a-session-removes) 中的拒绝消息会报告 hook 的结束方式(例如 `exited 1`),引用其 stderr 的开头部分,并说明再次删除该会话是否仍会删除该目录。3492* 如果您正在删除后台会话,该会话也会保留。[Agent 视图](/docs/zh-CN/agent-view#what-deleting-a-session-removes)中的拒绝消息会报告 hook 的结束方式(例如 `exited 1`),引用其 stderr 的开头部分,并说明再次删除该会话是否仍会删除该目录。
3467* 如果当时 `claude remote-control` 正在清理会话的 worktree,运行它的终端会显示 `worktree removal failed, kept: <path>`。3493* 如果 `claude remote-control` 正在清理会话的 worktree,运行它的终端会显示 `worktree removal failed, kept: <path>`。
3468 3494
3469<h3 id="precompact">3495<h3 id="precompact">
3470 PreCompact3496 PreCompact
3471</h3>3497</h3>
3472 3498
3473在 Claude Code 即将执行压缩操作之前运行。3499在 Claude Code 即将运行压缩操作之前运行。
3474 3500
3475匹配器值表示压缩是手动触发还是自动触发的:3501匹配器值表示压缩是手动触发还是自动触发:
3476 3502
3477| 匹配器 | 触发时机 |3503| 匹配器 | 触发时机 |
3478| :- | :- |3504| :- | :- |
3479| `manual` | `/compact` |3505| `manual` | `/compact` |
3480| `auto` | 对话达到[自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window)时的自动压缩 |3506| `auto` | 对话达到[自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window)时的自动压缩,以及[空闲压缩](/docs/zh-CN/settings-reference#idlecompaction) |
3481 3507
3482以退出码 2 退出可阻止压缩。对于手动 `/compact`,stderr 消息会显示给用户。您也可以通过返回包含 `"decision": "block"` 的 JSON 来阻止。3508以代码 2 退出可阻止压缩。对于手动 `/compact`,stderr 消息会显示给用户。您也可以通过返回包含 `"decision": "block"` 的 JSON 来阻止。
3483 3509
3484阻止自动压缩的效果取决于其触发时机。如果压缩是在达到上下文限制之前主动触发的,Claude Code 会跳过它,对话在未压缩的情况下继续。如果压缩是为了从 API 已返回的上下文限制错误中恢复而触发的,则底层错误会显示出来,当前请求失败。3510阻止自动压缩的效果取决于其触发时机。如果压缩是在达到上下文限制之前主动触发的,Claude Code 会跳过压缩,对话继续进行而不压缩。如果压缩是为了从 API 已返回的上下文限制错误中恢复而触发的,则底层错误会显现出来,当前请求失败。
3485 3511
3486Claude Code 会丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。3512Claude Code 会丢弃 PreCompact hook 的 `systemMessage` 和 `continue` 字段。
3487 3513
3489 PreCompact 输入3515 PreCompact 输入
3490</h4>3516</h4>
3491 3517
3492除[通用输入字段](#common-input-fields)外,PreCompact hook 还会接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传入 `/compact` 的内容,未传入任何内容时为 `null`。对于 `auto`,`custom_instructions` 为 `null`。3518除了[通用输入字段](#common-input-fields)之外,PreCompact hook 还会接收 `trigger` 和 `custom_instructions`。对于 `manual`,`custom_instructions` 包含用户传递给 `/compact` 的内容,如果用户未传递任何内容则为 `null`。对于 `auto`,`custom_instructions` 为 `null`。
3493 3519
3494```json theme={null}3520```json theme={null}
3495{3521{
3506 PostCompact3532 PostCompact
3507</h3>3533</h3>
3508 3534
3509在 Claude Code 完成压缩操作后运行。使用此事件对新的压缩状态作出响应,例如记录生成的摘要或更新外部状态。Claude Code 会丢弃 PostCompact hook 的 `systemMessage` 和 `continue` 字段。3535在 Claude Code 完成压缩操作后运行。使用此事件对压缩后的新状态作出反应,例如记录生成的摘要或更新外部状态。Claude Code 会丢弃 PostCompact hook 的 `systemMessage` 和 `continue` 字段。
3510 3536
3511适用与 `PreCompact` 相同的匹配器值:3537匹配器值与 `PreCompact` 相同:
3512 3538
3513| 匹配器 | 触发时机 |3539| 匹配器 | 触发时机 |
3514| :- | :- |3540| :- | :- |
3515| `manual` | `/compact` 之后 |3541| `manual` | `/compact` 之后 |
3516| `auto` | 对话达到[自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window)时的自动压缩之后 |3542| `auto` | 对话达到[自动压缩窗口](/docs/zh-CN/model-config#set-the-auto-compact-window)时的自动压缩之后,以及[空闲压缩](/docs/zh-CN/settings-reference#idlecompaction)之后 |
3517 3543
3518<h4 id="postcompact-input">3544<h4 id="postcompact-input">
3519 PostCompact 输入3545 PostCompact 输入
3520</h4>3546</h4>
3521 3547
3522除[通用输入字段](#common-input-fields)外,PostCompact hook 还会接收 `trigger` 和 `compact_summary`。`compact_summary` 字段包含压缩操作生成的对话摘要。3548除了[通用输入字段](#common-input-fields)之外,PostCompact hook 还会接收 `trigger` 和 `compact_summary`。`compact_summary` 字段包含压缩操作生成的对话摘要。
3523 3549
3524```json theme={null}3550```json theme={null}
3525{3551{
3538 PreModelSwitch3564 PreModelSwitch
3539</h3>3565</h3>
3540 3566
3541在 Claude Code 应用由您或客户端请求的模型切换之前运行。可用于阻止切换、要求确认,或在切换发生前显示切换的成本。3567在 Claude Code 应用您或客户端请求的模型切换之前运行。使用它可以阻止切换、要求确认,或在切换发生之前显示切换的成本。
3542 3568
3543PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 会针对以下请求运行它:3569PreModelSwitch 需要 Claude Code v2.1.251 或更高版本。Claude Code 会针对以下请求运行它:
3544 3570
3545* `/model <name>` 和 `/model` 选择器3571* `/model <name>` 和 `/model` 选择器
3546* `Option+P` 或 `Alt+P` 模型选择器3572* `Option+P` 或 `Alt+P` 模型选择器
3547* `/config` 中的 Model 设置3573* `/config` 中的 Model 设置
3548* 启用[快速模式](/docs/zh-CN/fast-mode)且这会更改会话的模型时3574* 启用[快速模式](/docs/zh-CN/fast-mode)且这会更改会话模型时
3549* 来自 [Agent SDK](/docs/zh-CN/agent-sdk/typescript#query-object) 宿主或 [Remote Control](/docs/zh-CN/remote-control) 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改3575* 来自 [Agent SDK](/docs/zh-CN/agent-sdk/typescript#query-object) 宿主或 [Remote Control](/docs/zh-CN/remote-control) 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改
3550 3576
3551对于 Claude Code 自行执行的切换,例如[自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback)或恢复会话时还原模型,Claude Code 不会运行 PreModelSwitch hook。这些更改只会触发 [PostModelSwitch](#postmodelswitch)。3577对于 Claude Code 自行进行的切换,例如[自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback)或恢复会话时还原模型,Claude Code 不会运行 PreModelSwitch hook。这些更改只会触发 [PostModelSwitch](#postmodelswitch)。
3552 3578
3553Claude Code 会将匹配器与会话要切换到的模型的规范名称进行比较,并忽略任何 `[1m]` 后缀。别名(如 `opus`)、带日期的模型 ID 以及特定提供商的 ID(如 Amazon Bedrock 模型 ID)都会匹配它们所解析到的同一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的所有写法。3579Claude Code 会将匹配器与会话将要切换到的模型的规范名称进行比较,忽略任何 `[1m]` 后缀。诸如 `opus` 之类的别名、带日期的模型 ID,以及提供商特定的 ID(例如 Amazon Bedrock 模型 ID)都会匹配它们解析到的同一个规范名称,因此 `claude-opus-5` 涵盖 Opus 5 的所有写法。
3554 3580
3555当 Claude Code 无法确定目标的规范名称时(例如只有您的 [LLM 网关](/docs/zh-CN/llm-gateway)知道的自定义模型 ID),它会运行所有 PreModelSwitch hook,无论匹配器为何。因此,用于阻止的 hook 应检查其输入中的 `to_model`,而不是仅依赖匹配器。3581当 Claude Code 无法确定目标的规范名称时,例如只有您的 [LLM 网关](/docs/zh-CN/llm-gateway)知道的自定义模型 ID,它会运行所有 PreModelSwitch hook,而不管匹配器如何。因此,执行阻止操作的 hook 应检查其输入中的 `to_model`,而不是仅依赖匹配器。
3556 3582
3557匹配器可以写成精确名称、以 `|` 分隔的列表(如 `claude-opus-4-6|claude-opus-5`),或正则表达式(如 `.*opus.*`)。此示例使用精确名称匹配器,同时检查 hook 输入中的 `to_model`,因此它通过以退出码 2 退出来拒绝切换到 Opus 4.6,并允许切换到任何其他目标:3583将匹配器写为精确名称、以 `|` 分隔的列表(例如 `claude-opus-4-6|claude-opus-5`),或正则表达式(例如 `.*opus.*`)。此示例使用精确名称匹配器,同时检查 hook 输入中的 `to_model`,因此它会通过以代码 2 退出来拒绝切换到 Opus 4.6,并允许切换到任何其他目标:
3558 3584
3559<Tabs>3585<Tabs>
3560 <Tab title="macOS/Linux">3586 <Tab title="macOS/Linux">
3620 </Tab>3646 </Tab>
3621</Tabs>3647</Tabs>
3622 3648
3623要确认 hook 是否生效,请在运行其他模型的会话中运行 `/model claude-opus-4-6`。Claude Code 会保留当前模型,并报告 PreModelSwitch hook 阻止了切换,以您的消息作为原因。3649要确认该 hook 是否正常工作,请在运行其他模型的会话中运行 `/model claude-opus-4-6`。Claude Code 会保留当前模型,并报告 PreModelSwitch hook 阻止了切换,以您的消息作为原因。
3624 3650
3625<h4 id="premodelswitch-input">3651<h4 id="premodelswitch-input">
3626 PreModelSwitch 输入3652 PreModelSwitch 输入
3627</h4>3653</h4>
3628 3654
3629除[通用输入字段](#common-input-fields)外,PreModelSwitch hook 还会接收下表中的字段。最后五个字段描述将对话重新发送到新模型的成本,以便 hook 可以在切换发生之前显示该数字。3655除了[通用输入字段](#common-input-fields)之外,PreModelSwitch hook 还会接收下表中的字段。最后五个字段描述将对话重新发送到新模型的成本,因此 hook 可以在切换发生之前显示该数值。
3630 3656
3631| 字段 | 类型 | 描述 |3657| 字段 | 类型 | 描述 |
3632| :- | :- | :- |3658| :- | :- | :- |
3633| `from_model` | string | 切换前的模型 ID |3659| `from_model` | string | 切换前的模型 ID |
3634| `to_model` | string | 切换后的模型 ID。匹配器会与此模型的规范名称进行比较 |3660| `to_model` | string | 切换后的模型 ID。匹配器会与此模型的规范名称进行比较 |
3635| `requested_model` | string 或 `null` | 请求中指定的模型:别名(如 `opus`)、完整模型 ID,或在请求默认模型时为 `null` |3661| `requested_model` | string 或 `null` | 请求中指定的模型:诸如 `opus` 之类的别名、完整的模型 ID,或者当请求的是默认模型时为 `null` |
3636| `source` | string | 请求的来源:`"command"` 表示 `/model <name>`、`/config` 中的 Model 设置或启用快速模式;`"picker"` 表示模型选择器;`"sdk"` 表示来自 Agent SDK 宿主或 Remote Control 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改 |3662| `source` | string | 请求的来源:`"command"` 表示 `/model <name>`、`/config` 中的 Model 设置或启用快速模式;`"picker"` 表示模型选择器;`"sdk"` 表示来自 Agent SDK 宿主或 Remote Control 的 `set_model` 请求,或 `apply_flag_settings` 请求中的模型更改 |
3637| `context_tokens` | number | 下一个请求作为提示词重新发送的 token 数:主对话中最后一个响应的输入、缓存读取、缓存创建和输出 token 的总和。第一个响应之前为 `0` |3663| `context_tokens` | number | 下一个请求作为提示词重新发送的 token 数:主对话中最后一次响应的输入、缓存读取、缓存创建和输出 token 的总和。在第一次响应之前为 `0` |
3638| `prompt_cache_warm` | boolean | 当前模型的提示缓存是否可能仍处于热状态,即切换会使其失效 |3664| `prompt_cache_warm` | boolean | 当前模型的提示缓存是否可能仍处于预热状态,即切换会使其失效 |
3639| `cache_ttl` | string | Claude Code 为此会话请求的[提示缓存生存期](/docs/zh-CN/prompt-caching#cache-lifetime):`"5m"` 或 `"1h"` |3665| `cache_ttl` | string | Claude Code 为此会话请求的[提示缓存生命周期](/docs/zh-CN/prompt-caching#cache-lifetime):`"5m"` 或 `"1h"` |
3640| `estimated_cache_write_usd` | number | 按 `cache_ttl` 费率在 `to_model` 上将 `context_tokens` 写入提示缓存的估计成本(美元),不包括下一个响应。服务器可能不需要重新缓存整个上下文,因此请将其视为估计值 |3666| `estimated_cache_write_usd` | number | 按 `cache_ttl` 费率在 `to_model` 上将 `context_tokens` 写入提示缓存的估算成本(美元),不包括下一次响应。服务器可能不需要重新缓存整个上下文,因此请将其视为估算值 |
3641| `pricing` | string | Claude Code 如何为 `estimated_cache_write_usd` 定价:`"configured"` 表示在您的组织已配置费率时按其自有费率计算,`"catalog"` 表示按标价计算,`"default"` 表示 `to_model` 没有已知价格、Claude Code 采用了默认费率 |3667| `pricing` | string | Claude Code 如何为 `estimated_cache_write_usd` 定价:`"configured"` 表示在您的组织已配置自有费率时按该费率计算,`"catalog"` 表示按标价计算,`"default"` 表示 `to_model` 没有已知价格,Claude Code 假定了默认费率 |
3642 3668
3643此示例显示在运行 Sonnet 5 的会话中执行 `/model opus` 时的输入:3669此示例显示在运行 Sonnet 5 的会话中执行 `/model opus` 时的输入:
3644 3670
3664 PreModelSwitch 决策控制3690 PreModelSwitch 决策控制
3665</h4>3691</h4>
3666 3692
3667`PreModelSwitch` hook 可以取消切换、请用户确认,或让切换继续进行。退出码 2 或顶层 `decision: "block"` 会取消切换。3693`PreModelSwitch` hook 可以取消切换、要求用户确认,或允许其继续。退出码 2 或顶层的 `decision: "block"` 会取消切换。
3668 3694
3669如需更精细的控制,请在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,与 [PreToolUse](#pretooluse-decision-control) 相同。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`,不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述了这两个字段:3695如需更精细的控制,请在 `hookSpecificOutput` 对象中返回 `permissionDecision` 和 `permissionDecisionReason`,与 [PreToolUse](#pretooluse-decision-control) 相同。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表描述了这两个字段:
3670 3696
3671| 字段 | 描述 |3697| 字段 | 描述 |
3672| :- | :- |3698| :- | :- |
3673| `permissionDecision` | `"allow"` 继续切换,并跳过[提示缓存处于热状态时 Claude Code 显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户确认 |3699| `permissionDecision` | `"allow"` 继续切换,并跳过[提示缓存处于预热状态时 Claude Code 显示的确认](/docs/zh-CN/prompt-caching#switching-models)。`"deny"` 取消切换。`"ask"` 提示用户确认 |
3674| `permissionDecisionReason` | 对于 `"deny"`,作为切换被阻止的原因显示给用户,或作为 `set_model` 请求的错误返回。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 则忽略 |3700| `permissionDecisionReason` | 对于 `"deny"`,作为切换被阻止的原因显示给用户,或作为 `set_model` 请求的错误返回。对于 `"ask"`,显示在确认提示中。对于 `"allow"` 会被忽略 |
3675 3701
3676只有交互式会话中的 `/model` 才能显示 `"ask"` 提示。在其他所有使用入口上,包括使用 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 都会将 `"ask"` 视为拒绝。3702只有交互式会话中的 `/model` 可以显示 `"ask"` 提示。在其他所有使用入口上,包括使用 `-p` 标志的非交互模式、`/config` 和 `set_model` 请求,Claude Code 都会将 `"ask"` 视为拒绝。
3677 3703
3678此示例请用户确认,并引用 `context_tokens` 中的 token 数:3704此示例要求用户确认,并引用 `context_tokens` 中的 token 数:
3679 3705
3680```json theme={null}3706```json theme={null}
3681{3707{
3689 3715
3690当多个 PreModelSwitch hook 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。3716当多个 PreModelSwitch hook 返回不同的决策时,优先级为 `deny` > `ask` > `allow`。
3691 3717
3692无论决策如何,Claude Code 都会向用户显示您的 hook 返回的任何 `systemMessage`,因此用于报告成本的 hook 可以返回 `{"systemMessage": "..."}` 并以 0 退出。3718无论决策如何,Claude Code 都会向用户显示您的 hook 返回的任何 `systemMessage`,因此报告成本的 hook 可以返回 `{"systemMessage": "..."}` 并以 0 退出。
3693 3719
3694在超时之前未响应的 PreModelSwitch hook 会阻止切换。关于超时对其他事件的影响,请参阅[超时](#timeouts)。此事件的默认超时时间为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hook,因此 `prompt` 和 `agent` 的默认值不适用。3720在超时之前未响应的 PreModelSwitch hook 会阻止切换。有关超时在其他事件上的作用,请参阅[超时](#timeouts)。此事件的默认超时时间为 30 秒。`PreModelSwitch` 仅运行 `command`、`http` 和 `mcp_tool` hook,因此 `prompt` 和 `agent` 的默认值不适用。
3695 3721
3696以 0 或 2 以外的代码退出且未打印 JSON 决策的 hook 属于非阻塞错误,如[其他退出码](#other-exit-codes)中所述。3722以 0 或 2 以外的代码退出且未打印 JSON 决策的 hook 属于非阻塞错误,如[其他退出码](#other-exit-codes)中所述。
3697 3723
3699 PostModelSwitch3725 PostModelSwitch
3700</h3>3726</h3>
3701 3727
3702在会话的模型更改后运行。可用于在不编辑每个 CLAUDE.md 的情况下为 Claude 提供特定于模型的指导,例如适用于某些模型的全组织范围指令。3728在会话的模型更改后运行。使用它可以为 Claude 提供特定于模型的指导,而无需编辑每个 CLAUDE.md,例如适用于某些模型的组织范围指令。
3703 3729
3704PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。Claude Code 会在以下任一更改之后运行 PostModelSwitch hook:3730PostModelSwitch 需要 Claude Code v2.1.251 或更高版本。它无法阻止,因为模型已经更改。在以下任何更改之后,Claude Code 都会运行 PostModelSwitch hook:
3705 3731
3706* 您或客户端请求的切换3732* 您或客户端请求的切换
3707* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),这会更改会话的模型3733* [自动模型回退](/docs/zh-CN/model-config#automatic-model-fallback),它会更改会话的模型
3708* 诸如 [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting) 之类的设置进入或离开计划模式3734* 诸如 [`opusplan`](/docs/zh-CN/model-config#opusplan-model-setting) 之类的设置进入或离开计划模式
3709* 恢复会话时 Claude Code 还原模型3735* 恢复会话时 Claude Code 还原模型
3710 3736
3711当[备用模型链](/docs/zh-CN/model-config#fallback-model-chains)中的某个模型服务于某一轮次时,Claude Code 不会运行 PostModelSwitch hook,因为该替换仅持续一轮,且不会更改会话的模型。3737当[备用模型链](/docs/zh-CN/model-config#fallback-model-chains)中的某个模型处理某一轮次时,Claude Code 不会运行 PostModelSwitch hook,因为该替换只持续一轮,且不会改变会话的模型。
3712 3738
3713匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 会将其与会话切换到的模型的规范名称进行比较。3739匹配器遵循与 [PreModelSwitch](#premodelswitch) 相同的规则:Claude Code 会将其与会话切换到的模型的规范名称进行比较。
3714 3740
3715此示例在会话的模型更改为任何 Opus 模型时添加指导:3741此示例会在会话的模型更改为任何 Opus 模型时添加指导:
3716 3742
3717```json theme={null}3743```json theme={null}
3718{3744{
3732}3758}
3733```3759```
3734 3760
3735要确认 hook 是否生效,请在运行其他模型的会话中切换到 Opus 模型,例如在 Sonnet 会话中运行 `/model opus`,然后询问 Claude 它对当前模型有什么指导。3761要确认该 hook 是否正常工作,请在运行其他模型的会话中切换到 Opus 模型,例如在 Sonnet 会话中运行 `/model opus`,然后询问 Claude 它对当前模型有什么指导。
3736 3762
3737<h4 id="postmodelswitch-input">3763<h4 id="postmodelswitch-input">
3738 PostModelSwitch 输入3764 PostModelSwitch 输入
3739</h4>3765</h4>
3740 3766
3741PostModelSwitch hook 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,其中 `hook_event_name` 设置为 `"PostModelSwitch"`,并且 `source` 多两个值:`"auto"` 表示自动回退或 Claude Code 自行做出的其他更改,`"resume"` 表示恢复会话时还原的模型。3767PostModelSwitch hook 接收与 [PreModelSwitch](#premodelswitch-input) 相同的字段,其中 `hook_event_name` 设置为 `"PostModelSwitch"`,并且多了两个 `source` 值:`"auto"` 表示自动回退或 Claude Code 自行进行的其他更改,`"resume"` 表示恢复会话时还原的模型。
3742 3768
3743当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 还原的已保存模型设置。3769当 `source` 为 `"auto"` 时,`requested_model` 为 `null`。当 `source` 为 `"resume"` 时,它是 Claude Code 还原的已保存模型设置。
3744 3770
3746 PostModelSwitch 决策控制3772 PostModelSwitch 决策控制
3747</h4>3773</h4>
3748 3774
3749Claude Code 会在退出码为 0 时获取 hook 的[纯文本 stdout](#exit-code-0),或从 JSON 输出中获取 `additionalContext`,并在切换后的下一个请求中将其传递给 Claude。除所有 hook 均可使用的 [JSON 输出字段](#json-output)外,您还可以返回:3775Claude Code 会在以 0 退出时获取您的 hook 的[纯文本 stdout](#exit-code-0),或获取 JSON 输出中的 `additionalContext`,并在切换后的下一个请求中将其传递给 Claude。除了所有 hook 都可用的 [JSON 输出字段](#json-output)之外,您还可以返回:
3750 3776
3751| 字段 | 描述 |3777| 字段 | 描述 |
3752| :- | :- |3778| :- | :- |
3753| `additionalContext` | 随下一个请求添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |3779| `additionalContext` | 随下一个请求添加到 Claude 上下文中的字符串。请参阅[为 Claude 添加上下文](#add-context-for-claude) |
3754 3780
3755如果在您发送下一个提示词后五秒内 hook 仍未完成,Claude Code 会在不附带该输出的情况下发送该请求,并将输出附加到后续请求中。如果在下一个请求之前模型更改了多次,Claude Code 只会传递针对最后一次切换目标模型的输出。3781如果在您发送下一个提示词后五秒内 hook 仍未完成,Claude Code 会在不包含该输出的情况下发送该请求,并改为将其附加到后续请求中。如果模型在下一个请求之前更改了多次,Claude Code 只会传递最后一次切换的目标模型的输出。
3756 3782
3757<h3 id="sessionend">3783<h3 id="sessionend">
3758 SessionEnd3784 SessionEnd
3759</h3>3785</h3>
3760 3786
3761在 Claude Code 会话结束时运行。适用于清理任务、记录会话3787在 Claude Code 会话结束时运行。适用于清理任务、记录会话统计信息或保存会话状态。支持使用匹配器按退出原因进行筛选。
3762统计信息或保存会话状态。支持使用匹配器按退出原因进行筛选。
3763 3788
3764hook 输入中的 `reason` 字段表示会话结束的原因:3789hook 输入中的 `reason` 字段表示会话结束的原因:
3765 3790
3768| `clear` | 使用 `/clear` 命令清除了会话 |3793| `clear` | 使用 `/clear` 命令清除了会话 |
3769| `resume` | 通过交互式 `/resume` 切换了会话 |3794| `resume` | 通过交互式 `/resume` 切换了会话 |
3770| `logout` | 用户已注销 |3795| `logout` | 用户已注销 |
3771| `prompt_input_exit` | 用户在提示词输入可见时退出 |3796| `prompt_input_exit` | 用户在提示词输入框可见时退出 |
3772| `other` | 其他退出原因 |3797| `other` | 其他退出原因 |
3773| `bypass_permissions_disabled` | 已在 v2.1.234 中移除;Claude Code 不会发送此值。请将其从您的 `SessionEnd` 匹配器中删除 |3798| `bypass_permissions_disabled` | 已在 v2.1.234 中移除;Claude Code 不会发送它。请将其从您的 `SessionEnd` 匹配器中删除 |
3774 3799
3775<h4 id="sessionend-input">3800<h4 id="sessionend-input">
3776 SessionEnd 输入3801 SessionEnd 输入
3777</h4>3802</h4>
3778 3803
3779除[通用输入字段](#common-input-fields)外,SessionEnd hook 还会接收一个 `reason` 字段,表示会话结束的原因。有关所有值,请参阅上方的[原因表](#sessionend)。3804除了[通用输入字段](#common-input-fields)之外,SessionEnd hook 还会接收一个 `reason` 字段,表示会话结束的原因。有关所有值,请参阅上面的[原因表](#sessionend)。
3780 3805
3781```json theme={null}3806```json theme={null}
3782{3807{
3790 3815
3791SessionEnd hook 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 会丢弃它们的 [JSON 输出字段](#json-output),例如 `systemMessage`。3816SessionEnd hook 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。Claude Code 会丢弃它们的 [JSON 输出字段](#json-output),例如 `systemMessage`。
3792 3817
3793SessionEnd hook 的默认超时时间为 1.5 秒。该超时适用于您退出、运行 `/clear` 或通过交互式 `/resume` 切换会话时。您可以通过两种方式为 hook 提供更多时间:3818SessionEnd hook 的默认超时时间为 1.5 秒。它适用于您退出、运行 `/clear` 或通过交互式 `/resume` 切换会话时。您可以通过两种方式为 hook 提供更多时间:
3794 3819
3795* **每个 hook 的 `timeout`**:在该 hook 的配置中设置 `timeout`。总体时间预算会自动提高,以匹配您设置文件中最高的单个 hook `timeout`,最长 60 秒。如果以这种方式提高预算,没有自己 `timeout` 的 hook 仍保持默认值。在插件提供的 hook 上设置的超时时间不会提高预算。3820* **单个 hook 的 `timeout`**:在该 hook 的配置中设置 `timeout`。总体时间预算会自动提高,以匹配设置文件中最高的单个 hook `timeout`,最多 60 秒。如果您以这种方式提高预算,没有设置自己 `timeout` 的 hook 仍保持默认值。在插件提供的 hook 上设置的超时时间不会提高预算。
3796* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:以毫秒为单位设置此环境变量,以显式覆盖预算。您设置的值也会成为每个没有自己 `timeout` 的 hook 的超时时间。3821* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:以毫秒为单位设置此环境变量,以显式覆盖预算。您设置的值也会成为每个没有设置自己 `timeout` 的 hook 的超时时间。
3797 3822
3798此示例将预算设置为 5 秒:3823此示例将预算设置为 5 秒:
3799 3824
3801CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude3826CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
3802```3827```
3803 3828
3804在 v2.1.268 之前,`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 只会提高总体预算,没有自己 `timeout` 的 hook 仍会在 1.5 秒后被取消。3829在 v2.1.268 之前,`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 只会提高总体预算,没有设置自己 `timeout` 的 hook 仍会在 1.5 秒后被取消。
3805 3830
3806<h3 id="elicitation">3831<h3 id="elicitation">
3807 Elicitation3832 Elicitation
3808</h3>3833</h3>
3809 3834
3810在 MCP 服务器于任务中途请求用户输入时运行。默认情况下,Claude Code 会显示一个交互式对话框供用户响应。hook 可以拦截此请求并以编程方式响应,完全跳过对话框。3835当 MCP 服务器在任务中途请求用户输入时运行。默认情况下,Claude Code 会显示一个交互式对话框供用户响应。hook 可以拦截此请求并以编程方式响应,完全跳过对话框。
3811 3836
3812有关包含设置条目和脚本的完整 hook,请参阅[通过脚本回答表单请求](#answer-a-form-request-from-a-script)。3837有关包含设置条目和脚本的完整 hook,请参阅[通过脚本回答表单请求](#answer-a-form-request-from-a-script)。
3813 3838
3817 Elicitation 输入3842 Elicitation 输入
3818</h4>3843</h4>
3819 3844
3820除[通用输入字段](#common-input-fields)外,Elicitation hook 还会接收 `mcp_server_name`、`message`,以及可选的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 字段。3845除了[通用输入字段](#common-input-fields)之外,Elicitation hook 还会接收 `mcp_server_name`、`message`,以及可选的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 字段。
3821 3846
3822对于表单模式的 elicitation(最常见的情况):3847对于表单模式的 elicitation(最常见的情况):
3823 3848
3858 Elicitation 输出3883 Elicitation 输出
3859</h4>3884</h4>
3860 3885
3861Elicitation hook 可以代替用户回答请求、拒绝或取消请求,或将其交给对话框处理。要回答、拒绝或取消,请以 0 退出并打印一个带有 `action` 的 `hookSpecificOutput` 对象。服务器会收到您的回答,并且不会出现对话框。下表的每一行显示某一结果应返回的内容以及 MCP 服务器收到的内容:3886Elicitation hook 可以代替用户回答请求、拒绝或取消请求,或将其留给对话框处理。要回答、拒绝或取消,请以 0 退出并打印一个带有 `action` 的 `hookSpecificOutput` 对象。服务器会收到您的回答,且不会出现对话框。下表的每一行显示了一种结果应返回的内容以及 MCP 服务器收到的内容:
3862 3887
3863| 目的 | 返回 | 服务器收到 |3888| 目的 | 返回 | 服务器收到 |
3864| :- | :- | :- |3889| :- | :- | :- |
3865| 代替用户回答 | `"action": "accept"`,并在 `content` 中提供表单字段值 | `accept` 以及您的 `content` |3890| 代替用户回答 | `"action": "accept"`,并在 `content` 中提供表单字段值 | `accept` 以及您的 `content` |
3866| 拒绝请求 | `"action": "decline"` | `decline` |3891| 拒绝请求 | `"action": "decline"` | `decline` |
3867| 取消请求 | `"action": "cancel"` | `cancel` |3892| 取消请求 | `"action": "cancel"` | `cancel` |
3868| 将请求交给用户 | 无输出,退出码为 0 | 用户在[对话框](/docs/zh-CN/mcp#respond-to-mcp-elicitation-requests)中的回答 |3893| 将请求留给用户 | 无输出,退出码为 0 | 用户在[对话框](/docs/zh-CN/mcp#respond-to-mcp-elicitation-requests)中的回答 |
3869 3894
3870此输出回答了 [Elicitation 输入](#elicitation-input)中所示的表单模式请求。`content` 中的键是该请求的 `requested_schema` 中的属性名称:3895此输出回答了 [Elicitation 输入](#elicitation-input)中所示的表单模式请求。`content` 中的键是该请求 `requested_schema` 中的属性名称:
3871 3896
3872```json theme={null}3897```json theme={null}
3873{3898{
3894 3919
3895在对话框中,选择 **Decline** 会发送 `decline`,按 `Esc` 会发送 `cancel`,因此请返回您希望服务器看到的那个值。3920在对话框中,选择 **Decline** 会发送 `decline`,按 `Esc` 会发送 `cancel`,因此请返回您希望服务器看到的那个值。
3896 3921
3897对于 URL 模式请求,返回 `accept` 的 hook 会跳过对话框,因此该 URL 永远不会打开。3922对于 URL 模式的请求,返回 `accept` 的 hook 会跳过对话框,因此该 URL 永远不会打开。
3898 3923
3899无论您返回哪个 `action`,Claude Code 都会丢弃 Elicitation hook JSON 输出中的 `reason`、`systemMessage` 和 `continue`。3924无论您返回哪个 `action`,Claude Code 都会丢弃 Elicitation hook JSON 输出中的 `reason`、`systemMessage` 和 `continue`。
3900 3925
3904 3929
3905您的 hook 还可以通过以下方式拒绝。服务器收到的 `decline` 与 `"action": "decline"` 相同:3930您的 hook 还可以通过以下方式拒绝。服务器收到的 `decline` 与 `"action": "decline"` 相同:
3906 3931
3907* **以退出码 2 退出**:Claude Code 会忽略同一 hook 打印的 `hookSpecificOutput`3932* **以代码 2 退出**:Claude Code 会忽略同一 hook 打印的 `hookSpecificOutput`
3908* **打印顶层 `"decision": "block"`**:该阻止会覆盖同一输出中的 `action`3933* **打印顶层的 `"decision": "block"`**:该阻止会覆盖同一输出中的 `action`
3909 3934
3910当多个 hook 匹配同一请求时,其中一个 hook 的拒绝会覆盖另一个 hook 的 `accept` 或 `cancel`。3935当多个 hook 匹配同一请求时,其中一个 hook 的拒绝会覆盖另一个 hook 的 `accept` 或 `cancel`。
3911 3936
3912此脚本拒绝 URL 模式请求,并将表单请求交给对话框处理:3937此脚本会拒绝 URL 模式的请求,并将表单请求留给对话框处理:
3913 3938
3914```bash theme={null}3939```bash theme={null}
3915#!/bin/bash3940#!/bin/bash
3920 3945
3921用户和服务器都看不到您的 hook 拒绝的原因,因为 Claude Code 不会显示您的 stderr 或 `reason`。3946用户和服务器都看不到您的 hook 拒绝的原因,因为 Claude Code 不会显示您的 stderr 或 `reason`。
3922 3947
3923从 v2.1.105 起直到 v2.1.284 中的修复之前,Claude Code 会忽略来自 `Elicitation` 和 `ElicitationResult` hook 的顶层 `decision`。3948从 v2.1.105 到 v2.1.284 中修复之前,Claude Code 会忽略 `Elicitation` 和 `ElicitationResult` hook 的顶层 `decision`。
3924 3949
3925<h4 id="answer-a-form-request-from-a-script">3950<h4 id="answer-a-form-request-from-a-script">
3926 通过脚本回答表单请求3951 通过脚本回答表单请求
3927</h4>3952</h4>
3928 3953
3929此示例代替用户回答一个反复出现的问题。名为 `issue-tracker` 的 MCP 服务器在表单中请求项目键,hook 会填入 `DOCS`。当 `project_key` 是表单的唯一字段时,脚本会接受。对于任何其他请求,它不打印任何内容,因此会显示对话框。3954此示例代替用户回答一个反复出现的问题。名为 `issue-tracker` 的 MCP 服务器在表单中询问项目键,hook 会填入 `DOCS`。当 `project_key` 是表单的唯一字段时,脚本会接受。对于其他任何请求,它不打印任何内容,因此会出现对话框。
3930 3955
3931<Tabs>3956<Tabs>
3932 <Tab title="macOS/Linux">3957 <Tab title="macOS/Linux">
3933 在您的设置文件中为该事件注册一个命令 hook,并将服务器名称作为匹配器:3958 在设置文件中为该事件注册一个命令 hook,以服务器名称作为匹配器:
3934 3959
3935 ```json theme={null}3960 ```json theme={null}
3936 {3961 {
3965 </Tab>3990 </Tab>
3966 3991
3967 <Tab title="Windows (PowerShell)">3992 <Tab title="Windows (PowerShell)">
3968 注册一个通过 PowerShell 运行脚本的命令 hook,并将服务器名称作为匹配器:3993 注册一个通过 PowerShell 运行脚本的命令 hook,以服务器名称作为匹配器:
3969 3994
3970 ```json theme={null}3995 ```json theme={null}
3971 {3996 {
4011 </Tab>4036 </Tab>
4012</Tabs>4037</Tabs>
4013 4038
4014要确认 hook 是否生效,请使用 `claude --debug` 启动 Claude Code,并给 Claude 一个会让服务器请求项目键的任务。不会出现对话框,并且[调试日志](#debug-hooks)中会有一行以 `Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}` 结尾。4039要确认该 hook 是否正常工作,请使用 `claude --debug` 启动 Claude Code,并给 Claude 一个会让服务器询问项目键的任务。不会出现对话框,并且[调试日志](#debug-hooks)中会有一行以 `Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}` 结尾。
4015 4040
4016<h3 id="elicitationresult">4041<h3 id="elicitationresult">
4017 ElicitationResult4042 ElicitationResult
4018</h3>4043</h3>
4019 4044
4020在用户响应 MCP elicitation 后运行。hook 可以在响应发回 MCP 服务器之前观察、修改或阻止该响应。4045在用户响应 MCP elicitation 之后运行。hook 可以在响应发送回 MCP 服务器之前观察、修改或阻止该响应。
4021 4046
4022当 [Elicitation](#elicitation) hook 回答了请求时,Claude Code 会将该回答发送给服务器,而不运行 ElicitationResult hook。4047当 [Elicitation](#elicitation) hook 回答了请求时,Claude Code 会将该回答发送给服务器,而不运行 ElicitationResult hook。
4023 4048
4027 ElicitationResult 输入4052 ElicitationResult 输入
4028</h4>4053</h4>
4029 4054
4030除[通用输入字段](#common-input-fields)外,ElicitationResult hook 还会接收 `mcp_server_name`、`action`,以及可选的 `mode`、`elicitation_id` 和 `content` 字段。4055除了[通用输入字段](#common-input-fields)之外,ElicitationResult hook 还会接收 `mcp_server_name`、`action`,以及可选的 `mode`、`elicitation_id` 和 `content` 字段。
4031 4056
4032```json theme={null}4057```json theme={null}
4033{4058{
4046 ElicitationResult 输出4071 ElicitationResult 输出
4047</h4>4072</h4>
4048 4073
4049ElicitationResult hook 可以让用户的响应通过、更改其值或阻止它。要更改或阻止响应,请以 0 退出并打印一个带有 `action` 的 `hookSpecificOutput` 对象。下表的每一行显示某一结果应返回的内容以及 MCP 服务器收到的内容:4074ElicitationResult hook 可以让用户的响应通过、更改其值或阻止它。要更改或阻止响应,请以 0 退出并打印一个带有 `action` 的 `hookSpecificOutput` 对象。下表的每一行显示了一种结果应返回的内容以及 MCP 服务器收到的内容:
4050 4075
4051| 目的 | 返回 | 服务器收到 |4076| 目的 | 返回 | 服务器收到 |
4052| :- | :- | :- |4077| :- | :- | :- |
4053| 让响应通过 | 无输出,退出码为 0 | 用户的响应,未经更改 |4078| 让响应通过 | 无输出,退出码为 0 | 用户的响应,未更改 |
4054| 更改提交的值 | `"action": "accept"`,并在 `content` 中提供新值 | `accept` 以及您的 `content`,替代用户的值 |4079| 更改提交的值 | `"action": "accept"`,并在 `content` 中提供新值 | `accept` 以及您的 `content`,取代用户的值 |
4055| 阻止响应 | `"action": "decline"` | `decline`,不含用户的值 |4080| 阻止响应 | `"action": "decline"` | `decline`,不包含用户的值 |
4056| 取消请求 | `"action": "cancel"` | `cancel`,以及用户提交的值。要隐去这些值,请返回 `"decline"` |4081| 取消请求 | `"action": "cancel"` | `cancel`,以及用户提交的值。要隐去这些值,请返回 `"decline"` |
4057 4082
4058此输出更改了 [ElicitationResult 输入](#elicitationresult-input)中所示的响应,因此在用户提交 `alice` 的位置,服务器收到的是 `alice@example.com`:4083此输出更改了 [ElicitationResult 输入](#elicitationresult-input)中所示的响应,因此在用户提交 `alice` 的地方,服务器收到的是 `alice@example.com`:
4059 4084
4060```json theme={null}4085```json theme={null}
4061{4086{
4071 4096
4072您的 `content` 会替换用户的整个 `content` 对象,因此请包含您未更改的字段。请同时返回 `action`,因为 Claude Code 会忽略没有 `action` 的 `hookSpecificOutput`。4097您的 `content` 会替换用户的整个 `content` 对象,因此请包含您未更改的字段。请同时返回 `action`,因为 Claude Code 会忽略没有 `action` 的 `hookSpecificOutput`。
4073 4098
4074当用户拒绝或取消时,ElicitationResult hook 也会运行,并且您的 `action` 会替换用户的。在返回 `accept` 之前,请检查输入中的 `action` 是否为 `accept`,否则您的 hook 会将被拒绝的请求变成被接受的请求。此脚本在用户接受时进行相同的更改,保留其他字段,否则不输出任何内容:4099当用户拒绝或取消时,ElicitationResult hook 也会运行,并且您的 `action` 会替换用户的 `action`。在返回 `accept` 之前,请检查输入的 `action` 是否为 `accept`,否则您的 hook 会将被拒绝的请求变成被接受的请求。此脚本在用户接受时进行相同的更改,保留其他字段,其他情况下不打印任何内容:
4075 4100
4076```bash theme={null}4101```bash theme={null}
4077#!/bin/bash4102#!/bin/bash
4093}4118}
4094```4119```
4095 4120
4096退出码 2 和顶层 `"decision": "block"` 也会阻止响应。[拒绝 elicitation 的其他方式](#other-ways-to-decline-an-elicitation)介绍了当 hook 组合使用这些方式时哪一种生效、用户会看到什么,以及哪些版本会忽略 `decision`。4121退出码 2 和顶层的 `"decision": "block"` 也会阻止响应。[拒绝 elicitation 的其他方式](#other-ways-to-decline-an-elicitation)介绍了当 hook 组合使用这些方式时哪一种生效、用户会看到什么,以及哪些版本会忽略 `decision`。
4097 4122
4098无论您返回哪个 `action`,Claude Code 都会丢弃 ElicitationResult hook JSON 输出中的 `reason`、`systemMessage` 和 `continue`。4123无论您返回哪个 `action`,Claude Code 都会丢弃 ElicitationResult hook JSON 输出中的 `reason`、`systemMessage` 和 `continue`。
4099 4124
4350* **单独输出到 stdout**:当响应是 stdout 上唯一的文本时,它可以跨越多行,例如经过格式化美化的 `jq` 输出。跨越多行需要 Claude Code v2.1.295 或更高版本。4375* **单独输出到 stdout**:当响应是 stdout 上唯一的文本时,它可以跨越多行,例如经过格式化美化的 `jq` 输出。跨越多行需要 Claude Code v2.1.295 或更高版本。
4351* **单独输出在一行上**:当响应可以单独放在一行中时(例如使用 `jq -c`),异步 hook 可以向 stdout 输出其他文本。4376* **单独输出在一行上**:当响应可以单独放在一行中时(例如使用 `jq -c`),异步 hook 可以向 stdout 输出其他文本。
4352 4377
4353Claude Code 根据与同步 hooks 相同的[输出架构](#json-output)验证 JSON 响应,并删除任何值类型错误的字段,例如不是字符串的 `systemMessage`,而不是传递它。使用 `--debug` 运行以查看命名每个删除字段的警告。在 v2.1.202 之前,来自异步 hook 的格式错误的 JSON 输出可能会导致会话崩溃,并且每次恢复会话时崩溃都会重复发生。4378Claude Code 根据与同步 hook 相同的[输出 schema](#json-output) 验证 JSON 响应,并删除任何值类型错误的字段,例如不是字符串的 `systemMessage`,而不是传递它。使用 `--debug` 运行以查看命名每个删除字段的警告。
4354 4379
4355异步 hook 完成通知默认被抑制。要查看它们,请使用 `Ctrl+O` 启用详细模式或使用 `--verbose` 启动 Claude Code。4380异步 hook 完成通知默认被抑制。要查看它们,请使用 `Ctrl+O` 启用详细模式或使用 `--verbose` 启动 Claude Code。
4356 4381