Hooks 钩子系统详解
Hooks 钩子系统详解
Hooks 是 Claude Code 中的事件驱动自动化机制,允许在特定事件触发时自动执行自定义脚本,用于自定义工作流、拦截危险操作、自动格式化代码等场景。
一、什么是 Hooks?
核心概念
Hooks 是在特定事件触发时自动执行的脚本,具有以下特点:
- 事件驱动:在特定事件发生时自动触发
- 自动化:可以自动执行预定义的操作
- 拦截能力:可以阻止危险操作
- 灵活配置:支持阻塞和非阻塞模式
核心价值
┌───────────────────────────┐
│ 事件触发流程 │
│ │
│ ┌─────────┐ ┌─────────────┐ │
│ │ 事件触发 │ → │ Hook 拦截 │ → │ 执行自定义脚本 │ │
│ └─────────┘ └─────────────┘ │
│ ↓ │
│ ┌───────────────┐ │
│ │ 返回结果 │ │
│ │ 继续/阻止操作 │ │
│ └───────────────┘ │
└─────────────────────────────┘
二、Hook 事件类型
| 事件类型 | 触发时机 | 典型用途 |
|----------|----------|----------|
| user-prompt-submit | 用户提交提示词前 | 验证、修改提示词 |
| tool-use | 工具使用前 | 权限检查、参数验证 |
| after-tool-use | 工具使用后 | 日志记录、结果处理 |
| permission-request | 权限请求时 | 拦截危险操作 |
| notification | 通知时 | 发送告警、更新状态 |
| task-complete | 任务完成时 | 发送通知、更新状态 |
三、配置方式
方式一:通过 /hooks 命令
# 在 Claude Code 中
/hooks
方式二:通过配置文件
在 ~/.claude/settings.json 或项目 .claude/settings.json 中配置:
{
"hooks": {
"user-prompt-submit-hook": {
"command": "npm run validate-prompt",
"enabled": true
},
"tool-use-hook": {
"command": "~/.claude/hooks/check-permission.sh",
"enabled": true,
"blocking": true
},
"after-tool-use-hook": {
"command": "echo 'Tool used: {{toolName}}' >> ~/.claude/hooks.log",
"enabled": true
},
"permission-request-hook": {
"command": "~/.claude/hooks/check-dangerous.sh",
"enabled": true,
"blocking": true
}
}
}
配置参数说明
| 参数 | 说明 | 必填 |
|------|------|------|
| command | 要执行的命令 | 是 |
| enabled | 是否启用 | 否(默认 true) |
| blocking | 是否阻塞主流程 | 否(默认 false) |
四、Hook 实战示例
示例 1:拦截危险命令
创建 ~/.claude/hooks/check-dangerous.sh:
#!/bin/bash
# ~/.claude/hooks/check-dangerous.sh
# 读取工具调用信息
TOOL_NAME=$(jq -r '.toolName' <<< "$CLAUDE_HOOK_INPUT")
# 危险操作列表
DANGEROUS_TOOLS=("rm" "delete" "format" "shutdown" "reboot")
if [[ " ${DANGEROUS_TOOLS[@]} " =~ " ${TOOL_NAME} " ]]; then
echo "⚠️ 警告:即将执行危险操作 - $TOOL_NAME"
echo "请确认是否继续? (yes/no)"
read -r confirmation
if [[ "$confirmation" != "yes" ]]; then
exit 1 # 阻止操作
fi
fi
exit 0
示例 2:自动格式化代码
{
"hooks": {
"after-write-hook": {
"command": "if [[ {{filePath}} == *.js ]]; then prettier --write {{filePath}}; fi",
"enabled": true,
"blocking": false
}
}
}
示例 3:发送通知
{
"hooks": {
"task-complete-hook": {
"command": "notify-send 'Claude Code' '任务已完成'",
"enabled": true
}
}
}
示例 4:日志记录
{
"hooks": {
"after-tool-use-hook": {
"command": "echo '$(date): {{toolName}} - {{filePath}}' >> ~/.claude/hooks.log",
"enabled": true,
"blocking": false
}
}
}
五、实战案例:消灭 CI 格式报错
来自 Claude Code 创始人的实战经验,使用 Hook 彻底解决 CI 中的格式问题:
配置
{
"hooks": {
"after-tool-use-hook": {
"command": "bun run format || true",
"enabled": true,
"blocking": false
}
}
}
工作原理
- 每次 Claude 使用
Write或Edit工具后自动触发 - 运行格式化命令(这里是
bun run format) || true确保即使格式化失败也不阻塞流程- Claude 已经写得很规范,但这最后 10% 的自动化处理能彻底解决格式问题
效果
- ✅ CI 中不再有格式报错
- ✅ 代码风格始终一致
- ✅ 无需手动运行格式化
- ✅ Git diff 更清晰
六、Hook 模板
通用 Hook 模板
#!/bin/bash
# Hook 名称:xxx
# 用途:xxx
# 触发事件:xxx
# 获取环境变量
TOOL_NAME=${CLAUDE_TOOL_NAME:-""}
FILE_PATH=${CLAUDE_FILE_PATH:-""}
USER_INPUT=${CLAUDE_USER_INPUT:-""}
# 业务逻辑
if [ 条件 ]; then
# 执行操作
echo "执行的操作"
fi
# 返回结果
exit 0 # 允许操作继续
# 或
exit 1 # 阻止操作
复杂 Hook 示例
#!/bin/bash
# 复杂的权限检查 Hook
# 读取完整输入
INPUT=$(cat)
# 解析参数
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
FILE_PATH=$(echo "$INPUT" | jq -r '.filePath')
USER_ID=$(echo "$INPUT" | jq -r '.userId')
# 危险操作检查
DANGEROUS_PATTERN=("rm" "format" "delete" "shutdown")
for pattern in "${DANGEROUS_PATTERN[@]}"; do
if [[ "$TOOL_NAME" == *"$pattern"* ]]; then
# 记录危险操作
echo "危险操作检测: $TOOL_NAME on $FILE_PATH"
# 发送告警
curl -X POST "https://hooks.slack.com/services/xxx" \
-d "{\"text\":\"危险操作: $USER_ID 执行了 $TOOL_NAME\"}"
exit 1 # 阻止操作
fi
done
exit 0
七、最佳实践
1. 最小权限原则
{
"hooks": {
"tool-use-hook": {
"command": "~/.claude/hooks/lightweight-check.sh",
"enabled": true,
"blocking": true
}
}
}
避免使用重量级的检查脚本,尽量保持轻量快速。
2. 非阻塞优先
{
"hooks": {
"after-tool-use-hook": {
"command": "~/.claude/hooks/log.sh",
"enabled": true,
"blocking": false
}
}
}
除非必要,否则使用非阻塞模式,不影响主流程。
3. 错误处理
#!/bin/bash
# 带有错误处理的 Hook
set -e # 遇到错误立即退出
# 主逻辑
if [ "$TOOL_NAME" == "write" ]; then
# 执行操作
echo "Write operation detected"
fi
exit 0
4. 调试技巧
#!/bin/bash
# 调试模式 Hook
# 开启调试
set -x
# 主逻辑
echo "Tool: $TOOL_NAME"
echo "File: $FILE_PATH"
exit 0
八、常见问题
问题 1:Hook 不触发
可能原因:
- Hook 未在配置中启用
- 命令路径错误
- 脚本没有执行权限
解决方案:
# 检查配置文件
cat ~/.claude/settings.json | grep hooks
# 检查脚本权限
ls -la ~/.claude/hooks/
# 手动测试脚本
~/.claude/hooks/check-dangerous.sh
问题 2:Hook 阻塞主流程
可能原因:
blocking设置为true- 脚本执行时间过长
解决方案:
{
"hooks": {
"tool-use-hook": {
"command": "~/.claude/hooks/slow-check.sh",
"enabled": true,
"blocking": false
}
}
}
问题 3:权限不足
错误信息:
Permission denied: xxx.sh
解决方案:
# 添加执行权限
chmod +x ~/.claude/hooks/*.sh
九、进阶技巧
1. 条件 Hook
{
"hooks": {
"tool-use-hook": {
"command": "~/.claude/hooks/conditional.sh",
"enabled": true,
"blocking": true,
"conditions": {
"tools": ["write", "edit"],
"paths": ["src/**/*.ts"]
}
}
}
}
2. 链式 Hook
#!/bin/bash
# 主 Hook 触发其他 Hook
# 执行前置检查
~/.claude/hooks/pre-check.sh
# 执行主操作
if [ "$TOOL_NAME" == "write" ]; then
~/.claude/hooks/format.sh
fi
# 执行后置处理
~/.claude/hooks/post-process.sh
3. 环境变量传递
#!/bin/bash
# 读取 Claude Code 环境变量
echo "当前工具: $CLAUDE_TOOL_NAME"
echo "当前文件: $CLAUDE_FILE_PATH"
echo "用户输入: $CLAUDE_USER_INPUT"
# 使用环境变量进行逻辑判断
if [ "$CLAUDE_TOOL_NAME" == "bash" ]; then
echo "检测到 bash 命令执行"
fi
十、总结
通过本指南,你已经了解了:
- ✅ Hooks 的核心概念和工作原理
- ✅ Hook 事件类型和触发时机
- ✅ Hook 的配置方式
- ✅ 实用的 Hook 实战示例
- ✅ Hook 的最佳实践
Hooks 是 Claude Code 强大的自动化机制,合理使用 Hooks 可以大大提高开发效率和安全性。