Claude Code Hooks 钩子系统与自动化工作流

Claude Code 学习笔记

分类:高级应用

核心主题:Hooks 的触发机制、事件类型与自动化配置

主要内容:深入解析 Claude Code Hooks 钩子系统的架构设计、全部七种事件类型的触发时机与配置方法,涵盖从基础配置到实战场景的全方位指南,帮助开发者利用 hooks 构建自动化工作流。

关键词:Hooks, 钩子, 自动化, 事件触发, settings.json, 工作流

一、概述

Hooks(钩子系统)是 Claude Code 提供的一套事件驱动自动化机制,它允许开发者在 Claude Code 执行特定操作的前后时机自动运行自定义 shell 命令。这套机制将 Claude Code 从单纯的 AI 编程助手升级为可编程的工作流引擎,在代码生成、安全检查、文件操作审计等方面开辟了广阔的应用空间。

理解 hooks 与 Claude 自身能力的区别至关重要。Hooks 并非由 Claude 模型直接控制或执行,而是由 Claude Code 的 harness(运行时框架)在检测到特定事件发生时负责调度执行。这意味着 hooks 的执行不依赖模型推理,具有确定性和可靠性。Claude 模型本身并不知道 hooks 的存在——它只专注于理解用户的指令并生成响应,而 harness 则在幕后默默监控操作流,在恰当的时机触发配置好的 hook 命令。

这种架构设计带来了显著的优势:hooks 可以用于实现那些 Claude 模型本身无法直接完成的任务,例如在写入文件前自动运行代码格式化工具、在执行命令前扫描是否存在危险指令、或在长时间运行的任务完成后发送系统通知。Hooks 充当了 Claude Code 与外部工具之间的桥梁,使得自动化工作流成为可能。

核心理解:Hooks 是由 Claude Code harness 在事件触发时执行的自动化机制,而非由 Claude 模型直接控制。这种设计确保了 hook 操作的确定性、可靠性和可预测性,使其成为构建自动化工作流的基础设施。

二、Hook 事件类型

Claude Code 的钩子系统目前支持七种不同的事件类型,覆盖了从命令执行到文件读写的完整操作生命周期。每种事件都有其特定的触发时机和典型应用场景,开发者可以根据实际需求组合使用这些事件来构建复杂的自动化流程。

以下表格汇总了所有支持的 hook 事件及其核心特征:

事件名称 触发时机 典型用途 可用的环境变量
BeforeCommand 任何 shell 命令执行之前 命令安全检查、操作审计日志、环境准备 CLAUDE_HOOK_EVENT, CLAUDE_HOOK_COMMAND
AfterCommand 任何 shell 命令执行完成之后 命令结果记录、通知提醒、清理操作 CLAUDE_HOOK_EVENT, CLAUDE_HOOK_COMMAND, CLAUDE_HOOK_EXIT_CODE
BeforeRead Claude Code 读取文件之前 文件访问审计、权限检查、内容预检 CLAUDE_HOOK_EVENT, CLAUDE_HOOK_FILE_PATH
AfterRead Claude Code 读取文件完成之后 读取日志记录、内容统计、缓存更新 CLAUDE_HOOK_EVENT, CLAUDE_HOOK_FILE_PATH
BeforeWrite Claude Code 写入或修改文件之前 自动备份、代码规范检查、文件锁定检测 CLAUDE_HOOK_EVENT, CLAUDE_HOOK_FILE_PATH
AfterWrite Claude Code 写入或修改文件完成之后 文件变更通知、自动编译、静态分析触发 CLAUDE_HOOK_EVENT, CLAUDE_HOOK_FILE_PATH
UserPromptSubmit 用户提交新的提示(prompt)时 提示预处理、上下文注入、会话统计 CLAUDE_HOOK_EVENT

BeforeCommand 事件详解

BeforeCommand 是最常用的 hook 事件之一。每当 Claude Code 准备执行一条 shell 命令时,该事件就会被触发。此时,被执行的命令全文会通过 CLAUDE_HOOK_COMMAND 环境变量传递给 hook 脚本。典型的应用场景包括:扫描命令中是否包含危险操作(如 rm -rf)、检查命令是否在允许列表中、记录命令执行历史等。需要注意的是,如果 BeforeCommand hook 执行失败(返回非零退出码),该命令将被阻止执行。

BeforeWrite / AfterWrite 文件写事件详解

文件写入事件在 Claude Code 修改或创建文件的时机触发。BeforeWrite 在文件实际写入前触发,此时可以通过 CLAUDE_HOOK_FILE_PATH 环境变量获取目标文件路径。这个时机非常适合执行文件备份操作——在当前文件被覆盖前将其复制到备份目录。AfterWrite 则在文件写入完成后触发,可用于触发后续的自动化流程,例如自动运行 ESLint 检查新生成的文件、触发文件监视器重新加载等。

UserPromptSubmit 事件详解

UserPromptSubmit 是最特殊的一个 hook 事件,它在用户提交新的提示信息时触发。这个 hook 为开发者提供了干预用户输入的机会,例如可以在提交前对提示进行预处理、注入额外的上下文信息、或者统计用户提问的类型分布。值得注意的是,该事件的触发时机在 Claude 模型处理提示之前,因此可以用于实现提示增强功能。

事件类型总结:七种事件类型覆盖了命令执行(BeforeCommand/AfterCommand)、文件读取(BeforeRead/AfterRead)、文件写入(BeforeWrite/AfterWrite)和用户交互(UserPromptSubmit)四大类操作场景。合理组合使用这些事件可以构建强大的自动化工作流。

三、Hook 配置方法

Hooks 的配置通过 Claude Code 的 settings.json 文件完成。settings.json 支持用户级和项目级两种配置层次,hooks 配置位于 settings.json 的顶级 hooks 字段下。每个 hook 定义包含三个核心组成部分:matchers(事件匹配器)、command(要执行的命令)和 timeout(超时时间)。

3.1 hook 基本结构

每个 hook 配置项是一个对象,包含以下关键字段:matchers 是一个对象数组,每个匹配器通过 type 字段指定要监听的事件类型(如 BeforeCommand),并可通过可选的 glob 字段进行更精细的文件路径匹配;command 字段指定事件触发时要执行的 shell 命令;timeout 字段以毫秒为单位设置命令执行的超时时间,默认为 5000 毫秒。

3.2 项目级 vs 用户级配置

Claude Code 的配置系统支持两个层次:项目级配置位于项目根目录下的 .claude/settings.json 文件,仅对当前项目生效,适合团队共享的标准化 hook 配置;用户级配置位于用户主目录下的 ~/.claude/settings.json 文件,对全局所有项目生效,适合个人偏好的通用 hook。当两个层次的配置文件同时存在时,用户级配置会合并到项目级配置之上,同名配置项以用户级为准。hooks 配置同样是合并而非覆盖。

配置层次要点:项目级 (.claude/settings.json) 和用户级 (~/.claude/settings.json) 的 hooks 配置采用合并策略。这意味着你可以在项目级设置基础的代码规范检查 hook,同时在用户级添加个人偏好的日志记录 hook,两者互不冲突。

3.3 完整配置示例

以下是一个综合的 hook 配置示例,展示了如何针对不同事件类型配置多个 hook:

// .claude/settings.json - 项目级 Hook 配置示例
{
  "hooks": {
    "pre-command": [
      {
        "matchers": [{ "type": "BeforeCommand" }],
        "command": "node scripts/check-dangerous-commands.js",
        "timeout": 3000
      }
    ],
    "post-command": [
      {
        "matchers": [{ "type": "AfterCommand" }],
        "command": "echo 'Exit code:' $CLAUDE_HOOK_EXIT_CODE >> .claude/hooks.log",
        "timeout": 2000
      }
    ],
    "pre-read": [
      {
        "matchers": [{ "type": "BeforeRead", "glob": "**/*.env" }],
        "command": "echo '[AUDIT] Reading file:' $CLAUDE_HOOK_FILE_PATH >> .claude/audit.log",
        "timeout": 1000
      }
    ],
    "pre-write": [
      {
        "matchers": [{ "type": "BeforeWrite", "glob": "src/**/*.ts" }],
        "command": "npx prettier --check {file}",
        "timeout": 10000
      }
    ],
    "post-write": [
      {
        "matchers": [{ "type": "AfterWrite", "glob": "**/*" }],
        "command": "git add -A && git commit -m 'auto-save' --no-verify || true",
        "timeout": 15000
      }
    ]
  }
}

配置小贴士

glob 字段支持标准的 glob 模式匹配,可以精确控制 hook 触发的文件范围。例如 src/**/*.ts 仅匹配 src 目录下的 TypeScript 文件。如果不指定 glob 字段,hook 将对所有匹配事件类型的操作生效。合理使用 glob 可以有效减少不必要的 hook 执行,提升系统性能。

四、Hook 命令编写

Hook 命令本质上是 shell 命令,因此几乎任何可以在终端中执行的操作都可以作为 hook 命令。然而,编写高质量的 hook 命令需要遵循一些重要的规范和最佳实践,以确保钩子系统的稳定运行和良好的用户体验。

4.1 环境变量使用

当 hook 被触发时,Claude Code harness 会设置多个环境变量,为 hook 命令提供上下文信息。这些环境变量包括:CLAUDE_HOOK_EVENT(当前触发的事件类型,如 BeforeCommand)、CLAUDE_HOOK_COMMAND(即将执行或已执行的命令全文,仅在命令相关事件中可用)、CLAUDE_HOOK_FILE_PATH(被读取或写入的文件路径,仅在文件相关事件中可用)、CLAUDE_HOOK_EXIT_CODE(已执行命令的退出码,仅在 AfterCommand 事件中可用)。hook 命令可以通过 $VARIABLE_NAME 语法直接引用这些环境变量。

#!/bin/bash
# 一个利用环境变量的 hook 脚本示例

echo "[$(date)] Event: $CLAUDE_HOOK_EVENT" >> .claude/hooks.log

if [ "$CLAUDE_HOOK_EVENT" = "BeforeCommand" ]; then
  echo " Command: $CLAUDE_HOOK_COMMAND" >> .claude/hooks.log
fi

if [ "$CLAUDE_HOOK_EVENT" = "BeforeWrite" ]; then
  echo " File: $CLAUDE_HOOK_FILE_PATH" >> .claude/hooks.log
  cp "$CLAUDE_HOOK_FILE_PATH" ".claude/backups/" 2>/dev/null || true
fi

4.2 超时控制的重要性

每个 hook 命令都有超时时间设置(默认 5000 毫秒)。超时控制至关重要:如果 hook 命令执行时间过长,可能会导致 Claude Code 的操作被延迟,影响用户体验。更严重的是,如果 BeforeCommand 或 BeforeWrite 等前置 hook 超时,对应的操作(命令执行或文件写入)将失败。因此,hook 命令应当尽量轻量快速,避免执行耗时的操作。对于确实需要长时间运行的任务(如代码编译、测试运行),应考虑使用 AfterCommand 或 AfterWrite 等后置事件,并通过异步方式处理。

4.3 错误处理策略

Hook 命令的错误处理需要特别关注。对于前置 hook(BeforeCommand、BeforeRead、BeforeWrite),如果命令返回非零退出码,对应的主操作将被阻止执行。这其实是 hooks 系统提供的一种安全检查机制——你可以利用这一点来实现命令黑名单、文件写入保护等功能。对于后置 hook(AfterCommand、AfterRead、AfterWrite),非零退出码不会影响主操作的结果,但会在控制台输出错误信息。无论哪种情况,都建议在 hook 命令中使用 || trueset -e 控制来管理错误传播。

命令编写黄金法则:前置 hook 应当快速返回(< 1秒),避免阻塞主操作;使用明确的退出码控制操作流程(非零退出码可阻止操作);充分利用环境变量获取上下文信息;始终考虑超时和错误处理,确保 hook 的健壮性。

五、实用 Hook 场景

Hooks 系统的真正价值体现在实际应用场景中。以下列举五个经过验证的实用 hook 配置,覆盖了代码质量管理、安全防护、自动化备份等核心领域。这些配置可以直接应用于实际项目中,也可以根据具体需求进行定制调整。

5.1 代码质量标准 - BeforeWrite 自动格式化检查

在文件写入前自动检查代码格式,确保 Claude Code 生成的代码符合项目的代码规范。这个 hook 特别适合团队协作场景,可以避免因代码风格不一致导致的 review 返工。当 Prettier 检查不通过时,hook 返回非零退出码,阻止不符合规范的文件写入。

// .claude/settings.json - 代码质量 Hook
{
  "hooks": {
    "pre-write": [
      {
        "matchers": [
          { "type": "BeforeWrite", "glob": "**/*.{js,ts,jsx,tsx}" }
        ],
        "command": "npx prettier --check \"$CLAUDE_HOOK_FILE_PATH\" 2>&1 || { echo 'Prettier check failed! Run npx prettier --write to fix.'; exit 1; }",
        "timeout": 15000
      }
    ]
  }
}

5.2 安全扫描 - BeforeCommand 危险命令拦截

在 Claude Code 执行任何命令前进行安全检查,阻止危险操作。这是 hooks 系统中最实用的安全防护手段。通过分析 CLAUDE_HOOK_COMMAND 环境变量中的命令文本,可以检测并拦截包含危险模式的操作,如强制删除、权限修改、敏感数据导出等。

// .claude/settings.json - 安全扫描 Hook
{
  "hooks": {
    "pre-command": [
      {
        "matchers": [{ "type": "BeforeCommand" }],
        "command": "echo \"$CLAUDE_HOOK_COMMAND\" | grep -E 'rm -rf|chmod -R 777|dd if=|:(){ :|:& };:' && echo 'DANGEROUS COMMAND BLOCKED!' && exit 1 || exit 0",
        "timeout": 3000
      }
    ]
  }
}

5.3 通知提醒 - AfterCommand 长时间任务通知

对于可能长时间运行的任务(如编译、测试、部署),可以在命令执行完成后发送桌面通知或 Slack 消息,让开发者及时了解任务状态。这种模式特别适合在后台运行的批量处理场景,开发者无需一直盯着终端等待任务完成。

// .claude/settings.json - 任务完成通知 Hook
{
  "hooks": {
    "post-command": [
      {
        "matchers": [{ "type": "AfterCommand" }],
        "command": "if [ $CLAUDE_HOOK_EXIT_CODE -eq 0 ]; then notify-send 'Claude Code' 'Command completed successfully'; else notify-send -u critical 'Claude Code' 'Command failed with exit code '$CLAUDE_HOOK_EXIT_CODE; fi",
        "timeout": 5000
      }
    ]
  }
}

5.4 自动备份 - BeforeWrite 文件版本备份

在文件被修改前自动创建备份,形成文件版本历史。这个 hook 为开发者提供了安全保障——即使 Claude Code 的修改出现问题,也可以随时回退到备份版本。备份文件按照时间戳组织,便于追溯和管理。

// .claude/settings.json - 自动备份 Hook
{
  "hooks": {
    "pre-write": [
      {
        "matchers": [{ "type": "BeforeWrite", "glob": "src/**/*" }],
        "command": "mkdir -p .claude/backups && cp \"$CLAUDE_HOOK_FILE_PATH\" \".claude/backups/$(basename $CLAUDE_HOOK_FILE_PATH).$(date +%Y%m%d%H%M%S)\"",
        "timeout": 5000
      }
    ]
  }
}

5.5 日志记录 - 全事件操作审计

记录 Claude Code 的完整操作日志,包括所有执行的命令、读取和写入的文件。这个 hook 配置对于审计追踪、问题排查和使用统计非常有用。通过组合使用多种事件类型的 hook,可以构建出一个完整的操作审计系统。

// .claude/settings.json - 全面审计日志 Hook
{
  "hooks": {
    "pre-command": [{
      "matchers": [{ "type": "BeforeCommand" }],
      "command": "echo \"[$(date '+%Y-%m-%d %H:%M:%S')] CMD: $CLAUDE_HOOK_COMMAND\" >> .claude/audit.log",
      "timeout": 2000
    }],
    "pre-read": [{
      "matchers": [{ "type": "BeforeRead" }],
      "command": "echo \"[$(date '+%Y-%m-%d %H:%M:%S')] READ: $CLAUDE_HOOK_FILE_PATH\" >> .claude/audit.log",
      "timeout": 2000
    }],
    "pre-write": [{
      "matchers": [{ "type": "BeforeWrite" }],
      "command": "echo \"[$(date '+%Y-%m-%d %H:%M:%S')] WRITE: $CLAUDE_HOOK_FILE_PATH\" >> .claude/audit.log",
      "timeout": 2000
    }]
  }
}
实战场景总结:五种实用场景展示了 hooks 在不同维度的应用——代码质量(Prettier 检查)、安全防护(危险命令拦截)、通知机制(桌面通知)、自动备份(文件版本管理)和审计追踪(操作日志)。这些配置可以直接组合使用,构建全面的自动化工作流。

六、Hook 注意事项

尽管 hooks 系统功能强大,但在实际使用中需要注意一些关键的限制和潜在的陷阱。理解这些问题可以帮助开发者避免常见的错误,确保 hook 系统的稳定运行。

6.1 超时导致操作失败

Hook 命令的超时设置直接影响 Claude Code 的操作流程。对于 BeforeCommand 和 BeforeWrite 这类前置 hook,如果命令执行超时,对应的主操作将被视为失败——这意味着一个简单的文件写入可能因为 hook 超时而无法完成。因此,推荐的超时策略是:前置 hook 的超时控制在 2-5 秒以内,确保不会阻塞正常操作;后置 hook 的超时可以适当放宽到 10-15 秒,因为它们不会影响主操作的成功与否。

6.2 避免死循环

Hook 命令执行时本身也会触发事件吗?这是一个需要特别注意的问题。假设你在 BeforeWrite hook 中执行了一个脚本,而这个脚本又写入了一个文件,那么新的写入操作会不会再次触发 BeforeWrite hook?答案是:取决于 harness 的实现。为了避免这种潜在的死循环风险,建议 hook 命令中避免执行可能触发同名事件的操作。例如,在 BeforeWrite hook 中不要直接写入项目文件,而是将输出写入临时文件或日志缓冲区。如果需要写入,考虑在命令中加入跳过逻辑(如检查环境变量标记)。

6.3 性能影响考虑

每个 hook 的执行都会增加操作的总耗时。如果配置了过多的 hook,或者 hook 命令本身执行缓慢,会显著影响 Claude Code 的响应速度。在文件密集型操作(如批量重构、大规模文件生成)场景下,这种性能影响尤为明显。建议采用以下优化策略:使用 glob 精确匹配需要监控的文件范围,避免全局匹配;保持 hook 命令的轻量化,避免在 hook 中执行编译、测试等重量级操作;对于非关键 hook,考虑将其改为后置事件,减少对主流程的影响。

6.4 调试 Hook 的方法

当 hook 出现问题时,有效的调试手段至关重要。推荐以下调试方法:首先,检查 hook 命令的标准输出和标准错误输出,这些信息会显示在 Claude Code 的控制台中;其次,在 hook 命令中添加详细的日志输出,将执行过程写入日志文件。一个实用的调试配置是创建一个专门用于日志记录的 hook,将所有事件信息输出到调试文件。此外,可以先在终端中手动执行 hook 命令来验证其正确性,确保命令独立运行时没有问题,再集成到 settings.json 中。

调试建议

当你怀疑 hook 有问题时,最简单的排查方法是先移除或注释掉 settings.json 中的 hooks 配置,确认问题是否由 hook 引起。你也可以创建一个最小化的测试 hook(如只执行 echo "hook triggered"),逐步增加复杂度来定位问题。另外,定期检查 .claude/ 目录下的日志文件,可以及时发现 hook 的异常行为。

6.5 跨平台兼容性

Hook 命令是在当前系统的默认 shell 中执行的,因此跨平台兼容性需要考虑。在 Windows 系统中,hook 命令可能需要使用 PowerShell 语法而非 bash 语法。如果团队中有多个平台的开发者,建议在 hook 脚本中使用跨平台兼容的命令,或者为不同平台准备不同的 hook 配置。

注意事项核心要点:合理设置超时时间(前置 hook 2-5s,后置 hook 10-15s);警惕 hook 中的死循环风险;使用 glob 精确匹配以控制性能开销;善用日志输出进行调试;注意跨平台的 shell 语法差异。

七、核心要点总结

Hooks 系统核心要点

  • 事件驱动架构:Hooks 是 Claude Code harness 在特定事件触发时自动执行的 shell 命令,与 Claude 模型本身解耦,具有确定性和可靠性。
  • 七种事件类型:覆盖命令执行 (BeforeCommand/AfterCommand)、文件读取 (BeforeRead/AfterRead)、文件写入 (BeforeWrite/AfterWrite) 和用户交互 (UserPromptSubmit) 四大类操作场景。
  • 配置在 settings.json 中:支持项目级 (.claude/settings.json) 和用户级 (~/.claude/settings.json) 两层配置,采用合并策略互不覆盖。
  • 丰富的环境变量:CLAUDE_HOOK_EVENT、CLAUDE_HOOK_COMMAND、CLAUDE_HOOK_FILE_PATH、CLAUDE_HOOK_EXIT_CODE 等环境变量为 hook 命令提供上下文信息。
  • 可用于安全检查:前置 hook (BeforeCommand/BeforeWrite) 的退出码控制机制可以用于阻止危险操作,实现安全防护。
  • 自动备份能力:BeforeWrite hook 可以在文件被修改前自动创建备份,实现文件版本管理。
  • 需要妥善处理错误和超时:超时设置、退出码处理、死循环预防是 hook 配置中必须考虑的三个关键问题。
  • glob 路径匹配:通过 glob 字段可以精确控制 hook 的触发范围,提升系统性能减少不必要的 hook 执行。

八、进一步思考

Hooks 系统使 Claude Code 具备了工作流自动化的能力,从简单的文件操作监控到复杂的 CI/CD 集成,hooks 为开发者提供了扩展 Claude Code 行为的灵活方式。它打破了传统 AI 编程助手只能"问答+生成代码"的局限,让开发者可以在 Claude Code 的操作流程中插入自定义的逻辑,实现对 AI 行为的精确控制和增强。

从更宏观的视角来看,hooks 系统体现了 AI 工具与开发者工作流深度融合的趋势。它不再是简单地用 AI 替代部分开发工作,而是在保留开发者控制权的前提下,让 AI 能力无缝嵌入已有的开发流程和工具链中。例如,通过 BeforeWrite hook 集成 ESLint/Prettier 检查,确保 AI 生成的代码自动符合项目规范;通过 AfterCommand hook 集成 CI 触发器,实现 AI 辅助开发后的自动验证。

展望未来,hooks 系统还有很大的扩展空间。可能的进化方向包括:支持更丰富的事件类型(如 git 操作事件、网络请求事件);提供更细粒度的条件控制(基于文件内容的匹配、基于时间窗口的触发等);以及更完善的 hook 编排能力(hook 链、条件分支、错误重试等)。对于深入使用 Claude Code 的开发者来说,掌握 hooks 系统不仅能够提升当下的工作效率,更是为适应未来 AI 辅助开发模式的演进做好准备。

Hooks 系统的本质,是将 Claude Code 从一个"对话式 AI 编程助手"升级为一个"可编程的 AI 开发代理"。hook 配置中的每一行命令,都是开发者在指导 AI 如何更好地融入自己的工作习惯和团队规范。