首页/Hook 系统

Hook 系统

生命周期钩子与事件驱动扩展

Hook 系统提供事件驱动的扩展机制,允许用户在 Claude Code 的关键生命周期点注入自定义逻辑。通过 settings.json 配置 shell 命令,在特定事件触发时执行。

核心要点

11 种生命周期事件:SessionStart, PreToolUse, PostToolUse 等
通过 settings.json 配置,由 harness 执行
支持同步和异步响应
可修改工具输入/输出、设置权限
超时保护机制

设计亮点

异步钩子像便利贴任务板

你可以把便利贴贴到任务板上就走,不用站在那里等任务完成——回头再来看结果

标记 async: true 的钩子不会阻塞 Claude 的主循环。它被放入一个异步任务注册表(像便利贴板),主循环继续工作。系统定期检查任务板上的便利贴是否完成,完成了就收集结果。这让耗时操作(如发通知、写审计日志)不拖慢 AI 的响应速度。

Promise.allSettled 防连坐

就像公司里一个部门出问题不应该让整个公司停工——其他部门继续正常运转

多个 Hook 用 Promise.allSettled(而非 Promise.all)并行执行。Promise.all 是'一个失败全部失败',而 allSettled 是'各管各的'。一个审计 Hook 崩溃了,不影响安全检查 Hook 和通知 Hook 正常完成。这种隔离设计在企业环境中尤为重要。

// Promise.all vs Promise.allSettled
// Promise.all: 一个reject,全部失败 ❌
// Promise.allSettled: 每个独立完成 ✅
const results = await Promise.allSettled(
  hooks.map(hook => executeHook(hook, context))
)
// results: [
//   { status: 'fulfilled', value: ... },
//   { status: 'rejected', reason: ... },  // 这个失败了
//   { status: 'fulfilled', value: ... },  // 但不影响这个
// ]

PreToolUse 钩子能篡改输入

就像机场安检员不只检查行李,还能没收危险物品再让你登机——修改后继续流程

PreToolUse Hook 不只是一个'观察者',它可以直接修改工具的输入参数。比如 Bash 工具要执行 rm -rf /,Hook 可以拦截它,把命令改成安全的版本,或者直接返回 deny 阻止执行。这让企业可以实现精细的安全策略,而无需修改 Claude Code 源码。

模块架构图

加载架构图...
核心文件
types/hooks.ts500 LOC

Hook 类型定义和 Zod Schema

utils/hooks/hooksConfigManager.ts400 LOC

Hook 配置管理

utils/hooks/hookEvents.ts300 LOC

Hook 事件追踪

utils/hooks/hookHelpers.ts200 LOC

Hook 工具函数

数据流程
1
事件触发
如工具即将执行
2
查找 Hook
在 settings.json 中查找匹配的 Hook
3
执行 Hook
运行 shell 命令
4
处理响应
修改输入/输出/权限
5
继续执行
Hook 处理完毕,继续主流程

关键代码

加载代码...
加载代码...

深入解析

Hook 是 Claude Code 的主要扩展机制,替代了传统插件系统。它比插件更轻量——只需在 settings.json 中配置 shell 命令,无需写完整的插件代码。

PreToolUse Hook 可以修改工具输入或直接设置权限(allow/deny),实现自定义安全策略。比如企业可以配置 Hook 禁止所有对 /etc 目录的写操作。

PostToolUse Hook 可以审计工具执行结果,实现合规日志记录。每次 AI 执行文件写入后,Hook 可以自动记录到审计日志。

所有 Hook 都有超时保护,防止挂起阻塞主流程。默认超时是合理的短值,确保一个失败的 Hook 不会让整个 Claude 卡住。

标记 async: true 的钩子不会阻塞主循环——它被放入异步任务注册表,主循环继续运行,定期检查任务完成状态。

多个钩子使用 Promise.allSettled 并行执行,而不是 Promise.all。区别在于:allSettled 即使某个钩子失败也不会中断其他钩子——一个坏了的钩子不会连坐拖垮整个系统。

Hook 的输入通过 stdin 以 JSON 格式传递——包含事件类型、工具名称、工具输入等完整上下文。Hook 的 stdout 输出也是 JSON,可以返回修改后的参数或权限决策。

11 种事件类型覆盖了完整生命周期:从 SessionStart(会话开始)到 FileChanged(文件变更),每个关键节点都可以被 Hook 拦截。