CLAUDE.md 让 Claude Code 真正听懂你的项目
很多人用 Claude Code 的方式是这样的:每次开启会话,先花几分钟解释项目背景,告诉 AI 这个函数是干什么的、那个目录放什么代码、用什么测试框架……然后下次会话再重复一遍。这不是 Claude Code 的正确用法,这是在把它当成一个没有记忆的聊天机器人用。
CLAUDE.md 就是解决这个问题的。它是 Claude Code 在启动时自动读取的上下文文件,相当于你给 AI 写的一份"项目说明书",永久存在、跨会话有效。但这个文件用好了能节省大量重复沟通成本,用不好就是一堆废话塞进了系统提示词,反而降低效果。
这篇文章讲清楚 CLAUDE.md 的机制、结构、实战技巧,以及大多数教程不会提到的坑。
一、CLAUDE.md 的工作原理
先理解它怎么工作的,才知道怎么写。
Claude Code 启动时,会按照固定的层级顺序加载 CLAUDE.md 文件,并将其内容注入到系统提示词(system prompt)中。加载顺序如下:
~/.claude/CLAUDE.md ← 全局配置(个人偏好、通用规范)
↓
{项目根目录}/CLAUDE.md ← 项目级配置(团队共享)
↓
{当前工作子目录}/CLAUDE.md ← 子目录配置(模块专属规范)
这三层是叠加关系,不是覆盖关系。子目录的 CLAUDE.md 会追加到父级内容之后,全部进入上下文。
关键点:这些内容进的是系统提示词,不是用户消息。这意味着:
- 它在每次对话开始前就已经存在
- 它比你后来输入的消息优先级更高
- 上下文有 token 限制,写太多会稀释有效信息
二、@import 拆分大型配置
当项目复杂、规范文档庞大时,把所有内容塞进一个文件会导致两个问题:维护困难、context 污染。
CLAUDE.md 支持 @import 语法来引入外部文件:
# 项目总规范
@./docs/architecture.md
@./docs/coding-standards.md
@./docs/team-conventions.md
被引入的文件内容会在加载时内联展开,效果等同于直接写在 CLAUDE.md 里。几个使用细节:
- 路径是相对路径,相对于 CLAUDE.md 文件本身所在目录
- 支持递归引入(被引入的文件里还可以继续
@import) - 循环引用会被静默跳过,不会报错也不会死循环
实际的组织方式可以这样:
项目根目录/
├── CLAUDE.md ← 只写 @import,作为入口
├── .claude/
│ ├── architecture.md ← 系统架构说明
│ ├── dev-commands.md ← 常用开发命令
│ ├── conventions.md ← 代码规范
│ └── known-issues.md ← 已知问题和解决方案
根目录的 CLAUDE.md:
@./.claude/architecture.md
@./.claude/dev-commands.md
@./.claude/conventions.md
@./.claude/known-issues.md
这样每个文件职责单一,改规范只改 conventions.md,加已知问题只改 known-issues.md,不会互相干扰。
三、CLAUDE.md 和 settings.json 的分工
这两个文件经常被混淆,但它们控制的是完全不同的层面。
CLAUDE.md 是给 AI 模型看的。它的内容进入系统提示词,影响 Claude 对项目的理解和行为决策。写在里面的是"你希望 Claude 知道什么"和"你希望 Claude 怎么做"。
settings.json 是给 Claude Code 这个工具本身看的。它控制的是工具层面的权限和行为,比如哪些 bash 命令可以自动执行、用哪个模型、环境变量怎么设。
// .claude/settings.json
{
"model": "claude-opus-4-6",
"permissions": {
"allow": [
"Bash(npm run test:*)",
"Bash(git log:*)",
"Bash(git diff:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)"
]
}
}
简单记法:
- 想让 Claude 理解某些东西 → 写 CLAUDE.md
- 想让 Claude Code 被允许或禁止做某些操作 → 写 settings.json
团队项目里,.claude/settings.json 应该提交到 git(约定团队共享的权限策略),而 .claude/settings.local.json 放个人配置并加入 .gitignore。
四、CLAUDE.md 该写什么——从低效到高效的对比
写 CLAUDE.md 最常见的错误是把它当成项目 README 来写,堆砌大量背景介绍。但 Claude 不需要你解释 React 是什么,它已经知道了。它需要的是你这个具体项目的特殊性。
低效写法(废话型)
## 技术栈
本项目使用 React 构建前端界面。React 是一个用于构建用户界面的 JavaScript 库,
由 Facebook 开发和维护。我们还使用了 TypeScript,这是 JavaScript 的超集...
这种写法在用 token 解释常识,对 Claude 毫无帮助。
高效写法(差异型)
只写 Claude 不知道、但必须知道的东西:
## 非标准约定
- 我们的组件库基于内部封装的 @company/ui,不使用 MUI 或 Ant Design
- 状态管理用 Zustand,禁止引入 Redux(历史遗留迁移中)
- API 请求统一走 src/lib/request.ts 的封装,不要直接用 axios 或 fetch
- 所有涉及金额的字段单位是分,不是元,显示层再做转换
## 目录结构特殊说明
- src/features/ 按业务域组织,每个子目录是一个独立的功能模块
- src/shared/ 放跨模块复用的代码,新增时需要考虑是否真的跨模块
- legacy/ 目录是待迁移的老代码,不要在里面加新逻辑
这才是有价值的上下文——那些 Claude 无法从代码本身推断出来的隐性知识。
五、六类必写内容
根据实际使用经验,以下六类内容是 CLAUDE.md 里投入产出比最高的部分:
1. 常用命令
每次让 Claude 运行测试或启动服务,它都需要猜或者问你用什么命令。直接告诉它:
## 开发命令
- 启动开发服务器:`pnpm dev`
- 运行全量测试:`pnpm test`
- 运行单个测试文件:`pnpm test path/to/file.test.ts`
- 构建:`pnpm build`
- 代码检查:`pnpm lint && pnpm typecheck`
- 数据库迁移:`pnpm db:migrate`
- 查看最近日志:`tail -f logs/app.log`
2. 禁止事项
这是最容易被忽略但效果最明显的一类。明确告诉 Claude 什么不能做:
## 禁止事项
- 不要修改 src/generated/ 目录,这里是自动生成的代码
- 不要直接操作数据库,数据库变更只通过迁移脚本
- 不要修改 .env.production,生产配置只能通过 CI 变量管理
- 不要把 console.log 提交进代码,调试完要清理
- 不要使用 any 类型,确实需要时用 unknown 并显式断言
3. 项目特有的陷阱和已知问题
把踩过的坑记下来,让 Claude 不要再踩:
## 已知陷阱
| 场景 | 问题 | 正确做法 |
|------|------|----------|
| 用户权限判断 | 不要直接读 user.role,角色可能有继承关系 | 用 checkPermission(user, 'action:resource') |
| 时区处理 | 数据库存的是 UTC,前端显示需要转本地时区 | 用 src/utils/time.ts 里的工具函数 |
| 文件上传 | 直传 OSS 需要先从后端获取签名 URL | 见 src/hooks/useUpload.ts |
| 分页 | 后端分页从第 1 页开始,不是第 0 页 | page 参数最小值是 1 |
4. 代码风格的非标准约定
ESLint 能约束的不用写,只写 lint 管不到的:
## 代码风格约定
- 错误处理:业务错误用 Result<T, E> 模式返回,不要直接 throw
- 注释语言:代码注释用中文(团队决策,非错误)
- 测试命名:`it('should...')` 格式,描述行为而不是实现
- 组件 props:复杂 props 单独定义类型,不要内联 FC<{...}>
- import 顺序:外部库 → 内部模块 → 相对路径(prettier-plugin-organize-imports 会自动处理)
5. 架构和模块边界
帮助 Claude 理解代码的组织逻辑,防止它把代码加到错误的地方:
## 架构说明
本项目是前后端分离的单体仓库(monorepo):
- apps/web:Next.js 前端,只负责 UI 和用户交互
- apps/api:Node.js 后端,负责业务逻辑和数据库操作
- packages/shared:前后端共用的类型定义和工具函数
模块边界规则:
- apps/web 不能直接访问数据库,所有数据通过 API
- packages/shared 不能引入 apps/ 下的任何内容
- 跨模块通信只通过公共接口,不允许跨层直接调用
6. 操作权限边界
明确哪些操作需要人工确认,给 Claude 设置心理安全边界:
## 操作权限
### 可以直接执行
- 读取和修改源代码
- 运行测试和构建命令
- 查看 git 历史和 diff
### 需要我确认再执行
- 数据库 schema 变更
- 安装或删除依赖包
- 修改 CI/CD 配置
### 不要执行
- 任何生产环境操作
- git push 到远程仓库
- 删除文件(除非我明确说要删)
六、Monorepo 的分层配置策略
单个项目的 CLAUDE.md 比较简单,Monorepo 需要更细致的规划。
推荐的结构:
monorepo/
├── CLAUDE.md ← 仓库级:整体架构、通用规范、工作流
├── apps/
│ ├── web/
│ │ └── CLAUDE.md ← Web 应用专属:组件规范、路由约定
│ └── api/
│ └── CLAUDE.md ← API 专属:接口设计规范、数据库操作
└── packages/
└── ui/
└── CLAUDE.md ← UI 库专属:组件设计原则、发布流程
进入不同子目录工作时,Claude Code 会自动叠加对应层级的 CLAUDE.md。在 apps/web/ 下工作时,它会同时读取根目录和 apps/web/ 的配置,不需要手动切换。
根目录 CLAUDE.md 只放真正全局的内容:
# Monorepo 全局规范
## 仓库结构
- apps/:可独立部署的应用
- packages/:被 apps 引用的共享包
- 依赖管理用 pnpm workspaces
## Git 工作流
- 主分支:main(保护分支,只接受 PR)
- 开发分支命名:feat/xxx、fix/xxx、chore/xxx
- commit 格式遵循 Conventional Commits
## 跨包依赖规则
- apps 可以引用 packages
- packages 之间禁止互相引用(防止循环依赖)
- 新增跨包依赖前先讨论
七、把 CLAUDE.md 当活文档维护
很多人写了 CLAUDE.md 就再也不更新了,导致里面充满过时信息。过时的信息比没有信息更糟糕——它会主动误导 Claude。
建立一个习惯:每次踩了新坑,立刻更新 CLAUDE.md。不需要等着整理,当时就写进去:
## 已知陷阱(最近更新)
- useEffect 里直接调用 setState 的问题:见 Issue #234,用 useCallback 包装
- 第三方库 date-fns v3 和 v2 API 不兼容,项目用的是 v3
同时,把维护 CLAUDE.md 纳入 code review 流程。凡是改了架构、引入了新约定、解决了重要 bug 的 PR,reviewer 都应该检查 CLAUDE.md 是否需要同步更新。
八、全局 CLAUDE.md 放什么
~/.claude/CLAUDE.md 是个人全局配置,对你所有项目都生效。适合放个人的工作偏好,而不是项目规范(项目规范应该在项目里,让团队共享)。
几个适合放在全局的内容:
# 个人全局配置
## 我的偏好
- 回复用中文
- 解释代码时给出具体的文件路径和行号,方便我跳转
- 提出修改方案时,先说要改什么,让我确认后再动手
- 不要在我没要求的情况下重构周边代码
## 我常用的工具
- 包管理器:pnpm(默认),部分老项目用 npm
- 测试框架:Vitest(新项目),Jest(老项目)
- 格式化:Prettier + ESLint
## 我不喜欢的风格
- 不要加过多注释,清晰的代码比注释更重要
- 不要生成过于冗长的函数,超过 50 行考虑拆分
- 错误信息要具体,不要只写 "something went wrong"
这部分纯粹是个人口味,提交到项目 CLAUDE.md 会影响其他团队成员,放全局最合适。
九、常见问题排查
写了 CLAUDE.md,但 Claude 好像没有遵守
检查步骤:
- 确认文件名是
CLAUDE.md,全大写,不是claude.md或Claude.md(大小写敏感) - 文件在项目根目录,不是某个子目录下
- 在 Claude Code 里输入
/memory命令,可以查看当前加载的所有记忆文件内容 - 指令是否太模糊,"注意代码质量"这种说法 Claude 无法执行,要写具体的规则
CLAUDE.md 写了很多,但感觉 Claude 回答质量变差了
可能是 context 稀释问题。文件太长会把有效的代码上下文挤出 context 窗口。检查是否有大量重复或冗余内容,精简到只保留关键信息。一般控制在 300 行以内比较合适。
子目录的 CLAUDE.md 内容和父目录冲突
Claude Code 的叠加机制不会自动解决冲突,两条矛盾的指令都会出现在系统提示词里,Claude 会尝试调和,结果不可预测。解决方法是在子目录 CLAUDE.md 开头明确说明优先级:
# 前端模块规范
以下规范针对 apps/web 模块,与根目录规范冲突时以本文件为准:
...
团队里有人把私人配置提交到了项目 CLAUDE.md
在 contributing guide 里说清楚分工:项目 CLAUDE.md 只放团队共识,个人偏好放 ~/.claude/CLAUDE.md。
十、可以直接用的模板
# [项目名] CLAUDE.md
## 项目概述
[一句话描述项目是什么,不需要介绍技术背景]
## 技术栈
- 语言:
- 框架:
- 数据库:
- 包管理器:
- 测试框架:
## 目录结构
[只列出非标准的、需要特别说明的目录]
## 常用命令
- 开发:
- 测试:
- 构建:
## 非标准约定
[这个项目里有别于业界惯例的做法——最重要的部分]
## 禁止事项
- 不要 [xxx]
- 不要修改 [xxx] 目录/文件
## 已知陷阱
| 场景 | 问题 | 正确做法 |
|------|------|----------|
| [场景] | [问题描述] | [解决方法或参考文件] |
## 操作权限
### 可直接执行
-
### 需要确认
-
### 禁止
-
总结
CLAUDE.md 的核心价值在于消除重复沟通。写好它的原则只有一条:只写 Claude 不知道但必须知道的东西。
通用知识不要写,项目特有的隐性知识一定要写。维护它的成本很低,一条有效的记录可以在未来几十次会话里节省时间。把它当成代码的一部分,纳入版本控制,纳入 code review,随项目一起演化。
用好这个文件,你和 Claude Code 的协作会从"反复解释背景的聊天"变成"直接干活的协作",这个差距比换模型更实际。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)