
如果你在命令行里正式跑过几天 Claude Code一定会遇到一个现象同一个仓库、同一套提示词在 A 机器上表现得像个老员工在 B 机器上却像个第一次进组的新人。差别通常不在模型而在配置。我最初也以为 Claude Code 的配置就是“写个 CLAUDE.md 就行了”后来把项目、用户、全局三层配置全理了一遍才发现真正决定协作效率的是三套东西settings.json控制工具行为CLAUDE.md控制项目规则memory 控制跨会话记忆。它们各管一摊又互相配合用好了是乘法效应用不好就是互相拆台。这篇文章我把自己的实测过程、踩过的坑、以及最终沉淀下来的配置习惯完整整理出来。适合刚开始接触 Claude Code 的人按图索骥也适合已经用了一段时间但总觉得“AI 不够懂我”的人对照检查。内容不涉及任何平台专属功能纯粹从配置原理和实践角度讲清楚这三套体系。1. 三个配置体系各管一摊事1.1 为什么不是“一个配置文件走天下”很多人第一次接触 Claude Code 时第一反应是找“那个配置文件”。但深入看下来会发现它的配置被刻意拆成了三个层面每一层解决一类问题。settings.json解决“工具怎么运转”的问题。比如用哪个模型、哪些操作需要询问、环境变量怎么注入、命令权限怎么控制。CLAUDE.md解决“项目有什么规矩”的问题。比如代码风格、测试命令、目录结构、禁止事项、提交规范。memory解决“模型怎么记住前后文之外的事”的问题。比如你上次说过的偏好、跨会话需要复用的背景信息。这个拆分逻辑其实和现实中的团队协作很像公司有行政制度settings.json项目组有项目章程CLAUDE.md老员工脑子里还存着历史经验和人情世故memory。三者缺一不可也不能互相替代。我见过不少人把项目规范全塞进 settings.json或者把工具权限写进 CLAUDE.md结果就是配置臃肿、优先级混乱、改一处崩一片。理解了这三者的分工后面所有操作才有意义。1.2 三者的定位差异与生效顺序三套配置最核心的区别在于“作用域”和“时效性”。配置项主要作用域更新方式典型用途settings.json用户级 / 项目级手动编辑重载生效模型选择、权限、环境变量、HookCLAUDE.md项目级 / 用户级每次都读取改完即用项目说明、代码规范、命令约定memory用户级 / 跨项目对话中动态写入长期偏好、历史结论、常用工作流从“时效性”上看settings.json 更像静态配置改完需要重开会话或重载才能稳定生效CLAUDE.md 是每次启动会话都会读取的静态指南改完可以立刻被下一次对话感知memory 则是动态积累的模型在对话过程中不断写入和检索。从“生效顺序”上看越具体的作用域越优先。项目级 settings 会覆盖用户级 settings项目根目录的 CLAUDE.md 会比用户目录下的 CLAUDE.md 更贴合当前任务。memory 则是一个独立的信息层它不覆盖前两者但会补充前两者没写的细节。提示这里说的“覆盖”不是整体替换而是逐项合并。比如用户级 settings.json 里指定了 model项目级 settings.json 里也指定了 model项目级生效但如果项目级没写 model用户级的就会兜底。2. settings.json工具行为的总开关2.1 文件在哪规则在哪层settings.json 不是只有一个。Claude Code 会按层级读取多个位置常见的是这三个用户级~/.claude/settings.json项目级项目根目录/.claude/settings.json本地级项目根目录/.claude/settings.local.json其中settings.local.json通常用来放本地私有的、不入库的配置比如开发者本人才用的调试环境变量、某个人的自定义权限。项目级的settings.json则适合提交进 Git 仓库方便团队共享。实际操作时我通常会先看一眼当前环境到底加载了哪些配置。可以在 Claude Code 会话里问它当前生效的 settings 路径或者直接翻~/.claude目录确认是否存在重复文件。有一次我改了项目里的.claude/settings.json结果一直不生效查了半天才发现~/.claude/settings.json里有一段旧配置把同名参数占住了。这个文件的格式是标准的 JSON。如果你习惯在编辑器里给 JSON 加注释注意要避免——Claude Code 加载配置时并不总会容忍注释一旦解析失败会直接跳过该文件甚至出现“改了配置但完全没变化”的诡异现象。最稳妥的做法是保持严格 JSON 语法每一项都检查逗号和括号。2.2 最常用的配置项逐个说清楚我从实际项目里挑几个高频配置项逐个说清楚。model指定会话所用模型。这个字段可以在配置里直接写比如model: opus或model: sonnet。如果你同时接入了多个模型服务这个字段的优先级会影响最终调用。需要留意的是第三方兼容接口有时不认这个字段反而要去环境变量里指定模型名。permissions权限控制是 settings.json 里我最看重的一块。它通常包含三种动作类型allow、deny、ask。比如允许执行git status、git diff拒绝执行危险的rm -rf其余命令弹窗询问。这个配置决定了 Claude 是“大胆干活”还是“事事问你”直接影响使用体验。我见过有人图省事把所有命令全 allow几天后 AI 在一个项目里执行了一串我根本不想跑的自动化脚本教训很直接。env注入环境变量。可以把 API Key、基础 URL、超时时间等写在这里。要注意的是env 里的内容会被 Claude Code 注入到它执行的命令环境中所以不要明文存放真正的敏感密钥。更稳妥的做法是引用系统已有的环境变量或者用系统密钥管理工具。hooks生命周期钩子。可以在某些事件触发时执行外部脚本比如每次对话结束往日志文件里写一条记录或者在某个工具调用前做一次校验。hooks 的配置稍复杂属于进阶用法但它能解决很多“靠对话约束不牢靠”的问题。includeCoAuthoredBy控制生成 commit 时是否附带协作署名信息。这个字段是个人偏好但团队协作时最好统一标准否则 commit 历史会花掉。还有一个容易被忽略的点settings.json 里可以设置的选项远不止这些不同版本会持续增加。我建议偶尔用配置检查命令或直接翻阅官方文档筛选当前版本支持的字段避免拿着旧版记忆写新配置。2.3 权限、环境变量和 hook 的实操示例一份我常用的项目级 settings.json 大概长这样{ model: sonnet, permissions: { defaultMode: acceptEdits, allow: [ Bash(git status*), Bash(git diff*), Bash(npm test*), Bash(npm run lint*) ], ask: [ Bash(rm -rf *), Bash(git push*) ], deny: [ Bash(rm -rf /), Read(/.env) ] }, env: { MY_PROJECT_DEBUG: false }, hooks: { PostToolUse: [ { matcher: Bash, hooks: [ { type: command, command: echo \$(date) bash executed\ .claude/hook.log } ] } ] } }这份配置的意图是默认接受文件编辑常规读写类命令可以直接跑删除目录和 push 前先问一遍完全禁止删除根目录和读取仓库敏感文件。defaultMode设置为acceptEdits可以减少很多确认弹窗但对不熟悉的项目我会改成plan模式先让它出方案再动手。环境变量这块我踩过一次不小的坑我把第三方模型的 base_url 写在了项目 env 里结果换到另一个模型服务时忘了改导致所有请求都打到旧地址。后来我把这类不稳定的变量从 settings.json 挪到了 shell 的 export 里settings 里只保留项目必需的稳定变量。hooks 配置也不宜写得过重。它适合做轻量级埋点不适合在链路里跑重量级脚本。重量级任务放进 CLAUDE.md 让模型自己决定是否执行反而更灵活。2.4 踩过的 settings.json 坑先说最普遍的配置了但没重载。Claude Code 虽然会动态读取很多内容但 settings.json 的变更在某些场景下不会立刻让当前会话感知到。最好的习惯是改完配置后重开一个会话或者至少用/config之类的命令确认当前配置状态。再说 JSON 解析问题。我曾经在一份配置里给最后一个对象加了尾逗号编辑器友好地没报错但 Claude Code 加载时直接忽略了整个文件导致所有权限全部回落到默认值。排查过程非常费劲因为表面上所有设置都“存在”实际上根本没被读出来。后来我会在改完配置后用一个简单的命令验证而不是直接打开会话。还有一点是关于路径的。项目级 settings.json 必须放在项目根目录的.claude文件夹下不是~/.claude也不是任意位置。如果你在一个子目录里启动 Claude Code它未必能找到项目根目录的配置。这个细节在 monorepo 结构里尤其容易踩子项目、根项目、用户级三份配置同时存在时务必要搞清楚以谁为准。3. CLAUDE.md把项目规矩喂给模型3.1 加载逻辑和作用域如果说 settings.json 是工具的“外壳”那 CLAUDE.md 就是模型的“外脑”。它告诉模型当前项目是怎么组织的、有哪些约定、哪些命令能用、哪些事情绝不能做。CLAUDE.md 的加载逻辑简单说就是每个会话启动时Claude Code 会把对应层级的 CLAUDE.md 作为上下文的一部分喂给模型。常见层级包括用户级~/.claude/CLAUDE.md和项目级项目根目录的CLAUDE.md。用户级内容对所有项目生效项目级内容只对当前项目生效。不同层级的 CLAUDE.md 不是“二选一”而是都会进入上下文。所以如果用户级文件里写了“所有项目都不要用 pnpm”项目级又写了“本仓库必须用 pnpm禁止用 npm”模型就面临指令冲突。这种冲突不一定会报错但会让模型在某些时刻选择性执行表现不稳定。我自己的做法是用户级 CLAUDE.md 只写“跨项目通用的偏好和底线”比如统一的 Git 提交格式、注释语言偏好、不允许在对话里泄露密钥项目级 CLAUDE.md 写“本仓库特有的事实”比如构建命令、测试命令、目录职责划分。3.2 写一份不废话的 CLAUDE.mdCLAUDE.md 是给模型看的项目文档但它不是越详细越好。模型上下文窗口再大也经不起大段无意义内容的消耗。一份能用的 CLAUDE.md应该像入职第一天发的新人手册而不是一整本规章制度汇编。我常用的结构是四段式# 项目名 ## 这是什么 一个用 Python 写的定时任务平台负责从上游拉取数据并写入仓库。 ## 常用命令 - 启动开发环境: make dev - 跑单元测试: make test - 跑 lint: make lint - 构建镜像: make build ## 目录结构 - src/ 核心代码 - tests/ 测试用例 - scripts/ 运维脚本 - docs/ 项目文档 ## 硬性约束 - 禁止把数据库密码写入任何代码文件 - 所有对外 API 必须带版本号 - 提交信息必须符合 Conventional Commits这个结构胜在短。模型读一遍就能记住主干遇到具体问题时再结合代码内容去理解。不要写“本项目的愿景是成为行业内领先的……”这类废话也不要贴大段架构图文字描述。模型需要的是可执行信息不是企业宣传材料。注意CLAUDE.md 里可以用 Markdown 列表但不要滥用层级。我自己踩过的坑是一个子项目 CLAUDE.md 写了七层嵌套列表结果模型在处理深层内容时经常忽略前面的列表关系犯一些比较低级的错误。后来我把所有嵌套关系压缩成“先说明一句话再列四五个要点”的形式效果明显更好。3.3 CLAUDE.md 的维护节奏CLAUDE.md 不需要频繁更新但也不能一年不动。我的维护节奏是项目结构发生重大变化时立刻更新新增或删除了常用命令时立刻更新引入新的代码规范时立刻更新。凡是模型需要“知道就能少犯错”的信息都值得写进去。有一个容易忽略的点CLAUDE.md 里写的命令必须经过验证。如果写了make dev但实际项目里用的是npm run dev模型照着执行会得到错误反馈并且可能反复尝试浪费大量时间。所以我每次更新 CLAUDE.md 后会在新会话里做一次冒烟测试让它描述项目启动流程看它提到的话语是否和文件里一致再让它执行一次最简单的命令确认命令本身真实可用。关于 CLAUDE.md 的长度我的经验阈值是一般不超过 80 到 120 行。超过这个范围说明项目规则过于复杂应该考虑拆分到独立的 docs 文件里然后在 CLAUDE.md 中只写索引和核心要点。模型在处理“索引”时确实能按需去读更多内容比把所有细节都堆在主文件里更高效。4. memory跨会话记忆的正确打开方式4.1 我理解的 memory 机制如果说 CLAUDE.md 是“静态文档”那 memory 就是“动态脑内笔记”。它不是一次写入永久生效的而是随着你的使用习惯持续积累、按需被检索。在实际使用中memory 通常由两部分构成一是 Claude Code 自动从对话中提炼并保存的关键事实二是用户明确要求记住的内容。比如你在一个 Python 项目里说“记住这个项目的依赖统一用 uv 管理别用 pip”它会尝试把这个约定写入记忆存储下次你重新打开一个会话它可能不需要你再解释一遍就按这个偏好执行。memory 与 CLAUDE.md 的区别非常关键CLAUDE.md 是显式文本模型每次启动都会读memory 是动态数据库或文件集合模型在需要的时候按相关性提取并不会把所有记忆一股脑塞进每一轮对话。因此 memory 适合放“事实型长期信息”不适合放“每轮必读的强约束”。不同版本对 memory 的交互命令可能略有差异但思路一致你可以用自然语言让它记住、调用、忘记也可以通过/memory或配置文件直接查看和编辑已存内容。我不建议把精力花在死记某个奇特命令上而是把行为模式固定下来换版本也不会乱。4.2 哪些内容值得进 memory这是全套配置里最需要克制的一环。memory 不是越多越好塞太多反而会让模型在提取信息时“拣了芝麻丢了西瓜”。我的筛选标准有三个是否跨会话长期有效。临时任务放进会话上下文就好不要写进 memory。是否属于“事实型信息”。比如项目部署流程、团队约定的命名规范、常用工具的路径。判断类的主观偏好如果经常变化也不适合写死。是否会影响后续行为。如果这段记忆不能让模型在后续任务中做出更合适的决策就不值得保存。举个例子我会让 model 记住这个项目的生产环境数据库千万不能执行迁移要改表结构必须先走评审流程。我对代码注释的语言偏好是中文代码里的标识符用英文。每次完成重构后必须顺手更新对应模块的 README。我不会让它记住的包括某次会话里的临时需求、一次性排障步骤、某个具体文件的实现细节。这些东西留着只会污染记忆库。同时memory 不是神圣不可改的。如果你发现模型总是因为某条旧记忆跑偏最简单粗暴的办法就是直接删除那条记忆。有些记忆甚至要主动“纠正”比如项目换了技术栈旧记忆里全是老框架的约定这时候不清洗只会让模型一直停留在过去。4.3 memory 的维护和存档技巧维护 memory 最现实的问题有两个看不见和失控。看不见是指你很难实时察觉模型到底记住了什么失控是指记忆越攒越多模型在某些关键时刻提取了过时或冲突的信息。我的解决办法是定期做一次“记忆审计”。每个周末我会抽几分钟打开记忆存储目录或命令面板浏览一遍已经保存的条目。凡是过时的、无用的、冲突的随手清理。如果 memory 支持分类或分组我会按项目维度来组织。比如为每个手头项目单独保存一份记忆上下文避免 A 项目的约定被模型带到 B 项目。没有分类能力的情况下我会在条目里显式写明项目名比如“项目 X 的部署要求”这样模型在提取时更容易定位。还有一个比较实用的技巧把 memory 当成“轻量级索引”把 CLAUDE.md 当成“完整手册”。memory 里只留下“这个项目有一个 CLAUDE.md里面记录了部署流程”CLAUDE.md 里再写完整流程。这样既能让模型快速感知项目有文档又不会因为 memory 内容过重而挤占上下文。5. 常见问题排查实录5.1 配置改了没生效这是出现频率最高的问题。我遇到的情况通常有四种。第一改错文件。检查一下你改的是不是当前项目真正加载的那份 settings.json 或 CLAUDE.md。项目里同时存在多份同名文件时很容易改到非生效文件。第二JSON 解析失败。settings.json 里只要有一个地方语法不正确整个配置文件就可能被跳过。这种情况视觉上最迷惑因为文件内容看起来一切正常。我一律采用严格 JSON 校验的编辑器插件保存后立即提示错误。第三会话未重载。settings.json 的很多变更需要新会话生效。旧会话里就算你反复说“现在重新加载配置”模型也可能只是在当前上下文里象征性处理实际的权限和钩子仍是旧的。第四优先级被覆盖。项目级配置被用户级配置中的同名项抢先或反过来。排查时可以用一个很小的测试在配置里写一个非常显眼的 env 变量然后让模型打印出来看它读取的是哪个值。5.2 配置内容互相打架settings.json、CLAUDE.md、memory 三套体系并行偶尔会出现同一个主题被不同层定义了。最典型的就是“包管理器”之争settings.json 的 hook 里写了 npmCLAUDE.md 里写了 pnpmmemory 里又说不要用 pnpm。模型在不同时间可能听不同的话。我的处理原则是强约束放进 permissions 或直接通过命令控制中等约束写进 CLAUDE.md弱偏好才交给 memory。不要把一件事同时写进三个体系只保留最高优先级的那一份。如果真的遇到冲突优先以项目级 CLAUDE.md 为准其次查看 settings.json 里的权限是否明确放行或禁止最后才是 memory。因为 memory 是动态内容不像显式文档那样稳定可靠。5.3 记忆混乱如何清理模型表现突然变差、频繁提起一些你没说过的话多半是 memory 出了问题。排查步骤很简单先查看当前记忆存储确认是否有旧条目内容与实际项目背离。如果有直接删除或重写。删除后开一个新会话测试同一任务观察行为是否恢复。有一回我发现模型在一个 Java 项目里反复建议用 Python 写脚本追查后发现是几个月前另一个项目的记忆串场了。那次之后我就养成了“换项目先审计记忆”的习惯尤其是切换技术栈时都会主动清理掉和当前项目无关的记忆条目。配置问题速查表症状可能原因处理方式配置没生效改错层级 / JSON 错误 / 未重载确认文件路径校验 JSON重开会话模型不执行项目规范CLAUDE.md 太长或优先级冲突压缩内容检查用户级文件是否冲突模型记忆混乱memory 串项目 / 长期未清理审计记忆删除无关条目权限弹窗太多settings.json permissions 设置过严适当扩展 allow 列表保留核心 deny命令执行异常settings.json 环境变量残留清理 env 信息检查系统 export6. 组合实测三层配置怎么配合6.1 一个真实项目的配置样本为了更直观地展示三套体系如何协同我以一个典型的 Python 服务项目为例写一份最小但完整的组合配置。项目背景一个 FastAPI 写的 REST 服务使用 uv 管理依赖pytest 跑测试代码格式化统一用 ruff部署到容器环境。团队要求所有 commit 用 Conventional Commits生产环境表结构变更必须评审。用户级 CLAUDE.md 写# 用户偏好 - 代码注释使用中文代码标识符使用英文 - 提交信息遵循 Conventional Commits - 涉及数据库变更优先询问并展示影响范围不要直接执行 - 不要在任何回复中输出真实的 API Key 或密钥项目级 CLAUDE.md 写# my-service ## 技术栈 Python 3.12 FastAPI SQLAlchemy uv ## 常用命令 - 安装依赖: uv sync - 运行服务: uv run uvicorn app.main:app --reload - 跑测试: uv run pytest - 格式化/lint: uv run ruff check . - 启动 postgres: docker compose up -d db ## 目录 - app/ 业务代码 - tests/ 测试 - infra/ 部署相关 - migrations/ 数据库迁移 ## 硬性约束 - 生产数据库迁移必须先评审禁止直接执行 - 所有接口响应统一包裹在 { code: 0, data: ... } 结构里 - 修改依赖前先同步 uv.lock项目级 settings.json 写{ permissions: { defaultMode: acceptEdits, allow: [ Bash(uv *), Bash(pytest *), Bash(git status*), Bash(git diff*), Bash(git log*) ], ask: [ Bash(git push*), Bash(docker compose*) ], deny: [ Bash(rm -rf *), Read(/.env), Read(app/core/config.py) ] } }最后在 memory 里留一条核心事实该项目从 2025 年 4 月起使用 uv 管理依赖旧版 requirements.txt 不再更新。这样即使是通过历史会话进入模型也能快速知道当前依赖管理的正确姿势。6.2 三层配合的关键顺序这套组合的核心价值是“各司其职”settings.json 限制模型能不能动某些命令、读某些文件属于底线控制CLAUDE.md 告诉模型这个项目应该用什么姿势干活属于主动引导memory 给模型补充跨会话的软信息属于背景知识。在真正开发时我会按这个顺序排查问题先看权限是不是挡住了该做的事再看 CLAUDE.md 是不是写了错误或过期的命令最后再审视 memory 里有没有残留的旧项目事实。从硬控制到软信息层层过滤基本能定位大多数“模型不听话”的根源。6.3 团队协作时的配置同步如果团队多人共用同一个仓库项目级 settings.json 和 CLAUDE.md 一定要入库这样所有人拿到的项目规则是一致的。settings.local.json 和个人 memory 不要入库前者放个人私有配置后者本身就在本地。要特别注意敏感信息。settings.json 的 env 字段里如果出现真实密钥一旦入库就会泄漏到整个项目历史里。我的习惯是只写变量占位符真正的值通过本地的.env或系统环境变量注入并且把任何含密钥的文件加入.gitignore。团队里最好有一个人负责维护 CLAUDE.md 的“主干结构”其他人只在需要时提 Merge Request。没人维护的 CLAUDE.md 会慢慢腐烂最终变成和代码脱节的废文档。最后再说一点目前在实操中的体会配置体系的搭建不是一次性工作而是伴随着项目和团队变化持续调整的活。我每个迭代周期都会花十几分钟审视一遍三层配置删掉不再适用的内容补上最近沉淀出的新共识。听起来琐碎但就是这些细节决定了 Claude Code 是越用越顺手还是越用越让我不放心。