Claude Code Hooks 超详细教程,附源码

8 阅读1分钟

Claude Code Hooks 超详细教程,附源码

上周五晚上十一点半,我让 Claude Code 帮我改一段 API 认证逻辑。结果它改完顺手把 .env 文件里的数据库密码给删了——你没看错,直接清空了。部署上去之后服务全挂,我硬生生排查到凌晨两点才发现问题。

当时我就想:能不能让 AI 在碰关键文件之前拦它一下?

翻了两天文档,发现 Claude Code 在 2026 年初正式上了 Hooks 系统。说白了就是给 AI 编码助手装了个"保险丝"——改文件之前自动检查,改完之后自动跑测试,完事了还能给你发个通知。

今天这篇文章把我踩过的坑和最终跑通的配置全部整理出来,你直接抄就行。

Hooks 到底是啥?

Hooks 就是你在 settings.json 里定义的自动触发规则。Claude Code 在特定的时间点会执行你指定的 shell 命令,比如:

  • 改文件之前 → 检查这个文件是不是受保护的
  • 改文件之后 → 自动跑 prettier 格式化
  • AI 干完活之后 → 发一条桌面通知
  • Claude 要执行命令之前 → 拦截危险操作(比如 rm -rf

配置文件放在项目根目录的 .claude/settings.json 里。

环境准备

先确认你的 Claude Code 版本支持 Hooks:

claude --version
# 需要 2026.1 以上版本

没有的话更新一下:

npm install -g @anthropic-ai/claude-code@latest

然后在项目根目录创建配置目录:

mkdir -p .claude
touch .claude/settings.json

六个核心事件

Claude Code Hooks 支持这些触发时机:

事件触发时间能不能拦截
PreToolUseAI 执行工具之前✅ 能,exit 1 就拦住了
PostToolUse工具执行之后❌ 只能做后续处理
StopAI 完成整轮回答后
NotificationAI 发通知时(等你确认等)
UserPromptSubmit你提交 prompt 时
SessionStart新会话开始时

其中 PreToolUse 是唯一能拦截动作的 hook——它就像一个安全门卫,不满意就直接 exit 1 拒绝执行。

实战一:保护关键文件(别再让 AI 碰 .env 了)

这是我配置的第一个 hook,也是我认为每个人都应该加的。

先写一个拦截脚本 .claude/hooks/block-critical.sh

#!/bin/bash
# 从 stdin 读取 Claude 传来的 JSON 数据
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# 受保护文件列表
BLOCKED_FILES=(
  ".env"
  ".env.production"
  "src/middleware.ts"
  "src/app/api/auth/route.ts"
  "docker-compose.yml"
)

for file in "${BLOCKED_FILES[@]}"; do
  if [[ "$FILE_PATH" == *"$file"* ]]; then
    echo "⛔ BLOCKED: $FILE_PATH 是受保护文件,需要手动编辑!"
    exit 2  # exit 2 = 拦截并告知原因
  fi
done

exit 0  # 放行

然后在 settings.json 里注册:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/block-critical.sh"
          }
        ]
      }
    ]
  }
}

matcher 用的是正则匹配工具名——Edit|Write|MultiEdit 覆盖了所有文件编辑操作。

现在 Claude Code 想动我的 .env?直接弹红字拒绝:

⛔ BLOCKED: .env 是受保护文件,需要手动编辑!

舒服了。

实战二:改完代码自动格式化 + 跑 lint

说实话,AI 写的代码功能没问题,但风格经常一言难尽。缩进忽大忽小、引号单双混用、import 顺序乱七八糟。

用 PostToolUse hook 在每次编辑后自动格式化:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $FILEPATH && npx eslint --fix $FILEPATH"
          }
        ]
      }
    ]
  }
}

Python 项目换成这样:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "black $FILEPATH && isort $FILEPATH"
          }
        ]
      }
    ]
  }
}

跑起来之后你发现 Claude 写完代码,eslint 自动修了一堆小问题,prettier 统一了风格——基本不需要手动调格式了。

实战三:拦截危险命令

这条救过我好几次命。AI 有时候会执行 npm install xxx 往 dependencies 里塞东西,或者跑 rm -rf 清目录。

创建 .claude/hooks/block-dangerous-cmd.sh

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# 危险命令黑名单
DANGEROUS_PATTERNS=(
  "rm -rf /"
  "rm -rf ~"
  "DROP TABLE"
  "truncate"
  "DROP DATABASE"
  "> /dev/sda"
)

for pattern in "${DANGEROUS_PATTERNS[@]}"; do
  if [[ "$CMD" == *"$pattern"* ]]; then
    echo "🚫 DANGER: 检测到危险命令 '$CMD',已拦截!"
    exit 2
  fi
done

# 拦截生产依赖安装(除非带 --save-dev)
if echo "$CMD" | grep -qE "npm install|yarn add|pnpm add"; then
  if ! echo "$CMD" | grep -q "\-\-save-dev\|-D"; then
    echo "⚠️ 拦截: 往生产依赖里装包需要人工确认。加上 --save-dev 或 -D 可以绕过。"
    exit 2
  fi
fi

exit 0

注册到 settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/block-dangerous-cmd.sh"
          }
        ]
      }
    ]
  }
}

这条规则拦住了 AI 往 dependencies 里塞包的行为——想装包?行,加 --save-dev 说明是开发依赖,否则不让装。

实战四:任务完成自动通知

跑长任务的时候(比如让 Claude 重构一整个模块),我不想一直盯着终端。用 Stop hook 发个桌面通知:

macOS 用户:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code 任务完成\" with title \"提示\" sound name \"default\"'"
          }
        ]
      }
    ]
  }
}

Linux 用户(需要 notify-send):

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' '任务完成!可以回来看了'"
          }
        ]
      }
    ]
  }
}

搭配 Slack webhook 还能推到群里,远程协作的时候特别方便。

我的完整配置(直接抄)

把上面几个 hook 合到一起,这是我目前在用的完整 settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/block-critical.sh"
          }
        ]
      },
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/block-dangerous-cmd.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $FILEPATH && npx eslint --fix $FILEPATH 2>/dev/null || true"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude 干完活了\" with title \"Claude Code\"' 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

注意 2>/dev/null || true——这很关键。hook 执行失败默认会中断 AI 操作,加上这俩可以确保通知失败也不影响正常流程。

三种 Handler 类型

上面我全用的 command 类型,其实 Hooks 还支持另外两种:

类型怎么工作适合干啥
command跑 shell 命令,stdin 传 JSON格式化、lint、文件检查
prompt把上下文发给 Claude 模型做单轮判断安全审查、架构评审
agent启动一个子 Agent 深度检查跨文件依赖分析、数据库迁移验证

prompt 类型挺有意思的——可以在 AI 改代码之前,让另一个 Claude 实例判断这个改动安不安全:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "分析这次编辑操作:$ARGUMENTS。如果涉及认证逻辑、数据库操作、支付相关、密钥处理中的任何一项,回复 DENY 并说明原因。否则回复 APPROVE。"
          }
        ]
      }
    ]
  }
}

不过这个会多消耗一次 API 调用的 token,我目前只在处理支付和认证模块的时候才开。

常见问题 FAQ

Q: Hooks 配置了但没生效?

检查三个地方:

  1. 文件路径对不对——必须在项目根目录的 .claude/settings.json
  2. JSON 格式有没有错——jq .claude/settings.json 跑一下验证
  3. hook 脚本有没有执行权限——chmod +x .claude/hooks/*.sh

Q: hook 脚本里怎么拿到 Claude 正在操作的文件路径?

通过 stdin 传入的 JSON。用 jq 提取:

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

Q: 能不能在 CI/CD 里用 Hooks?

当然可以。Claude Code 的 headless 模式(claude -p)同样触发 hooks。搭配 --allowedTools 参数可以把 AI 的权限锁死在特定命令范围内,再加上 hooks 做安全兜底,双层保险。

Q: prompt 类型的 hook 延迟太高怎么办?

确实,prompt 类型要调一次 API,通常多 2-5 秒。建议只在关键操作(认证、支付、数据库)上用 prompt hook,日常编辑用 command hook 就够了。

Q: 能不能异步执行 hook?

目前所有 hook 都是同步的——Claude 会等 hook 执行完再继续。所以 hook 脚本别写太重的操作(比如跑完整测试套件),会卡住 AI。轻量级检查(lint 单文件、检查文件名)通常几百毫秒搞定。

踩坑总结

搞了一周 Hooks,踩了几个坑分享下:

  1. hook 脚本里不要用 set -e——Claude 靠 exit code 判断结果,set -e 会让某些预期内的失败变成意外退出
  2. PostToolUse 里不要跑全量测试——太慢了,AI 会等你跑完才继续,体验很差。只对单个文件做 lint 就行
  3. matcher 是正则不是 glob——Edit|Write 这样写,别写成 Edit,Write
  4. Windows 用户注意——command 里的路径分隔符用 /,不要用 \

对了,Hooks 目前还在快速迭代中。Anthropic 最近几周每周都在加新功能(Week 13 加了条件 if hooks,Week 14 加了 per-tool MCP result-size override)。建议关注官方的 What's New 页面,每周看一眼。

说个有意思的事:自从配了 Hooks,我的 .env 再没被 AI 动过。上个月 Claude Code 改挂生产环境的事情再也没发生过——不是 AI 变聪明了,是 Hooks 帮我挡住了。

如果你觉得有帮助,欢迎点赞收藏 ❤️ 更多AI工具实战教程,关注我第一时间获取~