Skip to content

Hooks 钩子

Hooks 在 Claude Code 生命周期事件中自动触发的脚本,跟 AI 智能无关 — 是确定性控制

一句话

Hooks 保证执行;提示词只是建议。 用 hooks 跑必须每次都执行的检查(lint、security scan、备份)。

适用场景

场景用 Hook别用 Prompt
改完代码自动 format❌(Claude 可能忘)
阻止 Claude 修改 .env❌(提示能绕过)
写代码前先跑 lint
提交前必跑测试
让 Claude 用某编码风格✅(Prompt 够了)

Hook 事件类型

事件何时触发
PreToolUse工具调用 —— 可拦截/修改
PostToolUse工具调用 —— 看结果
Stop会话结束
UserPromptSubmit用户提交 prompt 时
NotificationClaude 发通知时

配置位置

json
// ~/.claude/settings.json(全局)
// 或 .claude/settings.json(项目级)
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo '🚨 Bash command: ' && echo \"$CLAUDE_TOOL_INPUT\""
          }
        ]
      }
    ]
  }
}

实战例子:3 个超有用的 hook

1. 自动 format(PostToolUse)

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "if [[ \"$CLAUDE_FILE_PATH\" == *.ts ]] || [[ \"$CLAUDE_FILE_PATH\" == *.tsx ]]; then npx prettier --write \"$CLAUDE_FILE_PATH\"; fi"
          }
        ]
      }
    ]
  }
}

Claude 改完 .ts / .tsx 文件自动跑 prettier。

2. 阻止改 .env(PreToolUse + 拦截)

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "if [[ \"$CLAUDE_FILE_PATH\" == *.env* ]]; then echo '🛑 BLOCKED: .env files cannot be modified' >&2; exit 1; fi"
          }
        ]
      }
    ]
  }
}

返回非 0 退出码会阻止该工具调用执行。

3. 提交前必跑测试(PreToolUse Bash)

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -q 'git commit'; then pnpm test || (echo '❌ Tests failed, commit blocked' >&2; exit 1); fi"
          }
        ]
      }
    ]
  }
}

Claude 想 git commit → 先跑测试,挂了拦下。

环境变量(hook 内可用)

变量含义
$CLAUDE_TOOL_NAME工具名(Bash / Edit / Write / Read ...)
$CLAUDE_TOOL_INPUT完整输入 JSON
$CLAUDE_FILE_PATH操作的文件路径(如有)
$CLAUDE_SESSION_ID当前会话 ID
$CLAUDE_CWD工作目录

高级:用脚本而不是 inline command

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/pre-edit.sh"
          }
        ]
      }
    ]
  }
}

.claude/hooks/pre-edit.sh

bash
#!/usr/bin/env bash
set -e

FILE="$CLAUDE_FILE_PATH"

# 多个规则
case "$FILE" in
  *.env*|*.pem|*.key|*secrets*)
    echo "🛑 BLOCKED: protected file $FILE" >&2
    exit 1
    ;;
  *.ts|*.tsx)
    # 改 TS 文件前先 check 是否会破坏类型
    npx tsc --noEmit --skipLibCheck && echo "✅ Type check passed"
    ;;
esac

chmod +x .claude/hooks/pre-edit.sh 给执行权限。

Hook 跟 deny rule 的区别

settings.json denyHook
阻止机制Claude 看到规则不去碰强制拦截,不靠 Claude 自觉
可绕过吗提示词社工有可能不能
编程逻辑静态规则动态 shell 脚本
推荐用于一般约束安全/合规关键文件

注意事项

Hook 是定时炸弹

  • Hook 命令在你机器上跑,有完整文件系统访问权
  • 写 hook 之前想清楚副作用
  • 不要 rm -rf 之类的破坏性操作
  • 定期 review ~/.claude/settings.json 防止被恶意 hook 注入

推荐安全 Hook(直接抄)

awesome-claude-code-toolkit 的 hooks 集合 已经预制了 20+ 个生产级 hook,包括:

  • 阻止 .env / .pem / secrets/ 访问
  • AWS / GCP credential 文件保护
  • kubeconfig 写保护
  • SSH key 保护
  • git 危险命令(force push / reset hard)拦截
bash
# 一键拉
cd ~/.claude
git clone https://github.com/rohitg00/awesome-claude-code-toolkit
ln -s awesome-claude-code-toolkit/hooks .claude-hooks
# 然后把 hooks 引到 settings.json

调试 hook

启动 claude 加 --debug

bash
claude --debug

每个 hook 触发都会打日志,方便调试。

Hook vs Skill vs Slash Command vs MCP

触发用途
Hook自动(生命周期事件)强制规则 / 自动化
Skill自动(任务匹配)复用工作流
Slash Command手动 /一次性指令
MCP自动(数据需要)外部数据/能力

四者互补,不冲突。

内容采用 CC BY-NC-ND 4.0 协议 · 禁止商业使用 / 禁止改编 / 禁止训练 AI 模型