Claude Code 学习站

Claude Agent SDK Hooks 拦截与控制行为参考

整理 Claude Agent SDK 的 hooks 机制:可用事件表、matcher 语法、回调输入输出字段、超时默认值与常见问题排查,面向 TypeScript/Python 开发者。

本页目录12
AI 摘要 · 已核查整理于 2026-07-27原文:Intercept and control agent behavior with hooks(Anthropic)Agent SDKHooksClaude CodeTypeScript/Python
要点速览
  • Hooks 通过 options.hooks(TypeScript)或 ClaudeAgentOptions(hooks=...)(Python)注册,结构是事件名 → 匹配器数组,每个匹配器包含 matcher/hooks/timeout。
  • 官方列出的 hook 事件已扩展到 30 余种,但只有约一半(PreToolUse、PostToolUse、PostToolUseFailure、UserPromptSubmit、Stop、SubagentStart/Stop、PreCompact、PermissionRequest、Notification)在 Python SDK 中可用,其余仅 TypeScript SDK 支持。
  • 回调返回值分两类:所有事件通用的顶层字段(systemMessage、continue/continue_),以及依事件而异的 hookSpecificOutput(如 PreToolUse 的 permissionDecision/updatedInput,PostToolUse 的 updatedToolOutput)。
  • 默认超时 600 秒,UserPromptSubmit 为 30 秒,MessageDisplay 为 10 秒,SessionEnd 在关机阶段仅有 1.5 秒预算;返回 async:true 可让副作用型 hook 不阻塞 agent 继续执行。
  • SessionStart/SessionEnd 等 TypeScript-only 事件在 Python 中需改用 settings 文件里的 shell command hook 或以首条消息作为初始化触发点来变通。

本文是对 Claude Agent SDK 官方文档「Hooks」页的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/hooks

说明:该页面篇幅较大,本整理以官方页面中可核实的字段名、类型、默认值与结构说明为主;文中「结构示意」代码块仅用占位名标注确认过的字段/键名,并非逐字复制的原文示例,如需可直接复制运行的完整示例代码,请查阅原文对应小节。

概述

Hooks 是在 agent 执行的关键节点运行你自己代码的回调函数,响应诸如工具调用、会话启动、执行停止等事件。典型用途包括:

  • 在危险操作执行前拦截(如破坏性 shell 命令、未授权文件访问)
  • 记录/审计每次工具调用,用于合规、调试或分析
  • 转换输入输出:清洗数据、注入凭据、重定向文件路径
  • 为敏感操作(数据库写入、API 调用)要求人工审批
  • 跟踪会话生命周期:管理状态、清理资源、发送通知

Hook 触发流程

  1. 事件触发(An event fires):agent 执行过程中发生某事,SDK 触发对应事件,例如工具即将被调用(PreToolUse)、工具返回结果(PostToolUse)、子代理启动或停止、agent 空闲,或执行结束。
  2. SDK 收集已注册的 hooks:SDK 检查该事件类型下已注册的 hooks,包括你在 options.hooks 中传入的回调 hook,以及在启用对应 settingSources(TypeScript)/setting_sources(Python)时,来自 settings 文件的 shell command hook(默认 query() 选项下该项是启用的)。
  3. matcher 过滤哪些 hooks 会运行:如果某个 hook 设置了 matcher 模式(例如 Write|Edit),SDK 会用它匹配事件的目标(例如工具名)。没有设置 matcher 的 hook 会对该事件类型的每次发生都运行。

可用的 Hook 事件

SDK 为 agent 执行的不同阶段提供 hooks。部分 hook 在两种 SDK 中都可用,部分仅限 TypeScript。

Hook 事件Python SDKTypeScript SDK触发条件典型用途
PreToolUse工具调用请求(可阻止或修改)阻止危险的 shell 命令
PostToolUse工具执行结果将所有文件变更记录到审计日志
PostToolUseFailure工具执行失败处理或记录工具错误
PostToolBatch一整批工具调用全部完成后触发,每批一次,发生在下一次模型调用之前为整批调用统一注入一次约定/规范
UserPromptSubmit用户提交提示词向提示词注入额外上下文
UserPromptExpansion用户输入的命令或 MCP 提示在到达 Claude 前展开为提示词;Claude 自己调用 skill 时不会触发阻止某命令被直接调用,或在输入 skill 时添加上下文
MessageDisplay一条助手消息的文本完成时触发,每条消息一次,带完整消息文本在不改变 transcript 的前提下屏蔽或重排显示文本
Stopagent 执行停止退出前保存会话状态
StopFailure本轮以 API 错误而非正常方式结束记录失败或发送告警
SubagentStart子代理初始化跟踪并行任务的派生
SubagentStop子代理完成汇总并行任务结果
PreCompact会话压缩请求摘要前先归档完整 transcript
PostCompact会话压缩完成记录生成的摘要
PermissionRequest某次工具调用需要权限决策自定义权限处理逻辑
PermissionDenied自动模式拒绝了某次工具调用,包括没有分类器裁决的拒绝记录拒绝情况,或告知模型可重试;对无裁决的拒绝,Claude Code 会忽略 retry: true
SessionStart会话初始化初始化日志与遥测
SessionEnd会话终止清理临时资源
Notificationagent 状态消息将 agent 状态更新发送到 Slack 或 PagerDuty
Setup会话设置/维护运行初始化任务
TeammateIdle队友(teammate)变为空闲重新分配工作或发通知
TaskCreated通过 TaskCreate 工具创建了任务强制任务命名规范
TaskCompleted任务被标记为完成要求测试通过后才能关闭任务
ElicitationMCP 服务器在任务中途请求用户输入以程序方式响应 MCP 输入请求
ElicitationResult用户对 MCP elicitation 做出响应在响应返回服务器前修改或阻止它
ConfigChange配置文件发生变化动态重新加载设置
InstructionsLoadedCLAUDE.md 或规则文件被加载进上下文审计加载了哪些指令文件
WorktreeCreate创建了 Git worktree跟踪隔离的工作区
WorktreeRemove移除了 Git worktree清理工作区资源
CwdChanged会话期间工作目录发生变化按目录重新加载环境变量
FileChanged被监视的文件被修改、创建或删除项目文件变化时重新加载配置
DirectoryAdded会话期间添加了新的工作目录为中途添加的仓库安装依赖

配置 Hook

把 hook 传入 agent 选项的 hooks 字段(Python 中是 ClaudeAgentOptions,TypeScript 中是 options 对象)即可完成配置。hooks 在 Python 中是一个 dict,在 TypeScript 中是一个 object,其中:

  • 键(Keys):hook 事件名称,例如 'PreToolUse''PostToolUse''Stop'
  • 值(Values):matcher 数组,每个 matcher 包含一个可选的过滤模式以及你的回调函数

Matcher(匹配器)

用 matcher 过滤回调何时触发。matcher 字段匹配的目标随 hook 事件类型而不同——例如基于工具的 hook 匹配工具名,而 Notification hook 匹配通知类型。SDK 中的 matcher 遵循与 settings 文件中 matcher 相同的规则(即精确字符串匹配与正则匹配两条路径,以及各事件类型对应的匹配值)。

选项类型默认值说明
matcherstringundefined匹配事件的过滤字段,规则与 settings 文件中的 matcher 一致。对工具类 hook,匹配的是工具名;内置工具包括 BashReadWriteEditGlobGrepWebFetchAgent 等。MCP 工具使用 mcp__<server>__<action> 模式
hooksHookCallback[]无(必填)模式匹配时要执行的回调函数数组
timeoutnumberundefined超时时间(秒)。不设置时使用该事件的默认超时;SDK 回调遵循 command 类型 hook 的默认值

应尽量使用 matcher 精确指定要作用的工具:设为 'Bash' 只会对 Bash 命令生效,省略该模式则会对该事件类型的每一次发生都运行回调。

回调函数

输入(Inputs)

每个 hook 回调都会收到三个参数:

  1. 输入数据:一个带类型的对象,包含事件详情。不同 hook 类型的输入形状不同,例如 PreToolUseHookInput 包含 tool_nametool_input,而 NotificationHookInput 包含 message
    • 所有 hook 输入都共享 session_idcwdhook_event_name
    • agent_idagent_type 在 hook 于子代理内触发时才会被填充。TypeScript 中这两个字段位于基础 hook input 类型上,对所有 hook 类型都可用;Python 中它们是 PreToolUsePostToolUsePostToolUseFailurePermissionRequest 的可选字段,是 SubagentStartSubagentStop 的必填字段。
  2. Tool use IDstr | None / string | undefined):用于关联同一次工具调用对应的 PreToolUsePostToolUse 事件。
  3. Context:TypeScript 中包含一个 signal 属性(AbortSignal)用于取消;Python 中该参数目前保留,供未来使用。

输出(Outputs)

回调返回的对象包含两类字段:

  • 顶层字段,对所有事件通用:systemMessage 向用户展示一条消息;continue(Python 中为 continue_)决定该 hook 运行后 agent 是否继续执行。部分事件会忽略这些字段,或将其投递到别处。
  • hookSpecificOutput:控制当前操作,内部字段随 hook 事件类型而不同。
    • PreToolUse:可设置 permissionDecision(取值 allowdenyaskdefer)、permissionDecisionReasonupdatedInput。返回 defer 会结束当前 query,以便你之后再恢复它。
    • PostToolUse:可设置 additionalContext 向工具结果追加信息;设置 updatedToolOutput 可在 Claude 看到结果前替换任意工具(两种 SDK 均支持)的输出;较旧的 updatedMCPToolOutput 字段仅替换 MCP 工具输出,已废弃。

返回 {} 表示放行且不做任何修改。SDK 回调 hook 使用与 Claude Code shell command hook 相同的 JSON 输出格式。

异步输出(Asynchronous output)

默认情况下,agent 会等待你的 hook 返回结果后才继续。如果 hook 只是执行副作用(如记录日志、发送 webhook),不需要影响 agent 行为,可以返回异步输出,让 agent 立即继续而无需等待 hook 完成:

字段类型说明
asynctrue表示异步模式,agent 不等待即继续执行。Python 中用 async_ 以避开保留字
asyncTimeoutnumber后台操作的超时时间(毫秒),可选

Hook 超时

Claude Code 为每个回调设置超时,可通过 HookMatcher 上的 timeout 字段以秒为单位设置。不设置时使用该事件的默认值:

  • 大多数事件:600 秒
  • UserPromptSubmit:30 秒
  • MessageDisplay:10 秒
  • SessionEnd:在关机阶段运行,使用更短的超时预算,默认 1.5 秒

TypeScript 中可通过 context 里的 AbortSignal 处理取消逻辑。

示例场景一览

官方文档在「Examples」一节给出以下场景(均为对 PreToolUse/PostToolUse/Notification 等 hook 的具体用法,建议直接查阅原文获取可运行代码):

示例说明
Modify tool input拦截 Write 工具调用,重写 file_path 参数(如加上沙箱前缀),通过 updatedInputpermissionDecision: allow 重定向文件写入位置
Add context and block a toolpermissionDecision: denypermissionDecisionReasonsystemMessage 阻止特定操作(如写入系统目录),并向模型/用户说明原因
Auto-approve specific tools对只读工具(读取、搜索、查找等)返回 permissionDecision: allow,免去用户确认
Register multiple hooks在同一事件上注册多个独立检查回调,其中任意一个返回 deny 都会阻止整个工具调用
Filter with multi-tool matchers用管道分隔的精确工具列表、正则表达式,或省略 matcher,为一组相关工具共享同一回调
Track subagent activitySubagentStop hook 监控子代理完成情况,记录每次完成的摘要信息
Make HTTP requests from hooks在 hook 中执行异步操作(如 HTTP 请求),需要在 hook 内部捕获错误,避免失败请求中断 agent
Forward notifications to SlackNotification hook 接收系统通知,通过 Slack webhook 转发 agent 状态消息到指定频道

常见问题排查

问题排查/解决思路
Hook not firing(hook 不触发)检查事件名大小写、matcher 是否精确匹配工具名、hook 是否配置在正确位置;确认会话未因 max_turns 限制而提前结束
Matcher not filtering as expected(matcher 过滤不符合预期)matcher 只按工具名过滤,不匹配文件路径等参数;需在 hook 内部检查 tool_input.file_path 等具体字段做进一步过滤
Hook timeout(hook 超时)可用 timeout 字段以秒为单位调高;不同事件类型超时后的处理策略不同,参见「Hook 超时」一节
Tool blocked unexpectedly(工具被意外阻止)检查所有 PreToolUse hook 的返回值是否含 deny;记录 permissionDecisionReason 排查;检查 matcher 是否过宽
Modified input not applied(修改后的输入未生效)确认 updatedInput 放在 hookSpecificOutput 内部;不要与 permissionDecision: defer 同时使用;输出中应带上 hookEventName 标明 hook 类型
Session hooks not available in Python(Python 中没有 session hooks)SessionStart/SessionEnd 仅 TypeScript 可用;Python 需通过 settings 文件把它们定义为 shell command hook,或用第一条消息充当初始化触发点
Subagent permission prompts multiplying(子代理权限提示反复出现)PreToolUse hook 自动批准特定工具,或配置权限规则让子代理继承父级权限设置
Recursive hook loops with subagents(子代理引发递归 hook 循环)在 hook 内检查子代理标识、用共享变量跟踪执行上下文,或只为顶层 agent 会话启用该 hook
systemMessage not appearing in output(systemMessage 未出现在输出中)该字段是给用户看的,不会传给模型;v2.1.227 及以后可能在消息流中以 SDKInformationalMessage 形式出现(是否出现取决于具体事件,见原文各事件小节);若要传上下文给模型,应使用 additionalContext