Claude Code 三大配置体系详解:settings.json / CLAUDE.md / memory
厘清 Claude Code 里三套容易混淆的配置机制各自的职责边界,以及作为开发者如何优雅地组合使用它们~~。~~
0. 一句话定位
三者解决的是三个完全不同层次的问题,不存在替代关系:
| 文件 / 目录 | 一句话职责 | 读者 | 加载时机 | 维护者 |
|---|---|---|---|---|
settings.json |
工具怎么运行 | 程序 | 进程启动时一次 | 人(手写) |
CLAUDE.md |
AI 该怎么做事 | AI | 每次会话全量注入 | 人(手写) |
memory/ |
AI 记住了什么事实 | AI | 索引全量 + 正文按需 | AI(自动写) |
常见误区是把它们当成「三个都能写规则的地方,随便挑一个」。实际上选错位置会带来真实代价: 写错到 settings.json 会不生效,写错到 CLAUDE.md 会白烧上下文,写错到 memory 会过期误导。
用一张图看清它们在启动链路上的位置差异:
图里最值得注意的是那个 此后改 settings 无效 的节点 ------ 这是三者里唯一有"启动时快照"语义的, 也是最容易踩坑的地方(改完在原会话反复验证,怎么看都没生效)。
1. settings.json --- 程序运行配置
1.1 定位
给程序读的运行参数,不是给 AI 读的指令。AI 完全感知不到这个文件的内容, 它只是在一个"已经被 settings 配置好"的环境里运行。
1.2 文件层级与覆盖关系
- 全局
~/.claude/settings.json--- 所有项目通用(token、网关地址、遥测、语言) - 项目
.claude/settings.json--- 团队共享,会提交进 git(团队统一的 hooks、permissions) - 项目
.claude/settings.local.json--- 个人本地,不提交(个人代理设置、个人放行的命令)
本机实例 (~/.claude/settings.json 顶层结构):
vbnet
env: dict(32) 环境变量注入
includeCoAuthoredBy: bool 提交是否带 Co-authored-by
permissions: dict(2) allow / deny 命令放行清单
hooks: dict(4) 工具调用前后钩子
statusLine: dict(2) 状态栏自定义
enabledPlugins: dict(5) 启用的插件
extraKnownMarketplaces: dict(2) 额外插件市场
language: str 交互语言
syntaxHighlightingDisabled: bool 语法高亮开关
1.3 各段实际用途
env --- 环境变量注入(最关键、最容易出问题的一段)
json
{
"env": {
"ANTHROPIC_BASE_URL": "https://xxx.com/anthropic/",
"ANTHROPIC_MODEL": "claude-opus-5[1m]",
"API_TIMEOUT_MS": "600000",
"no_proxy": "xxx.com,zhuaninc.com,127.0.0.1,localhost"
}
}
这一段的内容会真实注入到进程环境 ,可以用 env | grep -i anthropic 验证。 它的优先级高于 UI 里的交互式选择 ------ 这就是「/model 切了 1M 但重启失效」那个坑的根源。
permissions --- 命令放行清单
json
{
"permissions": {
"allow": [
"Bash(openspec list *)",
"mcp__dashen__getPageContent",
"WebFetch(domain:www.yuque.com)"
],
"deny": []
}
}
支持通配符(*)和精确匹配。放行后该类操作不再逐次弹确认,是提升流畅度的主要手段。 deny 优先于 allow,用来兜底禁掉危险操作。
hooks --- 工具调用钩子
在工具调用前后插入自定义脚本,典型用途是自动格式化、自动 lint、变更审计上报。
statusLine --- 状态栏
自定义底部状态栏显示内容(模型名、git 分支、context 占用百分比等)。
1.4 关键特性与坑
启动时读取一次,改完必须重开会话。
这是 settings.json 与另两者最大的行为差异。env 段在进程启动时注入, 之后无论怎么改文件,当前会话的环境变量都不会变。所以:
- 改完不要在原会话验证,要新开终端
- 想快速确认生效,用
env | grep看最终注入结果,别看配置文件声明
JSON 语法错误会静默失效。
整段配置失效时不会报明显错误,只在 /doctor 里留一个 setup issues: settings 提示, 很难联想到是自己刚改坏的。所以改完必须校验:
less
python3 -c "import json; json.load(open('/Users/zz/.claude/settings.json')); print('JSON OK')"
改全局配置前先备份。
javascript
cp ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%Y%m%d%H%M%S)
全局配置影响所有项目的所有会话,改坏的爆炸半径很大。
2. CLAUDE.md --- AI 行为规范
2.1 定位
给 AI 读的强制性指令 ,规定「在这个项目里该怎么写代码、怎么做事」。 它的地位相当于写给 AI 的团队开发规范,优先级高于 AI 的默认行为。
2.2 文件层级
本机实践 :全局 ~/.claude/CLAUDE.md 是空的(0 字节), 真正的全局规则拆到了 ~/.claude/rules/ 下按主题分文件:
javascript
~/.claude/rules/
├── zzcommon/
│ ├── common.md 日志规范
│ └── api-compatibility.md API 向后兼容规范
└── zzrd/
├── tech-stack.md 通用技术栈(SCF/ZZMQ/Apollo/K8s...)
├── java-conventions.md Java 编码约定
├── contract-conventions.md contract 模块约定
└── contract-dependencies.md contract 依赖管理
这种拆分方式值得推荐:按主题分文件比堆在一个大 CLAUDE.md 里更易维护, 也便于按需增删某一类规则,而不用在一个上千行的文件里定位。
2.3 该写什么
以本项目 meta/CLAUDE.md 为例,写进去的都是AI 无法从代码自行推断、且违反会出事的规范:
markdown
- **架构约束** --- 六层调用方向、`platform` 禁止直连 MySQL/ES、领域服务不得横向直连
- 分层纪律 ---
facade → service → dao → mapper严禁跨层 - 强制禁令 --- 禁止修改
service模块自身版本、merch/contract包路径约束 - 编码约定 ---
equals常量在前避免 NPE、空值判断各用哪个工具类、禁止魔法值 - 日志格式 ---
act={方法名} msg={信息} keyField={关键字段} - 流程规范 --- openspec change 必须含四个文件、
impact.md必须体现发布顺序与回滚策略
判断标准:如果 AI 不知道这条会写出「能编译但违反团队约定」的代码,就该写进去。
2.4 不该写什么
- 代码里已经能读到的 --- 目录结构、类名、函数签名。AI 直接读文件更准确,写进来只会过期。
- 一次性的临时结论 --- 「这次改动先不加测试」这种,属于当次对话的事。
- 机器/环境特定的事实 --- 「我这台机器的 Clash 会拦内网域名」。这不是团队规范, 而且项目
CLAUDE.md要提交进 git,会污染队友的环境认知。这类应该进memory。
2.5 关键特性:每次全量加载,所以必须精简
这是 CLAUDE.md 最重要的成本约束。它每次会话都被完整注入上下文, 无论这次对话是否用得上其中任何一条。
后果是:
- 写得越长,每次会话的固定上下文开销越大,留给实际任务的空间越小
- 长文档里的规则更容易被稀释 ------ 200 行里的一条禁令,注意力权重不如 20 行里的一条
所以 CLAUDE.md 应该保持高信息密度:每条都是真约束,不写解释性的背景介绍, 不写「建议」「最好」这种软性表述(要么是硬规则,要么就别写)。
3. memory/ --- AI 跨会话记忆
3.1 定位
AI 自己写的观察笔记,解决「每次开新会话都要把背景重讲一遍」的问题。
与 CLAUDE.md 的本质区别在于谁写、写什么:
CLAUDE.md是人写的规范 ------ 长期有效的应然规则(「日志必须是这个格式」)memory是AI 写的观察 ------ 从实际踩坑中提取的实然事实(「zzcli 报 SSL EOF 是 Clash 拦的」)
3.2 路径与结构
路径按项目隔离:
javascript
~/.claude/projects/<项目路径转义>/memory/
本机实例(-Users-zz-projects-meta 即 /Users/zz/projects/meta 转义后):
lua
memory/
├── MEMORY.md 索引,4.1KB,每次会话全量加载
├── env-zzcli-clash-proxy.md ┐
├── env-java-build-recipe.md │
├── feedback-markdown-output-format.md ├ 正文,共 100KB,按需加载
├── project-quality-adjustment-strategy.md │
└── ... (共 23 条) ┘
3.3 索引 + 正文两层设计(关键机制)
这是 memory 能规模化而 CLAUDE.md 不能的原因:
对比一下两种方案的成本:
- 全部写进
CLAUDE.md--- 100KB 每次会话都加载,绝大部分用不上,纯浪费 - 索引 + 按需 --- 固定成本只有 4.1KB 索引,正文只在相关时才读
索引行的格式(MEMORY.md 里每条一行):
scss
- [CLI 编译 Java 服务的配方](env-java-build-recipe.md) --- JDK8 + czy/maven/settings.xml(nexus) + no_proxy,否则 Lombok/依赖全挂
这行里的「hook」(破折号后那句)承担了相关性判断的职责 ------ 它要足够具体, 让 AI 光看这一行就能判断「当前任务是否需要展开这条」。写得太笼统(如「Java 相关」)会导致该读的时候没读到。
3.4 单条记忆的结构
yaml
---
name: env-claude-model-env-overrides-model-cmd
description: /model 选的默认模型会被 settings.json 里 env.ANTHROPIC_MODEL 压掉
metadata:
type: feedback
---
<结论:发生了什么,准确的 ID / 路径 / 日期>
**Why:** <为什么是这样,背后的机制>
**How to apply:** <下次遇到怎么用,具体命令和步骤>
相关:[[env-zzcli-clash-proxy]]
四种 type,对应四类事实:
user--- 你是谁:角色、技术栈偏好、习惯feedback--- 你给过的工作方式指导:纠正和确认过的做法,必须写清 whyproject--- 项目背景与目标:代码和 git 历史里读不出来的那部分reference--- 外部资源指针:URL、看板、工单号
[[name]] 双链把相关记忆连起来。链一个还不存在的名字也没关系 ------ 那标记了一个「以后值得写」的点。
3.5 关键特性:写入时快照,不是实时状态
memory 记的是写入那一刻的观察,可能已经过期。
所以引用记忆时的正确姿势是:如果某条记忆提到了具体的文件、函数、配置项, 先验证它现在还存在,再拿来当依据。这也是为什么写记忆时要带上绝对信息(准确 ID、绝对日期), 而不是「最近改的那个文件」这种相对表述。
3.6 什么不该记
- 仓库本身已记录的:代码结构、修过的 bug、git 历史
CLAUDE.md已有的规范(重复且更难维护)- 只在当次对话有意义的临时结论
判断标准:这条信息在三个月后的新会话里,还能帮我少问一个问题吗?
4. 三者对比总表
4.1 核心差异
读者与作用对象
settings.json--- 程序读。作用于运行环境(模型、网络、权限)CLAUDE.md--- AI 读。作用于行为方式(怎么写代码)memory/--- AI 读。作用于知识背景(知道什么事实)
加载时机
settings.json--- 进程启动时一次,改完必须重开会话CLAUDE.md--- 每次会话全量注入,改完下次会话生效memory/--- 索引全量注入 + 正文按需读取,可在会话中动态写入
维护方式
settings.json--- 人手写 JSON,语法错会静默失效CLAUDE.md--- 人手写 Markdown,需要主动精简memory/--- AI 自动写,人可以要求写/改/删
版本控制
settings.json--- 全局的不入 git;项目settings.json入 git,settings.local.json不入CLAUDE.md--- 项目级入 git,团队共享,这是它和另两者最大的协作差异memory/--- 不入 git,纯本地个人资产
内容规模约束
settings.json--- 无所谓,程序解析不占上下文CLAUDE.md--- 必须精简,每次全量加载,长度直接换成本memory/--- 可以很大(本机 100KB),索引控制在几 KB 即可
4.2 决策树:一条信息该放哪
4.3 边界案例辨析
「日志必须是 act=xx msg=xx 格式」 → CLAUDE.md。团队规范,稳定,需入 git 共享。
「我这台机器 Clash 会拦 *.xxx.com,要配 no_proxy」 → 两处都要,但内容不同:
settings.local.json的env段放实际的 no_proxy 值(让它真正生效)memory记**「报 SSL EOF 就是这个原因」**(让 AI 下次能快速定位,而不是重新排查)
这个例子很典型:配置负责「让它工作」,memory 负责「让 AI 知道为什么」。
「1M 上下文的模型 ID 是 claude-opus-5[1m]」 → settings.json 的 env.ANTHROPIC_MODEL 放值 + memory 记住这个坑的排查路径。同上。
「platform 禁止直连 MySQL」 → CLAUDE.md。架构硬约束,违反了会写出错误代码。
「成色调整策略的数据落在 mall 的 4 张表」 → memory(type: project)。是业务事实而非规范,且梳理过程有成本,不该每次重来。
「这次改动先不写测试」 → 哪都不放。当次对话说一句即可。
5. 优雅使用:开发者实践建议
5.1 settings.json 实践
分层归位,别把所有东西堆全局
- 全局
~/.claude/settings.json--- 只放跨项目通用的:token、网关地址、遥测、语言、模型 - 项目
.claude/settings.json--- 团队共享的 hooks、统一放行的命令(入 git) - 项目
.claude/settings.local.json--- 个人的代理设置、个人放行的命令(不入 git)
判断依据:换个项目还需要吗? 需要就全局,不需要就项目级。 队友也需要吗? 需要就 settings.json,不需要就 settings.local.json。
改动固定三步
bash
# 1. 备份
cp ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%Y%m%d%H%M%S)
# 2. 改完立刻校验
python3 -c "import json; json.load(open('/Users/zz/.claude/settings.json')); print('JSON OK')"
# 3. 新开终端验证(关键:原会话看不出效果)
用 permissions 换流畅度
反复弹确认最影响体验。把高频、安全的操作加进 allow:
json
"allow": [
"Bash(openspec list *)",
"Bash(git status)",
"Bash(git diff *)",
"mcp__dashen__getPageContent"
]
原则:只读操作和幂等操作大胆放行,写操作和外发操作保持确认。 危险的用 deny 明确禁掉(deny 优先级高于 allow),比留空更安全。
排查配置问题看结果不看声明
配置有多层覆盖,逐个翻文件容易漏。直接看最终注入结果:
bash
env | grep -i anthropic # 所有层叠加后的事实
5.2 CLAUDE.md 实践
按主题拆文件,不要堆单个大文件
本机的做法值得沿用 ------ 全局规则拆进 ~/.claude/rules/ 按主题分目录:
javascript
~/.claude/rules/
├── zzcommon/ 跨语言通用(日志、API 兼容)
└── zzrd/ 研发相关(技术栈、Java 约定、contract 规范)
好处是能按需增删某一类,且定位规则时不用在上千行里翻。
只写「违反了会出事」的硬约束
每加一条前问自己:AI 不知道这条会写出什么错的代码? 答不上来就别写。
反例(不该写):
- 「代码要有良好的可读性」 --- 无法执行的空话
- 「OrderService 在 service 包下」 --- AI 读代码就知道
- 「建议优先使用 Optional」 --- 软性表述,要么强制要么不写
正例(该写):
- 「
equals比较时常量放前面,避免变量为 null 时 NPE」 --- 具体、可执行、有明确后果 - 「禁止修改
service/pom.xml中模块自身的<version>」 --- 硬禁令,违反会引发发布事故
定期精简,把过期规则删掉
CLAUDE.md 会随项目演进堆积。每次大重构后回看一遍,删掉已经不适用的条目。 长度本身就是成本,留着过期规则比没有规则更糟(会误导 AI)。
用「强制执行」这类标记提升权重
本项目的做法:在关键章节标题里写 (强制执行)。这能让重要约束在长文档里不被稀释。
5.3 memory 实践
主动要求记,不要指望全自动
AI 会自动记一部分,但你觉得重要的应该明确说「把这个记进 memory」。 特别是这两类:
- 纠正过的做法 --- 「不要在主 clone 改,要在 worktree 改」这种,不记下次还犯
- 有成本的梳理结论 --- 花了一小时理清的业务链路,不记就白理了
hook 要写得能判断相关性
索引行的描述决定了 AI 会不会在需要时展开它。
不好:--- Java 编译相关 好:--- JDK8 + czy/maven/settings.xml(nexus) + no_proxy,否则 Lombok/依赖全挂
后者让 AI 光看索引就知道「我现在正遇到 Lombok 报错,该读这条」。
发现记忆过期就删掉
记忆是快照。如果某条已经不成立(配置变了、代码重构了),直接说「这条不对了,删掉」。 留着错的记忆比没有记忆危害更大。
定期回看索引
MEMORY.md 是全量加载的,条目会越积越多。隔一段时间扫一遍, 把重复的合并、过期的删掉、把「其实该进 CLAUDE.md 的规范」迁出去。
5.4 组合使用的典型工作流
关键节奏:规范往 CLAUDE.md 沉、事实往 memory 沉、参数往 settings 沉, 然后定期回头精简前两者。
6. 速查
症状 → 该查哪个文件
- 模型不对 / 网络不通 / 超时 →
settings.json的env段,先env | grep - 反复弹确认 →
settings.json的permissions.allow - AI 写的代码违反团队约定 →
CLAUDE.md里这条规则缺失或写得太软 - AI 每次都要重新问同样的背景 → 该记
memory了 - AI 引用了不存在的文件/函数 →
memory里有过期条目,删掉 /doctor报setup issues: settings→settings.jsonJSON 语法错了- 改了配置没生效 → 大概率是
settings.json,需要新开会话
三个必记的操作
bash
# 看配置最终生效结果(不看声明)
env | grep -i anthropic
# 改 settings 后校验
python3 -c "import json; json.load(open('/Users/zz/.claude/settings.json')); print('JSON OK')"
# 改 settings 前备份
cp ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%Y%m%d%H%M%S)