Claude Code Hooks 实战:6个自动化脚本,省掉每天30分钟重复操作
Claude Code Hooks 实战:6个自动化脚本,省掉每天30分钟重复操作
Pragmatic Engineer 今年3月的调查数据:Claude Code 发布8个月,已经是开发者用得最多的 AI 编程工具,超过了 GitHub Copilot 和 Cursor。
但大部分人只把它当"智能补全"用。其实 Claude Code 有个被低估的功能叫 Hooks——你可以在它的运行周期里插入自定义脚本,让格式化、测试、通知、权限拦截这些事情自动发生,不用每次手动敲命令。
这篇文章给你6个拿来就能用的 Hook 配置,每个都附完整 JSON 和脚本。
Hooks 是什么
一句话:Hooks 是在 Claude Code 特定时机自动执行的 shell 命令。
比如 Claude 改完一个文件后,你想自动跑 prettier 格式化。正常流程是你手动运行 npx prettier --write xxx.js。用 Hook 的话,只要在配置里写一条规则,Claude 每次改完文件就自动格式化,你什么都不用管。
Hooks 支持这些触发时机:
PreToolUse:工具调用前(比如写文件前检查是否是受保护文件)PostToolUse:工具调用后(比如写完文件自动格式化)Notification:Claude 等你输入时(发桌面通知)Stop:Claude 完成一轮回答后(跑测试、发通知)SessionStart:会话启动时(加载环境变量)PostCompact:上下文压缩后(重新注入关键信息)
配置写在 ~/.claude/settings.json 里,格式长这样:
{
"hooks": {
"事件名": [
{
"matcher": "匹配条件",
"hooks": [
{
"type": "command",
"command": "要执行的命令"
}
]
}
]
}
}
下面直接上实战。
1. 文件保存后自动格式化
这是用得最多的场景。Claude 改完代码文件,你不想每次手动跑 prettier 或 eslint --fix。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null || true"
}
]
}
]
}
}
matcher 设成 Edit|Write,意思是只在 Claude 用 Edit 或 Write 工具改文件时触发。stdin 会收到一段 JSON,里面有 tool_input.file_path 字段,用 jq 提取出来传给 prettier。
末尾加 || true 是因为有些文件 prettier 不认(比如 .md),报错也不影响流程。
实测下来,这个 Hook 每次执行不到 200ms,基本感觉不到延迟。
2. 保护关键文件不被误改
项目里总有些文件不能随便动:.env.production、docker-compose.yml、CI 配置之类的。可以用 PreToolUse Hook 拦截:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | grep -qE '(\\.env\\.production|docker-compose\\.yml|\\.(github|gitlab)/|Makefile)' && echo '{\"decision\": \"block\", \"reason\": \"受保护文件,请确认后手动修改\"}' || echo '{\"decision\": \"allow\"}'"
}
]
}
]
}
}
原理很简单:从 stdin 读文件路径,用 grep 匹配保护列表,命中就返回 {"decision": "block"},Claude 会收到拒绝信息,不会执行这次修改。
我在项目里加上这条之后,Claude 再也没有误改过 CI 配置。之前它"好心"帮我改 .github/workflows/deploy.yml,结果把部署搞挂了一次,从那以后就加了这个。
3. 任务完成桌面通知
Claude 有时候跑一个复杂任务要几分钟,你切到别的窗口干活,不知道它什么时候完事。加个通知 Hook:
macOS 版:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code 任务完成,等你回来\" with title \"Claude Code\"'"
}
]
}
]
}
}
Linux 版用 notify-send:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code 任务完成,等你回来'"
}
]
}
]
}
}
matcher 设为空字符串表示所有通知都触发。如果你觉得太频繁,可以在 command 里加个过滤逻辑,只在特定类型的通知时弹窗。
4. 每轮任务结束自动跑测试
这个很实用。Claude 改完代码后自动跑一遍测试,如果挂了你马上就知道:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cd \"$(jq -r '.cwd')\" && npm test --silent 2>&1 | tail -20 | jq -Rs '{output_to_claude: .}'"
}
]
}
]
}
}
Stop 事件在 Claude 完成一轮回答时触发。这里做了三件事:
cd到项目目录- 跑
npm test,取最后20行输出 - 把结果通过
output_to_claude字段反馈给 Claude
如果测试挂了,Claude 会看到失败信息,你可以直接让它修复。整个过程是闭环的——改代码、跑测试、看结果、修bug,全在一个对话里完成。
注意:如果你的测试跑得慢(超过30秒),建议改成只跑受影响文件的测试,不要全量跑。
5. 上下文压缩后自动恢复关键信息
Claude Code 对话长了会压缩上下文,有时候压缩完会"忘记"一些重要信息,比如你在对话开头告诉它的项目约定。PostCompact Hook 可以在压缩后自动注入关键上下文:
{
"hooks": {
"PostCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo '{\"output_to_claude\": \"提醒:本项目使用 TypeScript strict 模式,所有函数必须有返回类型声明。API 路由在 src/routes/ 下,数据库模型在 src/models/ 下。测试文件和源文件放同一目录,命名用 .test.ts 后缀。\"}'"
}
]
}
]
}
}
如果规则比较多,可以从文件读取:
{
"hooks": {
"PostCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cat .claude/project-context.txt | jq -Rs '{output_to_claude: .}'"
}
]
}
]
}
}
把项目约定写在 .claude/project-context.txt 里,压缩后自动重新喂给 Claude。我实际用下来,加了这个 Hook 之后 Claude 在长对话中"跑偏"的频率降了不少。
6. 会话启动时自动加载环境
每次开新会话都要告诉 Claude 项目背景信息?用 SessionStart Hook 自动搞定:
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo '{\"output_to_claude\": \"当前 Node 版本:'$(node -v)',npm 版本:'$(npm -v)',Git 分支:'$(git branch --show-current)',最近3条commit:'$(git log --oneline -3 | tr '\\n' '; ')'\"}'"
}
]
}
]
}
}
这样 Claude 一启动就知道你在哪个分支、用什么版本、最近改了什么。不用你每次手动交代。
完整配置参考
把上面6个 Hook 合在一起,一个完整的 ~/.claude/settings.json 长这样(只展示 hooks 部分):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null || true"
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | grep -qE '(\\.env\\.production|docker-compose\\.yml|\\.(github|gitlab)/)' && echo '{\"decision\": \"block\", \"reason\": \"受保护文件\"}' || echo '{\"decision\": \"allow\"}'"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code 等你回来\" with title \"Claude Code\"'"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cd \"$(jq -r '.cwd')\" && npm test --silent 2>&1 | tail -20 | jq -Rs '{output_to_claude: .}'"
}
]
}
],
"PostCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cat .claude/project-context.txt | jq -Rs '{output_to_claude: .}'"
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo '{\"output_to_claude\": \"Node: '$(node -v)', Branch: '$(git branch --show-current)'\"}'"
}
]
}
]
}
}
踩坑记录
用 Hooks 这几个月踩过一些坑,记下来供参考:
jq 必须装好。 Hooks 的输入输出走 JSON 格式,jq 是刚需。macOS 上 brew install jq,Ubuntu 上 apt install jq。没装 jq 的话 Hook 会静默失败,排查半天找不到原因。
命令超时默认10秒。 如果你的 Hook 执行时间长(比如全量跑测试),可能会被杀掉。长任务建议用异步 Hook 或者只跑增量测试。
stderr 输出会被吞掉。 Hook 的 stderr 不会显示在 Claude 界面里。调试的时候建议把 stderr 重定向到文件:2>/tmp/hook-debug.log。
配置改完要重启。 修改 settings.json 后,当前会话不会自动加载新 Hook,需要退出重新进。
路径问题。 Hook 里的相对路径是相对于 Claude Code 启动目录的,不是 settings.json 的位置。跨项目用的 Hook 建议写绝对路径。
总结
Hooks 的思路很简单:把重复的操作自动化,把危险的操作拦住,把重要的信息自动喂给 Claude。
上面6个配置覆盖了最常见的场景。你可以直接复制到自己的 settings.json 里,改改路径和命令就能用。如果你有其他好用的 Hook 配置,评论区见。
更多推荐
所有评论(0)