Claude Code 用了一段时间之后,我发现一个挺普遍的现象:很多人装完就开始用,用着用着觉得"也就那样",然后回头去翻文档,才发现自己压根没碰过它的配置体系。这其实挺可惜的,因为 Claude Code 真正拉开效率差距的地方,恰恰不在它默认能干什么,而在于你能通过配置文件把它调成什么样。
我自己是从一个"什么都不配,全靠默认"的状态起步的,中间踩过不少坑——比如在项目根目录写了个 CLAUDE.md 结果死活不生效,比如把权限配置写进 settings.json 之后发现每次都要重新确认,比如一直搞不清楚 memory 到底存在哪、什么时候会被读取。这些问题单看都不大,但堆在一起就会让人对整套配置体系产生"玄学"的感觉。
这篇内容就是把我这段时间对 Claude Code 三大配置体系的理解完整梳理一遍:settings.json、CLAUDE.md、memory。它们各自管什么、优先级怎么排、什么时候该用哪个、有哪些容易踩的坑,我都会结合自己的实际操作讲清楚。不管你是刚装完 Claude Code 想认真配一配,还是已经用了一阵子但总觉得没调顺,应该都能从里面找到对你有用的部分。
1. 先把三大配置体系的职责边界搞清楚
在动手写任何配置之前,我觉得最有必要先建立的一个认知是:这三样东西不是互相替代的关系,而是各管一摊、分层协作的关系。很多人配置出问题,根源就在于把该写进 A 的东西写进了 B,然后疑惑为什么没效果。
1.1 settings.json 管的是"行为规则"
settings.json 是 Claude Code 的运行时配置,它决定的是工具本身怎么运行——用哪个模型、权限怎么放行、哪些命令允许自动执行、环境变量怎么注入、hooks 怎么挂载。你可以把它理解成"这个工具的开关面板",它不关心你的项目是做什么的,只关心 Claude Code 这个进程该怎么跑。
它有几个层级,这是我踩坑最多的地方。实际生效顺序大致是这样的:
| 层级 | 位置 | 作用范围 | 典型用途 |
|---|---|---|---|
| 企业级 | 系统级托管路径 | 整台机器所有用户 | 组织统一策略 |
| 用户级 | ~/.claude/settings.json | 当前用户所有项目 | 个人偏好、常用权限 |
| 项目级 | 项目根目录.claude/settings.json | 当前项目 | 团队共享配置 |
| 本地项目级 | 项目根目录.claude/settings.local.json | 当前项目、仅自己 | 个人覆盖、不入库 |
优先级是从下往上覆盖的,也就是说本地项目级 > 项目级 > 用户级 > 企业级。这里有个很关键的细节:项目级的.claude/settings.json通常是会提交到 Git 的,团队共享;而settings.local.json一般加进.gitignore,放你自己的临时覆盖。我一开始把个人 API key 相关的环境变量写进了项目级配置,结果差点提交上去,这个坑一定要避开。
1.2 CLAUDE.md 管的是"项目知识"
CLAUDE.md 是给 Claude 看的项目说明书。它不控制工具行为,而是把项目的背景、约定、命令、目录结构这些"人需要知道、Claude 也需要知道"的信息喂给它。每次会话开始时,Claude Code 会自动读取相关层级的 CLAUDE.md 并注入上下文。
它的层级和 settings.json 类似,但语义完全不同:
- 用户级
~/.claude/CLAUDE.md:你个人的通用偏好,比如"回答用中文""提交信息用约定式提交格式",对所有项目生效。 - 项目级
项目根/CLAUDE.md:这个项目的架构说明、构建命令、代码规范,团队共享。 - 子目录级
某子目录/CLAUDE.md:当 Claude 处理该子目录下的文件时才会被加载,适合 monorepo 里给每个包写独立说明。
我自己的习惯是:用户级只放跨项目的个人偏好,项目级放真正跟这个仓库强相关的东西。把项目细节写进用户级是个常见错误,会导致你在别的项目里也被这些无关信息干扰。
1.3 memory 管的是"跨会话记忆"
memory 是 Claude Code 用来跨会话保留信息的机制。跟 CLAUDE.md 最大的区别在于:CLAUDE.md 是你手写的、静态的、可版本控制的;memory 更多是 Claude 在交互过程中记录下来的、动态的、跟着会话走的。它解决的是"上次聊到一半,这次不想重新解释一遍"的问题。
memory 的存储位置通常在用户目录下的.claude相关路径里,具体文件名和结构会随版本变化,但核心逻辑是:它按项目或按主题归档,在需要的时候被检索并注入上下文。你可以在会话里显式让 Claude 记住某件事,它也可能在你确认后自动记录。
1.4 三者的协作关系
把这三者串起来看,一次典型的会话大概是这样运转的:
- Claude Code 启动,读取各层级 settings.json,确定模型、权限、hooks 等运行参数。
- 加载各层级 CLAUDE.md,把项目知识注入上下文。
- 检索相关 memory,补充历史信息。
- 开始处理你的请求,过程中受 settings 约束、受 CLAUDE.md 引导、受 memory 辅助。
理解了这条链路,后面所有的配置问题基本都能定位到具体是哪一层出了岔子。
2. settings.json 的实战配置与权限模型
settings.json 是三者里最"硬核"的一个,因为它直接决定 Claude Code 能做什么、不能做什么。配得好,效率翻倍;配得糙,要么天天被权限确认打断,要么放得太开埋下隐患。
2.1 权限配置是核心中的核心
Claude Code 的权限系统围绕"允许/询问/拒绝"三态展开。默认情况下,很多操作(比如执行 shell 命令、写文件)都会弹确认。如果你在做一个需要频繁跑测试、频繁改文件的项目,这种确认会非常烦。
权限配置写在 settings.json 的permissions字段里,主要分两块:allow和deny。allow 里的规则自动放行,deny 里的规则直接拒绝,都不在里面的走默认询问。
一个我实际在用的配置片段大概长这样:
{ "permissions": { "allow": [ "Bash(npm run test:*)", "Bash(npm run lint:*)", "Bash(git status)", "Bash(git diff:*)", "Read(//Users/me/projects/**)" ], "deny": [ "Bash(rm -rf:*)", "Bash(curl:*)", "Read(./.env)", "Read(./secrets/**)" ] } }这里的规则语法是工具名(匹配模式)。Bash 后面跟的是命令前缀匹配,Read 后面跟的是路径匹配。我特意把rm -rf和curl放进 deny,是因为这两个一个危险一个涉及外部请求,宁可每次手动确认也不自动放行。
注意:allow 的匹配是前缀式的,
Bash(npm run test:*)里的:*表示匹配该前缀后的任意内容。如果你只写Bash(npm run test),那只有完全等于这条命令时才放行,带参数的就不匹配了。这个细节我第一次配的时候没注意,导致以为配置没生效。
2.2 模型与运行参数
除了权限,settings.json 还能指定默认模型、是否开启某些实验特性、环境变量等。比如你想让某个项目默认用更快的模型处理简单任务,可以在这里指定。
{ "model": "claude-sonnet-4-5", "env": { "NODE_ENV": "development", "MY_API_BASE": "http://localhost:3000" } }env字段注入的环境变量会在 Claude Code 执行命令时生效,这对需要特定环境变量的项目很有用。我有个项目本地开发依赖一个自定义的 API 地址,每次手动 export 很烦,写进项目级 settings.json 之后就省事了。
2.3 hooks:把自动化挂进生命周期
hooks 是 settings.json 里比较进阶的部分,允许你在特定事件(比如工具调用前后)触发自定义脚本。典型用途包括:每次 Claude 改完文件后自动跑格式化、在提交前跑 lint 等。
{ "hooks": { "PostToolUse": [ { "matcher": "Edit", "hooks": [ { "type": "command", "command": "npx prettier --write $CLAUDE_FILE_PATH" } ] } ] } }这段配置的意思是:每当 Claude 用 Edit 工具修改了文件,就对被修改的文件跑一次 prettier。这样你就不用担心 Claude 写出来的代码格式不统一了。
我踩过的坑是:hooks 里的命令如果失败,默认行为可能会阻塞后续流程,所以脚本本身要做好错误处理,别让一个格式化失败把整个会话卡住。
2.4 配置不生效时的排查顺序
配置写完没效果,是最高频的问题。我总结的排查顺序是这样的:
- 确认文件位置对不对。项目级必须是
项目根/.claude/settings.json,不是项目根直接放 settings.json。 - 确认 JSON 语法合法。一个多余的逗号就能让整个文件被忽略,用
jq . settings.json验证一下最稳。 - 确认层级优先级。本地项目级会覆盖项目级,检查是不是被上层覆盖了。
- 确认规则语法。allow/deny 的匹配模式写错是最隐蔽的问题。
- 重启会话。部分配置在会话启动时读取,改完不重启可能不生效。
这个顺序基本能覆盖九成以上的"配置不生效"问题。
3. CLAUDE.md 的写法与分层策略
CLAUDE.md 看起来简单——不就是写个 Markdown 嘛——但写得好不好,直接决定 Claude 对你项目的理解程度。我见过太多人把 CLAUDE.md 写成一句"这是一个 React 项目"就完事了,然后抱怨 Claude 老是给出不符合项目习惯的代码。
3.1 一份合格的 CLAUDE.md 该包含什么
我的经验是,CLAUDE.md 应该回答 Claude 在动手前最需要知道的几件事:
- 这个项目是做什么的,一句话说清。
- 技术栈和关键依赖,尤其是那些不常见的。
- 常用命令:怎么装依赖、怎么跑、怎么测、怎么构建。
- 代码规范:命名、目录组织、提交信息格式。
- 特殊约定:比如"所有 API 调用必须走统一的 request 封装""不要直接改 generated 目录"。
一个我实际项目里的 CLAUDE.md 骨架:
# 项目说明 这是一个基于 Next.js 的电商前台,使用 App Router。 ## 常用命令 - 安装依赖:pnpm install - 本地开发:pnpm dev - 跑测试:pnpm test - 构建:pnpm build ## 代码规范 - 组件用函数式,文件名用 PascalCase - 样式统一用 Tailwind,不写独立 CSS 文件 - 提交信息遵循 Conventional Commits ## 注意事项 - src/generated 下的文件是自动生成的,不要手动修改 - 所有网络请求必须通过 lib/request.ts 封装这份东西不长,但信息密度高,Claude 读完基本就能按项目习惯干活了。
3.2 分层:用户级、项目级、子目录级怎么分
分层用对了,能避免大量重复。我的分法是:
用户级~/.claude/CLAUDE.md只放跟具体项目无关的个人偏好,比如:
- 回答和注释默认用中文 - 解释代码时先给结论再给细节 - 提交信息用 Conventional Commits 格式项目级放这个仓库特有的东西。子目录级则用在 monorepo 场景,比如packages/web/CLAUDE.md写前端包的约定,packages/api/CLAUDE.md写后端包的约定,Claude 处理哪个包就读哪个。
这里有个容易忽略的点:子目录级的 CLAUDE.md 是"按需加载"的,只有当 Claude 实际处理该目录下的文件时才会被读进来。所以别指望在根目录的 CLAUDE.md 里写一句"详见各子目录"就能让 Claude 提前知道所有细节。
3.3 为什么你的 CLAUDE.md 没被读取
这是高频问题,我列几个真实遇到过的原因:
- 文件名大小写不对。必须是全大写
CLAUDE.md,写成claude.md在部分系统上不识别。 - 放错位置。项目级必须在项目根目录,不是
.claude/目录里。这点和 settings.json 正好相反,特别容易搞混。 - 项目根判断错误。Claude Code 认定的项目根可能和你以为的不一样,尤其是从子目录启动的时候。
- 内容太长被截断。CLAUDE.md 不是越长越好,超长内容可能被截断,重点信息要放前面。
提示:settings.json 在
.claude/目录下,CLAUDE.md 在项目根目录。这两个位置规则不一样,是新手最容易混淆的地方,记牢。
3.4 让 CLAUDE.md 真正被"用起来"的技巧
写完不等于用好。我的几个心得:
第一,把最重要的约束放最前面。Claude 读长文档时,开头和结尾的信息权重更高。
第二,用具体的例子代替抽象描述。与其写"代码要清晰",不如写"函数超过 50 行就考虑拆分"。
第三,定期更新。项目演进了,CLAUDE.md 不更新,Claude 就会按过时的约定干活,反而添乱。我一般会在每次大重构后顺手更新一下。
第四,别把它当成文档仓库。CLAUDE.md 是给 Claude 的"操作手册",不是给人看的完整文档。人看的文档该放 README 放 README。
4. memory 机制:跨会话记忆的边界与用法
memory 是三者里最容易被误解的。很多人以为它就是个"聊天记录",其实它的定位更接近"Claude 主动维护的长期笔记"。理解它的边界,才能用好它。
4.1 memory 和 CLAUDE.md 的本质区别
一句话概括:CLAUDE.md 是你写给 Claude 的,memory 是 Claude 记给自己的。
CLAUDE.md 是静态的、你完全掌控的、可以进版本控制的。memory 是动态的、Claude 参与维护的、通常不进版本控制的。前者适合放稳定的项目知识,后者适合放交互过程中产生的、可能变化的上下文。
举个例子:项目的构建命令是稳定的,写进 CLAUDE.md;而你今天跟 Claude 讨论"我们决定把状态管理从 Redux 换成 Zustand"这种决策过程,更适合让它记进 memory。
4.2 memory 什么时候被读取和写入
读取通常发生在会话开始时,Claude 会检索跟当前项目相关的 memory 注入上下文。写入则可能发生在几种情况:你显式要求"记住这个",或者 Claude 判断某条信息值得长期保留并征得你同意。
这里有个实际影响很大的点:memory 是会被检索的,不是全量加载。这意味着如果 memory 里积累了大量不相关信息,检索质量会下降,反而干扰当前任务。所以定期清理 memory 是有必要的,别让它变成一个只进不出的垃圾堆。
4.3 怎么让 memory 真正帮上忙
我的用法是把它当成"项目决策日志"来用。比如:
- 记录架构决策:"本项目选择用 Server Components 而非客户端渲染,原因是 SEO 需求。"
- 记录踩过的坑:"这个库的 v2 版本有内存泄漏,暂时锁在 v1.8。"
- 记录偏好:"用户希望所有日期显示用 YYYY-MM-DD 格式。"
这些信息写进 CLAUDE.md 也不是不行,但它们更偏"过程性"和"临时性",放 memory 更合适。等某个决策稳定下来、变成长期约定,再考虑迁移到 CLAUDE.md。
4.4 memory 的常见误区
误区一:以为 memory 是万能的。它只是辅助,不能替代 CLAUDE.md 的结构化知识。指望靠 memory 让 Claude 记住整个项目架构,不现实。
误区二:从不清理。memory 越积越多,检索噪音越大,最后反而拖累效果。
误区三:把敏感信息记进去。memory 可能以明文形式存储,API key、密码这类东西千万别让它记。
误区四:以为跨项目通用。memory 通常按项目隔离,A 项目的记忆不会自动带到 B 项目,这是设计使然,不是 bug。
5. 三套配置的协同与优先级实战
单独理解每个体系之后,真正的难点在于它们协同工作时怎么排优先级、怎么避免冲突。这部分我用几个真实场景来说明。
5.1 一个请求的完整生命周期
假设你在项目里输入"帮我重构这个函数",背后发生的事大致是:
- 会话启动时已加载各层级 settings.json,确定当前权限和模型。
- 加载用户级、项目级 CLAUDE.md,以及当前子目录的 CLAUDE.md。
- 检索相关 memory。
- Claude 综合这些信息理解你的请求。
- 执行过程中,每次工具调用都受 settings 的权限规则约束。
- 如果配置了 hooks,在相应节点触发。
理解这条链路的价值在于:当结果不符合预期时,你能快速判断是哪一层的信息出了问题。是权限拦住了?是 CLAUDE.md 没写清楚?还是 memory 里有过时信息干扰?
5.2 冲突场景:同一件事在三处都写了
这是很常见的冲突来源。比如"提交信息格式"这件事,你可能在用户级 CLAUDE.md 写了、项目级 CLAUDE.md 也写了、memory 里还记了一条。如果三处说法不一致,Claude 该听谁的?
我的经验是,越具体、越靠近当前项目的配置,权重越高。所以项目级 CLAUDE.md 通常压过用户级,memory 里的临时记录如果和 CLAUDE.md 冲突,一般以 CLAUDE.md 为准。但这不是绝对的,取决于具体实现,所以最稳妥的做法是:同一件事只在一个地方定义,避免冲突。
5.3 团队协作场景下的配置分工
如果是团队用 Claude Code,配置分工我建议这样:
| 内容 | 放哪 | 是否入库 |
|---|---|---|
| 团队统一的权限规则 | 项目级 settings.json | 是 |
| 个人权限偏好 | 用户级 settings.json | 否 |
| 项目架构与规范 | 项目级 CLAUDE.md | 是 |
| 个人回答偏好 | 用户级 CLAUDE.md | 否 |
| 临时决策记录 | memory | 否 |
| 个人本地覆盖 | settings.local.json | 否 |
这样分的好处是:团队共享的部分统一、可追溯;个人的部分互不干扰;临时的部分不污染仓库。
5.4 配置迁移与版本管理
settings.json 和 CLAUDE.md 都建议进版本控制(除了 local 那个),这样团队新成员拉下来就能用。但要注意几点:
- 别把个人路径、个人 token 写进项目级配置。
- 环境相关的值用环境变量占位,别硬编码。
- 配置变更走 PR,方便 review 和追溯。
memory 一般不进版本控制,它是个人和会话相关的。如果你有特别重要的决策记录想共享,手动整理进 CLAUDE.md 或项目文档更合适。
6. 我踩过的那些配置坑与排查心得
前面讲了不少原理,这一节专门讲踩坑。这些都是我实际遇到过、并且花时间排查过的问题,希望能帮你少走弯路。
6.1 权限配了却还是每次确认
这个我遇到过两次。第一次是规则语法写错,Bash(npm run test:*)写成了Bash(npm run test *),星号位置不对,匹配不上。第二次是层级问题,我在项目级配了 allow,但用户级有个更严格的规则把它覆盖了。
排查方法:先用最简单的规则测试,比如Bash(echo:*),确认基础机制通了,再逐步加复杂规则。层级问题就逐层检查,从本地项目级往上捋。
6.2 CLAUDE.md 内容太长导致重点被淹没
我一开始恨不得把所有项目知识都塞进 CLAUDE.md,结果写了两千多字,发现 Claude 反而抓不住重点。后来我做了减法,只留最关键的约束和命令,把详细文档挪到 README 里,效果明显好转。
经验是:CLAUDE.md 控制在合理长度,重点前置,用列表和短句,别写成散文。
6.3 memory 里的过时信息导致错误决策
有次 Claude 建议我用一个我们早就弃用的库,排查半天发现是 memory 里还留着几个月前的记录。清理之后问题解决。这让我养成了定期 review memory 的习惯。
6.4 hooks 脚本失败阻塞流程
前面提过,hooks 里的命令失败可能阻塞。我的做法是给脚本加容错,比如npx prettier --write $FILE || true,让失败不中断主流程。当然,这取决于你是否希望失败被感知,关键命令还是应该让它报错。
6.5 配置改了不生效的通用排查清单
最后给一个我常用的排查清单,遇到配置问题按这个顺序过一遍:
- 文件路径对不对(settings 在
.claude/,CLAUDE.md 在根目录)。 - JSON/Markdown 语法有没有问题。
- 层级优先级有没有被覆盖。
- 规则匹配语法对不对。
- 有没有重启会话。
- 有没有被 memory 里的旧信息干扰。
这套流程帮我解决了绝大多数配置问题。配置这东西,本质上就是"位置对、语法对、优先级对"三件事,把这三件捋清楚,剩下的都是细节。
用 Claude Code 的这段时间,我最大的体会是:默认配置能让你跑起来,但只有认真配过这三套体系,它才真正变成"你的"工具。settings.json 让它按你的规矩运行,CLAUDE.md 让它懂你的项目,memory 让它记得你们聊过什么。三者配合好了,那种"它怎么知道我要这个"的顺畅感,是默认状态给不了的。