Skip to main content

27 种 Hook 事件

Claude Code 定义了 27 种 Hook 事件(HOOK_EVENTS 数组,src/entrypoints/sdk/coreTypes.ts),覆盖完整的 Agent 生命周期:

6 种 Hook 类型

Hooks 配置支持 6 种执行方式,类型定义分布在 3 个文件中:
  • 可持久化类型commandpromptagenthttp)— Zod schema 定义在 src/schemas/hooks.ts,通过 z.discriminatedUnion('type', [...]) 声明
  • callback 类型 — TypeScript 接口定义在 src/types/hooks.ts,用于 SDK 注册的内部 JS 函数
  • function 类型 — 定义在 src/utils/hooks/sessionHooks.ts,用于运行时动态注册的函数 Hook

执行引擎:execCommandHook

execCommandHook()src/utils/hooks.tsexecCommandHook 函数)是命令型 Hook 的执行核心:

异步 Hook 的检测协议

Hook 进程的 stdout 第一行如果是 {"async":true},系统将其转为后台任务(isAsyncHookJSONOutput 检测 + executeInBackground 调用):
后台 Hook 通过 registerPendingAsyncHook() 注册到 AsyncHookRegistry,完成后通过 enqueuePendingNotification() 通知主线程。

asyncRewake:Hook 唤醒模型

asyncRewake 模式的 Hook 绕过 AsyncHookRegistry。当 Hook 退出码为 2 时,通过 enqueuePendingNotification()task-notification 模式注入消息,唤醒空闲的模型(通过 useQueueProcessor)或在忙碌时注入 queued_command 附件。

Hook 输出的 JSON Schema

同步 Hook 的输出遵循严格的 Zod schema(syncHookResponseSchema,定义在 src/types/hooks.tshookJSONOutputSchema 定义在 src/schemas/hooks.ts):

各事件的 hookSpecificOutput

Hook 匹配机制:getMatchingHooks

getMatchingHooks()src/utils/hooks.tsgetMatchingHooks 函数)负责从所有来源中查找匹配的 Hook:

多来源合并

匹配规则

matcher 字段支持三种模式(matchesPattern() 函数,src/utils/hooks.ts):

if 条件过滤

Hook 可以指定 if 条件,只在特定输入时触发。prepareIfConditionMatcher()src/utils/hooks.tsprepareIfConditionMatcher 函数)预编译匹配器:
if 条件使用 permissionRuleValueFromString 解析,支持与权限规则相同的语法(工具名 + 参数模式)。Bash 工具还会使用 tree-sitter 进行 AST 级别的命令解析。

Hook 去重

同一个 Hook 命令在不同配置层级(user/project/local)可能重复。系统按四部分复合键做 Map 去重:${pluginRoot}\0${shell}\0${command}\0${ifCondition}(由 hookDedupKey() 函数构建),保留最后合并的层级

工作区信任检查

所有 Hook 都要求工作区信任shouldSkipHookDueToTrust() 函数,src/utils/hooks.ts)。这是纵深防御措施——防止恶意仓库的 .claude/settings.json 在未信任的情况下执行任意命令。
SDK 非交互模式下信任是隐式的(getIsNonInteractiveSession() 为 true 时跳过检查)。

四种 Hook 能力的源码映射

1. 拦截操作(PreToolUse)

processHookJSONOutput()permissionDecision 映射为 result.permissionBehavior = 'deny',并设置 blockingError,阻止工具执行。

2. 修改行为(updatedInput / updatedMCPToolOutput)

updatedInput 替换原始工具输入;updatedMCPToolOutput(PostToolUse 事件)替换 MCP 工具的返回值——可用于过滤敏感数据。

3. 注入上下文(additionalContext / systemMessage)

  • additionalContext → 通过 createAttachmentMessage({ type: 'hook_additional_context' }) 注入为用户消息
  • systemMessage → 注入为系统警告,直接显示给用户

4. 控制流程(continue / stopReason)

continue: false 设置 preventContinuation = true,阻止 Agent 继续执行后续操作。

Session Hook 的生命周期

Agent 和 Skill 的前置 Hook 通过 registerFrontmatterHooks() 注册(调用位置:packages/builtin-tools/src/tools/AgentTool/runAgent.ts;定义位置:src/utils/hooks/registerFrontmatterHooks.ts),绑定到 agent 的 session ID。Agent 结束时通过 clearSessionHooks()(定义位置:src/utils/hooks/sessionHooks.ts)清理。
这确保 Agent A 的 Hook 不会泄漏到 Agent B 的执行中。