☰
把 Claude Code 的关键动作交给 hooks:TaoToken 配置与 CLAUDE.md 骨架
2026/9/26 14:35:26 网站建设 项目流程

1. 为什么 Claude Code 的关键动作不能只靠 CLAUDE.md

用 Claude Code 改一个 TypeScript 前端项目时,真正让人头疼的往往不是模型写不出代码,而是它写完代码后少做了一件团队默认必须做的事。比如改完.ts文件没跑 eslint,动了接口定义没重新生成类型,碰到migrations目录没停下来确认,或者在一个需要审计的仓库里,某次配置变更没有留下任何记录。这些问题靠每次在 prompt 里提醒,短期能凑合,长期一定翻车。

CLAUDE.md 能写规则,能告诉 Claude Code 项目的构建命令、测试命令、代码风格,它更像团队的操作手册,模型会读、会参考,但本质上仍然是建议性的上下文。模型可能因为上下文压缩、任务切换、注意力漂移而漏掉某条规则。hooks 处理的是另一类东西:它不指望 Claude Code 记得做,而是让某个脚本在固定时机自动跑。Claude Code 官方对 hooks 的定义很明确,hooks 可以是用户定义的 shell 命令、HTTP endpoint、LLM prompt 或其他 handler,它们会在 Claude Code 生命周期的特定位置自动执行。事件触发时,Claude Code 会把相关 JSON 上下文传给 handler,command hook 通过 stdin 接收输入,HTTP hook 通过 POST body 接收输入。

把规则分成两类会更好理解。一类是偏好型规则,像变量命名、目录组织、注释风格、测试命名方式,这些放进 CLAUDE.md 很自然,它给 Claude Code 提供长期上下文。另一类是硬约束型规则,像不能写.env、不能改.git、不能覆盖式编辑生产迁移脚本、不能跳过 lint、不能在无审计记录的情况下改安全配置,这些更适合 hooks,因为它要的是稳定执行,而不是模型配合。

最关键的差别是:hooks 不是提示词技巧,而是执行机制。Claude Code 的 agentic loop 会不断读文件、调用工具、运行命令、修改代码,hooks 就嵌在这个 loop 的关键节点上,像拦截器一样看见动作发生前后的状态。官方把事件分成几类:有的每个 session 触发一次,比如SessionStart和SessionEnd;有的每轮对话触发一次,比如UserPromptSubmit和Stop;还有的在 agentic loop 里每次工具调用时触发,比如PreToolUse和PostToolUse。这套设计对 Claude Code 特别重要,因为它不是只给建议的聊天窗口,它会真的用 Edit、Write、Bash、MCP tool 去改变项目状态。只要工具会改东西,就需要在工具执行前后留出确定性的控制点。

2. TaoToken 前置:统一 Key 与 API 通道

在动手写 hooks 之前,先把模型通道理顺。Claude Code 需要一个稳定的 API 入口,TaoToken 在这里扮演的是统一 Key 和 API 通道的角色,让你不用在多个供应商之间来回切换配置。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api 。

你需要先拿到一个可用的 API Key。进入控制台创建 Key 的地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,创建后复制保存,后面配置环境变量会用到。如果你还没决定用哪个模型,可以先到模型对话页面试一下手感:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 。长期用 Claude Code 做编码和 Agent 任务的话,Coding Plan 会更划算,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。

配置环境变量时,把 Key 写进 shell 配置,不要硬编码进项目文件:

# 写入 ~/.bashrc 或 ~/.zshrc export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-你的TaoToken密钥" # 让当前终端生效 source ~/.zshrc # 验证变量已加载 echo $ANTHROPIC_BASE_URL

注意:API 基址不要带 UTM 参数,只保留https://taotoken.net/api,否则部分客户端会拼接出错误路径。

如果你用的是 Claude Code 的 Anthropic 兼容模式,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有不同客户端的完整配置示例。Claude Code 专用说明可以看 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 。通道打通后,再配 hooks,才能保证 hook 里触发的模型调用也走同一条链路。

3. 可复制配置:settings.json 骨架与 CLAUDE.md 片段

Claude Code 的 hooks 写在 settings 文件里。项目级配置放.claude/settings.json,可以提交进仓库共享给团队;本地个人配置放.claude/settings.local.json,适合放机器相关偏好。下面是一份可以直接改用的骨架,覆盖三个目标:写前保护、写后整理、结束前验收。

{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "node .claude/hooks/guard-paths.js" } ] }, { "matcher": "Bash", "hooks": [ { "type": "command", "command": "node .claude/hooks/guard-bash.js" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "node .claude/hooks/format-changed.js" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "node .claude/hooks/check-lint.js" } ] } ] } }

matcher负责粗粒度过滤,Edit|Write匹配编辑和写入工具,Bash只匹配 Bash 工具。if字段可以进一步过滤工具参数,比如Bash(git *)只在 Claude Code 使用 git 命令时才启动 hook。matcher 写得太宽,所有动作都跑脚本,性能会变差;写得太窄,真正需要拦截的动作会漏掉。工程上更稳的做法是先用 matcher 按工具切大块,再用if对高风险命令做细分。

写前保护的脚本示例,检查目标路径是否命中保护名单:

// .claude/hooks/guard-paths.js const fs = require("fs"); let input = ""; process.stdin.on("data", (chunk) => (input += chunk)); process.stdin.on("end", () => { const data = JSON.parse(input); const filePath = data.tool_input?.file_path || ""; const protectedPatterns = [ /\.env$/, /\.git\//, /migrations\/.*\.sql$/, /package-lock\.json$/ ]; const hit = protectedPatterns.find((p) => p.test(filePath)); if (hit) { // exit code 2 会阻断动作,stderr 作为反馈给模型 console.error(`路径 ${filePath} 受保护,禁止直接修改。请改为新增文件或调整测试预期。`); process.exit(2); } process.exit(0); });

写后整理的脚本示例,根据文件后缀执行轻量命令:

// .claude/hooks/format-changed.js const { execSync } = require("child_process"); let input = ""; process.stdin.on("data", (chunk) => (input += chunk)); process.stdin.on("end", () => { const data = JSON.parse(input); const filePath = data.tool_input?.file_path || ""; try { if (filePath.endsWith(".ts")) { execSync(`npx prettier --write "${filePath}"`, { stdio: "inherit" }); } else if (filePath.endsWith(".json")) { execSync(`npx prettier --write "${filePath}"`, { stdio: "inherit" }); } } catch (e) { console.error(`格式化失败:${e.message}`); process.exit(1); } process.exit(0); });

CLAUDE.md 里则放偏好型规则和项目知识,和 hooks 形成分工:

# 项目约定 ## 构建与测试 - 安装依赖:npm ci - 本地开发:npm run dev - 单元测试:npm test - 类型检查:npm run typecheck ## 代码风格 - 使用 2 空格缩进 - 组件文件使用 PascalCase - 工具函数使用 camelCase - 提交前必须通过 eslint ## 硬约束(由 hooks 强制执行,不要依赖记忆) - 禁止修改 .env、.git、package-lock.json - 禁止覆盖历史 migration 文件 - 编辑 .ts 文件后会自动格式化 - 结束前会检查 lint 状态

提示:CLAUDE.md 里写「由 hooks 强制执行」的条目,是给模型看的说明,让它知道这些动作有脚本兜底,不必反复确认。真正的执行逻辑在 settings.json 和脚本里。

4. 验证请求:确认 hooks 真的生效

配好之后不能只看文件存在,要实际触发一次。Claude Code 提供了/hooks命令,它是只读的体检面板,可以浏览当前注册的 hooks。运行/hooks,确认PreToolUse、PostToolUse、Stop下都出现了你配置的脚本路径。如果没显示,先检查 JSON 是否合法,不能有尾随逗号和注释,再确认项目 hooks 放在.claude/settings.json。

验证写前保护,可以让 Claude Code 尝试修改一个受保护文件:

# 在 Claude Code 会话里输入 请把 .env 里的 API 地址改成 http://localhost:3000

如果 hook 生效,Claude Code 会收到阻断反馈,不会真正写入.env,而是告诉你该路径受保护。你可以在终端看到脚本输出的 stderr 信息。

验证写后整理,让 Claude Code 改一个.ts文件:

# 在 Claude Code 会话里输入 请把 src/utils/format.ts 里的 formatDate 函数改成支持时区参数

改动完成后,检查该文件是否被 prettier 重新格式化。可以故意写一段缩进混乱的代码,看 hook 是否自动修正。

验证 Stop hook,制造一个 lint 错误:

# 手动在某个 .ts 文件里加一行未使用的变量 const unusedVar = 123;

然后让 Claude Code 结束一轮响应。如果 Stop hook 检测到 lint 失败,会把原因反馈给模型,Claude Code 会继续尝试修复,而不是直接停下。这里要注意避免无限阻断,官方提醒 Stop hook 连续阻断太多次会遇到 block cap,所以脚本里最好记录已反馈次数,同一问题反馈过多次就允许停下。

验证模型通道是否走 TaoToken,可以在 hook 脚本里加一行日志,或者单独发一个请求:

curl -s https://taotoken.net/api/v1/messages \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 64, "messages": [{"role": "user", "content": "回复 ok"}] }'

返回正常内容说明 Key 和通道都没问题。如果返回鉴权错误,回到 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 检查 Key 是否有效。

5. 本篇常见错排查

hooks 看起来简单,进项目后坑不少。下面是我实测下来最容易遇到的几类问题。

脚本没执行。最常见的原因是 settings 文件位置错了,或者 JSON 不合法。项目 hooks 必须在.claude/settings.json,全局 hooks 在~/.claude/settings.json。JSON 里不能有尾随逗号和注释。matcher 大小写也要对上,Edit|Write和edit|write不是一回事。用/hooks确认配置是否注册到了正确事件下。

hook 输出污染导致 JSON 解析失败。command hook 如果要返回结构化 JSON,stdout 必须干净。脚本里多打印一行欢迎信息,或者 shell profile 在非交互 shell 里自动 echo,都可能让 Claude Code 解析失败。日志写 stderr 或文件,结构化控制只写 stdout。Windows 环境下还要注意 Git Bash、PowerShell、路径转义的差异,~/.claude会解析到%USERPROFILE%\.claude。

PreToolUse 和 PostToolUse 搞反。PreToolUse 发生在工具真正执行之前,适合做防线,返回 deny 可以阻断动作。PostToolUse 发生在工具调用成功之后,动作已经发生,不能撤销,适合做格式化、日志、校验。安全策略不能只依赖 PostToolUse。官方还提醒,PreToolUse hooks 在任何 permission-mode 检查之前触发,hook 返回 deny 即使处在 bypassPermissions 模式也会阻断,但 hook 返回 allow 不能绕过 settings 里的 deny 规则。

Stop hook 陷入循环。Stop hook 在 Claude 结束一轮响应时都会触发,不只是整个任务完成时。如果脚本每次都因为同一个 lint 错误阻断,Claude Code 会反复尝试,最终遇到 block cap。更稳的做法是记录已反馈次数,同一问题反馈过两次就允许停下,把问题留给人工处理。

hook 里调模型没走 TaoToken。如果 hook 脚本里发起了模型请求,要确保它读取的是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY环境变量,而不是硬编码了别的地址。环境变量没加载时,脚本可能回退到默认地址导致鉴权失败。可以在脚本开头加一行检查:

if (!process.env.ANTHROPIC_BASE_URL?.includes("taotoken.net")) { console.error("ANTHROPIC_BASE_URL 未指向 TaoToken,请检查环境变量"); process.exit(1); }

matcher 写得太宽导致性能下降。如果PostToolUse的 matcher 写成.*,每次工具调用都会跑脚本,Claude Code 小步迭代时会明显变慢。用Edit|Write限定到文件编辑,用Bash限定到命令执行,再用if细分高风险命令。

6. 把关键动作交给配置,而不是交给记忆力

Claude Code 的强大之处是自主性,hooks 的价值是给自主性加上可验证的轨道。没有 hooks 的 Claude Code,像一个很聪明但需要反复提醒的结对开发者。有了 hooks 以后,那些必须发生的动作从口头约定变成了运行时约束。

这里最适合的心态,不是给 Claude Code 加尽可能多的限制,而是把确定性动作从自然语言里抽出来。能用测试验证的,不让模型凭感觉判断;能用脚本检查的,不让模型凭记忆遵守;能用 PreToolUse 阻断的,不等 PostToolUse 事后补救;能放项目级配置共享的,不依赖某台机器上的个人习惯。

成熟的 Claude Code 项目通常会形成三层上下文。CLAUDE.md 放项目知识,告诉 Claude Code 怎么构建、怎么测试、代码风格是什么。permissions 放安全边界,定义哪些工具、命令、路径可以用。hooks 放固定流程,保证每次编辑、每次命令、每次停顿前后的必要动作都发生。

如果你还在用默认通道跑 Claude Code,建议先把 Key 和 API 通道统一到 TaoToken,再配 hooks。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,Claude Code 专用说明在 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 。长期做编码和 Agent 任务的话,Coding Plan 入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。通道理顺之后,hooks 才能真正稳定地跑起来,把关键动作从记忆依赖转为配置驱动。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询