前情提要
- CLAUDE.md 有好几层:用户级的
~/.claude/CLAUDE.md、项目根目录的CLAUDE.md、不提交到仓库的CLAUDE.local.md,还有子目录里的- 多层 CLAUDE.md 不是互相覆盖,而是拼接在一起;离你启动位置越近的,越晚进入上下文
- 可以用
@路径把内容拆到别的文件里;.claude/rules/下的规则文件可以用paths限定只在碰到某些文件时生效- CLAUDE.md 是「建议」,不是「强制」,有小概率不遵守;用
/context能看到加载了哪些
关于 CLAUDE.md,有两个常见的困惑:
- 我在里面写了「必须」「绝对不要」,它为什么还是偶尔不听?
- 用户级、项目级、本地级好几份,到底谁先谁后、谁说了算?
这一节去源码里找答案。主要看两个文件:src/utils/claudemd.ts(找文件、读文件、拼文字)和 src/context.ts(交给循环)。
整个过程分四步:找 → 读 → 拼 → 放。
一、找:从根目录一路往下走

找文件的函数叫 getMemoryFiles(),简化之后是这样:
// src/utils/claudemd.ts → getMemoryFiles()(简化)
result.push(组织级 CLAUDE.md 和规则) // 1. IT 统一下发的
result.push(~/.claude/CLAUDE.md, ~/.claude/rules/*.md) // 2. 用户级
const dirs = [] // 3. 先收集「当前目录 → 根目录」的每一层……
for (let dir = cwd; dir !== 根目录; dir = 上一级(dir)) dirs.push(dir)
for (const dir of dirs.reverse()) { // ……再反过来,从根目录往下走到当前目录
result.push(dir/CLAUDE.md, dir/.claude/CLAUDE.md)
result.push(dir/.claude/rules/*.md) // 只要不带 paths 的
result.push(dir/CLAUDE.local.md)
}
result.push(MEMORY.md) // 4. 自动记忆的索引「离你启动位置越近的,越晚进入上下文」,就是 dirs.reverse() 这一行。为什么要倒过来?文件开头的注释给了答案:
文件按优先级从低到高加载:越晚加载的优先级越高,模型对它们的注意力也越多。
所以顺序是刻意安排的:组织级最先,然后是你的全局习惯,然后从外层目录往里走,最后是你启动的那个目录。同一层里 CLAUDE.local.md 排在 CLAUDE.md 后面,你的个人偏好也比团队规范更晚出现。
还有一个细节:result 就是一个数组,所有文件都往里 push。整个函数里没有任何「后面的替换前面的」的逻辑。两层规则打架时,代码不会帮你裁决,只能交给模型自己挑。
越具体的规则越靠后、越受重视;所有文件只拼接,不覆盖。
二、读:进上下文之前的四道处理

每个文件读进来,要先过 parseMemoryFileContent() 这一关。有四件你可能不知道的事。
1. paths 被取出来
frontmatter 里如果有 paths,这份规则就变成「条件规则」,启动时不加载,等 Claude 碰到匹配的文件再说。
2. HTML 注释被删掉
块级的 <!-- ... --> 注释会在进入上下文之前被删掉,代码块里的注释保留。
这是一个很实用的小技巧:给人看的说明写成 HTML 注释,不占模型的上下文。
<!-- 这条规则是 2026-09 线上事故之后加的,详见 docs/incident-0912.md -->
- 改数据库迁移文件之前,先跟我确认模型只看到第二行,维护的人能看到第一行。
3. @ 引入的六条规矩
用 @路径 可以把 CLAUDE.md 拆到别的文件里。源码里有几条文档没细说的规矩:
| 规矩 | 源码里的写法 |
|---|---|
| 最多嵌套 5 层 | MAX_INCLUDE_DEPTH = 5 |
| 只引入文本文件 | 有一份很长的扩展名白名单(.md、.json、.ts、.py……),图片、PDF 会被跳过 |
| 找不到文件不报错 | 注释原文:Non-existent files are silently ignored |
代码块里的 @ 不算 |
只在普通文本里识别 @路径 |
| 引入项目外的文件要你批准一次 | 用户级的 ~/.claude/CLAUDE.md 例外,可以随便引 |
| 同一个文件不会加载两次 | 防止循环引用 |
第三条最值得注意:路径写错了,Claude Code 不会提醒你。 所以引入之后,一定要用 /context 看一眼 Memory files 里有没有它。
4. 太长只警告,不截断
单个文件超过 4 万字符(MAX_MEMORY_CHARACTER_COUNT = 40000),界面上会提示 Large CLAUDE.md file detected,但内容照样全部加载。
官方建议的「200 行以内」是写作建议,代码不会帮你砍。真正会被截断的是自动记忆的索引 MEMORY.md:超过 200 行或 25KB 的部分直接截掉。
HTML 注释白送你一块「只给人看」的地方;@ 引入写错了不会报错,要自己检查。
三、拼:变成一段什么样的文字
所有文件读完,getClaudeMds() 把它们拼成一大段文字: