Claude Code: 钩子系统
最后更新:2026-08-31
钩子让你在 Claude Code 的关键节点插入自定义逻辑——修改前自动备份、提交前自动测试、出错时自动回滚。
💡 提示:钩子是 Claude Code 生命周期中的"拦截器"——你在特定事件发生时执行自定义脚本,实现自动化工作流。
📋 前置知识:第十七章 输出样式
1. 你将学到
- 钩子的生命周期与事件类型
- 内置钩子与自定义钩子
- 钩子配置方法
- 实战场景
- 钩子调试与排错
2. 钩子生命周期
(1) 事件类型
graph LR
A[用户输入] --> B[before:prompt]
B --> C[意图解析]
C --> D[before:tool:read]
D --> E[读取文件]
E --> F[after:tool:read]
F --> G[before:tool:write]
G --> H[写入文件]
H --> I[after:tool:write]
I --> J[before:tool:bash]
J --> K[执行命令]
K --> L[after:tool:bash]
L --> M[生成回复]
M --> N[after:response]
| 事件 | 触发时机 | 常见用途 |
|---|---|---|
| before:prompt | 处理用户输入前 | 输入预处理 |
| before:tool:read | 读取文件前 | 记录访问日志 |
| after:tool:read | 读取文件后 | 敏感内容过滤 |
| before:tool:write | 写入文件前 | 自动备份 |
| after:tool:write | 写入文件后 | 自动格式化 |
| before:tool:bash | 执行命令前 | 安全检查 |
| after:tool:bash | 执行命令后 | 结果后处理 |
| after:response | 回复生成后 | 发送通知 |
(2) 钩子上下文
每个钩子接收上下文对象:
TYPESCRIPT
interface HookContext {
event: string;
timestamp: string;
tool?: string;
filePath?: string;
command?: string;
content?: string;
result?: string;
sessionId: string;
}
▶ 示例 1: 钩子触发流程
TEXT
📖 仅展示
> 修改 src/auth/jwt.ts
触发钩子序列:
1. [before:tool:write] → 自动备份 jwt.ts
2. [写入文件]
3. [after:tool:write] → 运行 ESLint --fix
4. [before:tool:bash] → 检查命令安全性
5. [执行: npm test -- auth.test.ts]
6. [after:tool:bash] → 解析测试结果
7. [after:response] → 发送 Slack 通知
3. 钩子配置
(1) 全局钩子配置
JSON
// ~/.claude/hooks.json
{
"hooks": {
"before:tool:write": [
{
"name": "auto-backup",
"command": "cp ${filePath} ${filePath}.bak",
"enabled": true
}
],
"after:tool:write": [
{
"name": "auto-format",
"command": "npx prettier --write ${filePath}",
"enabled": true
}
],
"after:tool:bash": [
{
"name": "log-commands",
"command": "echo '${command}' >> ~/.claude/command-log.txt",
"enabled": true
}
]
}
}
(2) 项目级钩子配置
JSON
// .claude/hooks.json
{
"hooks": {
"before:tool:write": [
{
"name": "protect-config",
"condition": "filePath.endsWith('.env') || filePath.includes('config/prod')",
"command": "echo '拒绝修改配置文件' && exit 1",
"enabled": true
}
],
"after:tool:write": [
{
"name": "lint-fix",
"command": "npx eslint --fix ${filePath} 2>/dev/null || true",
"enabled": true,
"files": ["src/**/*.ts"]
}
]
}
}
4. 实战场景
▶ 示例 2: 自动备份钩子
JSON
{
"hooks": {
"before:tool:write": [
{
"name": "git-backup",
"command": "git stash push -m 'auto-backup-before-claude' -- ${filePath} 2>/dev/null || true",
"enabled": true
}
]
}
}
▶ 示例 3: 安全审查钩子
JSON
{
"hooks": {
"before:tool:bash": [
{
"name": "block-dangerous-commands",
"condition": "command.includes('rm -rf') || command.includes('DROP TABLE') || command.includes('npm publish')",
"command": "echo '⚠️ 危险命令被拦截' && exit 1",
"enabled": true
}
]
}
}
▶ 示例 4: 自动测试钩子
JSON
{
"hooks": {
"after:tool:write": [
{
"name": "auto-test",
"condition": "filePath.includes('src/') && filePath.endsWith('.ts')",
"command": "npm test -- ${filePath.replace('src/', 'tests/').replace('.ts', '.test.ts')} 2>&1 | tail -5",
"enabled": true
}
]
}
}
5. 自定义钩子脚本
▶ 示例 5: 复杂钩子脚本
BASH
#!/bin/bash
# .claude/hooks/notify.sh
# 文件修改后发送通知
FILE_PATH=$1
CHANGE_TYPE=$2
# 只通知关键文件变更
if [[ "$FILE_PATH" == *"/auth/"* ]] || [[ "$FILE_PATH" == *"/payment/"* ]]; then
curl -X POST "https://hooks.slack.com/services/xxx" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"Claude Code 修改了关键文件: $FILE_PATH ($CHANGE_TYPE)\",
\"channel\": \"#code-changes\"
}" 2>/dev/null
fi
JSON
{
"hooks": {
"after:tool:write": [
{
"name": "notify-critical-changes",
"command": "bash .claude/hooks/notify.sh ${filePath} write",
"enabled": true
}
]
}
}
6. 钩子调试与排错
(1) 调试技巧
BASH
# 启用钩子日志
export CLAUDE_HOOK_DEBUG=1
# 查看钩子执行日志
cat ~/.claude/hooks.log
# 临时禁用所有钩子
claude --no-hooks
(2) 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 钩子不触发 | enabled: false | 检查配置 |
| 钩子报错 | 命令路径问题 | 使用绝对路径 |
| 钩子慢 | 脚本执行时间长 | 异步执行或精简逻辑 |
| 循环触发 | 钩子触发另一个钩子 | 加条件避免循环 |
| 权限不足 | 脚本无执行权限 | chmod +x script.sh |
7. 综合示例:完整钩子方案
JSON
{
"hooks": {
"before:tool:write": [
{
"name": "auto-backup",
"command": "cp ${filePath} /tmp/claude-backup/$(basename ${filePath}).$(date +%s)",
"enabled": true
},
{
"name": "protect-env",
"condition": "filePath.endsWith('.env') || filePath.endsWith('.env.local')",
"command": "echo '❌ 禁止修改环境变量文件' && exit 1",
"enabled": true
}
],
"after:tool:write": [
{
"name": "format",
"command": "npx prettier --write ${filePath} 2>/dev/null; npx eslint --fix ${filePath} 2>/dev/null; true",
"enabled": true,
"files": ["src/**/*.ts", "src/**/*.tsx"]
}
],
"before:tool:bash": [
{
"name": "block-dangerous",
"condition": "command.match(/rm -rf|DROP|npm publish|git push --force/)",
"command": "echo '⛔ 危险命令已拦截' && exit 1",
"enabled": true
}
],
"after:response": [
{
"name": "log-session",
"command": "echo '$(date): ${sessionId}' >> ~/.claude/sessions.log",
"enabled": true
}
]
}
}
❓ 常见问题
Q 钩子会拖慢 Claude Code 吗?
A 会。每个钩子需要执行命令,慢钩子会明显影响体验。建议钩子脚本控制在 1 秒内完成。
Q 钩子失败会阻止操作吗?
A before 钩子失败(exit 1)会阻止操作;after 钩子失败不影响已完成操作。
Q 钩子能修改 Claude Code 的输出吗?
A 不能直接修改。钩子只能执行副作用操作(备份、格式化、通知),不改变返回内容。
Q 钩子和插件有什么区别?
A 钩子是轻量级的事件响应(执行命令),插件是完整的功能扩展(注册工具、修改行为)。简单需求用钩子,复杂需求用插件。
Q 钩子配置能提交到 git 吗?
A
.claude/hooks.json 可以提交,团队共享。个人钩子放在全局配置中。Q 如何查看所有已配置的钩子?
A 运行
claude /hooks 查看当前所有钩子配置和状态。📖 小节
- 钩子在 Claude Code 生命周期关键节点触发自定义逻辑
- 核心事件:before/after:tool:write/read/bash
- 自动备份、安全审查、自动格式化是最常用场景
- before 钩子失败可阻止操作,after 钩子失败不影响
- 钩子要快(<1秒),否则影响体验
📝 作业
- 基础题(难度⭐):配置一个
after:tool:write钩子,在文件修改后自动运行 Prettier 格式化。 - 进阶题(难度⭐⭐):配置安全钩子,拦截
rm -rf和npm publish等危险命令。 - 挑战题(难度⭐⭐⭐):设计一套完整的钩子方案,覆盖备份、格式化、安全检查、通知四个维度。