Claude Code Hooks 完全指南——自动化你的开发工作流
Claude Code Hooks 是 Claude Code 提供的生命周期脚本机制,允许你在特定时机自动执行自定义脚本。通过 Hooks,你可以实现代码保存时自动格式化、运行前自动检查、任务完成后自动通知等场景,将重复性工作完全自动化。
目录
一、什么是 Hooks?
Hooks 是 Claude Code 的生命周期回调系统。你可以为特定事件(如文件保存前、任务完成后)注册自定义脚本,Claude Code 会在对应时机自动调用这些脚本。
Hooks vs Skills vs Commands
| 概念 | 触发方式 | 用途 |
|---|---|---|
| Hooks | 自动触发(事件驱动) | 自动化流程、格式化、检查 |
| Skills | 自动匹配(自然语言触发) | 教会 Claude 怎么做某事 |
| Commands | 手动调用(斜杠命令) | 用户主动执行的流程 |
| Agents | 手动调用(@引用) | 专用子代理完成子任务 |
工作流程示意
用户编辑代码 → 文件保存 → [before_write Hook 触发]
↓ 自动格式化/检查
文件写入磁盘 → [after_write Hook 触发]
↓ 自动编译/lint
任务完成 → [after_task Hook 触发]
↓ 自动总结/通知
二、Hooks 的类型与触发时机
Claude Code 支持以下 7 种 Hook 类型:
| Hook 名称 | 触发时机 | 典型用途 |
|---|---|---|
before_read | 读取文件之前 | 文件解密、权限验证 |
after_read | 读取文件之后 | 内容过滤、日志记录 |
before_write | 写入文件之前(可修改内容) | 格式化代码、注入版权头 |
after_write | 写入文件之后 | 运行 linter、编译检查 |
before_command | 执行 shell 命令之前 | 安全检查、环境验证 |
after_command | 执行 shell 命令之后 | 结果分析、日志记录 |
after_task | 整个任务完成之后 | 生成报告、发送通知 |
重要:Hook 的执行顺序
任务开始 → before_read → after_read → ... → before_write → 写入
→ after_write → ... → before_command → 执行命令
→ after_command → ... → after_task → 任务完成
三、环境配置与前置要求
系统要求
- Claude Code CLI 已安装(
npm install -g @anthropic-ai/claude-code) - Node.js 18+(部分 Hook 需要)
- Bash/Zsh shell 环境
配置位置
Hooks 配置在 Claude Code 的 settings.local.json 文件中:
- 项目级:
<项目根目录>/.claude/settings.local.json - 全局级:
~/.claude/settings.local.json
⚠️ 优先级:项目级配置覆盖全局级配置。
settings.local.json不会被提交到 Git(已添加到.gitignore),适合存放个人配置。
配置文件结构
{
"hooks": {
"before_write": {
"command": "node scripts/pre-format.js",
"timeout": 5000,
"blocking": true,
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"]
},
"after_write": {
"command": "./scripts/lint-check.sh",
"timeout": 10000,
"blocking": false
},
"before_command": {
"command": "bash scripts/command-guard.sh",
"timeout": 3000,
"blocking": true,
"exclude_commands": ["git*", "npm*", "pnpm*"]
},
"after_task": {
"command": "node scripts/task-summary.js",
"timeout": 15000,
"blocking": false
}
}
}
配置字段说明
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
command | string | 必填 | 要执行的命令或脚本路径 |
timeout | number | 10000 | 超时时间(毫秒),超过此时间 Hook 会被终止 |
blocking | boolean | true | 是否阻塞主流程(false 表示异步执行,不等待结果) |
files | string[] | 全部 | 文件匹配模式(仅对 before_write/after_write 有效) |
exclude_commands | string[] | 无 | 排除的命令匹配模式(仅对 before_command 有效) |
四、创建你的第一个 Hook
步骤 1:创建配置目录
# 在项目根目录下创建 .claude 目录
mkdir -p .claude/hooks
步骤 2:编写 Hook 脚本
创建一个通用的格式化 Hook 脚本:
cat > .claude/hooks/format-code.sh << 'SCRIPT'
#!/bin/bash
# Claude Code Hook: 在写入文件前自动格式化代码
# 用途:保证所有写入代码的格式一致性
FILE_PATH="$1"
FILE_EXT="${FILE_PATH##*.}"
case "$FILE_EXT" in
js|jsx|ts|tsx)
npx prettier --write "$FILE_PATH" 2>/dev/null || true
;;
py)
python -m black --quiet "$FILE_PATH" 2>/dev/null || true
;;
go)
gofmt -w "$FILE_PATH" 2>/dev/null || true
;;
rs)
rustfmt "$FILE_PATH" 2>/dev/null || true
;;
esac
echo "[Hook] 已格式化: $FILE_PATH"
SCRIPT
chmod +x .claude/hooks/format-code.sh
步骤 3:注册 Hook
创建或编辑 .claude/settings.local.json:
{
"hooks": {
"before_write": {
"command": "bash .claude/hooks/format-code.sh \"$CLAUDE_HOOK_FILE\"",
"timeout": 5000,
"blocking": true,
"files": ["*.js", "*.ts", "*.tsx", "*.py", "*.go", "*.rs"]
}
}
}
步骤 4:验证 Hook 生效
在 Claude Code 中让 Claude 修改一个代码文件:
# Claude Code 会自动调用 before_write Hook
# 你应该在终端中看到类似输出:
# [Hook] 已格式化: src/app.ts
五、Hook 脚本编写指南
环境变量
Hook 脚本可以访问以下环境变量:
| 变量名 | 说明 | 适用 Hook |
|---|---|---|
CLAUDE_HOOK_FILE | 当前操作的文件路径 | before_write, after_write, before_read, after_read |
CLAUDE_HOOK_TYPE | Hook 类型名称 | 全部 |
CLAUDE_HOOK_COMMAND | 即将执行的命令 | before_command, after_command |
CLAUDE_PROJECT_ROOT | 项目根目录路径 | 全部 |
脚本签名规范
#!/bin/bash
# 对于 before_write / after_write:
# 第一个参数通常是文件路径,也可以通过 $CLAUDE_HOOK_FILE 获取
set -euo pipefail # 推荐:严格模式
# 日志输出(会显示在 Claude Code 终端中)
echo "[Hook:$CLAUDE_HOOK_TYPE] 开始处理 $CLAUDE_HOOK_FILE"
# 你的逻辑...
echo "[Hook:$CLAUDE_HOOK_TYPE] 处理完成"
返回值约定
- 退出码 0:Hook 执行成功,主流程继续
- 退出码非 0(仅在 blocking=true 时):Hook 执行失败,主流程停止并报错
# before_write Hook 返回非 0 会阻止文件写入!
# 适用于:检查到安全问题、格式校验失败等场景
if ! npx eslint "$CLAUDE_HOOK_FILE"; then
echo "[Hook] ESLint 检查失败,阻止写入"
exit 1 # ❌ 这会阻止文件保存
fi
超时处理
为所有 Hook 设置合理的超时时间:
| Hook 类型 | 建议超时 | 原因 |
|---|---|---|
| before_write | 3-10 秒 | 格式化应该很快 |
| after_write | 5-15 秒 | Lint/编译可能需要更多时间 |
| before_command | 3-5 秒 | 安全检查应迅速 |
| after_task | 10-30 秒 | 报告生成可能稍慢 |
六、实战案例
案例 1:Python 项目自动格式化 + 类型检查
.claude/hooks/python-check.sh:
#!/bin/bash
set -euo pipefail
FILE="$CLAUDE_HOOK_FILE"
if [[ ! "$FILE" =~ \.py$ ]]; then
exit 0
fi
echo "[Hook] Python 格式化检查: $FILE"
# 第一步:自动格式化
black --quiet "$FILE"
# 第二步:排序 import
isort --quiet "$FILE"
# 第三步:类型检查(非阻塞,仅提示)
mypy "$FILE" --show-error-codes 2>&1 | head -5 || true
echo "[Hook] Python 文件处理完成"
注册配置:
{
"hooks": {
"before_write": {
"command": "bash .claude/hooks/python-check.sh",
"timeout": 10000,
"blocking": true,
"files": ["*.py"]
}
}
}
案例 2:安全命令守卫
.claude/hooks/command-guard.sh:
#!/bin/bash
set -euo pipefail
COMMAND="$CLAUDE_HOOK_COMMAND"
# 危险命令列表
DANGEROUS_COMMANDS=(
"rm -rf /"
"sudo rm"
"dd if=/dev/zero"
"chmod -R 777"
">.*/dev/"
"DROP DATABASE"
"TRUNCATE TABLE"
"git push --force"
)
echo "[安全卫士] 检查命令: ${COMMAND:0:100}..."
for pattern in "${DANGEROUS_COMMANDS[@]}"; do
if echo "$COMMAND" | grep -iqE "$pattern"; then
echo "[安全卫士] ⚠️ 检测到危险命令: $pattern"
echo "[安全卫士] 操作已阻止!如需执行,请在 Claude Code 中手动确认。"
exit 1
fi
done
echo "[安全卫士] 命令安全检查通过 ✓"
案例 3:任务完成自动生成摘要
.claude/hooks/task-summary.sh:
#!/bin/bash
set -euo pipefail
SUMMARY_FILE="$CLAUDE_PROJECT_ROOT/.claude/task-summary.md"
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
{
echo "## 任务完成报告 — $TIMESTAMP"
echo ""
echo "**项目**: $CLAUDE_PROJECT_ROOT"
echo "**Hook 类型**: $CLAUDE_HOOK_TYPE"
echo ""
echo "### 修改的文件"
git diff --name-only 2>/dev/null || echo "(未检测到 Git 仓库)"
echo ""
echo "---"
echo ""
} >> "$SUMMARY_FILE"
echo "[Hook] 任务摘要已追加到 $SUMMARY_FILE"
案例 4:TypeScript/React 项目全流程自动化
完整的 .claude/settings.local.json:
{
"hooks": {
"before_write": {
"command": "bash .claude/hooks/pre-write.sh",
"timeout": 8000,
"blocking": true,
"files": ["*.ts", "*.tsx", "*.js", "*.jsx", "*.css", "*.json"]
},
"after_write": {
"command": "bash .claude/hooks/post-write.sh",
"timeout": 15000,
"blocking": false,
"files": ["*.ts", "*.tsx"]
},
"before_command": {
"command": "bash .claude/hooks/command-guard.sh",
"timeout": 3000,
"blocking": true,
"exclude_commands": ["npm*", "pnpm*", "yarn*", "git status*", "ls*", "cat*"]
},
"after_task": {
"command": "bash .claude/hooks/task-summary.sh",
"timeout": 5000,
"blocking": false
}
}
}
七、调试与排查
检查 Hook 是否生效
# 查看当前 Claude Code 配置
claude config list
# 查看 settings.local.json 内容
cat .claude/settings.local.json
查看 Hook 执行日志
Claude Code 会在终端输出 Hook 的执行信息。如果 Hook 出错,你会看到类似:
[Hook] before_write: ❌ 退出码 1
[Hook] 错误: ESLint 检查失败
常用调试技巧
- 先跑脚本本身:在终端直接运行 Hook 脚本,确保它独立工作正常
# 模拟 Hook 环境变量
CLAUDE_HOOK_FILE="src/app.ts" bash .claude/hooks/format-code.sh
-
逐步减少复杂性:先用一个简单的
echo "Hello"脚本确认 Hook 机制工作,再替换为真实逻辑 -
检查路径:Hook 脚本的工作目录是项目根目录,不是脚本所在目录。使用绝对路径或
$CLAUDE_PROJECT_ROOT -
日志重定向:将日志写入文件而非仅输出到终端
# 在 Hook 脚本中
exec >> "$CLAUDE_PROJECT_ROOT/.claude/hooks.log" 2>&1
echo "[$(date)] Hook 开始: $CLAUDE_HOOK_TYPE"
常见错误与解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| Hook 不执行 | 配置文件语法错误 | 检查 JSON 格式,用 jsonlint 验证 |
| Hook 超时 | 脚本执行时间过长 | 增大 timeout 值或优化脚本 |
| 文件写入被阻止 | blocking=true 的 Hook 返回非 0 | 检查 Hook 脚本逻辑 |
| 环境变量为空 | 使用方式不正确 | 使用 $CLAUDE_HOOK_FILE 而非参数传递 |
| 脚本路径错误 | 相对路径问题 | 使用脚本所在目录的完整路径 |
八、安全注意事项
正确做法
- ✅ 使用
files字段限制 Hook 只作用于特定文件类型 - ✅ 使用
exclude_commands跳过已知安全的命令 - ✅ 在开发和测试阶段使用
blocking: false - ✅ 为脚本设置合理的 timeout 值
- ✅ 定期审查 Hook 脚本的内容
错误做法
- ❌ 在 Hook 中执行
rm -rf等破坏性操作 - ❌ Hook 脚本读取敏感信息(密码、密钥)
- ❌ 设置过长(> 60 秒)的 blocking 超时
- ❌ 跳过错误处理(不使用
set -e) - ❌ 在生产环境中调试未测试的 Hook
九、常见问题
Q1:Hook 脚本可以访问网络吗?
可以。Hook 脚本可以执行任何 shell 命令,包括网络请求。但建议将网络操作放在 blocking: false 的 Hook 中,避免阻塞主流程。
Q2:多个 Hook 可以同时注册吗?
是的。可以为同一个事件注册多个 Hook,但每个事件只能有一个 command 配置。如果需要执行多个操作,请在脚本内部串联:
#!/bin/bash
# 在单个 Hook 脚本中执行多个操作
npm run format
npm run lint
npm run test:quick
Q3:如何在不同项目间共享 Hook?
你可以将 Hook 脚本放在 Git 仓库中共享,或者创建一个模板项目:
# 创建 Hook 模板
mkdir -p ~/.claude-templates/hooks/
cp my-hooks/* ~/.claude-templates/hooks/
# 在新项目中引用
ln -s ~/.claude-templates/hooks/ .claude/hooks/
Q4:before_write Hook 修改了文件内容会怎样?
Claude Code 会将你修改后的内容写入磁盘。这意味着 Hook 可以修改即将写入的内容——这是格式化和代码注入的基础机制。
Q5:生产环境 vs 开发环境需要不同的 Hook 配置?
推荐使用 Git 分支或环境变量区分:
{
"hooks": {
"before_write": {
"command": "bash .claude/hooks/pre-write.sh --env ${NODE_ENV:-development}",
"timeout": 10000,
"blocking": true,
"files": ["*.ts", "*.tsx"]
}
}
}
然后在脚本内根据 $NODE_ENV 执行不同的逻辑。
Q6:Hook 执行失败会影响我正在编辑的代码吗?
- blocking: true:如果 Hook 返回非 0 退出码,会阻止操作进行(如阻止文件写入)。你的代码不会被修改。
- blocking: false:Hook 异步执行,即使失败也不影响主流程。
总结:Hooks 是 Claude Code 中极具威力的自动化工具。通过合理配置 before_write 实现格式化自动化、before_command 提供安全防护、after_task 生成报告总结,你可以大幅减少重复性工作,将精力集中在真正需要创造力的编码任务上。