深度剖析Claude Code 的CLAUDE.md加载逻辑

Claude Code 配置文件加载机制详解

搞懂 CLAUDE.md 的优先级,让 AI 在不同目录下自动切换"人格"。


1. 背景:为什么需要多层配置?

先打个比方。你在一家公司上班:

arduino 复制代码
公司有一份《员工手册》          ← 全员通用规则
你的部门有一份《部门规范》       ← 部门特有规则
你自己有一份《个人备忘》         ← 你的私人习惯

当三者冲突时,谁说了算?
答案:离你最近的那个。

  公司手册:"统一用钉钉"
  部门规范:"我们用飞书"
  个人备忘:"我本地测试用微信"

  → 最终你用微信(最近的说了算)

Claude Code 的 CLAUDE.md 配置体系,逻辑完全一样:

objectivec 复制代码
问题                    解决方案
───────────────────    ─────────────────────────
团队规范不统一           根目录 CLAUDE.md(全员共享)
个人习惯被团队覆盖       CLAUDE.local.md(个人私有,不提交 git)
Monorepo 子项目各有技术栈  子目录 CLAUDE.md(模块特定配置)

2. 核心结论:最近原则

一句话

离当前工作目录最近的配置文件,优先级最高。

优先级排序(从低到高)

objectivec 复制代码
优先级从低 → 高:

  /CLAUDE.md             ← 最远(团队共享规则)
  /CLAUDE.local.md       ← 同层但更近(个人覆盖)
  /foo/CLAUDE.md         ← 距离更近(子目录规则)
  /foo/CLAUDE.local.md   ← 最近(子目录私有配置)
       ▲
       │
  最终说了算的是这个

"近"的两个维度

用一张图理解:

bash 复制代码
                    优先级高 ▲
                            │
    .local.md  ─────────────────  .md        ← 维度一:类型(私有 > 共享)
                            │
    子目录 /foo/ ───────────────  根目录 /    ← 维度二:距离(近 > 远)
                            │
                    优先级低 ▼
维度 规则 原因
距离 子目录 > 父目录 物理路径上离工作目录更近
类型 .local.md > .md 私有配置比共享配置更贴近个人意图

综合判断:距离优先,同层内类型优先。


3. 加载机制详解

扫描路径

从项目根目录出发,沿路径向下逐层扫描到当前工作目录,越靠近工作目录的文件优先级越高。

arduino 复制代码
扫描方向:

  项目根 ──────→ 当前工作目录
  (从这里开始)      (到这里结束)

  只扫"路径上的"目录,不扫旁支

合并逻辑(两步)

vbnet 复制代码
Step 1: 同层内 → .local.md 覆盖 .md
Step 2: 跨层间 → 子层覆盖父层

关键理解:不会向下扫描

objectivec 复制代码
project/
├── CLAUDE.md          ✅ 在根→工作目录的路径上,会加载
├── foo/
│   ├── CLAUDE.md      ✅ 在路径上,会加载(假设工作目录在 foo/bar/)
│   └── bar/           ← 工作目录在这里
│       └── CLAUDE.md  ❌ 这是工作目录自身,但不会再往下扫
└── other/
    └── CLAUDE.md      ❌ 不在路径上,完全忽略

4. 四种场景图解

实验目录结构

objectivec 复制代码
test-project/                    ← 项目根目录
├── CLAUDE.md                    # 内容:"包管理器用 npm"
├── CLAUDE.local.md              # 内容:"包管理器用 yarn"
└── foo/
    ├── CLAUDE.md                # 内容:"包管理器用 cnpm"
    ├── CLAUDE.local.md          # 内容:"包管理器用 pnpm"
    └── bar/                     ← 空目录

场景 1:在根目录工作

工作目录test-project/

objectivec 复制代码
扫描范围:只有根目录这一层

  /CLAUDE.md        → npm     ← 加载(远)
  /CLAUDE.local.md  → yarn    ← 加载(近,覆盖 npm)
  /foo/             → ❌ 不在路径上,跳过
文件 类型 内容 结果
/CLAUDE.md 共享 npm 被覆盖
/CLAUDE.local.md 私有 yarn 最终生效

最终答案yarn

要点foo/ 下的文件虽然存在,但不在"根→工作目录"的路径上,所以不加载。


场景 2:在 foo/bar/ 工作(完整四层叠加)

工作目录test-project/foo/bar/

objectivec 复制代码
扫描路径:根 → foo → bar

  根目录层:
    /CLAUDE.md        → npm     ← ①最远
    /CLAUDE.local.md  → yarn    ← ②同层覆盖

  foo 层:
    /foo/CLAUDE.md        → cnpm    ← ③更近,覆盖②
    /foo/CLAUDE.local.md  → pnpm    ← ④最近,覆盖③

  bar 层:
    (空,无配置文件)

覆盖链条

复制代码
npm → yarn → cnpm → pnpm
 ↑      ↑      ↑      ↑
最远   近    更近   最近(最终生效)

最终答案pnpm


场景 3:在 foo/ 工作

工作目录test-project/foo/

结果与场景 2 相同(pnpm),因为 bar/ 没有自己的配置文件,不影响覆盖链。


场景 4:不同维度的规则不冲突,合并生效

目录结构

objectivec 复制代码
test-project/
├── CLAUDE.md              # "禁止使用 console.log"
└── foo/
    ├── CLAUDE.md          # "优先使用 TypeScript"
    └── bar/               ← 工作目录
层级 文件 规则维度 内容 结果
/CLAUDE.md Lint 规范 禁止 console.log ✅ 生效
foo /foo/CLAUDE.md 语言选择 优先 TypeScript ✅ 生效

最终答案 :禁止 console.log + 优先 TypeScript(两条规则合并)

核心规则

  • 同维度规则(都是包管理器)→ 近的覆盖远的
  • 不同维度规则(lint 和语言)→ 不冲突,都生效

5. 流程图

css 复制代码
graph TD
    A[用户发起对话] --> B[确定当前工作目录]
    B --> C[从项目根到工作目录逐层扫描]
    C --> D{该层有 CLAUDE.md?}
    D -->|有| E[加入加载列表]
    D -->|无| F[跳过]
    E --> G{该层有 CLAUDE.local.md?}
    G -->|有| H[.local.md 覆盖同层 .md]
    G -->|无| I[继续下一层]
    H --> I
    F --> I
    I --> J{还有下一层?}
    J -->|有| C
    J -->|无| K[按距离从远到近排序]
    K --> L{规则是否同维度冲突?}
    L -->|是| M[近的覆盖远的]
    L -->|否| N[合并生效]
    M --> O[最终配置]
    N --> O
    O --> P[Claude 按此配置工作]

    style H fill:#ff9999
    style M fill:#ffcc99
    style N fill:#99cc99
    style O fill:#9999ff,color:#fff

6. 实际场景最佳实践

场景 A:团队协作 + 个人偏好

bash 复制代码
项目根目录/
├── CLAUDE.md              # 团队:npm + 缩进 2 空格 + 禁止 console.log
└── CLAUDE.local.md        # 个人:pnpm(不提交 git)

效果

你问 Claude 答案 原因
"包管理器用什么?" pnpm .local.md 更近,覆盖 npm
"缩进规则?" 2 空格 .local.md 没提缩进,远的规则保留
"能用 console.log 吗?" 不能 .local.md 没提这条,远的规则保留

场景 B:Monorepo 多模块

bash 复制代码
monorepo/
├── CLAUDE.md                    # 全仓库:TypeScript 严格模式
├── frontend/
│   ├── CLAUDE.md                # React 18 + Tailwind
│   └── CLAUDE.local.md          # 个人:开启 React DevTools
└── backend/
    ├── CLAUDE.md                # NestJS + PostgreSQL
    └── CLAUDE.local.md          # 个人:开启 SQL 日志
工作目录 加载文件(按距离远→近) 最终配置
monorepo/ .md TypeScript 严格模式
monorepo/frontend/ .md → frontend .md → frontend .local TS 严格 + React 18 + Tailwind + DevTools
monorepo/backend/ .md → backend .md → backend .local TS 严格 + NestJS + PostgreSQL + SQL 日志

价值:切换工作目录时,Claude 自动应用对应模块的配置,无需手动切换。


场景 C:临时调试

bash 复制代码
项目/
├── CLAUDE.md              # 生产:严格 lint,无调试输出
└── CLAUDE.local.md        # 调试:关闭 lint,verbose 日志

.local.md 不提交 git,调试完删掉即可,不影响团队。


7. 文件分工速查表

文件 放什么 提交 git? 优先级
根/CLAUDE.md 团队规范、安全红线、架构原则 最低
根/CLAUDE.local.md 个人习惯、调试偏好
子目录/CLAUDE.md 模块技术栈、框架选择
子目录/CLAUDE.local.md 模块调试配置 最高

内容示例

CLAUDE.md(团队共享)

markdown 复制代码
# 项目规范
- 编码语言:TypeScript 严格模式
- 包管理器:npm
- 缩进:2 空格
- 禁止:console.log、硬编码 secret
- 测试覆盖率:≥ 80%

CLAUDE.local.md(个人私有)

markdown 复制代码
# 个人偏好
- 包管理器:pnpm(覆盖团队 npm)
- 调试模式:开启 verbose 日志
- 临时关闭:eslint 部分规则

8. 常见疑问

Q1:距离近 vs 类型近,谁优先?

子目录/CLAUDE.md父目录/CLAUDE.local.md 冲突时:

bash 复制代码
/CLAUDE.local.md    → "用 yarn"    ← 类型近(.local),但距离远
/foo/CLAUDE.md      → "用 cnpm"    ← 类型远(.md),但距离近

答案:距离优先。 加载顺序是:

scss 复制代码
根 .md → 根 .local(yarn) → foo .md(cnpm)
                               ↑
                         距离更近,覆盖 yarn

最终结果是 cnpm

Q2:工作目录下的子目录配置会加载吗?

不会。Claude 只扫描"根→工作目录"这条路径,不会扫工作目录的子目录。

Q3:如果同层只有 .local.md 没有 .md 呢?

正常加载。.local.md 不要求 .md 必须存在。


9. 一句话总结

最近原则 :从项目根到当前工作目录逐层扫描,离你最近的配置文件说了算------同层内 .local.md 近,跨层间子目录比父目录近,不同维度的规则不冲突则合并。


参考资料:官方文档 - CLAUDE.md 加载顺序

相关推荐
米沙AI1 小时前
MSYS2 快速使用版本
后端
Csvn1 小时前
Docker 进阶 — 网络模型、数据持久化与多阶段构建
后端
用户4279254051711 小时前
《微博开放平台官方CLI开源了:70+API一行搞定,AI Agent原生支持》
后端
Csvn1 小时前
文本处理三剑客 — grep、sed、awk 实战精讲
后端
sarasuki1 小时前
JavaScript的对象、new的机制与原型包装类
javascript·后端
某鹏1 小时前
java伪共享问题的稳定解法
后端
fliter1 小时前
Rust 不是手动内存管理:它是声明式内存管理
后端
AI人工智能_电脑小能手1 小时前
【大白话说Java面试题 第125题】【并发篇】第25题:说说 Java 线程的中断机制
java·后端·面试
fliter2 小时前
Box 里到底装了什么:从 Go interface 到 Rust trait object
后端