用 Hooks 给 Claude Code 加上自动化外骨骼
Hooks 是 Claude Code 里最被低估的功能之一。它让你在特定事件触发时自动执行命令,相当于给你的 AI 开发流程加了一层看不见的自动化外骨骼。我用了两周,再也不想回到手动运行格式化命令的日子。
Summary: Hooks 是 Claude Code 里最被低估的功能之一。它让你在特定事件触发时自动执行命令,相当于给你的 AI 开发流程加了一层看不见的自动化外骨骼。我用了两周,再也不想回到手动运行格式化命令的日子。
我最早注意到这个问题,是在连续改了三天 ReviX 项目的配置文件之后。
每次让 Claude Code 帮我改完 docker-compose.yml 或者 .env.example,我都得手动执行一遍 prettier --write 再 git 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 里有没有敏感信息。
下次聊。
评论
发表评论