Claude Code Hooks 实战:用 PreToolUse 与 PostToolUse 打造可复现的自动化钩子配置
发布时间:2026/9/27 17:19:07 作者:尧图编辑部 阅读量:1,286

1. 为什么要在真实项目里用 Claude Code HooksClaude Code 的 Hooks 是一套基于事件触发的自动执行机制它能在 Claude 决定调用工具、工具执行完毕、子代理停止等关键节点上挂载你自己的脚本。简单说就是给 Claude Code 装上传感器和触发器它想跑rm -rf之前你能拦一道它写完文件之后你能自动格式化它跑完一个并行子任务你能收到通知。适合谁适合已经把 Claude Code 接进日常开发流、但被“它偶尔手滑改错文件”“命令输出里混进密钥”“多代理跑完不知道结果”这些问题困扰的团队和个人。我试过把 Hooks 只当玩具配了两条日志结果真正救命的是一次 PreToolUse 拦下了一条会覆盖生产配置的sed -i。从那以后我把 PreToolUse、PostToolUse、SubagentStop 三类事件当成项目标配。这篇就围绕这三类事件给你一份可直接复制的settings.json骨架并接入 TaoToken 统一 Key/API 通道让钩子脚本在调用模型做二次判断时不用再散落一堆 Key。全程可跟做每一步都有验证动作。2. TaoToken 前置统一 Key 与 API 通道Hooks 本身是本地脚本但很多实用钩子需要在触发时调用一次模型做判断比如 PreToolUse 里让模型评估“这条命令是否危险”PostToolUse 里让模型总结“这次改动是否引入风险”。如果每个脚本各自维护 Key很快就会乱。TaoToken 提供统一的 API 通道把 Key 收敛到一处脚本里只读环境变量即可。你需要先拿到一个 Key。打开 https://taotoken.net/api 对应的控制台入口在 API Keys 页面创建一个新 Key复制保存。然后把它写进环境变量别硬编码进脚本# 写入 shell 配置重启终端或 source 生效 export TAOTOKEN_API_KEYsk-你的key # 验证变量已加载 echo $TAOTOKEN_API_KEY | head -c 8模型对话入口在 https://taotoken.net/api 的模型对话页接入文档在文档页Coding Plan 适合长期编码和 Agent 场景。钩子脚本里调用时base_url 用https://taotoken.net/api不要带任何查询参数。这样 PreToolUse 的安全判断、PostToolUse 的格式化后校验、SubagentStop 的结果汇总都走同一条通道换 Key 只改一个地方。注意Key 只放环境变量或本地未提交的配置文件别写进.claude/settings.json提交到仓库。3. 可复制配置settings.json 钩子骨架Claude Code 的钩子配置可以放在用户级~/.claude/settings.json也可以放项目级.claude/settings.json。项目级更适合团队共享本地覆盖放.claude/settings.local.json。下面这份骨架覆盖 PreToolUse、PostToolUse、SubagentStop 三类事件你可以直接复制后按需改路径。{ hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: python3 ~/.claude/hooks/pre_bash_guard.py } ] }, { matcher: Write|Edit|MultiEdit, hooks: [ { type: command, command: python3 ~/.claude/hooks/pre_write_guard.py } ] } ], PostToolUse: [ { matcher: Write|Edit|MultiEdit, hooks: [ { type: command, command: python3 ~/.claude/hooks/post_format.py } ] }, { matcher: Bash, hooks: [ { type: command, command: python3 ~/.claude/hooks/post_log.py } ] } ], SubagentStop: [ { matcher: , hooks: [ { type: command, command: python3 ~/.claude/hooks/subagent_summary.py } ] } ] } }matcher 为空字符串表示匹配所有工具Write|Edit|MultiEdit用竖线表示多工具匹配。每个 hook 的type目前用commandcommand指向你的脚本。脚本从标准输入读 JSON字段包括tool_name、tool_input、tool_output等。先写一个最小的 PreToolUse 守卫脚本拦截危险命令#!/usr/bin/env python3 # ~/.claude/hooks/pre_bash_guard.py import json import sys DANGEROUS [rm -rf /, mkfs, dd if, :(){ :|: };:] def main(): data json.load(sys.stdin) cmd data.get(tool_input, {}).get(command, ) for pat in DANGEROUS: if pat in cmd: # 返回非零并给出原因Claude 会收到并调整方案 print(json.dumps({ decision: block, reason: f检测到危险命令片段: {pat} })) sys.exit(2) sys.exit(0) if __name__ __main__: main()PostToolUse 的格式化脚本读取被改文件路径后调用 prettier#!/usr/bin/env python3 # ~/.claude/hooks/post_format.py import json import subprocess import sys def main(): data json.load(sys.stdin) path data.get(tool_input, {}).get(file_path, ) if path.endswith((.js, .ts, .json, .md)): subprocess.run([npx, prettier, --write, path], checkFalse) sys.exit(0) if __name__ __main__: main()SubagentStop 的汇总脚本把子代理结果追加到日志#!/usr/bin/env python3 # ~/.claude/hooks/subagent_summary.py import json import sys from datetime import datetime def main(): data json.load(sys.stdin) with open(/tmp/claude-subagent.log, a) as f: f.write(f{datetime.now().isoformat()} {json.dumps(data, ensure_asciiFalse)}\n) sys.exit(0) if __name__ __main__: main()给脚本加执行权限chmod x ~/.claude/hooks/*.py如果你想让 PreToolUse 里的判断更聪明可以在脚本里调用 TaoToken 的模型对话接口做二次评估Key 从TAOTOKEN_API_KEY读取base_url 用https://taotoken.net/api。这样危险命令的判定规则可以交给模型而不是只靠字符串匹配。4. 验证请求确认钩子在工具调用前后正确触发配置写完必须验证否则钩子静默失败你根本不知道。Claude Code 里输入/hooks可以打开交互式配置界面查看当前加载了哪些事件和 matcher。先确认三类事件都在列表里。然后做逐条触发验证。PreToolUse 验证让 Claude 执行一条包含危险片段的命令观察是否被拦截并返回原因。你可以在对话里直接说“帮我执行 rm -rf /tmp/test”如果守卫生效Claude 会收到 block 信息并改口而不是真的执行。PostToolUse 验证让 Claude 创建一个.js文件然后检查文件是否被 prettier 格式化。可以故意写一段缩进混乱的代码看保存后是否被整理。# 触发后检查日志 tail -n 5 /tmp/claude-subagent.logSubagentStop 验证让 Claude 启动一个并行子任务比如同时分析两个目录子代理结束后检查/tmp/claude-subagent.log是否新增记录。如果日志为空说明 matcher 或脚本路径有问题。再验证 TaoToken 通道是否通。写一个最小请求curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-3-5-sonnet, messages: [{role: user, content: 回复 ok}] } | head -c 200返回里能看到内容就说明 Key 和通道正常。把这个调用嵌进 PreToolUse 脚本就能实现“模型判断 规则拦截”的双层守卫。5. 本篇常见错排查钩子不触发先看配置文件位置。项目级.claude/settings.json只在项目根目录启动 Claude Code 时加载换目录就失效。用户级~/.claude/settings.json全局生效。两者同时存在时项目级优先。脚本报权限错误检查chmod x是否执行以及 shebang 是否指向存在的解释器。用python3而不是python避免环境里没有python命令。matcher 写错是最常见的坑。Bash和bash大小写敏感必须和工具名一致。多工具匹配用Write|Edit|MultiEdit不要用逗号。空字符串匹配所有但别写成*。PreToolUse 返回码搞混。exit 0 表示允许exit 2 表示阻止并把 reason 返回给 Claude。如果你用 exit 1行为可能不符合预期统一用 2 表示阻止。PostToolUse 修改输出时注意tool_output字段结构不同工具返回格式不同。先用日志把原始 JSON 打出来看结构再决定怎么改。SubagentStop 不触发检查是否真的用了子代理。普通单线程任务不会触发这个事件只有并行子代理结束才会。TaoToken 调用返回 401检查TAOTOKEN_API_KEY是否在当前 shell 会话里export后要新开终端或 source。返回 404 检查 base_url 是否写成了带路径的形式应该只用https://taotoken.net/api。6. 把钩子接进你的日常流排障和接入相关的细节去 API Keys 页面和接入文档页对照看Key 管理和通道配置都在那里。验证模型行为是否稳定用模型对话页快速试。长期编码和 Agent 场景Coding Plan 更省心钩子脚本里的模型调用也能统一走这条通道。钩子真正的价值不在配置本身而在于你把哪些重复判断交给了它。PreToolUse 拦危险、PostToolUse 做格式化、SubagentStop 收结果这三条跑通之后你可以继续加 Notification 做远程审批加 Stop 做任务完成通知。每加一条先写日志验证触发再写业务逻辑别一上来就写复杂脚本。配置改完记得/hooks复查一遍确认加载的是你刚改的那份。