用Claude Code写了两周代码,我最大的感受是:这东西好不好用,八成取决于你的CLAUDE.md写得怎么样。

很多人装上Claude Code就开干,结果改一行代码它动十个文件,命名风格随缘飘,每次对话都得重新交代项目背景。折腾下来,效率还不如自己敲。

CLAUDE.md就是Claude Code的配置文件——跟Cursor的.cursorrules类似,但分量更重。Claude Code跑在终端里,没有编辑器界面给它提供上下文线索,CLAUDE.md几乎是它理解你项目的唯一入口。

CLAUDE.md到底是什么

在项目根目录下放一个叫CLAUDE.md的文件就行,Claude Code每次启动会自动读取。里面可以写项目说明、编码规范、技术栈、注意事项,随便你。

your-project/
├── CLAUDE.md      ← 项目级配置
├── src/
├── package.json
└── ...

家目录还能放一个全局的:

~/.claude/CLAUDE.md   ← 全局配置,对所有项目生效

两者同时存在时,项目级的覆盖全局的。

我实际在用的CLAUDE.md

项目是Node.js + TypeScript后端,贴一下配置(敏感信息已脱敏):

# 项目概述

这是一个用户管理系统的后端服务,基于Node.js 20 + TypeScript 5 + Express。

# 技术栈

- 运行时:Node.js 20(ESM模式)
- 语言:TypeScript 5,strict模式
- 框架:Express 4
- ORM:Prisma 5
- 数据库:PostgreSQL 16
- 测试:Vitest

# 编码规范

- 使用函数式风格,避免class
- 变量和函数用camelCase,类型/接口用PascalCase
- 错误处理统一用Result模式,不抛异常
- API响应格式:{ code: number, data: T, message: string }
- 所有public函数必须写JSDoc注释

# 项目结构

- src/routes/ - 路由定义
- src/services/ - 业务逻辑
- src/repositories/ - 数据访问层
- src/middlewares/ - 中间件
- src/utils/ - 工具函数
- prisma/schema.prisma - 数据库模型

# 重要约束

- 数据库迁移用 prisma migrate,不要手动改SQL
- 环境变量从 .env 读取,不要硬编码配置
- 日志用 winston,不要用 console.log
- 新增API端点必须同时写测试

看着挺简单的对吧?但这玩意解决了我90%的"AI不听话"问题。

踩过的5个坑

1:CLAUDE.md写得太笼统

刚开始我的CLAUDE.md就一句话:“这是一个TypeScript后端项目”。然后Claude Code给我生成了class风格的代码、用了TypeORM、日志全打的console.log——每一个都是错的,但我压根没告诉它不该这么做。

后来我学乖了:宁可多写,别嫌啰嗦。特别是项目里"不用什么"比"用什么"还重要。“不要手动改SQL”、"不要用console.log"这种否定式约束,比正面描述管用得多。

2:忘了写错误处理规范

我的项目统一用Result模式处理错误,但CLAUDE.md里一开始没写。Claude Code默认就给你try-catch加throw,跟项目风格完全对不上。每次生成代码我都得手动改错误处理那块。

在"编码规范"里加了"错误处理统一用Result模式,不抛异常"之后,这个问题就没了。

3:项目结构描述缺失

有个接口要新增一个数据查询方法。Claude Code把数据库查询逻辑直接塞进了路由处理函数——三层架构愣是变成了面条代码。

根源就是我根本没在CLAUDE.md里提项目结构。它不知道我有repositories层专门做数据访问,也不知道services层负责业务逻辑。加上结构说明之后,新增接口它就老老实实地分三层写代码了。

4:全局和项目级配置打架

我在全局CLAUDE.md里写了"测试用Jest",但有个项目实际用的是Vitest。Claude Code在那个项目里也用Jest写测试——全局配置把项目实际情况给盖了。

正确做法:全局配置只放真正通用的东西,比如"git commit message用conventional commits格式"这种。项目特定的配置一定写在项目级CLAUDE.md里,因为项目级和全局合并时,项目级优先。

5:不更新CLAUDE.md

项目迭代了几周,引入了Redis做缓存,认证方案从JWT换成了Session。但我忘了更新CLAUDE.md。Claude Code还在按旧规范写代码——用JWT而不是新的Session方案,Redis完全不沾边。

一条经验:每次技术栈有变化,第一时间更新CLAUDE.md。过时的CLAUDE.md比没有还糟糕,因为它会给AI错误的方向,而AI还会很自信地照着走。

几条让CLAUDE.md更有效的写法

否定句式比肯定句式更管用。比起"使用winston记录日志","不要用console.log,用winston"效果更好。AI对明确的禁止指令响应更准确。

给示例比纯文字描述强。比如API响应格式,写一个类型定义比说"统一返回code、data、message"清楚太多:

interface ApiResponse<T> {
  code: number;
  data: T;
  message: string;
}

写清楚依赖版本。"Node.js 20"比"Node.js"靠谱,"Prisma 5"比"Prisma"靠谱。版本号能避免AI用已废弃的API,省得后面擦屁股。

区分约束强度也很有用。我一般分三档:必须/不要(违反就是bug),建议用(优先但不强制),可以考虑(可选方案)。措辞不一样,AI的执行力度也不一样。

CLAUDE.md和.cursorrules的关系

如果你同时用Cursor和Claude Code(我就这么干的),两个配置文件可以互相参考,但不建议直接照搬。

原因很简单:两者的上下文获取方式不一样。Cursor能直接读你打开的文件、知道光标在哪儿,它对"当前在干什么"门儿清。Claude Code靠的是CLAUDE.md和命令行对话,所以CLAUDE.md得写得更详尽,把Cursor能自动获取的那些上下文显式交代清楚。

我的做法是CLAUDE.md比.cursorrules多写30%的内容,基本上就是Cursor能自动感知但我得手动告诉Claude Code的那些东西。


CLAUDE.md不是写一次就完事的。它得跟着项目一起迭代,跟代码一样需要维护和更新。

花10分钟写好CLAUDE.md,省的是之后每次对话都得重复交代背景的那10分钟。怎么算都划算。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐