Hooks触发时机与生命周期

掌握Hooks的触发与生命周期

一、支持的触发事件

Claude Code Hooks 支持多种触发事件(Trigger Events),用于在不同阶段拦截和扩展工具行为。以下是所有支持的触发事件类型:

触发事件 触发时机 说明
user-prompt-submit 用户提交提示时 用户输入消息并发送后触发,是 Hook 流程的起点
after:user-prompt-submit 用户提交提示后 用户提示提交后的处理阶段
before:tool/* 任何工具调用前 通配符模式,匹配所有工具调用之前的事件
after:tool/* 任何工具调用后 通配符模式,匹配所有工具调用之后的事件
before:tool/Read 特定 Read 工具前 精确匹配 Read 工具调用之前
after:tool/Edit 特定 Edit 工具后 精确匹配 Edit 工具调用之后
before:tool/git_* 所有 git 相关工具前 glob 模式匹配所有以 git_ 开头的工具
要点: 触发事件可以精确到单个工具,也可以使用 glob 通配符匹配一组工具。合理组合可以实现精细化的 Hook 控制。

二、事件匹配机制

Claude Code 使用以下规则来匹配 Hook 的触发事件:

1. 精确匹配

写完整的事件名称,如 before:tool/Read,仅在该事件发生时触发。精确匹配具有最高优先级,不会被通配符覆盖。

2. 通配符匹配

使用 * 通配符匹配一组事件,如 before:tool/git_* 匹配所有以 git_ 开头的工具调用前事件,before:tool/* 匹配所有工具。

3. 优先级规则

当同一个事件匹配多个 Hook 时,精确匹配优先于通配符匹配。例如,同时定义了 before:tool/Readbefore:tool/*,前者会优先执行。

4. 多个匹配的执行顺序

如果多个 Hook 匹配同一个事件,它们按照在配置文件中的定义顺序依次执行。精确匹配的 Hook 先执行,然后按照配置顺序执行通配符匹配的 Hook。这种设计确保了可预测的行为。

匹配优先级:精确匹配 > glob 模式匹配 > 通配符 * 同级别匹配按照配置定义顺序执行

三、Hook 的加载和执行顺序

理解 Hook 的完整生命周期对于正确使用 Hook 至关重要:

1. 加载时机

Claude Code 在启动时加载所有配置的 Hook。加载过程包括读取 settings.jsonsettings.local.json 中的 Hook 配置,验证 Hook 脚本路径、可执行权限以及超时设置。配置格式如下:

{ "hooks": { "before:tool/Read": { "run": "node scripts/validate-path.js", "timeout": 5000 }, "before:tool/*": { "run": "node scripts/log-tool.js", "timeout": 3000 }, "after:tool/Edit": { "run": "node scripts/format-output.js", "timeout": 5000 } } }

2. 串行执行顺序

当一个事件触发时,所有匹配的 Hook 按照配置顺序串行执行。每个 Hook 完成后才会执行下一个,确保可预测的行为。不会出现并发执行的情况。

串行执行
多个匹配 Hook 按定义顺序依次执行,前一个完成后才执行下一个
无并发
同一事件不会并行触发多个 Hook,避免竞态条件
阻断传播
单个 Hook 失败可阻断后续执行,保障操作安全

3. before 事件 → 工具执行 → after 事件 流程

典型的执行流程为:

4. before 阻断后 after 是否执行

如果 before Hook 执行失败(返回非零退出码),则工具本身不会执行,after Hook 同样不会执行。这确保了操作的原子性和安全性——before 验证失败意味着操作条件不满足,整个操作序列被安全中止。

注意: 如果 before Hook 失败,整个工具调用会被阻断。设计 Hook 时需要考虑这种级联影响,避免在 before 中执行不可逆的操作。

四、Hook 超时机制

为避免 Hook 长时间阻塞工具调用流程,Claude Code 提供了超时机制:

1. 默认超时时间

每个 Hook 默认有 10 秒的超时时间(10000ms)。如果 Hook 脚本在 10 秒内未完成执行,超时机制会介入。可以通过配置中的 timeout 字段自定义:

{ "hooks": { "before:tool/Bash": { "run": "node scripts/slow-validation.js", "timeout": 30000 // 自定义 30 秒超时 } } }

2. 超时后的默认行为

超时后,默认行为取决于 Hook 的配置。可以通过 onTimeout 字段配置:

{ "hooks": { "after:tool/*": { "run": "node scripts/log.js", "timeout": 5000, "onTimeout": "continue" // 日志超时不阻断流程 } } }

3. 长时间运行 Hook 的处理策略

对于可能长时间运行的 Hook,建议:

五、生命周期流程图

以下是 Hook 完整生命周期的 ASCII 流程图,展示了从用户输入到结果返回的完整过程:

┌─────────────────────────────────────┐ │ 用户提交提示 │ │ user-prompt-submit 触发 │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 事件匹配阶段 │ │ 精确匹配 → glob 匹配 → 通配符 │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ before Hook 串行执行 │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │Hook #1 │→│Hook #2 │→ ... │ │ │精确匹配 │ │通配符 │ │ │ └────┬────┘ └────┬────┘ │ │ │ │ │ │ ┌───▼───┐ ┌───▼───┐ │ │ │通过/ │ │通过/ │ │ │ │阻断? │ │阻断? │ │ │ └───┬───┘ └───┬───┘ │ │ │(通过) │(通过) │ └───────┼────────────┼─────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────┐ │ 工具执行 │ │ Read / Edit / Bash / Glob ... │ │ (超时控制: 默认 10s) │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ after Hook 串行执行 │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │Hook #1 │→│Hook #2 │→ ... │ │ │结果处理 │ │日志记录 │ │ │ └─────────┘ └─────────┘ │ └──────────────┬──────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ 结果返回给用户 │ │ after:user-prompt-submit 触发 │ └─────────────────────────────────────┘

生命周期关键阶段总结:

1. 加载阶段 — Claude Code 启动时加载 Hook 配置到内存

2. 触发阶段 — 用户提交提示或工具调用事件发生

3. 匹配阶段 — 根据事件名称按优先级匹配对应 Hook(精确 > glob > 通配符)

4. before 阶段 — 匹配的 before Hook 按配置顺序串行执行

5. 工具执行 — 所有 before Hook 通过后执行实际工具操作(含超时控制)

6. after 阶段 — 工具执行完成后串行执行匹配的 after Hook

7. 结果返回 — 处理完成的结果返回给用户

核心原则: before 用于前置校验和准备,after 用于后置处理和日志记录。合理规划 Hook 的超时和失败处理策略,可以构建既安全又高效的自动化工作流。