Hooks 是 Claude Code 的工作流自动化机制,让你在 Claude 的生命周期关键节点运行自定义 Shell 命令——无需 LLM 判断,确定性地执行。格式化代码、发送通知、保护文件、注入上下文……一切皆可自动化。
30 秒创建第一个 Hook
最快的方式是通过 /hooks 交互菜单:
1. 在 Claude Code 中输入 /hooks
2. 选择 Notification 事件
3. 设置 matcher 为 *(匹配所有通知)
4. 选择 + Add new hook...
5. 输入通知命令(见下文)
6. 选择保存位置(User settings = 所有项目)
各平台通知命令:
# macOS(原生系统通知)
osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'
# Linux(notify-send,大多数桌面预装)
notify-send 'Claude Code' 'Claude Code needs your attention'
# Windows PowerShell
powershell.exe -Command "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')"五大常用自动化场景
1. Claude 需要输入时通知你
{
"hooks": {
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}]
}]
}
}触发时机:Claude 完成工作等待你的输入,或需要权限确认时。
2. 编辑后自动格式化代码
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}]
}]
}
}用 jq 从 Hook 输入 JSON 中提取被编辑的文件路径,然后运行 Prettier 格式化。
需要安装
jq:brew install jq(macOS)或apt-get install jq(Ubuntu)
3. 阻止对受保护文件的编辑
#!/bin/bash
# ~/.claude/hooks/protect-files.sh
FILE=$(cat | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *".env"* ]] || [[ "$FILE" == *"secrets"* ]]; then
echo '{"decision": "block", "reason": "Cannot edit sensitive files"}'
exit 0
fi
echo '{}'{
"hooks": {
"PreToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "~/.claude/hooks/protect-files.sh"
}]
}]
}
}4. 压缩后重新注入上下文
{
"hooks": {
"PostCompact": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "cat ~/.claude/project-context.md"
}]
}]
}
}/compact 后,Hook 的输出会注入到下一轮对话的上下文中,确保关键信息不丢失。
5. 审计配置变更
#!/bin/bash
# 监控 Claude 对 settings.json 的修改
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *"settings.json"* ]]; then
echo "[$(date)] Claude modified: $FILE" >> ~/.claude/audit.log
echo "$INPUT" | jq '.tool_input' >> ~/.claude/audit.log
fi
echo '{}'Hook 生命周期事件
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
PreToolUse | 工具执行前 | 验证命令、阻止危险操作、修改输入 |
PostToolUse | 工具执行后 | 格式化、测试、发送通知 |
Notification | Claude 需要注意时 | 桌面通知、消息推送 |
PostCompact | 对话压缩后 | 重新注入关键上下文 |
SessionStart | 新会话开始时 | 加载项目状态、设置环境 |
Stop | Claude 完成任务时 | 最终验证、汇报、清理 |
三类 Hook 类型
1. Command Hook(Shell 命令)
最常用的类型,直接运行 Shell 命令:
{
"type": "command",
"command": "your-shell-command"
}2. Prompt Hook(LLM 判断)
需要 AI 判断而非固定规则时使用:
{
"type": "prompt",
"prompt": "检查这个命令是否安全可以执行。如果安全返回 allow,否则返回 block 并说明原因。"
}适合:动态安全检查、语义验证、需要理解上下文的决策。
3. Agent Hook(独立 Agent 执行)
使用独立的 Subagent 执行复杂逻辑:
{
"type": "agent",
"agent": "security-reviewer"
}适合:复杂的代码审查、多步骤验证、需要访问文件系统的 Hook 逻辑。
HTTP Hook(Webhook)
向外部服务发送事件:
{
"type": "http",
"url": "https://your-webhook.example.com/claude-events",
"method": "POST"
}适合:CI/CD 集成、监控系统通知、团队协作工具推送。
Hook 输入/输出规范
输入(stdin JSON):
{
"session_id": "abc123",
"tool_name": "Edit",
"tool_input": {
"file_path": "/path/to/file.py",
"old_string": "old code",
"new_string": "new code"
}
}输出(stdout JSON):
| 字段 | 类型 | 说明 |
|---|---|---|
decision | string | allow(允许)/ block(阻止)/ ask(询问用户) |
reason | string | 决策原因(显示给用户或 Claude) |
output | string | 注入到 Claude Context 的内容 |
updatedInput | object | 修改后的工具输入(PreToolUse 专用,可改写 Claude 的操作) |
简单示例——格式化后注入结果:
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ -n "$FILE" ]]; then
RESULT=$(npx prettier --write "$FILE" 2>&1)
echo "{\"output\": \"Formatted: $FILE. $RESULT\"}"
else
echo '{}'
fi阻止危险命令:
#!/bin/bash
COMMAND=$(cat | jq -r '.tool_input.command // empty')
if echo "$COMMAND" | grep -qE 'rm -rf|DROP TABLE|DELETE FROM.*WHERE 1'; then
echo '{"decision": "block", "reason": "Potentially destructive command blocked"}'
else
echo '{"decision": "allow"}'
fi用 Matcher 过滤 Hook 触发条件
Matcher 决定 Hook 在哪些情况下触发:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write", // 只在 Edit 或 Write 工具后触发
"hooks": [{"type": "command", "command": "prettier ..."}]
},
{
"matcher": "Bash", // 只在 Bash 工具后触发
"hooks": [{"type": "command", "command": "echo 'Bash executed'"}]
},
{
"matcher": "", // 空 = 所有工具都触发
"hooks": [{"type": "command", "command": "log-tool-use.sh"}]
}
]
}
}存储位置与作用域
| 文件位置 | 作用范围 | 适合场景 |
|---|---|---|
~/.claude/settings.json | 所有项目(User 级) | 通知、个人偏好 |
.claude/settings.json | 当前项目(Project 级) | 项目特定的格式化、保护规则 |
.claude/settings.local.json | 当前项目(Local,不入 git) | 个人项目偏好 |
故障排查
| 问题 | 解决方案 |
|---|---|
| Hook 不触发 | 检查 matcher 是否匹配工具名称,确认 settings.json 路径正确 |
| Hook 输出显示错误 | 检查 Shell 脚本权限(chmod +x),确认命令路径正确 |
/hooks 显示未配置 | 确认 settings.json 格式正确(用 jq . settings.json 验证) |
| Stop Hook 永远运行 | 检查脚本是否有无限循环或等待输入,设置超时 |
| JSON 验证失败 | Hook 输出必须是有效 JSON 或空字符串,用 jq 生成输出 |
调试技巧:
# 在 Hook 脚本中加日志
echo "[$(date)] Hook triggered: $TOOL_NAME" >> /tmp/hook-debug.log
cat >> /tmp/hook-debug.log # 记录完整输入原文:Automate workflows with hooks | 来源:Anthropic 官方文档