Skip to content

用 Hooks 自动化工作流

Hooks 是用户自定义的 shell 命令,在 Claude Code 生命周期的特定节点自动执行——确保某些操作必然发生,而不是依赖 LLM 去"选择"是否执行。本文涵盖最常用的自动化场景:编辑后代码格式化、保护敏感文件、桌面通知、上下文压缩后重注入关键信息、配置变更审计、目录切换时重载环境变量,以及自动批准特定权限请求。每个场景都附有可直接使用的配置块。

Hooks 让你对 Claude Code 的行为有确定性控制,确保某些操作总是发生,而不是依赖 LLM 来决定要不要执行。可以用 Hooks 来强制执行项目规范、自动化重复任务,以及将 Claude Code 与现有工具集成。

对于需要"判断力"而非确定性规则的场景,还可以使用基于 prompt 的 hooks基于 agent 的 hooks,让 Claude 模型来评估条件。

其他扩展 Claude Code 的方式:skills(给 Claude 添加指令和可执行命令)、subagents(在隔离上下文中运行任务)、plugins(打包扩展以跨项目共享)。


配置第一个 Hook

创建 Hook 需要在设置文件中添加 hooks 块。下面以"桌面通知"为例演示:当 Claude 等待你输入时发送通知,这样就不用一直盯着终端了。

第一步:添加配置

打开 ~/.claude/settings.json,添加 Notification hook:

macOS

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Linux

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
          }
        ]
      }
    ]
  }
}

Windows(PowerShell)

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
          }
        ]
      }
    ]
  }
}

macOS 通知不显示?osascript 通过内置 Script Editor 应用发送通知。如果 Script Editor 没有通知权限,命令会静默失败。在终端运行一次 osascript -e 'display notification "test"',然后打开系统设置 → 通知,找到 Script Editor,开启允许通知


常用自动化场景

编辑后自动格式化代码

每次 Claude 编辑文件后自动运行 Prettier,保持格式统一。这个 hook 使用 PostToolUse 事件配合 Edit|Write matcher,只在文件编辑工具后触发。命令用 jq 从事件中提取编辑的文件路径,传给 Prettier。

将以下配置添加到项目根目录的 .claude/settings.json

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

保护敏感文件不被修改

防止 Claude 修改 .envpackage-lock.json.git/ 等文件。Claude 会收到说明被拦截原因的反馈,从而调整方案。这个例子使用独立脚本文件,检查目标文件路径是否匹配保护规则,匹配则以退出码 2 拦截操作。

第一步:创建脚本 .claude/hooks/protect-files.sh

bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done
exit 0

第二步:赋予执行权限

bash
chmod +x .claude/hooks/protect-files.sh

第三步:在 .claude/settings.json 注册 Hook

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

上下文压缩后重注入关键信息

上下文窗口满了会触发压缩(compaction),可能丢失重要细节。用带 compact matcher 的 SessionStart hook,在每次压缩后自动重注入关键信息。命令写到 stdout 的文本都会加入 Claude 的上下文。

json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
          }
        ]
      }
    ]
  }
}

可以将 echo 替换为动态输出的命令,比如 git log --oneline -5 显示最近提交。

如果要在每次会话开始时注入上下文(而非只在压缩后),考虑使用 CLAUDE.md。环境变量的持久化参见 CLAUDE_ENV_FILE

记录配置变更审计日志

追踪会话中 settings 或 skills 文件的变更,可用于合规或拦截未授权修改。这个例子把每次变更追加到审计日志:

json
{
  "hooks": {
    "ConfigChange": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{timestamp: now | todate, source:.source, file:.file_path}' >> ~/claude-config-audit.log"
          }
        ]
      }
    ]
  }
}

matcher 过滤配置类型:user_settingsproject_settingslocal_settingspolicy_settingsskills。以退出码 2 退出或返回 {"decision": "block"} 可以阻止变更生效。详见 ConfigChange 参考

目录切换时重载环境变量

有些项目根据目录设置不同的环境变量,direnv 在普通 shell 中可以自动处理,但 Claude 的 Bash 工具不会自动感知目录变更。CwdChanged hook 在每次 Claude 切换目录时运行,写入 CLAUDE_ENV_FILE 的值会在每条 Bash 命令前应用:

json
{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}

自动批准特定权限请求

对于总是允许的操作,可以跳过确认对话框。这个例子自动批准 ExitPlanMode 权限请求(Claude 展示计划后请求继续执行时):

json
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
          }
        ]
      }
    ]
  }
}

尽量缩小 matcher 范围。空 matcher 会自动批准所有权限请求,包括文件写入和 shell 命令,非常危险。


Prompt-based Hooks

对于需要判断而非规则的场景,可以使用 type: "prompt" hooks,让 Claude 模型(默认 Haiku)来评估条件,返回 {"ok": true}{"ok": false, "reason": "..."}


Agent-based Hooks

需要访问文件或运行命令来验证条件时,用 type: "agent" hooks。子代理可以读文件、搜索代码,再返回决策,比 prompt hook 更强大。


配置文件位置

Hook 配置写在 hooks 块中,添加到任意设置文件即可。不同位置的设置文件作用范围不同:

文件作用范围
~/.claude/settings.json所有项目(全局)
.claude/settings.json当前项目(可提交到版本控制)
.claude/settings.local.json当前项目本地(不共享)

故障排查题排查

Hook 没有触发

  • 运行 /hooks 确认 hook 出现在正确事件下
  • 检查 matcher 是否大小写匹配(区分大小写)
  • 非交互模式(-p)下 PermissionRequest hook 不触发,改用 PreToolUse

命令找不到 用绝对路径或 $CLAUDE_PROJECT_DIR 引用脚本;确保脚本有执行权限(chmod +x)。

Stop hook 死循环 在 hook 脚本中检查 stop_hook_active 字段:

bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0
fi

claude --debugCtrl+O 开启详细模式查看 hook 执行详情。


相关文档

  • Hooks 完整参考:事件完整列表、JSON schema、HTTP hooks
  • Skills:给 Claude 添加自定义指令和可执行命令
  • Sub-agents:在隔离上下文中运行任务

常见问题

Q: Hooks 和 CLAUDE.md 有什么区别,什么时候该用哪个?

CLAUDE.md 是静态指令,Claude 读取后"知道"要怎么做,但不一定每次都会执行。Hooks 是确定性的,事件触发时必然执行,不依赖 Claude 的判断。需要"每次都要发生"的操作(格式化、通知、保护文件)用 Hooks;需要 Claude 理解项目规范用 CLAUDE.md。

Q: Hook 命令可以访问哪些上下文信息?

通过 stdin 以 JSON 格式接收事件数据,用 jq 提取需要的字段。不同事件包含不同字段,例如 PreToolUse 包含 tool_nametool_inputSessionStart 包含 trigger(启动原因)。完整字段列表见 Hooks 参考

Q: 如何安全地自动批准权限请求,防止过度授权?

用精确的 matcher 限定只自动批准特定工具或操作,绝不用空 matcher 批准所有请求。比如 Bash(npm test) 只允许 npm test,而不是所有 Bash 命令。批准范围越小越安全。