CLAUDE.md 是道德劝说,Hooks 才是法律。四个生命周期钩子,让你的 AI 编程助手从不靠谱的实习生变成靠谱的高级工程师。
▲ Claude Code Hooks 四层防线:PreToolUse、PostToolUse、Stop、Notification 生命周期事件
前言
如果你在用 Claude Code 写代码,你一定遇到过这些场景:
- Claude 改完三个文件,你手动跑了三遍
eslint --fix - Claude 写了一段代码,你担心它是不是偷偷引入了安全漏洞
- 你让 Claude "每次改完文件跑一下测试",但它在第 10 轮对话后"忘了"
- 团队里有人用 Claude Code 改了生产配置,你想知道到底改了什么
这些问题的根源是一样的:你只有口头约定,没有代码强制。
Claude Code 在 2025 年底推出的 Hooks 系统,正是解决这个问题的。它不是在 prompt 里"建议"AI 做什么,而是在引擎层面——到达某个生命周期节点时,强制执行你的脚本。今天这篇文章,我们就把 Hooks 从概念到生产级配置,全部讲透。
什么是 Hooks
Hooks 是 Claude Code 的"生命周期事件监听器"。当某个事件发生时(比如工具调用前、工具调用后、会话结束时),Claude Code 会自动触发你预定义的脚本。
这是 Claude Code 从"AI 编程 CLI 工具"向"Agent 工程平台"演进的关键一步。有了 Hooks,你不再是一个人在用 AI,而是你在编程 AI 的行为。
Hooks 的配置放在 .claude/settings.json 中(项目级)或 ~/.claude.json 中(用户级)。项目级配置优先级更高。
四类 Hook 事件类型
Claude Code 目前支持四种 Hook 事件,覆盖了 Agent 生命周期的关键节点:
| Hook 事件 | 触发时机 | 典型用途 |
|---|
| PreToolUse | 工具执行之前 | 安全检查、敏感操作拦截、命令白名单 |
| PostToolUse | 工具执行之后 | 自动格式化、审计日志、结果校验 |
| Stop | 会话结束时 | 运行测试套件、检查覆盖率、门禁 |
| Notification | 关键事件发生时 | 桌面弹窗提醒、耗时通知 |
下面我们逐一深入,每种 Hook 都配有可复制的配置代码。
1. PreToolUse —— AI 动手前的最后一道防线
PreToolUse 在 Claude 调用任何工具(Bash、Edit、Write 等)之前触发。你的脚本可以检查 Claude 想干什么,如果发现危险操作,直接拒绝并返回原因。
典型场景:
- 禁止
rm -rf / 或 DROP TABLE - 限制 Claude 只能修改特定目录下的文件
- 拦截对
.env、credentials.json 等敏感文件的读取
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "python3 .claude/hooks/pre_bash_check.py"
}
]
}
}
配套的 Python 脚本 pre_bash_check.py 示例:
#!/usr/bin/env python3
import json, sys
# Claude Code 通过 stdin 传入工具调用信息
tool_input = json.loads(sys.stdin.read())
command = tool_input.get("command", "")
# 危险命令黑名单
DANGEROUS_PATTERNS = [
"rm -rf /",
"DROP TABLE",
"> /dev/sda",
"chmod 777 /",
"git push --force origin main"
]
for pattern in DANGEROUS_PATTERNS:
if pattern in command:
print(json.dumps({
"decision": "block",
"reason": f"危险命令被拦截: {pattern}"
}))
sys.exit(2) # 非零退出 = 阻止执行
# 允许执行
print(json.dumps({"decision": "allow"}))
踩坑提醒:PreToolUse 脚本的 exit code 决定了是否允许执行。exit 0 = 允许,exit 非零 = 阻止。如果你想让 Claude 看到你的理由,用 stdout 输出 JSON 格式的 reason。
2. PostToolUse —— 事后检查与自动修复
PostToolUse 在工具执行之后触发。这是最常用的 Hook,因为大部分自动化需求都是"改完文件之后做点什么"。
典型场景:
- 每次 Bash 执行后记录审计日志(谁、什么时候、执行了什么、结果如何)
- 每次 Edit/Write 文件后自动运行
eslint --fix 或 prettier --write - 检测 git diff 中是否包含 API key 等敏感信息
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "python3 .claude/hooks/post_edit_lint.py"
},
{
"matcher": "Bash",
"command": "python3 .claude/hooks/audit_log.py"
}
]
}
}
审计日志脚本 audit_log.py:
#!/usr/bin/env python3
import json, sys, os
from datetime import datetime
tool_result = json.loads(sys.stdin.read())
log_entry = {
"timestamp": datetime.now().isoformat(),
"tool": tool_result.get("tool_name", "unknown"),
"input": tool_result.get("tool_input", {}),
"exit_code": tool_result.get("exitCode"),
"output_preview": str(tool_result.get("output", ""))[:500]
}
# 追加写入审计日志
with open(".claude/audit.log", "a") as f:
f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")
# 检测敏感信息泄露
output_text = str(tool_result.get("output", ""))
sensitive_keys = ["sk-", "api_key", "password", "token", "secret"]
for key in sensitive_keys:
if key.lower() in output_text.lower():
print(f"⚠️ 警告: 输出中可能包含敏感信息 ({key}),已记录到审计日志",
file=sys.stderr)
print(json.dumps({"decision": "allow"}))
3. Stop —— 会话门禁
Stop Hook 在 Claude Code 会话结束时触发。这是你的"质量门禁"——在 Claude 说"搞定"之前,先跑一遍测试。
典型场景:
- 自动运行
pytest / npm test - 检查代码覆盖率是否达标
- 验证 git status 是否干净
{
"hooks": {
"Stop": [
{
"command": "bash .claude/hooks/stop_gate.sh"
}
]
}
}
stop_gate.sh 示例:
#!/bin/bash
echo "=== 会话门禁检查 ==="
# 1. 运行测试
echo "[1/3] 运行测试..."
if ! python3 -m pytest tests/ -x --tb=short 2>&1; then
echo "❌ 测试失败,请修复后再结束会话"
exit 1
fi
# 2. 检查是否有未提交的敏感文件
echo "[2/3] 敏感文件检查..."
if git diff --cached --name-only | grep -E '\.env$|credentials|\.pem$'; then
echo "⚠️ 检测到敏感文件被修改,请确认"
fi
# 3. 检查代码覆盖率
echo "[3/3] 覆盖率检查..."
coverage=$(python3 -m pytest --cov=src --cov-report=term 2>&1 | grep "TOTAL" | awk '{print $NF}' | tr -d '%')
if [ -n "$coverage" ] && [ "$coverage" -lt 70 ]; then
echo "⚠️ 代码覆盖率 ${coverage}%,低于 70% 阈值"
fi
echo "✅ 门禁检查通过"
▲ .claude/settings.json 配置结构与 hooks/ 目录脚本文件的对应关系
4. Notification —— 桌面弹窗提醒
Notification Hook 让你在 Claude 完成长时间任务后收到桌面通知。这在运行耗时操作(如全量测试、数据库迁移脚本生成)时特别有用。
{
"hooks": {
"Notification": [
{
"matcher": "Bash",
"command": "python3 .claude/hooks/notify_on_long_task.py"
}
]
}
}
#!/usr/bin/env python3
import json, sys, subprocess, os
tool_input = json.loads(sys.stdin.read())
command = tool_input.get("command", "")
# 只对长时间运行的命令发通知
LONG_COMMANDS = ["pytest", "npm run build", "docker build", "terraform apply"]
for keyword in LONG_COMMANDS:
if keyword in command:
# macOS 通知
if os.uname().sysname == "Darwin":
subprocess.run([
"osascript", "-e",
f'display notification "命令完成" with title "Claude Code" subtitle "{command[:50]}"'
])
# Linux 通知
else:
subprocess.run([
"notify-send", "Claude Code",
f"命令完成: {command[:100]}"
], capture_output=True)
break
print(json.dumps({"decision": "allow"}))
完整生产级配置
把以上四类 Hook 组合起来,你得到的是一个自带质量保障体系的 AI 编程环境。以下是可直接复制到 .claude/settings.json 的完整配置:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "python3 .claude/hooks/pre_bash_guard.py"
},
{
"matcher": "Write|Edit",
"command": "python3 .claude/hooks/pre_write_check.py"
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "python3 .claude/hooks/post_edit_format.py"
},
{
"matcher": "Bash",
"command": "python3 .claude/hooks/post_bash_audit.py"
}
],
"Stop": [
{
"command": "bash .claude/hooks/stop_quality_gate.sh"
}
],
"Notification": [
{
"matcher": "Bash",
"command": "python3 .claude/hooks/notify_long_task.py"
}
]
}
}
对应的 .claude/hooks/ 目录结构:
.claude/hooks/
├── pre_bash_guard.py # 命令安全检查
├── pre_write_check.py # 文件写入白名单
├── post_edit_format.py # 改完自动格式化
├── post_bash_audit.py # 审计日志
├── stop_quality_gate.sh # 会话门禁
└── notify_long_task.py # 桌面通知
三个真实事故与 Hooks 如何救场
以下场景来自社区实战反馈,每个都对应一个 Hook:
事故 1:Claude 误删了生产配置
一个团队让 Claude 优化 Nginx 配置,Claude 在 Bash 中执行了 rm /etc/nginx/sites-enabled/*(想先清理再重建),导致生产服务中断 17 分钟。
修复方案——PreToolUse 拦截:
if "rm" in command and ("/etc/" in command or "/var/" in command):
return {"decision": "block", "reason": "禁止修改系统目录文件"}
事故 2:API Key 泄露到前端代码
Claude 在帮助调试时,将 .env 中的 OpenAI Key 复制到了 config.js 并提交到了 GitHub。
修复方案——PostToolUse 检测:
# 在 post_edit_format.py 中
import subprocess
diff = subprocess.run(["git", "diff"], capture_output=True, text=True).stdout
if "sk-" in diff or "api_key" in diff.lower():
print("🚨 提交中检测到疑似 API Key,请立即检查!", file=sys.stderr)
事故 3:未经测试的代码直接上线
Claude 写完一个"重构"后说"完成了",但 3 个测试用例失败,没人发现。
修复方案——Stop 门禁:
# stop_quality_gate.sh
python3 -m pytest tests/ -x --tb=short || exit 1
Hooks vs CLAUDE.md:为什么两者都要用
很多开发者以为在 CLAUDE.md 里写"每次改完文件后运行 prettier"就够了。但这是建议,不是强制。
| CLAUDE.md | Hooks |
|---|
| 性质 | Prompt 指令 | 引擎级强制执行 |
| Claude 能忽略吗 | 能(长对话后会"忘记") | 不能(绕过除非你删配置) |
| 适用场景 | 代码风格偏好、项目约定 | 安全检查、质量门禁、审计 |
| 团队共享 | ✓ | ✓ |
| 执行时机 | Claude 决定什么时候读 | 按事件自动触发 |
一句话总结:CLAUDE.md 是道德劝说,Hooks 才是法律。 两者搭配使用:CLAUDE.md 管"风格",Hooks 管"底线"。
踩坑与排障
坑1:Hook 脚本路径问题
Hook 的 command 字段中,脚本路径相对于项目根目录,不是你放 .claude/settings.json 的目录。
如果你把脚本放在 .claude/hooks/ 下,配置里要写完整的 python3 .claude/hooks/xxx.py。
▲ CLAUDE.md vs Hooks:道德劝说与法律的对比——建议 vs 强制
坑2:Hook 脚本超时
每个 Hook 脚本默认有 30 秒超时。如果你的 PostToolUse 里跑了 eslint 整个项目,大概率超时。解决方案:
- 只对修改的文件跑检查:
git diff --name-only | grep '\.js$' | xargs eslint --fix - 把重任务放 Stop Hook(超时更长)
坑3:PostToolUse 里别做耗时操作
PostToolUse 会在每次工具调用后触发。如果你的脚本里跑了 npm run build,那 Claude 改一个注释你就要等 30 秒。原则是:PostToolUse 只做轻量操作(格式化、审计日志),重型操作放 Stop Hook。
坑4:exit code 的含义
exit 0 = 允许继续(PreToolUse)/ 表示成功(PostToolUse)exit 1 = 通用错误exit 2 = 明确阻止(PreToolUse 专用,Claude Code 会告诉用户被拦截的原因)
坑5:版本兼容性
Hooks 功能在 Claude Code 2.1.0 及以上版本可用。如果你的 claude --version 低于此版本,需要先升级:
npm update -g @anthropic-ai/claude-code
进阶:Hooks + Slash Commands 组合技
Hooks 负责"自动触发",Slash Commands 负责"手动控制"。两者结合形成完整的自动化体系:
Slash Command: /deploy
→ PreToolUse 检查环境变量是否完整
→ 正常部署
→ PostToolUse 记录部署日志 + 发通知
→ Stop 确认部署状态码
Slash Command: /fix-lint
→ Claude 修改文件
→ PostToolUse 自动运行 prettier + eslint --fix
→ 人只需要确认最终结果
你可以在 .claude/settings.json 中同时定义 hooks 和 commands:
{
"hooks": { "PostToolUse": [...] },
"commands": [
{
"name": "deploy",
"description": "安全部署到生产环境",
"prompt": "按照 deploy.md 中的流程执行部署,每一步都要确认"
}
]
}
总结
Claude Code Hooks 是把 AI 编程从"个人玩具"升级为"团队工具"的关键基础设施。四个生命周期钩子覆盖了:
- PreToolUse:在 Claude 动手前拦截危险操作
- PostToolUse:在每次工具调用后自动执行格式化、审计、校验
- Stop:在会话结束前强制跑测试和质量门禁
- Notification:在关键任务完成时弹窗提醒
把本文的完整配置复制到你的项目中,给 .claude/hooks/ 目录配上对应的脚本文件,你就拥有了一个自带安全防线、审计能力、质量保障的 AI 编程环境。
记住那句话:CLAUDE.md 是道德劝说,Hooks 才是法律。
| 踩坑笔记 |
|---|
| ⚠️ PostToolUse 只做轻量操作(格式化、审计),重型操作放 Stop Hook |
| ⚠️ Hook 脚本路径相对于项目根目录,不是 .claude/ 目录 |
| ⚠️ PreToolUse exit 2 = 明确阻止,exit 0 = 允许 |
| ⚠️ 需要 Claude Code 2.1.0+,低版本请升级 |
| ⚠️ 30 秒超时限制,大项目请限缩检查范围 |
#AI创业 #Agent工坊 #ClaudeCode #Hooks #自动化 #AI编程
本文由AI辅助创作,经人工审核编辑发布
更多一人公司案例与工具,微信搜索「AI创业内参」关注我们