Claude Code Hooks 实战:让 Agent 自动遵守团队规范
Hooks 是 Claude Code 中容易被忽视但极强大的特性——它能拦截工具调用,让 Agent 在每次操作前后跑一段你定义的命令。本文给几个生产用法。
Hook 是什么
~/.claude/settings.json 里配置:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "/usr/local/bin/check-bash.sh"
}]
}
]
}
}
Agent 每次要跑 Bash 命令前,先调用 check-bash.sh。脚本返回非 0 就阻断。
用法 1:禁止某些命令
#!/bin/bash
# /usr/local/bin/check-bash.sh
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
# 禁止 rm -rf /
if [[ "$CMD" =~ "rm -rf /" ]]; then
echo "DANGEROUS COMMAND BLOCKED" >&2
exit 2
fi
# 禁止 force push 到 main
if [[ "$CMD" =~ "git push.*--force.*main" ]]; then
echo "Force push to main is forbidden" >&2
exit 2
fi
exit 0
用法 2:每次文件修改后自动 lint
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "bash -c 'PATH=$PATH:/usr/local/bin; FILE=$(cat | jq -r .tool_input.file_path); [[ $FILE == *.py ]] && ruff check $FILE'"
}]
}
]
}
}
修改 Python 文件后自动跑 ruff,有问题 Agent 会看到并修复。
用法 3:操作生产前必须二次确认
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "/usr/local/bin/prod-check.sh"
}]
}
]
}
}
#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
# 涉及生产环境的命令
if echo "$CMD" | grep -qE "kubectl.*-n.*prod|ssh.*prod-"; then
# 通过 macOS 通知 + 阻断,让人确认
osascript -e "display notification "Claude wants to: $CMD" with title "Prod Action""
echo "Prod operation needs manual approval. Add 'CONFIRMED:' prefix to bypass." >&2
exit 2
fi
exit 0
用法 4:所有 git commit 加固定 footer
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "/usr/local/bin/inject-footer.sh"
}]
}
]
}
}
#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
if [[ "$CMD" =~ ^git\ commit ]]; then
# 修改命令,注入 footer
NEW_CMD=$(echo "$CMD" | sed 's/\(-m "[^"]*\)/\1\n\nReviewed-by: AI/')
jq -n --arg cmd "$NEW_CMD" '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"ok","updatedInput":{"command":$cmd}}}'
fi
exit 0
Hook 类型一览
| 事件 | 触发时机 |
|---|---|
| PreToolUse | 工具调用前 |
| PostToolUse | 工具调用后 |
| Notification | 需要用户输入时 |
| Stop | 对话结束时 |
| SubagentStop | 子 Agent 结束时 |
调试 Hook
加 2>>/tmp/hook.log 把 stderr 留下来:
"command": "/usr/local/bin/check-bash.sh 2>>/tmp/hook.log"
然后 tail -f /tmp/hook.log 看实际触发情况。
教训:Hook 是给 Agent 加"硬约束"的唯一方式,比 CLAUDE.md 里写"不要做 X"可靠 10 倍——Agent 可能忘记规则,但 Hook 不会。