Claude Code Hooks 超详细教程,附源码
"command": "osascript -e 'display notification \"Claude 干完活了\" with title \"Claude Code\"' 2>/dev/null || true""command": "osascript -e 'display notification \"Claude Code 任务完成\" with title \"提示\" sou
·
# 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: ```bash claude --version # 需要 2026.1 以上版本 ``` 没有的话更新一下: ```bash npm install -g @anthropic-ai/claude-code@latest ``` 然后在项目根目录创建配置目录: ```bash mkdir -p .claude touch .claude/settings.json ``` ## 六个核心事件 Claude Code Hooks 支持这些触发时机: | 事件 | 触发时间 | 能不能拦截 | |------|---------|-----------| | `PreToolUse` | AI 执行工具**之前** | ✅ 能,exit 1 就拦住了 | | `PostToolUse` | 工具执行**之后** | ❌ 只能做后续处理 | | `Stop` | AI 完成整轮回答后 | ❌ | | `Notification` | AI 发通知时(等你确认等) | ❌ | | `UserPromptSubmit` | 你提交 prompt 时 | ❌ | | `SessionStart` | 新会话开始时 | ❌ | 其中 **PreToolUse 是唯一能拦截动作的 hook**——它就像一个安全门卫,不满意就直接 exit 1 拒绝执行。 ## 实战一:保护关键文件(别再让 AI 碰 .env 了) 这是我配置的第一个 hook,也是我认为每个人都应该加的。 先写一个拦截脚本 `.claude/hooks/block-critical.sh`: ```bash #!/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` 里注册: ```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 在每次编辑后自动格式化: ```json { "hooks": { "PostToolUse": [ { "matcher": "Edit|Write|MultiEdit", "hooks": [ { "type": "command", "command": "npx prettier --write $FILEPATH && npx eslint --fix $FILEPATH" } ] } ] } } ``` Python 项目换成这样: ```json { "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`: ```bash #!/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: ```json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash .claude/hooks/block-dangerous-cmd.sh" } ] } ] } } ``` 这条规则拦住了 AI 往 `dependencies` 里塞包的行为——想装包?行,加 `--save-dev` 说明是开发依赖,否则不让装。 ## 实战四:任务完成自动通知 跑长任务的时候(比如让 Claude 重构一整个模块),我不想一直盯着终端。用 Stop hook 发个桌面通知: macOS 用户: ```json { "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "osascript -e 'display notification \"Claude Code 任务完成\" with title \"提示\" sound name \"default\"'" } ] } ] } } ``` Linux 用户(需要 `notify-send`): ```json { "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "notify-send 'Claude Code' '任务完成!可以回来看了'" } ] } ] } } ``` 搭配 Slack webhook 还能推到群里,远程协作的时候特别方便。 ## 我的完整配置(直接抄) 把上面几个 hook 合到一起,这是我目前在用的完整 `settings.json`: ```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 实例判断这个改动安不安全: ```json { "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` 提取: ```bash 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](https://code.claude.com/docs/en/whats-new) 页面,每周看一眼。 说个有意思的事:自从配了 Hooks,我的 `.env` 再没被 AI 动过。上个月 Claude Code 改挂生产环境的事情再也没发生过——不是 AI 变聪明了,是 Hooks 帮我挡住了。 如果你觉得有帮助,欢迎点赞收藏 ❤️ 更多AI工具实战教程,关注我第一时间获取~
更多推荐



所有评论(0)