如何写好 CLAUDE.md:一份精简实用指南

作者:袖梨 2026-09-14

Claude Code 每次进入新的项目会话时,都需要重新建立对代码库的认识。若缺少清晰的项目说明,它可能反复检索文件、误解架构约束,甚至重复已有实现。CLAUDE.md 的价值,就是以尽可能短的内容补齐这些关键信息;接下来将从编写原则、内容结构和超长后的拆分策略三个方面展开。

这个指南同样也适用于 AGENTS.md

CLAUDE.md 有什么用

首先我们要知道 CLAUDE.md 有什么用。因为模型就像一个新生儿。你每一次跟它对话,它都不知道你是谁,它是谁,你们前面说了什么。它都是通过你传给它的上下文得知这一切的。当然,Claude Code 有一些预设的上下文,所以它知道自己是 Claude Code,一个帮你写代码的工具。 所以每一次新的会话开始的时候,它对你的项目是一无所知的。之所以它工作得还不错,是因为 Claude Code 自己的预设上下文教它在遇到一个项目改动前,应该做什么来了解项目的信息。 所以你会发现它似乎很了解你的项目,但是又常常会重复造轮子。因为它有一套快速理解项目的方法论,但是还是做不到了解你项目的所有细节。当然你也不会希望它这么做,否则太烧 token 了。 这个时候就需要有人用简短的语言向它介绍这个项目的背景、架构等等信息。这样做的好处是:

  1. 它就不会去遍历你的项目,可以节省 token
  2. 它不会做很明显违背你的项目代码意图的事情,或者重复造轮子 这些简短的语言就会被放在 CLAUDE.md 中,或者 AGENTS.md 中。这个指南同时也适用于 AGENTS.md

编写原则

一份好的 CLAUDE.md 应该像: 新员工的最短上手指南: 想象着你在带一个新员工做一个任务。努力用最短的语言告诉他足够的知识。只要能够达到他上手可以干活,而且不至于把你的代码库搞砸就行。 用词犹如简历一般简洁: 我前一段时间在找工作,曾经向 HR 学习过怎么写简历。然后我就绞尽脑汁地把我长达 4 页的简历压缩成了 2 页。几乎删除了所有冗余的词语。每个句子都精简到无法再减少。你也应该这么写 CLAUDE.md高度抽象的知识: 你不需要告诉 Claude CodeCodex CLI 代码缩进是多少格,或者连接数据库参考什么文件的第几行。很多事情交给 hook 去做,代码的名字和行数都是会变的。你要告诉模型的是一些高度抽象的设计理念。 一般来说,一份好的 CLAUDE.md 长度应该在 200 行以内。

种类

包括项目根目录下的 CLAUDE.md 在内,其实有 3 种 CLAUDE.md

  1. ~/.claude/CLAUDE.md,作用范围是全局。你的所有项目都会用到它。
  2. ./CLAUDE.md,作用范围是项目。
  3. ./subdirectory/CLAUDE.md,子文件夹也可以有 CLAUDE.md

框架

并没有一个严格的、完美的 CLAUDE.md 框架。但是我参考了一些比较好的 CLAUDE.md 和相关文章,总结出了一个比较合理的 CLAUDE.md

  1. 一句话介绍
  2. 架构
  3. 技术栈
  4. 命令
  5. 约定
  6. 边界
  7. 领域文档映射表

一句话介绍

简单介绍这个项目是什么,大概的功能是什么。例子:

这是一个多智能体编排框架,用于协调并行运行的 Claude Code 子智能体,在 FastAPI + React 代码库上自动化执行开发/QA 工作流。

架构

简单介绍项目的架构,比如:

## Architecture
- Controller 保持轻量 —— 业务逻辑放在 `app/Services/` 中
- 数据库访问只能通过 `app/Repositories/`。禁止在 controller 中直接使用 Eloquent。
- `app/Http/Resources/` 中的 API resources 负责规范每一个 JSON 响应的结构。

技术栈

简单介绍项目的技术栈,类似:

## Tech Stack
- FastAPI,Python 3.11
- PostgreSQL 15(SQLAlchemy 2.0 异步)
- Celery + Redis 用于后台任务处理
- Poetry 用于依赖管理

命令

一些项目的常用命令,比如:

## Commands
- 开发服务器:`uvicorn app.main:app --reload`
- 运行测试:`pytest -x -v`
- 数据库迁移:`alembic upgrade head`

约定

无法被 linter 包含的抽象约定,类似:

## Conventions
- 布尔类型的变量/属性以 `is`、`has` 或 `should` 开头
- 所有日期时间统一以 UTC 格式存储和传递
- 事件名称遵循 `domain.action` 的命名格式

边界

文件修改的边界:

## Boundaries
- `legacy/` — 老版支付系统,只做紧急 bug 修复,不引入新模式或重构
- `src/generated/` — Prisma/GraphQL 自动生成
- `vendor/`, `third_party/` — 第三方代码,通过升级依赖版本解决问题,不直接修改

领域文档映射表

领域名词和文档的对应关系:

## Domain Doc Map
| 提及 | 阅读 |
|---|---|
| billing, stripe, payment, subscription, invoice | docs/billing.md |
| auth, login, session, oauth, jwt | docs/auth.md |
| migration, schema, drizzle, kysely | docs/db-migrations.md |
| feature flag, rollout, kill switch | docs/feature-flags.md |

我们把这几个例子拼起来,看一个好的 CLAUDE.md 应该像这样:

这是一个多智能体编排框架,用于协调并行运行的 Claude Code 子智能体,在 FastAPI + React 代码库上自动化执行开发/QA 工作流。

## Architecture
- Controller 保持轻量 —— 业务逻辑放在 `app/Services/` 中
- 数据库访问只能通过 `app/Repositories/`。禁止在 controller 中直接使用 Eloquent。
- `app/Http/Resources/` 中的 API resources 负责规范每一个 JSON 响应的结构。
  
## Tech Stack
- FastAPI,Python 3.11
- PostgreSQL 15(SQLAlchemy 2.0 异步)
- Celery + Redis 用于后台任务处理
- Poetry 用于依赖管理

## Commands
- 开发服务器:`uvicorn app.main:app --reload`
- 运行测试:`pytest -x -v`
- 数据库迁移:`alembic upgrade head`

## Conventions
- 布尔类型的变量/属性以 `is`、`has` 或 `should` 开头
- 所有日期时间统一以 UTC 格式存储和传递
- 事件名称遵循 `domain.action` 的命名格式

## Boundaries
- `legacy/` — 老版支付系统,只做紧急 bug 修复,不引入新模式或重构
- `src/generated/` — Prisma/GraphQL 自动生成
- `vendor/`, `third_party/` — 第三方代码,通过升级依赖版本解决问题,不直接修改

## Domain Doc Map
| 提及 | 阅读 |
|---|---|
| billing, stripe, payment, subscription, invoice | docs/billing.md |
| auth, login, session, oauth, jwt | docs/auth.md |
| migration, schema, drizzle, kysely | docs/db-migrations.md |
| feature flag, rollout, kill switch | docs/feature-flags.md |

要不要写 Never

你可能在别的指导上看到一个段落叫 Never,用来记录曾经犯过的错。听起来很好。但是我不太建议增加这个部分。因为 Never 的特点是 只有添加的动机,没有删除的动机。导致这个部分越来越长,甚至 Claude Code 自己都会去加,而且没有人会去删除它。时间久了就会变成一个历史事故墓地。 我建议的做法是:当问题出现了,把出问题的模式反过来,写成一种正向的规则。比如“不要在 webhook/stripe.ts 里做同步数据库写入”,改成“只在 repository/ 内做数据库操作”。

修剪

就算你按照以上的框架编写了 CLAUDE.md,对于一个大项目,或者维护周期较长的项目,或者这个项目已经有了 CLAUDE.md,你还是会发现这个文件的长度无法控制在 200 行以内。那么就要进入修剪步骤。 修剪就是把东西从 CLAUDE.md 中移除出去。具体的移动方法和路径有以下几种:

  1. 自定义子智能体:.claude/agents
  2. 规则文件夹:.claude/rules
  3. 子目录 CLAUDE.md:./subdirectory/CLAUDE.md
  4. 固定工作流:.claude/skills/
  5. 其他文档:docs/ 你会发现我给它们编了号。这是因为文档的抽取是有优先级的。顺序是从具体到抽象,从精准到泛化。

自定义子智能体

把所有关于子智能体的指导文档都抽取到 .claude/agents 下,比如: 你可以定义一个专门用来跑集成测试的 agent。文件名叫 integration-tester.md。内容:

---
name: integration-tester
description: Runs integration tests
tools: Bash
model: sonnet
---

You run and diagnose integration tests. You should follow these steps.....

规则文件夹

具体的规则文件可以放在 .claude/rules 中。分为带路径和不带路径两种。不带路径的优先级等同于 CLAUDE.md,比如:

# Security Rules

- All user input is validated at the API boundary
- Secrets and API keys are read from environment variables only
- SQL queries always use parameterized statements

带路径的会在满足指定路径的条件下才被加载,比如:

---
paths:
  - "tests/**/*.py"
  - "**/*.spec.ts"
---

# Unit Testing Rules

- One assertion concept per test
- Test names describe behavior, not implementation
....

规则文件和领域文档映射表: 你可能会有疑问:“规则文件和领域文档映射表会不会重复定义了相同的东西?”是的,确实会出现这个问题。比如,你可能会定义 billings/ 路径下的文件应该遵循 billings 相关的文档,然后在领域文档映射表中也有一行 | billings | docs/billings.md |,这样确实是重复了。 解决的办法就是把文档分为 规则背景。规则文件强制性高,放到 .claude/rules 中。背景文件相对较弱,放到 docs/ 中。

子目录 CLAUDE.md

针对某些子目录的规则可以移动到这些目录下,常见的场景有 sql/domains/adapters/ 文件夹。在这些目录下的 CLAUDE.md 不必遵循特定的框架。但是还是要保持简短。

固定工作流

如果有一些固定的、需要按顺序做的操作,就尽量做成项目级的 skill,然后放到 .claude/skills/ 下。

其他文档

其他的文档放到 docs/ 目录下。这个目录下放一些比较泛化的文档。比如更具体的 architecture.md,或者把 ADR(Architecture Decision Record)文档放到 docs/adr/ 文件夹下,比如 docs/adr/0001-migrate-to-drizzle.md

如何开始

如果你还没有一份 CLAUDE.md 或者 AGENTS.md,那么按照以下步骤开始做:

  1. 运行 /init 生成一份初稿
  2. 开始根据以上方法来修改初稿

未来也要记得定时运行 /doctor 来优化 CLAUDE.md

关于作者

我是代码Plato。

我相信,人类的创造力才是 AI Coding 的真实之树,而代码与模型不过是投射在洞穴墙上的影子。

微博:@代码Plato 主页:weibo.com/u/104125788…

相关文章

精彩推荐