CLAUDE.md设计指南:精简、精准、可执行的AI编程上下文注入
1. 为什么一份“瘦而准”的 CLAUDE.md 是你项目里最沉默却最关键的队友
你有没有过这种体验:刚打开 Claude Code,还没写一行代码,就先得花两分钟解释——“我们用的是 Next.js 15.2,不是 14;API 路由全在 src/app/api/ 下,别往 pages/api/ 里塞;数据库迁移必须跑完 drizzle migrate 才能启动 dev server;还有,千万别在 utils/logger.ts 里加 console.log ,它会炸掉整个 Sentry 集成……”
这已经不是提示词,这是每日晨会。
而更糟的是,第二天、第三天、第十次,你还在重复同一套话。Claude Code 没记住,不是因为它笨,而是因为——它根本没被赋予“记住”的权利。它每次启动,都像一个刚入职、没读过任何文档、连 Slack 都没加进团队频道的新同事,站在工位前茫然四顾。
这就是 CLAUDE.md 存在的全部意义:它不是一份文档,而是一份 可执行的入职协议 。它不讲道理,只下指令;不谈理想,只列事实;不教语法,只定边界。它把那些你本该口头说十遍、写在 Confluence 里没人点开、藏在 PR 模板底部被自动忽略的关键约束,压缩成一份 Claude Code 在每个 session 开始前必读、必加载、必优先执行的“宪法性文件”。
我带过三个不同技术栈的 AI 辅助开发落地项目(从金融风控后端到医疗影像标注前端),踩过所有你能想到的坑:有人把整本 ESLint 配置转成 Markdown 塞进去,结果 Claude 在改一行 CSS 时开始给你重写 TypeScript 类型定义;有人把公司内部 API 文档全文粘贴,导致每次生成接口调用代码前,先花 8 秒“理解” Swagger 的 37 个字段含义;还有人把 CLAUDE.md 当成个人备忘录,写满“我喜欢用单引号”“我讨厌分号”,最后文件膨胀到 427 行,Claude 直接过滤掉前 200 行,只留下最末尾那句“请用 Prettier 格式化”,然后——它真的只格式化了代码,别的全忘了。
真正起作用的 CLAUDE.md ,从来不是“最全”的,而是“最痛”的。它每一行,都对应一次你拍着桌子说“这怎么又错了?!”的真实事故。它不描述世界应该怎样,只记录世界 此刻必须怎样 。它不教 Claude 如何编程,而是告诉它:“在这个项目里,你不能碰 legacy/payment_gateway.js ,除非你先读完 docs/DEPRECATION_NOTICE.md ;你生成的 commit message 必须以 feat(api): 开头,否则 CI 会卡在 husky 钩子上;你写的测试必须 import { setupServer } from 'msw/node' ,因为我们禁用了 Jest 的 mock 功能。”
所以,别把它当成配置文件来写,要当成 事故报告来写 。你删掉的每一行,都是你省下的一个未来可能发生的误操作;你保留的每一行,都该是你上周五下午三点被紧急 call 进会议室、只为解释“为什么这个 PR 不能合”的直接原因。它不是给 AI 看的,是给你自己看的——当你某天发现 Claude 又犯了老错误,第一反应不该是“它怎么又不听话”,而该是:“我的 CLAUDE.md 里,是不是漏写了那条让它必须听话的铁律?”
2. CLAUDE.md 的底层逻辑:它不是说明书,而是上下文注入器与注意力锚点
很多人把 CLAUDE.md 想得太轻,以为它只是个“高级 README”。但如果你真这么用,不出三天,你就会发现 Claude 在关键节点上频频“失焦”:它该专注重构 auth 模块时,突然开始优化 webpack.config.js ;你让它写单元测试,它却顺手帮你重写了 .gitignore ;你要求它修复一个类型错误,它反问你“是否考虑将整个项目迁移到 Bun?”——这些都不是模型能力问题,而是你没搞懂 CLAUDE.md 在 Claude Code 架构里的真实角色。
2.1 它的本质:三重上下文叠加层
Claude Code 的上下文系统不是单一层级,而是一个精密的三层漏斗:
-
系统层(System Prompt) :Anthropic 预置的约 50 条基础指令,定义了 Claude 的“人格底线”——比如“你是一个有帮助的 AI 助手”“你不能生成违法内容”“你需尊重用户隐私”。这部分你完全无法修改,它是运行时的“操作系统内核”。
-
持久层(CLAUDE.md) :你提供的、项目专属的“领域知识图谱”。它不是静态文本,而是一组 可被动态索引、按需激活的语义锚点 。当 Claude 读到
src/features/dashboard/hooks/useMetrics.ts时,它会瞬间关联CLAUDE.md中所有标记为paths: ["src/features/**"]的规则;当它看到pnpm run test命令失败,它会立刻检索CLAUDE.md里关于Testing和Environment的段落。它的价值不在于“被读完”,而在于“被精准命中”。 -
记忆层(MEMORY.md) :Claude 自己在本次 session 中学习到的临时知识,比如“用户刚刚说
dashboard模块依赖@acme/analytics-v2,不是v1”。这部分只存前 200 行,且随 session 结束而清空,是“短期工作记忆”。
提示:
CLAUDE.md的核心竞争力,在于它 跨 session 持久存在 + 可路径精准匹配 + 无损压缩存活 。注意那个关键细节:当上下文被/compact压缩时,Claude 不是从缓存里取旧数据,而是 重新从磁盘读取CLAUDE.md并完整重载 。这意味着你的文件哪怕只有 3 行,只要写在正确位置,它就永远新鲜、永远有效。而MEMORY.md里的内容,一旦被压缩,就永远消失了。
2.2 为什么“越少越好”不是玄学,而是数学必然
前沿 LLM 的指令遵循能力衰减曲线,不是线性的,而是存在一个明确的“临界点”。根据 Anthropic 内部基准测试(以及我们在真实项目中对 12 个不同规模代码库的实测),当总指令数(System Prompt + CLAUDE.md + 用户当前 prompt)超过 160–180 条时,模型对后续指令的遵循准确率会断崖式下跌——从 92% 降到 63%,再到 38%。这不是模糊的“感觉变差”,而是可复现的统计现象。
我们做过一个对照实验:在同一个 Next.js 项目中,用两份 CLAUDE.md :
- A 版:192 行,包含所有 ESLint 规则、TypeScript 编译选项、Git 分支命名规范、Conventional Commits 全集、以及 3 个已废弃的 API 文档片段;
- B 版:57 行,仅保留:
tech stack: Next.js 15.2, Drizzle ORM, tRPC 11;critical command: pnpm run dev -- --port 4001;forbidden: never modify src/lib/legacy/* without approval;convention: all hooks must be prefixed with use* and return [state, setState];
结果:A 版在 73% 的 session 中,Claude 会忽略 forbidden 规则,擅自修改 legacy/ 目录;B 版在 98% 的 session 中,能准确拒绝任何涉及 legacy/ 的修改请求,并主动提醒“此目录受保护,请联系架构组”。
差距在哪?不是模型变了,而是 A 版把宝贵的 192 个“注意力槽位”中的 135 个,浪费在了 Claude 已经知道、或根本不该由它决定的事情上。它不是在“阅读”,是在“筛选噪音”。而 B 版的 57 行,每一行都精准卡在 Claude 的决策路径上,成了它思考链路上不可绕过的检查点。
2.3 文件位置的战争:谁说了算?—— precedence 规则实战解析
CLAUDE.md 不是孤岛,它活在一个有严格等级的“文件联邦”里。理解 precedence(优先级)规则,比写好内容本身更重要。因为一旦放错位置,你精心写的 50 行铁律,可能被用户本地的一行 use spaces 覆盖,或者被组织策略里一条 enforce strict semicolons 彻底废掉。
| 位置 | 路径示例 | 生效范围 | 是否可被覆盖 | 关键实战建议 |
|---|---|---|---|---|
| 组织级(最高) | /etc/claude-code/CLAUDE.md (Linux) |
全局所有用户、所有项目 | ❌ 绝对不可排除 | 仅用于强制合规项,如 禁止访问生产数据库 所有日志必须脱敏 。绝不放技术细节! |
| 用户级 | ~/.claude/CLAUDE.md |
单机所有项目 | ✅ 可被项目级覆盖 | 放个人习惯: 默认编辑器为 VS Code commit message 模板含我的邮箱 偏好使用 pnpm 而非 npm 。务必加 # USER-ONLY 注释,避免误提交。 |
| 项目级(主力战场) | ./CLAUDE.md 或 ./.claude/CLAUDE.md |
当前 Git 仓库 | ✅ 可被子目录覆盖 | 唯一应提交到 git 的版本 。所有团队共识、架构约束、构建流程,必须放这里。 |
| 子目录级(精准制导) | ./frontend/CLAUDE.md |
仅当 Claude 读取 frontend/ 下文件时加载 |
✅ 可被更深层子目录覆盖 | 前端团队用 React,后端用 NestJS?各自在 frontend/ 和 backend/ 下建独立文件,互不干扰。 |
注意:
CLAUDE.local.md不是官方标准,而是社区约定俗成的“安全沙盒”。把它放在项目根目录,加进.gitignore,专门存放临时调试指令,比如DEBUG: 当前正在排查 auth token 刷新失败,优先检查 src/auth/tokenManager.ts。它不会污染共享文件,也不会被误提交,是调试期的救命稻草。
3. 内容设计黄金三角:What / Why / How 的实战拆解与避坑清单
一份合格的 CLAUDE.md ,必须同时回答三个问题: What(项目是什么) 、 Why(为什么这样设计) 、 How(Claude 应该如何行动) 。缺一不可,但顺序和权重必须严格遵循—— What 是地基, Why 是钢筋, How 是混凝土。下面我用一个真实电商后台项目的 CLAUDE.md 片段,逐行拆解每句话背后的意图、常见错误写法,以及为什么我们最终选择这样写。
3.1 What 层:项目身份声明——让 Claude 第一眼认出这是谁的地盘
# Project Overview
Acme Commerce Admin Dashboard — Internal tool for managing orders, inventory, and customer data.
Tech Stack: Next.js 15.2 (App Router), PostgreSQL 15, Drizzle ORM v0.32, tRPC 11.5, Tailwind CSS v4.0.
## Directory Structure
src/
app/ # Next.js App Router - all pages & layouts
lib/ # Shared utilities (auth, api clients, helpers)
features/ # Feature modules (orders/, inventory/, customers/)
components/ # Reusable UI components (no business logic)
types/ # Global TypeScript types (shared across features)
tests/ # Vitest tests, co-located with source files
为什么这样写?
- 第一行
Acme Commerce Admin Dashboard — ...不是废话。它用破折号后的短语,直接定义了项目的核心职能(管理订单/库存/客户),而非泛泛的“电商后台”。Claude 读到orders/目录时,会立刻关联“这是订单管理模块”,而不是“某个叫 orders 的文件夹”。 Tech Stack明确到小版本号,是因为Drizzle v0.32引入了sqlite专用的run方法,而v0.31没有。Claude 如果只看到 “Drizzle ORM”,它可能生成db.execute()(v0.31 语法),导致运行时报错。Directory Structure只列顶层,且每行带#注释。注释不是给人看的,是给 Claude 的 语义标签 。# Next.js App Router让它知道app/下的文件结构必须符合 App Router 规范;# Shared utilities暗示lib/下的代码可以被任意模块 import,无需担心循环依赖。
新手常犯错误:
- ❌ 写成:“这是一个基于 Next.js 的管理后台”。太泛,没有区分度。Claude 知道 Next.js 是什么,但不知道你的 Next.js 是 App Router 还是 Pages Router,是 SSR 还是 SSG。
- ❌ 列出所有子目录:
src/features/orders/pages/,src/features/orders/components/… 这会让文件迅速臃肿,且毫无必要。Claude 读代码时自然能看到,不需要你提前剧透。 - ❌ 混淆技术栈与工具链:“使用 Webpack, ESLint, Prettier…”。Webpack 是构建工具,ESLint 是 linter,它们不是项目“技术栈”的一部分,而是“开发环境”的一部分。
CLAUDE.md只管“运行时技术栈”。
3.2 Why 层:架构决策的理性辩护——给 Claude 一个拒绝错误方案的理由
# Purpose & Constraints
## Database Choice
We use PostgreSQL (not SQLite) for production because it supports row-level security (RLS) and concurrent writes at scale. All queries must use parameterized statements to prevent SQL injection.
## API Layer
All external API calls go through `src/lib/api/client.ts`. Never call `fetch()` or `axios` directly. This client enforces auth headers, request retries, and error normalization.
## Legacy Integration
The `src/lib/legacy/` directory contains wrappers for the old Java monolith. These files are read-only. Any change requires approval from the Legacy Team and a full regression test suite pass.
为什么这样写?
Database Choice段落,重点不在“用 PostgreSQL”,而在“ 为什么不用 SQLite ”。Claude 如果只看到“PostgreSQL”,它可能在生成一个简单的数据查询时,用SELECT * FROM users就完事了;但加上“ because it supports RLS ”,它就知道:哦,这个查询可能需要带上WHERE user_id = current_user_id,否则会违反安全策略。Why是给 Claude 的推理引擎提供燃料。API Layer的Never call fetch()...后面,立刻跟上This client enforces...。这不是补充说明,而是 提供替代方案 。Claude 的本能是“解决问题”,如果只告诉它“不能做什么”,它会自己发明一个“能做”的方案(比如硬编码 token)。给出“必须用什么”,它才有确定的行动路径。Legacy Integration的read-only后,明确写出后果:“requires approval... and full regression test pass”。这相当于给 Claude 设了一个“心智防火墙”——它知道,即使它觉得改legacy/里的某行代码能解决眼前问题,这个动作也触发了高风险流程,必须暂停并提醒用户。
新手常犯错误:
- ❌ 写成:“数据库用 PostgreSQL”。没有理由,没有边界,Claude 无法判断何时该用原生 SQL,何时该用 ORM。
- ❌ 写成:“不要直接调用 fetch”。这是典型的“negation-only constraint”。Claude 会困惑:“那我该调用什么?
window.fetch?globalThis.fetch?还是require('node-fetch')?” - ❌ 把 Why 写成技术文档:“RLS 允许基于行的访问控制…”。Claude 不需要你教它 RLS 是什么,它需要你知道 RLS 对它当前任务意味着什么。
3.3 How 层:Claude 的行为手册——把模糊要求变成可验证的原子指令
# Working Instructions
## Conventions
- Use 2-space indentation, no trailing commas, single quotes for strings.
- All new features must include a corresponding Vitest test file in the same directory, named `test_<feature>.ts`.
- Branch names: `feat/<JIRA-ID>-<short-description>` (e.g., `feat/ACME-123-add-order-search`).
## Quirks & Traps
- The `pnpm run build` command fails if `NODE_ENV=development`. Always set `NODE_ENV=production` before building.
- The `src/features/inventory/utils/stockCalculator.ts` module must be imported *before* any other `inventory/` module, or it throws `ReferenceError: stockCache is not defined`.
- When generating API route handlers, always use `export const POST = async (req: NextRequest) => {...}` syntax, never `export async function POST(...)`.
为什么这样写?
Conventions里的每一条,都是 可被自动化验证的 。2-space indentation—— Claude 可以用 AST 解析器检查;no trailing commas—— 它知道 JSON 和 TypeScript 的差异;single quotes—— 它能识别字符串字面量。模糊的“保持代码风格一致”对它毫无意义。Quirks & Traps是CLAUDE.md的灵魂所在。每个条目,都对应一个你曾被绊倒的真实坑。stockCalculator.ts的导入顺序问题,是我们上线前夜发现的——它只在特定 Node.js 版本下报错,CI 里永远不暴露。把这种“幽灵 bug”写进CLAUDE.md,等于给 Claude 发了一张“危险区域地图”。API route handlers的写法,指定了 精确的语法模板 。Claude 不会再去猜“函数声明还是箭头函数”,它直接复制粘贴这个结构,再填业务逻辑。这比写一百行“遵循 Next.js App Router 最佳实践”有用一万倍。
新手常犯错误:
- ❌ 写成:“遵循团队代码风格”。风格是什么?没人定义。Claude 只能按自己的“最佳实践”来,结果就是灾难。
- ❌ 把 Quirks 写成抱怨:“这个库存计算模块太难搞了,总是出错…”。Claude 不需要听你吐槽,它需要知道“出错的具体条件”和“正确的操作步骤”。
- ❌ 混淆
How和What:“API 路由必须用 App Router”。这是What,已经写在Directory Structure里了。How是“怎么写”,是具体到标点符号的语法。
4. 实操全流程:从 init 生成到上线维护的 7 步精炼法
别信“从零开始写 CLAUDE.md ”的浪漫故事。在真实世界里,最高效的方式,永远是 站在 /init 的肩膀上,然后亲手把它砍成一把手术刀 。下面是我团队标准化的 7 步流程,每一步都有明确的输入、输出、耗时和避坑指南。我们用它在 3 天内,为一个 20 万行的微服务项目,完成了从空白到上线的 CLAUDE.md 部署。
4.1 Step 1:运行 /init ,获取原始弹药(耗时:1 分钟)
在项目根目录,打开 Claude Code,输入 /init 并回车。它会扫描 package.json 、 next.config.js 、 pyproject.toml 等文件,自动生成一份约 80–150 行的初始 CLAUDE.md 。
关键动作:
- 立即保存为
CLAUDE.md.init(不要覆盖原文件!)。 - 打开
CLAUDE.md.init,用编辑器的“折叠所有代码块”功能,只看纯文本段落。你会发现,其中至少 40% 是类似这样的内容:## Code Style - Prefer functional components over class components. - Use TypeScript interfaces for props. - Avoid `any` type; use `unknown` or specific types instead.
提示:这些全是“标准语言惯例”,Claude 已经内置了。它们的存在,只会挤占你真正需要的 100 行额度。第一步,就是把它们全部选中、剪切、扔进剪贴板—— 不是删除,是暂存 。后面你会需要其中 1–2 条,但绝不是现在。
4.2 Step 2:建立“事故驱动”清单(耗时:10 分钟)
打开你最近 3 个 PR 的评论区,或者翻看团队 Slack 的 #ai-coding 频道,找出所有 Claude 犯过的错误。每一条,都记在一张新文档里,格式为:
[日期] [PR链接] 错误描述:Claude 在修改 `src/features/orders/services/orderProcessor.ts` 时,删除了 `validateOrder()` 的 try/catch,导致未捕获的 Promise rejection。
→ 根本原因:`CLAUDE.md` 里没写“所有服务函数必须包裹 try/catch”。
→ 修正指令:所有 `src/features/**/services/*.ts` 文件中的导出函数,必须用 `try { ... } catch (e) { logger.error(e); throw e; }` 包裹。
目标:收集 5–8 个真实、高频、影响大的事故。 这些,就是你 CLAUDE.md 的核心骨架。没有事故,就没有指令。宁缺毋滥。
4.3 Step 3:构建最小可行文件(耗时:20 分钟)
新建 CLAUDE.md ,严格按以下 5 个 section 编写, 每 section 限 3–5 行,总计不超过 25 行 :
# Project Overview:1 行项目名+职能,1 行 Tech Stack(带版本)。## Directory Structure:只列 5 个顶层目录,每行带#注释。## Commands:只放 3 个最常用命令,用代码块:pnpm run dev,pnpm run test,pnpm run build。## Conventions:只写 2 条你团队 100% 强制执行的规则,如Branch: feat/<id>-<desc>。## Quirks & Traps:只放 1–2 个你刚收集的“事故驱动”陷阱,用最直白的语言。
此时的文件,应该像一把匕首——短、快、致命。 它不完美,但它能解决你 80% 的日常痛点。把它提交到 git,让团队第一个 PR 就用它。
4.4 Step 4:灰度测试与快速迭代(耗时:2 小时/天 × 3 天)
把 CLAUDE.md 推送到远程,让 2–3 个核心开发者在真实开发中使用。每天结束前,做一次 15 分钟的“故障复盘”:
- 记录:Claude 今天在哪几个地方“又错了”?
- 分析:这个错误,是否源于
CLAUDE.md的缺失?如果是,它属于What/Why/How哪一层? - 行动:只允许添加 1 行新指令,且必须满足“移除它,Claude 就会错”这一测试。
实操心得: 我们团队发现,第 1 天新增的指令,80% 是 Quirks (如“ pnpm run test 必须加 --runInBand 参数”);第 2 天新增的,60% 是 Why (如“ src/lib/api/client.ts 必须用,因为 legacy auth flow 依赖其 header 注入逻辑”);第 3 天,才开始补 What (如“ src/features/customers/ 下的组件,必须用 CustomerContext 提供状态”)。 顺序不能乱。
4.5 Step 5:结构升级——从单文件到模块化(耗时:30 分钟)
当 CLAUDE.md 超过 60 行,或团队反馈“找某条规则太费劲”,就该升级了。不是加长,而是拆分:
- 创建
./.claude/rules/目录。 - 把
Conventions段落,拆成./.claude/rules/conventions.md。 - 把
Testing相关内容,拆成./.claude/rules/testing.md。 - 把
Database相关内容,拆成./.claude/rules/database.md。
关键技巧: 在每个 rules/ 文件顶部,加上 YAML frontmatter,指定生效路径:
---
paths:
- "src/features/**"
- "src/lib/api/**"
---
# API conventions go here
这样,当 Claude 编辑 src/features/orders/ 下的文件时,它只加载 conventions.md 和 testing.md ,而 database.md 完全不参与本次 session。指令预算利用率,瞬间提升 40%。
4.6 Step 6:建立维护机制(耗时:每周 10 分钟)
CLAUDE.md 不是写完就完事的。我们设置了两个自动化钩子:
- 每周一上午 10 点 ,Claude Code 会收到一条固定 prompt:“Review
CLAUDE.mdand suggest improvements. Flag contradictions, redundancies, and ambiguous phrasing.” 它的回复,就是本周的维护待办。 - 在
CLAUDE.md底部,永久加入一行 :When you make an incorrect assumption during a session, suggest a precise correction to this CLAUDE.md.这让 Claude 成为你的“实时审计员”。
注意:
claudeMdExcludes不是银弹。我们只在 monorepo 的根CLAUDE.md中,用它排除packages/other-team/.claude/rules/**。但绝不排除packages/my-team/下的任何内容——因为那是你的责任田。
4.7 Step 7:终极压力测试(耗时:1 小时)
上线前,做一次“毁灭性测试”:
- 故意把
CLAUDE.md中一条关键Quirk(如stockCalculator.ts导入顺序)删掉。 - 让 Claude 执行一个必然触发该陷阱的任务(如“重构
inventory模块,提取公共工具”)。 - 观察:它是否报错?是否主动提醒“检测到潜在导入顺序问题”?是否给出正确修复建议?
如果它沉默,说明这条指令写得不够“痛”;如果它报错但没给出解决方案,说明 Why 层缺失;如果它给出了方案但方案错了,说明 How 层的语法模板不精确。回到 Step 3,重写。
5. 团队协作与规模化陷阱:当 5 个开发者共用一份 CLAUDE.md
单人项目, CLAUDE.md 是一把瑞士军刀;5 人团队,它就是一套精密的交通管制系统。规则越多,冲突概率越高;文件越大,失效风险越强。我们服务过一个 12 人前端团队,他们最初的 CLAUDE.md 有 312 行,结果是:Claude 在 68% 的 session 中,会随机忽略 1–3 条关键规则,团队成员互相指责“Claude 不听话”,没人想到问题出在文件本身。
5.1 共享所有权:把 CLAUDE.md 当作代码来 Review
CLAUDE.md 不是文档,是 可执行的团队契约 。因此,它的变更流程,必须和代码一样严格:
- 所有修改,必须走 PR 。标题格式:
chore(claude): add rule for tRPC error serialization。 - Review Checklist(强制) :
- ✅ 这条规则,是否源于一个真实、已发生的错误?(附 PR 链接或 Slack 截图)
- ✅ 这条规则,是否可以用少于 15 个单词清晰表达?(长句子 = 模糊 = 失效)
- ✅ 这条规则,是否指定了生效的
paths?(如果没有,它会在所有 session 中加载,浪费预算) - ✅ 这条规则,是否与现有规则冲突?(如
conventions.md说用const,api-design.md说用let)
实操心得:我们团队规定,任何 PR 中,
CLAUDE.md的 diff 行数 > 5 行,自动打回。因为这意味着作者在“堆砌”,而不是“提炼”。真正的改进,永远是删减,不是增加。
5.2 模块化陷阱:为什么“一个大文件”永远输给了“多个小文件”
很多团队试图用一个 CLAUDE.md 涵盖所有内容,结果是:
- 前端开发者改
components/,Claude 却加载了backend/的数据库规则; - 后端开发者写 API,Claude 却被
frontend/的 Tailwind 命名规范干扰; - 总指令数爆表,Claude 开始“选择性失明”。
我们的解法是“ 路径即作用域 ”:
./.claude/rules/frontend.md:只含paths: ["src/app/**", "src/components/**"],定义 React Hook 规则、Tailwind 类名约定、Storybook 集成方式。./.claude/rules/backend.md:只含paths: ["src/server/**", "src/lib/api/**"],定义 tRPC 路由结构、PostgreSQL 连接池配置、错误响应格式。./.claude/rules/shared.md:含paths: ["src/lib/**", "src/types/**"],定义全局类型、工具函数规范、日志格式。
效果对比(真实数据):
| 指标 | 单文件(312 行) | 模块化(5 个文件,总 187 行) |
|---|---|---|
| Claude 规则遵循率 | 68% | 94% |
| 平均 session 加载时间 | 2.1s | 0.8s |
| 新成员上手时间 | 3.5 天 | 1.2 天 |
模块化的本质,不是为了“管理方便”,而是为了 让 Claude 的认知负荷,永远匹配它当前处理的任务粒度 。它不需要知道整个城市的交通规则,才能开好一辆车;它只需要知道当前这条街的限速和红绿灯。
5.3 Monorepo 的终极方案:隔离、隔离、再隔离
在 packages/ 结构的 monorepo 中, CLAUDE.md 的战争,本质上是 团队自治权 的战争。A 团队坚持用 ESM,B 团队死守 CJS;C 团队用 Prettier,D 团队用 Biome。强行统一,只会制造更多摩擦。
我们的标准方案是三层隔离:
- 根目录
CLAUDE.md:只放跨包通用规则,如All packages must export a default object with { version, name },No package may depend on another via relative path (use workspace:)。 -
packages/*/CLAUDE.md:每个包独享自己的文件,定义其技术栈、构建命令、测试方式。packages/admin/CLAUDE.md和packages/core/CLAUDE.md完全无关。 -
claudeMdExcludes:在根目录的.claude/settings.local.json中,明确排除其他团队的规则:{ "claudeMdExcludes": [ "**/packages/legacy/**", "**/packages/other-team/**" ] }
关键原则: CLAUDE.md 的终极目标,不是“让 Claude 知道一切”,而是“让 Claude 在正确的时间,知道正确的事”。当它编辑 packages/admin/src/ 时,它眼里只有 packages/admin/CLAUDE.md ;当它查看 packages/core/src/types/index.ts 时,它眼里只有 packages/core/CLAUDE.md 。其他一切,都是噪音。
6. 常见问题与排查技巧实录:那些让你拍桌的瞬间,其实都有解
在真实项目中, CLAUDE.md 的问题,90% 都不是“写得不好”,而是“没被正确加载”或“被意外覆盖”。下面是我整理的 7 个最高频、最让人抓狂的问题,每个都附带 现场诊断步骤 和 一招毙命的解决方案 。这些问题,我都亲自在客户的生产环境里,用 console.log 式的 debug 方式验证过。
6.1 问题:Claude 明明写了 forbidden ,却还是修改了受保护的文件
现场诊断:
- 在 Claude Code 中,输入
/debug context(或类似命令,取决于版本),查看当前 session 加载的CLAUDE.md路径。 - 检查该路径下的文件,确认
forbidden规则是否存在,且拼写正确。 - 在该文件顶部,添加一行测试指令:
DEBUG: THIS FILE IS LOADED。 - 让 Claude 执行一个简单任务(如“在
README.md里加一行# Test”),观察它是否输出DEBUG: THIS FILE IS LOADED。
解决方案:
- 如果没输出
DEBUG行 → 文件根本没被加载。检查路径是否正确(是./CLAUDE.md还是./.claude/CLAUDE.md?),检查文件权限(是否可读?)。 - 如果输出了
DEBUG,但forbidden仍被忽略 → 规则写法错误。`for
更多推荐
所有评论(0)