Claude Code Hooks 测评:零成本自动化开发新体验
要说Claude Code里哪个功能最被低估,Hooks绝对算一个。它能在关键时刻自动跑脚本:文件保存后做格式化、危险命令执行前拦一把、任务搞定后发通知。更关键的是——它不占上下文窗口,这是真正的“零成本”自动化。
一、什么是Hooks
简单来说,Hooks就是一系列事件驱动的脚本,在Claude Code生命周期的特定节点自动触发。
Claude的执行流程大致是这样:
用户输入 → Claude推理 → PreToolUse → 工具执行 → PostToolUse → Claude响应 → Stop
↑↑
拦截点 后处理点
核心优势在于,Hooks是作为外部脚本运行的,完全独立于Claude的上下文。你在Hooks里做的任何操作,都不消耗那宝贵的200K token——这才是真正“免费”的自动化手段。
二、触发时机
Hooks支持多种事件,覆盖了整个生命周期:
事件 | 触发时机 | 典型用途 |
|---|---|---|
PreToolUse | 工具执行前 | 拦截危险命令、修改参数 |
PostToolUse | 工具执行后 | 自动格式化、通知 |
Notification | Claude等待输入时 | 桌面通知 |
SessionStart | 会话开始时 | 加载环境变量 |
SessionEnd | 会话结束时 | 清理临时文件 |
Stop | Claude完成响应时 | 验证任务完成 |
PreCompact | 上下文压缩前 | 保存关键信息 |
PostCompact | 上下文压缩后 | 重新注入上下文 |
ConfigChange | 配置文件变化时 | 审计日志 |
三、配置方式
Hooks的配置写在settings.json里,举个例子:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write \"$CLAUDE_FILE_PATH\""
          }
        ]
      }
    ]
  }
}
配置文件可以放在三个位置,作用范围不同:
位置 | 作用域 | 可共享 |
|---|---|---|
~/.claude/settings.json | 所有项目 | 否 |
.claude/settings.json | 单个项目 | 是,可提交Git |
.claude/settings.local.json | 单个项目 | 否,gitignored |
四、实战案例
案例一:桌面通知
让Claude完成任务后自动弹窗提醒你,不用一直盯着终端看进度。
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
macOS用osascript,Linux用notify-send,Windows直接用PowerShell就行。
案例二:自动格式化
每次写完代码,自动跑Prettier格式化:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
案例三:保护敏感文件
阻止Claude修改.env、package-lock.json这些关键文件:
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH is protected"
    exit 2 # exit 2 = 阻止操作
  fi
done
exit 0 # exit 0 = 放行
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
案例四:压缩后重新注入上下文
上下文压缩之后,把项目规则重新注入进去:
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: use Bun, not npm. Run bun test before committing.'"
          }
        ]
      }
    ]
  }
}
案例五:自动审批特定权限
跳过ExitPlanMode的审批对话框:
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"beha vior\": \"allow\"}}}'"
          }
        ]
      }
    ]
  }
}
案例六:环境变量自动加载
配合direnv,目录切换时自动加载环境变量:
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ],
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
五、输入输出机制
Hooks通过stdin接收事件数据,通过stdout/stderr和exit code返回结果。
输入示例
{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}
输出控制
Exit Code | 行为 |
|---|---|
0 | 放行,继续执行 |
2 | 阻止,stderr作为反馈给Claude |
其他 | 放行,但显示警告 |
结构化输出
如果需要更精细的控制,可以返回JSON:
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
六、匹配器
matcher字段
按工具名来过滤:
{
  "matcher": "Edit|Write" // 匹配Edit或Write
}
{
  "matcher": "Bash" // 只匹配Bash
}
{
  "matcher": "mcp__github__.*" // 匹配所有GitHub MCP工具
}
if字段
更细腻一点,按工具参数过滤:
{
  "matcher": "Bash",
  "hooks": [
    {
      "type": "command",
      "if": "Bash(git *)",
      "command": "echo 'Git command detected'"
    }
  ]
}
七、高级用法
HTTP Hooks
把事件数据POST到外部服务:
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "http://localhost:8080/hooks/tool-use",
            "headers": {
              "Authorization": "Bearer $MY_TOKEN"
            },
            "allowedEnvVars": ["MY_TOKEN"]
          }
        ]
      }
    ]
  }
}
Prompt Hooks
让Claude模型来做决策:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains\"}."
          }
        ]
      }
    ]
  }
}
Agent Hooks
启动子Agent做验证:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Verify that all unit tests pass. Run the test suite and check results.",
            "timeout": 120
          }
        ]
      }
    ]
  }
}
八、常见问题
Hook没触发
1. 运行/hooks确认配置存在
2. 检查matcher是否正确(注意大小写)
3. 确认事件类型对不对路
Hook报错
可以先手动测试脚本:
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $? # 查看退出码
常见问题排查:
- 命令找不到 → 用绝对路径
- jq找不到 → 安装jq
- 脚本不执行 → chmod +x ./my-hook.sh
Stop Hook无限循环
需要检查stop_hook_active字段:
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0 # 已经触发过,允许停止
fi
九、最佳实践
1. 优先用PostToolUse而非PreToolUse——PreToolUse可能被拒绝,PostToolUse更稳定
2. 脚本放项目目录——.claude/hooks/可以提交Git,团队共享
3. 用jq解析JSON——比awk/sed靠谱得多
4. stderr给Claude,stdout返回JSON——各司其职
5. 超时设置要合理——默认10分钟,复杂任务可以适当调长
十、Hooks vs Skills vs CLAUDE.md
维度 | Hooks | Skills | CLAUDE.md |
|---|---|---|---|
加载时机 | 事件触发 | 按需加载 | 每次会话 |
上下文成本 | 零 | 描述常驻 | 每次请求都带 |
能力 | 运行脚本 | 提供知识 | 提供规则 |
适用场景 | 自动化 | 工作流 | 项目约定 |
总结一下:Hooks是“自动化”,Skills是“知识库”,CLAUDE.md是“项目宪法”。三者配合得当,效率才能最大化。