Claude Code 三套配置体系详解:settings.json、CLAUDE.md 与 memory 的分工与协同
1. 三套配置体系到底在管什么很多人第一次接触 Claude Code看到项目根目录下同时存在settings.json、CLAUDE.md又听说还有个 memory 机制第一反应是懵的这三个东西不都是配置吗为什么要分三套我该把东西写哪儿我一开始也踩过这个坑。最初把所有规则一股脑塞进CLAUDE.md结果文件越写越长到了三四百行模型开始选择性失忆——前面写的代码风格约定它记得后面写的测试命令它当没看见。后来又把权限配置写进CLAUDE.md发现根本不起作用因为权限是settings.json的活儿写在 markdown 里模型只会当成一段普通文字读过去不会真的改变工具调用行为。所以先把三者的定位掰清楚这是后面所有操作的地基配置体系本质谁在读它生效时机典型内容settings.json结构化配置Claude Code 程序本身启动/会话加载时权限、环境变量、模型、hooksCLAUDE.md自然语言指令模型作为上下文每次会话注入项目约定、编码规范、常用命令memory持久化记忆模型 程序跨会话累积用户偏好、历史决策、学到的经验一句话概括settings.json管程序怎么跑CLAUDE.md管模型该怎么做memory 管它记住了什么。这三者的边界如果搞混轻则配置不生效重则出现我明明写了规则它却不遵守的抓狂场景。下面我按这个顺序把每一套体系拆开讲透包括文件放哪儿、写什么、怎么写、怎么验证生效。2. settings.json程序行为的硬开关2.1 文件位置与优先级settings.json是 Claude Code 的运行时配置它决定了程序层面的行为——能不能执行某个命令、用哪个模型、注入哪些环境变量。它的位置决定了作用范围这一点和很多工具的多级配置逻辑一致用户级~/.claude/settings.json对你所有项目生效适合放个人偏好比如默认模型、通用权限。项目级项目根目录下的.claude/settings.json只对这个项目生效适合放团队共享的配置。本地级.claude/settings.local.json通常加进.gitignore放你个人的、不想提交的临时配置。优先级上项目级覆盖用户级本地级覆盖项目级。这个设计意图很明确团队约定放项目级保证一致性个人临时调整放本地级不污染仓库。我见过有人把 API key 写进项目级settings.json然后提交了这是大忌密钥类的东西永远放本地级或者环境变量。注意.claude/settings.local.json一定要确认在.gitignore里。默认模板通常会加但如果你手动初始化过项目务必自己检查一遍。2.2 权限配置allow / deny / ask 三档权限是settings.json里最核心、也最容易配错的部分。Claude Code 执行任何工具调用读文件、写文件、跑命令前都会过一遍权限规则规则分三档allow直接放行不再询问。deny直接拒绝模型连尝试的机会都没有。ask每次询问你确认。配置结构长这样{ permissions: { allow: [ Read(*), Bash(npm run test:*), Bash(git status), Bash(git diff:*) ], deny: [ Read(.env), Read(**/*.pem), Bash(rm -rf:*), Bash(curl:*) ], ask: [ Bash(git push:*), Write(*) ] } }这里的匹配语法值得单独说。Bash(npm run test:*)里的:*是通配表示以npm run test开头的所有命令。Read(**)里的**匹配任意层级路径。写规则的时候要特别注意通配的粒度——Bash(git:*)会把git push --force也放行如果你不想让它强推就得单独把Bash(git push --force:*)放进 deny。我个人的经验是allow 列表只放高频、低风险、幂等的操作比如读文件、跑测试、看 git 状态。deny 列表放所有破坏性和外发类操作比如删除、网络请求、读取密钥文件。剩下的全部丢给 ask让程序每次问你。这样既减少了频繁确认的打扰又守住了安全底线。2.3 环境变量与模型选择settings.json还能注入环境变量和指定模型{ env: { NODE_ENV: development, PROJECT_ROOT: /Users/me/workspace/myapp }, model: claude-sonnet-4-5, hooks: { PostToolUse: [ { matcher: Write, hooks: [ { type: command, command: npx prettier --write $CLAUDE_FILE_PATH } ] } ] } }env里定义的环境变量会在 Claude Code 执行命令时注入这对需要特定环境才能跑起来的项目很有用。model指定默认模型如果你在多个模型间切换比如复杂任务用强模型、简单任务用快模型可以在这里设默认值会话里再临时覆盖。hooks是进阶玩法它让你在工具调用前后自动执行脚本。上面这个例子的意思是每次 Claude 写完文件Write工具自动跑一遍 prettier 格式化。这样模型写出来的代码风格就自动统一了不用在CLAUDE.md里反复叮嘱记得格式化。hooks 的价值在于把能自动化的规则从提示变成强制——提示模型可能忘hook 是程序级的一定会执行。2.4 验证配置是否生效配完settings.json别急着信一定要验证。最直接的办法是在会话里让它执行一个被 deny 的命令看是否被拦执行一个 allow 的命令看是否不询问直接过。如果行为不符合预期按这个顺序排查检查文件位置对不对是不是放到了不生效的层级。检查 JSON 语法一个多余的逗号就会让整个文件解析失败而程序可能只是静默忽略。检查优先级是不是被更高优先级的文件覆盖了。用/config之类的内置命令如果版本支持查看当前生效的配置。JSON 语法错误是最常见的坑因为很多编辑器不会对.claude/settings.json做 schema 校验。我的习惯是改完用python -m json.tool .claude/settings.json过一遍确认能解析再继续。3. CLAUDE.md给模型的自然语言说明书3.1 它和 settings.json 的本质区别如果说settings.json是给程序看的机器指令那CLAUDE.md就是给模型看的人类语言说明书。它不改变程序行为而是作为上下文注入到每次会话里影响模型的判断和输出。这个区别决定了很多事。比如你在CLAUDE.md里写不要执行 rm -rf模型大概率会遵守但这是软约束——它可能因为上下文太长而忽略也可能被后续指令覆盖。而你在settings.json的 deny 里写Bash(rm -rf:*)那是硬约束程序层面直接拦死模型再想执行也没用。安全相关的规则永远优先放 settings.jsonCLAUDE.md 只放风格和流程约定。3.2 该写什么、不该写什么CLAUDE.md最容易犯的错就是写成大杂烩。我总结了一个判断标准只写模型无法从代码本身推断出来的信息。该写的项目架构的非显而易见约定比如所有 API 响应必须包一层{code, data, message}。常用命令比如跑测试用pnpm test:unit不要用npm test。代码风格里工具管不到的部分比如注释用中文变量名用英文。业务背景比如这个模块处理的是跨境结算金额单位统一用分。不该写的能从代码读出来的东西比如这个文件导出了一个函数。通用编程常识比如写代码要注意边界条件。权限和安全规则这些归settings.json。大段大段的框架文档模型不需要你复述 React 怎么用。我见过一个CLAUDE.md写了八百多行把整个项目的目录结构、每个文件的作用都列了一遍。结果模型每次会话都要吞这么多 token既慢又贵而且真正重要的约定被淹没在噪音里。精简是 CLAUDE.md 的第一美德。3.3 分层组织全局、项目、目录CLAUDE.md支持分层这一点很多人不知道全局级~/.claude/CLAUDE.md对你所有项目生效放个人通用偏好比如回答用中文、代码块标注语言。项目级项目根目录的CLAUDE.md放这个项目的约定。目录级子目录里的CLAUDE.md只在该目录及其子目录相关操作时生效。分层的好处是按需加载。比如你有个frontend/目录用 React、backend/目录用 Go就可以在各自目录下放CLAUDE.md写各自的规范模型处理前端代码时不会读到后端的 Go 约定减少干扰。一个典型的项目级CLAUDE.md可以这样组织# 项目约定 ## 技术栈 - 前端React 18 TypeScript Vite - 后端Node.js Fastify - 数据库PostgreSQL Prisma ## 常用命令 - 安装依赖pnpm install - 启动开发pnpm dev - 跑测试pnpm test不要用 npm - 类型检查pnpm typecheck ## 代码规范 - 组件文件用 PascalCase工具函数用 camelCase - 所有异步操作必须处理错误不允许裸 await - 提交信息遵循 Conventional Commits ## 业务背景 - 金额单位统一用分避免浮点误差 - 时间统一用 UTC 存储展示时转本地时区这个结构的好处是分块清晰模型容易定位。我建议每个块用二级标题块内用列表避免长段落——模型对结构化内容的遵循度明显高于大段文字。3.4 写法技巧怎么让模型真的遵守写CLAUDE.md有几个实操技巧都是踩坑踩出来的第一用祈使句别用描述句。测试用 pnpm 比 本项目使用 pnpm 作为包管理器 更容易被遵守。前者是命令后者是陈述模型对命令的敏感度更高。第二把最重要的放最前面。上下文有首因效应开头的规则被遵守的概率更高。如果你有十条规则把最不能违反的放第一条。第三避免自相矛盾。我见过一个文件里前面写注释用英文后面又写关键逻辑加中文注释模型就懵了最后随机选一个。规则之间要一致有例外就明确写清楚例外条件。第四定期清理。项目演进后有些约定过时了要及时删。过时的规则比没有规则更糟因为它会误导模型。提示改完CLAUDE.md后新开会话验证效果。已经加载的会话不会自动重读文件你得重启才能看到变化。4. memory跨会话的持久记忆4.1 memory 解决的是什么问题前两套配置都是你写什么它读什么是静态的。但实际协作中有很多信息是在交互过程中产生的你纠正了模型一个错误、你表达了一个偏好、你们一起做了一个技术决策。这些信息如果每次都靠你手动写进CLAUDE.md太累了。memory 就是干这个的。它让 Claude Code 能够把会话中值得记住的信息持久化下来下次会话自动带上。这解决了每次都要重新交代一遍的痛点。举个我自己的例子我习惯用pnpm而不是npm但项目里没写死。第一次会话我纠正了它一次它把用户偏好 pnpm记进了 memory。之后所有会话它都默认用 pnpm不用我再提醒。这就是 memory 的价值——它把一次性的纠正变成长期的默认。4.2 memory 的存储与读取机制memory 通常以文件形式存在位置一般在~/.claude/下的某个目录里具体路径随版本可能变化用内置命令查看最准。它和CLAUDE.md的区别在于CLAUDE.md是你主动写的内容你完全掌控。memory 是模型自动积累的你只能间接影响。读取时机上memory 会在会话开始时加载和CLAUDE.md一起作为上下文注入。所以它俩本质上是同一类东西——都是给模型的上下文只是来源不同。这里有个关键认知memory 不是越多越好。它和CLAUDE.md共享上下文预算memory 塞太多留给实际任务的空间就少了。而且 memory 是模型自己写的质量参差不齐可能记了一堆没用的东西。所以定期review和清理 memory 是必要的维护工作。4.3 怎么管理 memory管理 memory 有几个实操手段查看当前 memory。用内置命令不同版本命令名可能不同常见的是/memory或类似入口查看当前积累了哪些记忆。第一次看可能会惊讶——它记的东西比你想象的多。手动编辑。memory 文件本质是文本你可以直接编辑删掉不想要的、修正记错的。这比让模型自己改更可控。用指令引导。你可以在会话里明确说记住这个项目所有日期用 ISO 8601 格式它会倾向于把这条写进 memory。反过来如果它记了你不想要的东西明确说忘掉刚才那条。定期清理。我一般每周花几分钟过一遍 memory把过时的、重复的、没用的删掉。保持精简和CLAUDE.md一样。4.4 memory 与 CLAUDE.md 的边界这两者容易混我给一个简单的判断标准稳定的、团队共享的、你希望明确掌控的→ 写进CLAUDE.md。个人的、动态积累的、模型自己总结的→ 交给 memory。比如项目用 pnpm这种团队约定应该写进项目级CLAUDE.md让所有人都受益。而我这个人喜欢简洁的回答这种个人偏好交给 memory 就行不用污染项目文件。还有一个细节如果 memory 和CLAUDE.md冲突了怎么办通常CLAUDE.md的优先级更高因为它是显式配置。但不同版本行为可能有差异遇到冲突时以实际测试为准。我的建议是避免让它们冲突发现冲突就手动清理 memory 里那条。5. 三套体系协同的实战配置5.1 一个完整项目的配置清单把三套体系串起来一个配置良好的项目应该是这样的myproject/ ├── .claude/ │ ├── settings.json # 团队共享权限、hooks │ └── settings.local.json # 个人本地密钥、临时调整gitignore ├── CLAUDE.md # 项目约定技术栈、命令、规范 ├── frontend/ │ └── CLAUDE.md # 前端专属约定 ├── backend/ │ └── CLAUDE.md # 后端专属约定 └── src/ └── ...用户级还有~/.claude/settings.json和~/.claude/CLAUDE.md放个人通用配置memory 则在~/.claude/下自动维护。5.2 配置分工的决策流程遇到一条新规则怎么决定放哪儿我总结了一个决策流程它涉及安全或程序行为吗权限、环境变量、hooks→settings.json。它是团队共享的稳定约定吗→ 项目级CLAUDE.md。它只对某个子目录生效吗→ 目录级CLAUDE.md。它是你个人的通用偏好跨项目适用吗→ 用户级CLAUDE.md。它是交互中动态产生的、模型自己总结的吗→ 交给 memory。按这个流程走基本不会放错地方。5.3 配置冲突的排查顺序当行为不符合预期时按这个顺序排查排查项检查内容常见问题settings.json 语法JSON 能否解析多余逗号、缺引号文件位置是否在生效层级放错目录优先级是否被覆盖本地级覆盖了项目级CLAUDE.md 内容是否自相矛盾前后规则冲突memory 干扰是否有过时记忆旧偏好覆盖新约定会话缓存是否需重启改了文件没重开会话这个表我贴在显示器边上出问题就从上往下过一遍八成能定位到。6. 踩坑记录与常见问题6.1 权限配置的五个坑坑一通配符写太宽。Bash(git:*)放行了所有 git 命令包括git push --force。正确做法是只放行读操作写操作走 ask。坑二deny 顺序问题。有些实现里 allow 和 deny 同时匹配时行为取决于具体规则引擎。保险起见别让同一条命令同时出现在两个列表里。坑三路径通配不生效。Read(*.env)可能只匹配当前目录匹配不到子目录的.env。要用Read(**/.env)或Read(**/*.env)。坑四忘了本地级文件。团队共享的settings.json里放了个人路径别人拉下来就报错。个人相关的永远放settings.local.json。坑五改了不重启。settings.json的改动通常需要重启会话才生效改完记得重开。6.2 CLAUDE.md 写不好的典型症状症状一模型不遵守。先检查是不是写成了描述句改成祈使句试试。再检查是不是被更长的上下文淹没了精简一下。症状二遵守了但很死板。说明规则写得太绝对没有留例外空间。加上除非...否则...的条件。症状三每次都要重复交代。说明该写进CLAUDE.md的东西你只在会话里说了没落盘。把它写进文件。症状四文件越来越长。定期清理把过时的删掉把能合并的合并。超过 200 行就该警惕了。6.3 memory 相关的疑问问memory 会无限增长吗不会自动无限但会持续累积需要你手动清理。不清理的话它会占用上下文预算拖慢响应。问怎么知道 memory 里有什么用内置命令查看或者直接找 memory 文件读。不同版本路径不同以实际为准。问memory 记错了怎么办直接编辑文件删掉或者在会话里明确纠正让它改。问多个项目的 memory 会混吗通常按项目隔离但用户级偏好可能共享。具体行为看版本测试一下最准。6.4 一个真实的排查案例有次我发现模型死活不用我配的测试命令明明CLAUDE.md里写了pnpm test它却一直跑npm test。排查过程检查CLAUDE.md命令写对了。检查settings.json没有相关权限问题。检查 memory发现里面有一条早期会话记下的用户使用 npm。这条 memory 和CLAUDE.md冲突且 memory 的加载顺序可能在后覆盖了文件约定。删掉那条 memory重启会话问题解决。这个案例的教训是memory 和CLAUDE.md冲突时不一定是文件赢。定期清理 memory避免它积累过时信息是必须的维护动作。7. 我个人的配置习惯最后分享几个我长期用下来觉得顺手的习惯不一定适合所有人但可以参考。settings.json 我分三层用。用户级放通用权限和默认模型项目级放团队共享的 hooks 和权限本地级放密钥和个人临时调整。三层各司其职互不干扰。CLAUDE.md 我控制在 100 行以内。超过就说明有东西该挪走——要么挪到目录级要么挪到 memory要么根本不该写。精简的文件模型遵守度明显更高。memory 我每周清一次。花五分钟过一遍删掉过时的、重复的、没用的。保持精简响应速度和准确度都更好。改完配置一定重开会话验证。不验证等于没改很多配置不生效的问题其实是没重启。安全规则永远放 settings.json 的 deny。不依赖模型的自觉用程序层面拦死。这是底线。这套配置体系用熟了之后你会发现 Claude Code 的协作体验会有质的提升——它不再是每次都要重新调教的工具而是一个记得你习惯、遵守你约定、在安全边界内自主工作的搭档。关键就在于把这三套体系用对地方别让它们互相打架。