Claude Code 的 CLAUDE.md 规则是"建议性的"——Claude 会尽量遵守,但不保证每次都执行。Hooks 不同:Hooks 每次都执行,不依赖模型的判断。
这个差异很重要。CLAUDE.md 里写"每次修改后运行 lint",Claude 可能忘。Hooks 里配置同样的规则,lint 就会每次在修改后自动运行。
Hooks 是什么
Hooks 是绑定在 Claude Code 工具调用生命周期上的脚本:
- PreToolUse:工具调用之前执行(可以阻止)
- PostToolUse:工具调用之后执行
- Notification:有通知时执行
- Stop:Claude 完成任务时执行
与 CLAUDE.md 规则的区别:
| 特性 | CLAUDE.md 规则 | Hooks |
|---|---|---|
| 执行保证 | 模型"尽量"遵守 | 每次都执行 |
| 可以阻止操作 | ❌ | ✅(PreToolUse exit 1) |
| 适合场景 | 风格指南、偏好 | 安全守卫、自动化 |
| 复杂逻辑 | 有限 | 任意 shell 脚本 |
配置位置
// .claude/settings.json(项目级)
// 或 ~/.claude/settings.json(全局级)
{
"hooks": {
"PostToolUse": [...],
"PreToolUse": [...],
"Stop": [...],
"Notification": [...]
}
}PostToolUse Hooks:每次修改后自动执行
1. 自动 Lint + 格式化
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "cd $(git rev-parse --show-toplevel) && npm run lint --fix 2>&1 | tail -5"
}
]
}
]
}
}效果:每次 Claude 修改文件后自动运行 lint,修复风格问题,不需要手动触发。
2. 自动运行受影响的测试
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "bash -c 'FILE=\"$CLAUDE_TOOL_INPUT_PATH\"; TEST_FILE=\"${FILE%.ts}.test.ts\"; [ -f \"$TEST_FILE\" ] && npx jest \"$TEST_FILE\" --passWithNoTests 2>&1 | tail -10 || echo \"No test file found\"'"
}]
}
]
}效果:修改 auth.service.ts 时,自动检查是否有对应的 auth.service.test.ts,有的话自动运行。
3. 自动提交检查(git status 通知)
{
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [{
"type": "command",
"command": "git diff --stat HEAD 2>/dev/null | tail -3"
}]
}
]
}效果:每次文件修改后,显示当前的 git 改动统计,保持对改动范围的可见性。
PreToolUse Hooks:在执行前拦截
1. 阻止写入生产配置文件
{
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [{
"type": "command",
"command": "bash -c 'FILE=\"$CLAUDE_TOOL_INPUT_PATH\"; if echo \"$FILE\" | grep -qE \"(production|prod|.env.production)\"; then echo \"ERROR: 禁止直接修改生产配置文件: $FILE\"; exit 1; fi'"
}]
}
]
}效果:如果 Claude 试图写入文件名包含 production 或 .env.production 的文件,直接阻止并报错。
2. 阻止危险的 bash 命令
{
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash -c 'CMD=\"$CLAUDE_TOOL_INPUT_COMMAND\"; if echo \"$CMD\" | grep -qE \"(rm -rf|DROP TABLE|DELETE FROM.*WHERE 1=1)\"; then echo \"ERROR: 潜在危险命令被拦截: $CMD\"; exit 1; fi'"
}]
}
]
}效果:在 Claude 执行 bash 命令之前检查,拦截 rm -rf、DROP TABLE 等危险操作。
3. 在操作前备份重要文件
{
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "bash -c 'FILE=\"$CLAUDE_TOOL_INPUT_PATH\"; if echo \"$FILE\" | grep -qE \"(config|settings|.env)\"; then cp \"$FILE\" \"${FILE}.backup.$(date +%Y%m%d_%H%M%S)\" 2>/dev/null && echo \"备份已创建: ${FILE}.backup.*\"; fi'"
}]
}
]
}效果:修改配置文件前自动备份,文件名带时间戳。
Stop Hooks:任务完成时通知
发 Telegram 通知
{
"Stop": [
{
"hooks": [{
"type": "command",
"command": "bash -c 'curl -s -X POST \"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage\" -d \"chat_id=${TELEGRAM_CHAT_ID}&text=Claude+Code+任务完成\" > /dev/null'"
}]
}
]
}效果:Claude 完成一个长任务时,自动发 Telegram 通知,不需要一直盯着终端。
播放系统提示音(macOS)
{
"Stop": [
{
"hooks": [{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff 2>/dev/null || true"
}]
}
]
}实战配置:前端项目完整 Hooks 设置
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [{
"type": "command",
"command": "bash -c 'FILE=\"$CLAUDE_TOOL_INPUT_PATH\"; if echo \"$FILE\" | grep -q \".env.production\"; then echo \"ERROR: 拒绝修改生产环境文件\"; exit 1; fi'"
}]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "cd $(git rev-parse --show-toplevel 2>/dev/null || echo .) && npx eslint \"$CLAUDE_TOOL_INPUT_PATH\" --fix --quiet 2>&1 | grep -v 'npm warn' | head -10 || true"
},
{
"type": "command",
"command": "bash -c 'FILE=\"$CLAUDE_TOOL_INPUT_PATH\"; TEST=\"${FILE%.tsx}.test.tsx\"; [ -f \"$TEST\" ] && npx vitest run \"$TEST\" --reporter=verbose 2>&1 | tail -8 || true'"
}
]
}
],
"Stop": [
{
"hooks": [{
"type": "command",
"command": "echo '✅ Claude Code 任务完成' && git diff --stat HEAD 2>/dev/null | tail -5"
}]
}
]
}
}Hooks 调试技巧
查看 Hooks 输出:Claude Code 在输出面板显示 Hook 执行结果。如果 Hook 有 echo 输出,能在终端看到。
测试 Hook 命令:在 Hook 正式使用前,先在终端单独运行命令验证:
# 模拟 Hook 环境变量并测试
CLAUDE_TOOL_INPUT_PATH="src/auth.ts" bash -c '你的hook命令'处理 Hook 失败:
# 非零退出码 = 阻止操作(PreToolUse)
# 给 PostToolUse Hook 加 || true,防止 Hook 本身的失败影响 Claude
command || true常见 Hooks 模式总结
| 需求 | Hook 类型 | 核心命令 |
|---|---|---|
| 每次修改后 lint | PostToolUse | npm run lint --fix |
| 自动运行对应测试 | PostToolUse | jest ${file.test.ts} |
| 阻止写入生产配置 | PreToolUse + exit 1 | grep production && exit 1 |
| 拦截危险命令 | PreToolUse + exit 1 | grep "rm -rf" && exit 1 |
| 任务完成时通知 | Stop | Telegram/Slack API 调用 |
| 操作前备份文件 | PreToolUse | cp file file.backup |
| 追踪改动范围 | PostToolUse | git diff --stat |
来源:morphllm.com Claude Code Hooks 指南 | Anthropic 官方 Hooks 文档 | 整理:ClaudeEagle