ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code Hooks 实战:把自动验证接进工作流,而不是让 AI 乱改

Claude Code Hooks 实战:把自动验证接进工作流,而不是让 AI 乱改 1. Claude Code Hooks 自动验证为什么你的 AI 总在乱改文件Claude Code Hooks 是 Claude Code 提供的一套事件钩子机制允许你在工具调用前后、会话开始结束等节点自动执行 shell 命令。它能做什么简单说就是让 Claude Code 在改完文件后自动跑一遍你指定的校验脚本失败就阻断成功才继续。适合谁适合所有用 Claude Code 写代码、但被 AI 改坏过文件的开发者。我见过太多人把 Hooks 当成自动修复器来用文件一改就自动格式化、自动跑测试、自动 commit、自动 push。结果呢AI 改错了一个函数签名Hook 自动跑了格式化把错误扩散到十个文件测试失败后 Hook 又触发 Claude 自动改改完又失败无限循环烧掉几百万 token。问题的根源不是 Hooks 不好用而是用错了位置。Claude Code 的核心流程可以拆成读项目 → 出方案 → 改文件 → 运行验证 → 解释结果 → 人工确认。Hooks 最该插的地方是改文件和运行验证之间用来自动触发低风险检查而不是替你做高风险决策。阶段适合 Hook 吗原因读取项目不太需要普通上下文读取即可写文件后适合可自动跑格式/测试/扫描测试失败后谨慎可以报告不应无限自动修commit 前适合检查 secret、lint、测试push / deploy不建议外部可见动作必须人工确认安全 Hook 的共同点是只读、可重复、失败可解释。适合做的格式检查、单元测试、类型检查、secret 扫描、生成验证摘要、检查是否改了禁止目录。不适合做的自动改业务逻辑、自动覆盖未提交文件、自动 commit/push、自动发布、自动改数据库、自动调外部平台。这篇文章会给你三套可直接复制的 settings 配置片段覆盖文件修改后提醒、commit 前 secret 扫描、内容站构建验证三个场景并说明如何把校验结果回传给 Claude Code让它知道这次改动没通过别继续说完成了。2. TaoToken 前置给 Claude Code 配一个稳定的模型入口在配 Hooks 之前得先保证 Claude Code 本身能稳定跑起来。Claude Code 默认走 Anthropic 官方接口国内直连经常超时导致 Hook 还没触发会话就断了。这时候可以用 TaoToken 作为模型入口它兼容 Anthropic 的 API 格式Claude Code 不需要改代码只改环境变量就行。TaoToken 官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数配置时直接用这个。Claude Code 读取的是环境变量ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY。你需要在 TaoToken 控制台创建一个 API Key然后写进 shell 配置。控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API Keys 管理页https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。配置方式有两种一种是临时 export一种是写进~/.zshrc或~/.bashrc持久化。推荐后者因为 Hooks 触发时是新开子进程临时变量不一定继承得到。# 写入 ~/.zshrc 或 ~/.bashrc export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的TaoToken密钥改完执行source ~/.zshrc生效。验证是否配好可以跑一句echo $ANTHROPIC_BASE_URL # 应输出 https://taotoken.net/api如果你用的是 Claude Code 的 settings.json 方式管理模型也可以在~/.claude/settings.json里指定 model 字段。但 Base URL 和 Key 还是走环境变量最稳因为 Hooks 子进程读的是环境变量不是 settings.json。这里有个坑很多人把 Key 写进项目级的.claude/settings.json然后提交到 Git结果 Key 泄露。正确做法是 Key 只放本地环境变量或~/.claude/settings.json用户级不进版本库项目级 settings 只放 Hooks 配置。配好之后你可以先用模型对话页快速验证 Key 是否可用https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果那边能正常对话说明 Key 没问题Claude Code 这边大概率也能通。如果你打算长期用 Claude Code 跑 Agent 任务可以考虑 Coding Plan额度更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各客户端的详细配置。3. 可复制配置三套 settings 片段直接抄Claude Code 的 Hooks 配置写在settings.json里位置可以是用户级~/.claude/settings.json也可以是项目级.claude/settings.json。项目级配置会覆盖用户级同名 Hook。下面三套配置你可以直接复制改改命令路径就能用。3.1 文件修改后提醒验证PostToolUse这是最保守的一套。Claude Code 每次调用 Edit 或 Write 工具后Hook 只输出一句提醒不自动改任何东西。目的是让 Claude 知道文件改了该跑验证了。{ hooks: { PostToolUse: [ { matcher: Edit|Write, hooks: [ { type: command, command: echo Files changed. Review diff and run the relevant test/build command before saying done. } ] } ] } }matcher是正则Edit|Write表示匹配 Edit 或 Write 工具。type固定是commandcommand是你要执行的 shell 命令。这段配置放在项目级.claude/settings.json里团队每个人都能用。3.2 commit 前 secret 扫描PreToolUse这套在 Claude Code 执行git commit之前拦截扫描暂存区里有没有疑似密钥。有就 exit 1 阻断没有就放行。{ hooks: { PreToolUse: [ { matcher: Bash(git commit:*), hooks: [ { type: command, command: git diff --cached | grep -Ei api[_-]?key|secret|password|token exit 1 || exit 0 } ] } ] } }注意matcher的写法Bash(git commit:*)这是 Claude Code 的语法表示匹配 Bash 工具里以git commit开头的命令。grep命中就 exit 1Claude Code 会收到失败信号并停止执行 commit。注意这只是示意真实项目最好用成熟 secret scanner比如 gitleaks、trufflehog而不是只靠 grep。grep 会误报也会漏报。3.3 内容站改文后提醒构建PostToolUse 路径过滤如果你维护的是 Hexo、Hugo 这类内容站改完 Markdown 不能只看源文件得看构建产物。这套配置在source/_posts/下的文件被改后提醒跑构建并检查关键字段。{ hooks: { PostToolUse: [ { matcher: Edit|Write, hooks: [ { type: command, command: if echo \$CLAUDE_FILE_PATHS\ | grep -q source/_posts/; then echo Post modified. Run npm run build and check target URL, meta description, canonical, and internal links.; fi } ] } ] } }CLAUDE_FILE_PATHS是 Claude Code 传给 Hook 的环境变量包含本次改动的文件路径。用它做条件判断避免每次改代码都触发内容站提醒。三套配置可以合并到一个 settings.json 里Hooks 数组会按顺序执行。合并后大概长这样{ hooks: { PreToolUse: [ { matcher: Bash(git commit:*), hooks: [ { type: command, command: git diff --cached | grep -Ei api[_-]?key|secret|password|token exit 1 || exit 0 } ] } ], PostToolUse: [ { matcher: Edit|Write, hooks: [ { type: command, command: echo Files changed. Review diff and run the relevant test/build command before saying done. } ] } ] } }保存后不需要重启 Claude Code下次工具调用就会生效。如果没生效检查 settings.json 的 JSON 语法有没有错Claude Code 对格式很敏感多一个逗号就整个文件不加载。4. 验证请求一次完整的 Hook 触发过程配置写好了得实际跑一次看它到底有没有生效。下面用文件修改后提醒这套配置走一遍完整流程。第一步确认 settings.json 位置和内容。项目根目录下建.claude/settings.json把 3.1 的配置粘进去。然后开一个终端cd 到项目根目录启动 Claude Codecd /path/to/your-project claude第二步让 Claude Code 改一个文件。在会话里输入把 README.md 里的 Hello 改成 Hello WorldClaude Code 会调用 Edit 工具修改 README.md。修改完成后Hook 应该触发你会在 Claude Code 的输出里看到类似这样的内容Files changed. Review diff and run the relevant test/build command before saying done.这行就是 Hook 的 stdoutClaude Code 会把它作为工具调用结果的一部分回传给模型。模型看到这句话就知道文件改了该跑验证了而不是直接说已完成。第三步验证 Hook 是否真的阻断了。把配置换成 3.2 的 secret 扫描然后在项目里造一个假密钥echo API_KEYsk-test-1234567890 test-secret.txt git add test-secret.txt然后在 Claude Code 里输入帮我提交这次改动Claude Code 会尝试执行git commit但 PreToolUse Hook 会先跑git diff --cached | grep ...命中API_KEY后 exit 1。Claude Code 收到非零退出码会停止执行 commit并告诉你 Hook 失败了。你会在输出里看到类似Hook command failed with exit code 1这时候 commit 没有执行假密钥没被提交。这就是失败即阻断的效果。第四步把校验结果回传给 Claude Code。Hook 的 stdout 和 stderr 都会被 Claude Code 捕获作为工具调用结果的一部分喂回模型。所以你在 Hook 里 echo 的内容模型是能看到的。这意味着你可以让 Hook 输出结构化的验证摘要比如echo VERIFY_RESULT: FAIL echo REASON: secret detected in staged files echo ACTION: remove secret and re-stage模型看到这三行就知道该干什么而不是盲目重试。提示Hook 的退出码很重要。exit 0 表示通过Claude Code 继续exit 非 0 表示失败Claude Code 会停止当前工具调用并把失败信息回传给模型。不要用 exit 0 掩盖失败否则阻断就失效了。如果你在验证过程中遇到模型连接问题比如请求超时或 401先检查 TaoToken 的 Key 和 Base URL 是否配对。可以用模型对话页单独测一下 Keyhttps://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。Key 没问题再回来查 Hooks 配置。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth配 Hooks 的过程中报错基本集中在两类模型连接类和 Hook 执行类。下面按真实报错逐个拆。5.1 401 Unauthorized报错长这样API Error: 401 Unauthorized原因通常是ANTHROPIC_API_KEY没设、设错、或者 Key 被撤销了。排查步骤echo $ANTHROPIC_API_KEY # 应该输出 sk- 开头的字符串不是空如果是空说明环境变量没生效。检查你写的是~/.zshrc还是~/.bashrc以及当前 shell 是哪个。macOS 默认 zshLinux 服务器可能是 bash。改完记得source。如果 Key 有值但还是 401去 TaoToken 控制台确认 Key 状态https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。看是不是额度用完或被禁用。5.2 local proxy failed报错长这样Error: local proxy failed to connect这个通常出现在你本地配了代理但代理没起来或者ANTHROPIC_BASE_URL指向了一个不可达的地址。先确认 Base URLecho $ANTHROPIC_BASE_URL # 应该是 https://taotoken.net/api如果地址对但还是连不上用 curl 直接测curl -I https://taotoken.net/api能返回 HTTP 状态码说明网络通。返回不了就是网络层问题检查 DNS 和防火墙。5.3 reading choices 相关报错报错长这样Error reading choices: unexpected end of JSON input这是响应体解析失败通常是 Base URL 配错了比如把/api漏了或者多加了/v1。TaoToken 的 Anthropic 兼容端点是https://taotoken.net/api不要自己拼/v1/messagesClaude Code 会自己拼。检查你的ANTHROPIC_BASE_URL是不是精确等于https://taotoken.net/api末尾不要有斜杠。5.4 OAuth 相关报错报错长这样OAuth error: invalid_grantClaude Code 某些版本会尝试走 OAuth 登录流程。如果你用的是 API Key 模式不需要 OAuth。检查~/.claude/settings.json里有没有残留的 OAuth 配置有就删掉。同时确认没有设置CLAUDE_CODE_USE_OAUTH之类的环境变量。5.5 Hook 不触发配置写好了但 Hook 没跑排查顺序第一确认 settings.json 路径对。项目级是.claude/settings.json用户级是~/.claude/settings.json。路径错了 Claude Code 读不到。第二确认 JSON 语法对。用python -m json.tool .claude/settings.json验证有语法错会直接报出来。第三确认 matcher 匹配。Edit|Write是正则如果你写的是edit|write小写匹配不上。工具名是大小写敏感的。第四确认 Hook 命令本身能跑。把 command 里的内容复制到终端单独执行看有没有报错。Hook 子进程的环境变量和你的交互 shell 可能不一样命令里尽量用绝对路径。5.6 Hook 无限循环这是最危险的。表现是 Claude Code 改文件 → Hook 失败 → Claude 自动改 → Hook 又失败循环烧 token。防法Hook 里不要调用会修改文件的命令。只做只读检查。如果确实需要自动修复限制在格式化这种无歧义的机械操作并且加最大重试次数。另外Hook 失败后 Claude Code 默认不会自动重试但如果你的 prompt 里写了失败就修到通过模型可能会自己循环。所以 prompt 里也要加约束如果 Hook 失败报告失败原因不要自动修改。6. 把验证接进工作流从 Hook 到人工确认的完整链路Hooks 只是工作流里的一环它负责让验证稳定发生但不负责替你做决策。完整的链路应该是Claude Code 改文件 → Hook 自动跑低风险检查 → 检查结果回传给模型 → 模型解释结果 → 人工看 diff 和验证输出 → 人工决定是否 commit。这套链路里Hook 的职责边界要清楚。它做格式检查、单元测试、类型检查、secret 扫描、生成验证摘要。它不做业务逻辑修改、不覆盖未提交文件、不 commit、不 push、不发布、不改数据库、不调外部平台。如果你想让 Claude Code 长期跑 Agent 任务建议把 Coding Plan 配上额度更稳https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。接入细节看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后给一个配置检查表每次加新 Hook 前过一遍是否只做低风险检查是否会修改文件如果会是否真的必要是否可能覆盖用户未提交内容失败时是否有清晰输出是否会触发外部服务是否有无限循环风险是否需要人工确认七个问题里有一个答不上来就先别加这个 Hook。Hooks 的价值不是让 AI 自动做更多事而是让验证更稳定地发生。把业务判断、提交、部署和外部操作留给人确认这才是可控的 AI 编程自动化。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进