用 Hooks 给 Claude Code 加上自动化外骨骼

Hooks 是 Claude Code 里最被低估的功能之一。它让你在特定事件触发时自动执行命令,相当于给你的 AI 开发流程加了一层看不见的自动化外骨骼。我用了两周,再也不想回到手动运行格式化命令的日子。

Summary: Hooks 是 Claude Code 里最被低估的功能之一。它让你在特定事件触发时自动执行命令,相当于给你的 AI 开发流程加了一层看不见的自动化外骨骼。我用了两周,再也不想回到手动运行格式化命令的日子。


我最早注意到这个问题,是在连续改了三天 ReviX 项目的配置文件之后。

每次让 Claude Code 帮我改完 docker-compose.yml 或者 .env.example,我都得手动执行一遍 prettier --writegit add。不是说做不到,而是人总有忘的时候。结果那段时间我 CI 里跑出来的 diff,有一半是格式化问题。

那时候我就在想:有没有一种方式,让 Claude 做完修改之后自动跑一遍格式化,再顺手把文件加到暂存区?

后来才知道,这个功能早就有了。只是名字叫 Hooks,而且藏在文档的角落。

Hooks 是什么

简单说,Hooks 就是让你在 Claude Code 的特定生命周期事件发生时,自动插入一段自定义命令。

比如:
- 工具调用之前 / 之后
- Claude 停下来思考之前 / 之后
- Session 开始 / 结束

Claude Code 会在对应的时间点,把你配置的命令跑一遍,然后把结果喂回上下文。

我自己的配置主要集中在 PostToolUse 上。主要是想让文件修改完之后自动格式化,避免我的 CI 因为我忘跑 prettier 而报错。

具体怎么用

Hooks 的配置放在 .claude/settings.json 里(如果没有这个文件就新建一个)。

PostToolUse 的配置长这样:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "prettier --write \"$CLAUDE_FILE_PATH\"",
        "timeout": 30000
      }
    ]
  }
}

$CLAUDE_FILE_PATH 是 Claude Code 提供的内置环境变量,代表当前被操作的文件路径。如果你的编辑器修改文件时用的是 Edit 工具,这里就会自动触发 prettier --write

我还配了一个 SessionStart 的 hook,用来每次启动 Claude Code 的时候自动同步一下 git 状态:

{
  "hooks": {
    "SessionStart": [
      {
        "command": "git status -sb",
        "timeout": 10000
      }
    ]
  }
}

这样每次我切进 Claude Code,第一眼就能看到当前工作区是什么状态,不用手动敲 git status

Tricks

Trick 1: 用 Stop hook 做自动提交

我配了一个 Stop hook,在 Claude Code 停下来之前自动执行提交。前提是你的项目里有 Conventional Commits 规范。

{
  "hooks": {
    "Stop": [
      {
        "matcher": "Edit|Write",
        "command": "git add -A && git commit -m \"chore: Claude Code automated commit\"",
        "timeout": 15000
      }
    ]
  }
}

现在 Claude 改完代码、停下来之前,我会在终端看到 git commit 的输出。省掉了我手动 git add . && git commit 这一步。

Trick 2: 在 PostToolUse 里跑测试

如果你的项目跑测试很快,可以在 Edit 之后自动跑一遍单元测试,确保 Claude 的修改没有把东西改坏。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "command": "npm test --silent",
        "timeout": 60000
      }
    ]
  }
}

这样 Claude 每改一个文件,你的测试就跟着跑一遍。如果测试挂了,Claude 会在下一次工具调用时看到失败信息,通常会自己修复。

注意事项 / 踩坑

坑 1: 别配太重的命令

Hooks 是同步执行的。如果你配了一个要跑 30 秒的命令,Claude Code 会卡在那里等。我试过在 PostToolUse 里配 npm run lint,结果每个文件修改之后要等七八秒,整个对话节奏直接崩了。

后来我改成只跑 prettier --write 这种单文件的、毫秒级的命令。重的校验我用 CI 做,不在 Hooks 里做。

坑 2: 环境变量不是所有 hook 都有

$CLAUDE_FILE_PATH 只在 PostToolUse 里有意义。SessionStart 或者 Stop 这种全局事件里,这个变量是空的。我第一次配 SessionStart 的 hook 也带了 $CLAUDE_FILE_PATH,结果命令直接报错。

坑 3: Hook 失败会影响 Claude 的判断

如果你的 hook 命令 exit code 不是 0,Claude Code 会把 stderr 输出塞回上下文。有时候这会误导 Claude,让它以为有什么错误需要修复。我在实践里发现,格式化命令偶尔会因为文件锁而失败,这时候最好把 stderr 吞掉,不要让 Claude 看到一堆无意义的报错。

结尾

现在我已经离不开 Hooks 了。它把那些本来应该自动化的小步骤,悄无声息地处理掉了。

我今天配的这套流程已经稳定跑了两周。下一个我想研究的,是怎么让 Claude Code 在自动提交之前,先检查一下 diff 里有没有敏感信息。

下次聊。

评论

此博客中的热门博文

我写了半年 prompt,这是我发现的最好的技巧