1. 三套配置体系到底在解决什么问题
很多人第一次接触 Claude Code,装完之后发现能跑,但用着用着就开始困惑:为什么每次都要重复交代项目背景?为什么有些命令它记得住、有些记不住?为什么换台机器或者换个项目,行为完全不一样?这些问题的根源,其实都指向同一件事——你还没搞清楚 Claude Code 的配置体系是怎么分层的。
Claude Code 的配置不是“一个文件搞定所有事”,而是分成了三个层次,各管各的:settings.json管的是工具层面的行为,比如权限、环境变量、模型选择、钩子命令;CLAUDE.md管的是项目层面的上下文,比如这个项目用什么技术栈、代码规范是什么、目录结构怎么组织;memory管的是跨会话的持久记忆,比如你个人的偏好、常用命令、踩过的坑。三者职责不同,混在一起用就会乱。
我刚开始用的时候也犯过这个错,把所有东西都往 CLAUDE.md 里塞,结果文件越写越长,每次对话都要加载一大堆无关信息,既浪费上下文窗口,又让模型抓不住重点。后来把权限相关的挪到 settings.json,把个人偏好挪到 memory,CLAUDE.md 只留项目相关的硬信息,整个体验才顺起来。
这篇文章适合两类人看:一类是刚装好 Claude Code、还在摸索怎么配置的新手;另一类是用了一段时间但觉得“不太顺手”、想系统梳理配置逻辑的老用户。我会把三套体系拆开讲清楚,每个文件放什么、为什么这么放、实际怎么操作,最后再给一套可以直接抄的配置模板。
2. settings.json:工具行为的控制中枢
2.1 这个文件到底管什么
settings.json 是 Claude Code 的运行时配置文件,它决定了工具“怎么干活”。具体来说,它控制以下几类东西:
- 权限规则:哪些命令可以自动执行,哪些需要你手动确认,哪些直接禁止。
- 环境变量:比如 API 地址、模型名称、超时时间等。
- 钩子(hooks):在特定事件前后自动执行的脚本,比如每次执行命令前先跑一遍格式化。
- 模型参数:默认用哪个模型、温度设多少、最大输出长度等。
你可以把它理解成 Claude Code 的“控制面板”。它不关心你的项目是做什么的,只关心工具本身的行为边界。
2.2 文件放在哪,优先级怎么算
settings.json 有三个可能的位置,优先级从高到低:
- 项目级:
<项目根目录>/.claude/settings.json,只对当前项目生效。 - 用户级:
~/.claude/settings.json,对当前用户的所有项目生效。 - 企业级:由系统管理员统一配置,普通用户一般接触不到。
优先级规则很简单:项目级覆盖用户级,用户级覆盖企业级。也就是说,如果你在项目里写了一条权限规则,它会覆盖你用户目录下的同名规则。
注意:项目级的 settings.json 建议提交到版本控制,这样团队里每个人拉下来就是一致的。但如果你在里面写了个人 token 或者敏感路径,就要用
.gitignore排除掉,改用环境变量注入。
2.3 权限配置:最核心也最容易踩坑的部分
权限配置是 settings.json 里最常用的功能。它的逻辑是:你预先定义好哪些操作是安全的,Claude Code 在执行时就会自动放行;没定义的,它会停下来问你。
一个典型的权限配置长这样:
{ "permissions": { "allow": [ "Bash(npm run lint)", "Bash(npm run test:*)", "Bash(git status)", "Bash(git diff:*)", "Read(*)", "Edit(src/**)" ], "deny": [ "Bash(rm -rf:*)", "Bash(curl:*)", "Read(.env)", "Read(**/*.pem)" ] } }这里有几个关键点需要解释:
allow 列表里的通配符:Bash(npm run test:*)表示所有以npm run test开头的命令都自动放行。这个设计很实用,因为测试命令经常带不同参数,你不可能一个个列出来。
deny 列表的优先级高于 allow:如果一条命令同时匹配 allow 和 deny,deny 生效。所以你可以放心地在 allow 里写宽泛的规则,然后用 deny 精确封堵危险操作。
Read 和 Edit 的路径匹配:Read(*)表示允许读取任何文件,但Read(.env)在 deny 里,所以 .env 读不了。Edit(src/**)表示只允许编辑 src 目录下的文件,其他目录的修改需要手动确认。
我自己的习惯是:allow 列表尽量宽松,把日常高频操作都放进去,减少打断;deny 列表严格把关,把所有涉及密钥、凭证、删除操作的全部封死。这样既流畅又安全。
2.4 环境变量与模型配置
除了权限,settings.json 还管环境变量和模型参数。比如你想让 Claude Code 默认用某个特定模型,或者调整超时时间,都可以在这里配:
{ "env": { "ANTHROPIC_MODEL": "claude-sonnet-4-20250514", "ANTHROPIC_BASE_URL": "https://your-proxy.example.com", "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "8192", "CLAUDE_CODE_TIMEOUT_MS": "120000" } }这里ANTHROPIC_BASE_URL的用途是当你需要通过中转服务访问时,把请求指向你自己的网关。CLAUDE_CODE_MAX_OUTPUT_TOKENS控制单次输出的最大 token 数,设太小会导致长代码被截断,设太大又浪费额度,一般 8192 是个比较平衡的值。
实操心得:如果你在公司内网使用,可能需要配置代理地址。这时候建议把
ANTHROPIC_BASE_URL写在用户级 settings.json 里,而不是项目级,因为网络配置通常跟项目无关。
2.5 钩子命令:自动化你的工作流
钩子是 settings.json 里比较高级的功能,但用好了能省很多事。它的原理是:在 Claude Code 执行某个动作的前后,自动触发你指定的 shell 命令。
常见的钩子场景包括:
- PreToolUse:在执行工具前触发,可以用来做安全检查或日志记录。
- PostToolUse:在执行工具后触发,可以用来做格式化或通知。
- Notification:在 Claude Code 发出通知时触发,可以转发到你的手机或桌面。
举个例子,你想让每次文件被修改后自动跑一遍 prettier:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit", "command": "npx prettier --write $CLAUDE_FILE_PATH" } ] } }这里的$CLAUDE_FILE_PATH是 Claude Code 注入的环境变量,指向被修改的文件路径。matcher 指定只对 Edit 工具生效,Read 之类的不会触发。
注意:钩子命令是在你的本地 shell 里执行的,所以它有和你一样的文件系统权限。写钩子的时候一定要小心,别把
rm -rf之类的危险命令放进去。另外,钩子执行失败不会阻塞主流程,但会在日志里留下记录,排查问题时可以去看。
3. CLAUDE.md:项目上下文的载体
3.1 为什么需要这个文件
settings.json 解决的是“工具怎么干活”,但它解决不了“这个项目是什么”。每次你打开一个新会话,Claude Code 对项目的了解是零。你得告诉它:这是什么语言写的、用什么框架、代码风格是什么、测试怎么跑、目录怎么组织。
这些信息如果每次对话都手动输入,效率太低。CLAUDE.md 就是用来持久化这些项目上下文的。它本质上是一个 Markdown 文件,放在项目根目录,Claude Code 启动时会自动读取并注入到系统提示里。
3.2 应该写什么,不应该写什么
CLAUDE.md 的内容应该聚焦在“这个项目特有的、模型不知道的”信息上。具体来说:
应该写的:
- 项目简介:一句话说清楚这个项目是干什么的。
- 技术栈:语言、框架、主要依赖。
- 目录结构:关键目录的用途。
- 开发命令:怎么装依赖、怎么跑测试、怎么构建。
- 代码规范:命名约定、格式化规则、提交信息格式。
- 特殊约定:比如“所有 API 调用必须走统一的 client 封装”。
不应该写的:
- 通用编程知识:比如“Python 用缩进表示代码块”,模型本来就知道。
- 个人偏好:比如“我喜欢用单引号”,这属于 memory 的范畴。
- 敏感信息:密钥、token、内部地址,绝对不能写。
- 频繁变动的信息:比如当前分支名、最新 commit hash。
我见过有人把 CLAUDE.md 写成了一本开发手册,洋洋洒洒几千字,结果每次对话都要加载,既慢又浪费上下文。正确的做法是精简到最必要的几十行,只保留模型每次都需要知道的核心信息。
3.3 一个可直接参考的模板
下面是我自己在用的 CLAUDE.md 模板,你可以根据项目情况调整:
# 项目名称 一句话描述这个项目是做什么的。 ## 技术栈 - 语言:TypeScript 5.x - 框架:Next.js 14 (App Router) - 数据库:PostgreSQL + Prisma - 测试:Vitest + Playwright ## 目录结构 - `src/app/` - 页面和路由 - `src/components/` - 可复用组件 - `src/lib/` - 工具函数和业务逻辑 - `prisma/` - 数据库 schema 和迁移 ## 开发命令 - 安装依赖:`pnpm install` - 启动开发:`pnpm dev` - 跑单元测试:`pnpm test` - 跑端到端测试:`pnpm test:e2e` - 类型检查:`pnpm typecheck` - 格式化:`pnpm format` ## 代码规范 - 组件文件用 PascalCase,工具函数用 camelCase - 所有异步操作必须处理错误,不允许裸 await - 提交信息遵循 Conventional Commits - 新增依赖前先确认是否已有替代方案 ## 特殊约定 - 所有数据库操作必须通过 `src/lib/db.ts` 导出的 client - 环境变量统一在 `src/lib/env.ts` 里校验后再使用 - API 路由必须做输入校验,用 zod schema这个模板大概 40 行,覆盖了模型每次都需要知道的信息,又不会太长。
3.4 多层级 CLAUDE.md 的加载逻辑
Claude Code 支持多个层级的 CLAUDE.md,加载顺序是:
- 企业级:系统管理员配置的全局规则。
- 用户级:
~/.claude/CLAUDE.md,对你所有项目生效。 - 项目级:项目根目录的
CLAUDE.md。 - 子目录级:子目录里的
CLAUDE.md,只在该目录下的操作生效。
加载时是叠加的,不是覆盖。也就是说,用户级的内容和项目级的内容会合并在一起。这个设计的好处是:你可以把通用规范放在用户级,项目特有的放在项目级,互不干扰。
实操心得:我习惯在用户级 CLAUDE.md 里放一些通用的编码偏好,比如“优先使用函数式写法”“避免深层嵌套”。项目级的只放这个项目特有的信息。这样新项目初始化时,只需要写项目级的内容,通用部分自动继承。
3.5 维护 CLAUDE.md 的节奏
CLAUDE.md 不是写完就不管了。项目在演进,技术栈在变,规范也在调整。我的做法是:
- 每次引入新依赖或新工具时,更新技术栈和开发命令部分。
- 每次发现模型反复犯同一个错误时,把对应的规范写进去。
- 每个季度做一次精简,删掉过时的内容,合并重复的条目。
这样维护下来,CLAUDE.md 始终保持在 50 行以内,既精简又实用。
4. memory:跨会话的持久记忆
4.1 memory 和 CLAUDE.md 的区别
很多人分不清 memory 和 CLAUDE.md,觉得都是“记住一些东西”。其实两者的定位完全不同:
- CLAUDE.md 是项目级的、共享的、静态的。它跟着项目走,团队成员拉下来都一样,内容相对稳定。
- memory 是用户级的、私有的、动态的。它跟着你走,跨项目生效,内容会随着你的使用不断积累。
举个例子:你在 CLAUDE.md 里写“这个项目用 pnpm”,这是项目事实;你在 memory 里写“我习惯用 pnpm 而不是 npm”,这是个人偏好。前者换个人看也成立,后者只对你自己有意义。
4.2 memory 是怎么工作的
Claude Code 的 memory 机制基于一个本地存储目录,通常在~/.claude/memory/下。每次会话开始时,它会读取相关的记忆条目,注入到上下文里。会话过程中,如果你明确告诉它“记住这个”,它也会写入新的条目。
memory 的条目通常包含几个要素:
- 内容:要记住的具体信息。
- 标签:用于分类和检索的关键词。
- 时间戳:什么时候记录的。
- 来源:是用户明确要求的,还是自动推断的。
检索时,Claude Code 会根据当前对话的上下文,匹配相关的标签,只加载最相关的几条,而不是把所有记忆都塞进去。这个设计避免了上下文爆炸。
4.3 什么值得记,什么不值得
memory 的空间是有限的,不是什么都要记。我的经验是,以下几类值得记:
- 个人偏好:比如“我喜欢用 early return 而不是嵌套 if”。
- 常用命令:比如“部署用
make deploy-prod”。 - 踩过的坑:比如“这个库的 2.3 版本有 bug,别升级”。
- 工作流习惯:比如“提交前先跑 lint 和 typecheck”。
不值得记的:
- 一次性的信息:比如“今天要改哪个文件”。
- 模型本来就知道的:比如“JavaScript 用 const 声明常量”。
- 项目特有的:这些应该放 CLAUDE.md,不是 memory。
注意:memory 是本地存储的,不会同步到其他机器。如果你换电脑,需要手动迁移
~/.claude/memory/目录。另外,memory 里的内容不会自动过期,需要你定期清理,否则会越积越多,检索效率下降。
4.4 手动管理 memory 的实操方法
虽然 Claude Code 支持自动记忆,但我更推荐手动管理,因为自动记忆容易记一堆没用的东西。手动管理的方法有几种:
方法一:直接编辑文件。memory 目录下的文件是纯文本或 JSON,你可以直接用编辑器打开修改。这种方式最直接,适合批量整理。
方法二:通过对话指令。在会话里说“记住:XXX”,Claude Code 会把它写入 memory。说“忘掉关于 XXX 的记忆”,它会删除对应条目。这种方式适合零散添加。
方法三:定期导出和清理。每隔一段时间,把 memory 目录导出备份,然后删掉过时的条目。我一般一个月做一次,保持 memory 精简。
4.5 memory 的常见误区
误区一:把 memory 当 CLAUDE.md 用。有人把所有项目信息都往 memory 里塞,结果换个项目还在加载上一个项目的内容,干扰很大。记住:项目相关的放 CLAUDE.md,个人相关的放 memory。
误区二:记太多细节。memory 不是日记,不需要记录每次对话的细节。只记那些“下次还会用到”的信息。
误区三:从不清理。memory 越积越多,检索时匹配到的噪音就越多,反而降低了效果。定期清理是必须的。
5. 三套体系的协作与优先级
5.1 加载顺序与冲突处理
三套体系在会话启动时的加载顺序是:
- 先加载 settings.json,确定工具的行为边界。
- 再加载 CLAUDE.md,注入项目上下文。
- 最后加载 memory,补充个人偏好。
如果出现冲突,优先级是:项目级 > 用户级 > 企业级,CLAUDE.md > memory。也就是说,如果 CLAUDE.md 里说“用 pnpm”,而 memory 里说“我习惯用 npm”,模型会优先遵循 CLAUDE.md。
这个优先级设计是合理的:项目规范应该高于个人偏好,因为项目是团队协作的基础。
5.2 一个完整的配置示例
假设你有一个 Next.js 项目,团队协作,你个人有一些编码偏好。完整的配置应该是这样的:
项目级 settings.json(提交到仓库):
{ "permissions": { "allow": [ "Bash(pnpm install)", "Bash(pnpm dev)", "Bash(pnpm test:*)", "Bash(pnpm lint)", "Bash(git status)", "Bash(git diff:*)" ], "deny": [ "Bash(rm -rf:*)", "Read(.env*)", "Read(**/*.pem)" ] } }项目级 CLAUDE.md(提交到仓库):
# 电商后台管理 基于 Next.js 14 的电商后台,包含商品、订单、用户三个模块。 ## 技术栈 - Next.js 14 (App Router) - TypeScript 5.x - Prisma + PostgreSQL - Tailwind CSS ## 开发命令 - 安装:`pnpm install` - 开发:`pnpm dev` - 测试:`pnpm test` - 类型检查:`pnpm typecheck` ## 代码规范 - 组件用 PascalCase,工具函数用 camelCase - 所有 API 路由必须做 zod 校验 - 数据库操作统一走 `src/lib/db.ts`用户级 memory(本地,不提交):
- 偏好:使用 early return 而非嵌套 if - 偏好:注释用中文,变量名用英文 - 习惯:提交前先跑 typecheck 和 lint - 踩坑:Prisma 的 findMany 不加 take 会全表扫描这样配置下来,团队协作有统一规范,个人偏好也能生效,互不冲突。
5.3 配置迁移与团队同步
如果你要把配置同步给团队,需要注意几点:
- settings.json 和 CLAUDE.md 可以提交到仓库,但要去掉个人相关的部分。
- memory 不要提交,它是私有的,每个人应该有自己的。
- 敏感信息用环境变量,不要硬编码在配置文件里。
团队同步时,建议在 README 里写清楚:哪些配置是必须的,哪些是可选的,新成员怎么初始化。这样能减少很多沟通成本。
6. 常见问题与排查技巧
6.1 配置不生效怎么办
这是最常见的问题。排查思路是:
- 确认文件位置对不对。项目级 settings.json 必须在
<项目根>/.claude/下,不是项目根目录。 - 确认 JSON 格式合法。用
jq . settings.json检查一下,语法错误会导致整个文件被忽略。 - 确认优先级。项目级会覆盖用户级,如果你在用户级改了但项目级有同名配置,以项目级为准。
- 重启会话。配置是在会话启动时加载的,改完需要新开一个会话才生效。
6.2 权限规则匹配不上
权限规则的匹配是基于字符串前缀的,不是正则。比如Bash(npm run test:*)能匹配npm run test:unit,但匹配不了npm run test-unit。写规则的时候要注意这个细节。
另外,命令里的空格和引号也会影响匹配。如果命令是git commit -m "fix: bug",你的规则要写成Bash(git commit:*)才能匹配上。
6.3 CLAUDE.md 太长导致响应变慢
CLAUDE.md 的内容会注入到每次对话的上下文里,太长会占用大量 token,导致响应变慢、成本上升。建议控制在 100 行以内,只保留最必要的信息。
如果确实有很多内容要写,可以拆分成多个文件,用引用链接的方式组织。但要注意,Claude Code 不会自动读取被引用的文件,除非你明确让它读。
6.4 memory 检索不准
memory 检索是基于标签匹配的,如果标签写得太泛,匹配到的噪音就多。建议给每条记忆打上具体的标签,比如用#typescript#testing而不是#code。
另外,定期清理过时记忆也很重要。我一般每个月清理一次,删掉三个月没用到的条目。
6.5 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 配置改了没反应 | 文件位置不对或格式错误 | 检查路径,用 jq 验证 JSON |
| 权限规则不生效 | 通配符写法不对 | 确认用:*后缀匹配前缀 |
| 响应变慢 | CLAUDE.md 太长 | 精简到 100 行以内 |
| memory 记不住 | 没明确说“记住” | 用明确指令,或手动编辑文件 |
| 换机器后配置丢失 | memory 是本地存储 | 手动迁移~/.claude/memory/ |
| 团队配置不一致 | 项目级配置没提交 | 把 settings.json 和 CLAUDE.md 加入版本控制 |
7. 我个人的配置演进过程
刚开始用 Claude Code 的时候,我只有一个 CLAUDE.md,把所有东西都往里塞。结果文件越来越长,模型反而抓不住重点,经常忽略关键规范。
后来我把权限相关的拆到 settings.json,发现自动放行常用命令后,打断少了很多,效率明显提升。再后来开始用 memory 记录个人偏好,发现跨项目的一致性好了很多,不用每个项目都重复交代。
现在的配置策略是:settings.json 只管权限和环境变量,保持精简;CLAUDE.md 只写项目特有的硬信息,控制在 50 行以内;memory 记录个人偏好和踩坑经验,每月清理一次。三套体系各司其职,互不干扰。
最后分享一个小技巧:如果你不确定某条信息该放哪里,问自己三个问题——它是项目特有的还是个人通用的?它是稳定的还是经常变的?它是团队共享的还是私有的?答案会告诉你该放 settings.json、CLAUDE.md 还是 memory。