接着源码泄露系列往下讲。上一篇说的是指令文件
CLAUDE.md——你用自然语言写给 AI 看的"工作须知"。这一篇讲的是配置文件settings.json——一份结构化的"参数表"。两者最大的区别:指令文件是写给 AI 读的"软约定",配置文件是写给程序读的"硬开关"。普通用户不需要会写代码也能用好它,关键是搞清楚有几个文件、谁管谁、放哪里。
一、什么是配置文件
简单说,配置文件就是一份 JSON 格式的"参数表",告诉 Claude Code 几件事:
- 默认用哪个模型(
model,比如 Opus / Sonnet) - 给 AI 多大的权限(
permissionMode,能不能改文件、能不能跑命令) - 注入哪些环境变量(
env,比如数据库地址、API Key) - 工具调用前后自动执行什么命令(
hooks,生命周期钩子) - 给 AI 装哪些"插件"(
mcpServers,外部工具服务器) - 是否开启沙箱隔离(
sandbox,限制 AI 的系统访问范围) - 以及认证(
oauth)等
它和指令文件的分工可以这样记:
| | 指令文件 CLAUDE.md | 配置文件 settings.json |
|---|---|---|
| 写给谁看 | 写给 AI 读的自然语言 | 写给程序读的结构化字段 |
| 内容 | "该怎么干活"的约定 | "用什么、能做什么"的开关 |
| 格式 | Markdown 大白话 | 标准 JSON |
二、3个配置文件分别是什么
Claude Code 源码里其实定义了 5 个配置文件的加载位置,但其中 2 个是旧格式兼容文件(~/.claude.json 和 <project>/.claude.json),新用户根本不需要创建,可以直接忽略。
配置文件加载顺序(优先级从低到高):
1. ~/.claude.json ← ⚠️ 旧格式兼容,新用户无需创建
2. ~/.claude/settings.json ← ✅ 全局默认设置(所有项目通用)
3. <project>/.claude.json ← ⚠️ 旧格式兼容,新用户无需创建
4. <project>/.claude/settings.json ← ✅ 当前项目专属设置
5. <project>/.claude/settings.local.json ← ✅ 个人本地覆盖(最高优先级,不进 Git)
普通用户只需关注 3 个文件:
~/.claude/settings.json(全局)、<project>/.claude/settings.json(项目)、<project>/.claude/settings.local.json(个人覆盖)。标注 ⚠️ 的旧格式文件可忽略。
1. 全局配置 ~/.claude/settings.json
- 位置:你的用户主目录下(Windows 是
C:\Users\<你的用户名>\.claude\) - 作用范围:这台电脑上、你这个账户的所有项目都生效
- 适合放:你个人长期不变的默认偏好,比如默认模型、全局权限白名单、状态栏设置
2. 项目级配置 <项目>/.claude/settings.json
- 位置:某个具体项目文件夹里的
.claude/目录下 - 作用范围:只对这一个项目生效,但对所有打开这个项目的人都生效
- 这个文件会进 Git——也就是说,团队成员 clone 下来就能直接用同一套设置
- 适合放:项目专属的东西,比如这个项目该用哪个模型、专属的 MCP 工具、自动跑 lint 的钩子
- 重要:绝对不要在这里写密码、API Key,因为它会被提交到 Git 仓库里
3. 个人本地覆盖 <项目>/.claude/settings.local.json
- 位置:和项目级配置同一个
.claude/目录,只是文件名多了.local - 作用范围:这一个项目 × 这台机器 × 你这个用户——最小、最私人
- 这个文件不进 Git(
.local.json后缀会被自动忽略),只存在于你本地 - 适合放:你的私人 token、个人偏好(比如团队用 Sonnet 但你想用 Opus)、本机专属的绝对路径
- 它的优先级最高——存在时会覆盖项目级和全局的同名字段
一句话记忆:全局管所有项目,项目级管一个项目所有人,本地覆盖只管你自己这台机器。范围越小,优先级越高。
三、3个配置文件之间的关系
这是最容易绕晕、也最关键的一节。三个文件不是"三选一",而是同时存在、层层叠加。
3.1 它们是怎么合并的:深度合并
Claude Code 有一套多层级配置合并系统。三个文件按优先级从低到高排列:
1. ~/.claude/settings.json ← 全局默认(优先级最低)
2. <项目>/.claude/settings.json ← 项目级
3. <项目>/.claude/settings.local.json ← 个人本地覆盖(优先级最高)
合并用的是深度合并(源码里叫 deep_merge_objects)——意思是嵌套的内容会递归地合在一起,而不是简单地整个替换掉。
举个最直观的例子:假设你在全局配了 1 个 MCP 工具,又在项目级配了 1 个,再在本地配了 1 个。最终结果不是"只剩最后那 1 个",而是3 个工具都能用(合并叠加)。
3.2 三类字段,三种合并规则
不同类型的字段,合并方式不一样,记住这三条就够了:
| 字段类型 | 例子 | 合并规则 |
|---|---|---|
| 标量字段(单个值) | model、permissionMode、sandbox.enabled | 后者覆盖前者(本地 > 项目 > 全局),最后只生效一个 |
| 对象字段(带子项) | env、mcpServers | 递归合并——不同的子项全部保留,相同的子项再按规则继续合并 |
| 数组字段(列表) | permissions.allow、permissions.deny | 设计意图是取并集(许可叠加),多个文件里的项会累加到一起 |
深度合并(deep merge)VS 递归合并(recursive merge):
深度合并:用作整个三层配置合并机制的名字——它是个统称,里面其实包含三套子规则:标量覆盖、数组取并集、对象递归合并。合并会"深入"到嵌套的内层,与"浅合并(shallow merge,只合最外层)"相对
递归合并:专门用来描述其中对象字段那一档(env / mcpServers)的行为
- 不同的 key → 全部保留(这一点确实像并集)
- 相同的 key → 仍然按优先级覆盖(这一点不是并集)
- 真正发生"递归"动作的只有对象字段。标量字段(model)是直接覆盖、不往下钻;数组字段(hooks)是整体取并集、也不往下钻。只有对象字段才会"进入内层 、对相同 key 继续合并"——这一步才是字面意义上的递归
3.3 用"作用域"理解:一层套一层
如果你读过上一篇的指令文件,会发现配置文件其实是同一个套娃结构:
┌──────────────────────────────────┐
│ 全局 / 所有项目 │ 优先级最低
│ ┌──────────────────────────┐ │
│ │ 项目级 / 一个项目 │ │
│ │ ┌──────────────────┐ │ │
│ │ │ 本地 / 你这台机器 │ │ │ 优先级最高
│ │ └──────────────────┘ │ │
│ └──────────────────────────┘ │
└──────────────────────────────────┘
局部覆盖全局,从外向内优先级递增
本质上就是"用户 / 项目 / 机器"三个维度被层层收窄。范围越小越靠内、优先级越高——更具体的设置会覆盖更通用的设置。
⚠️ 这里有一个和指令文件不同的细节,值得普通用户特别注意:
指令文件(CLAUDE.md)因为是塞进 Prompt 给大模型读的,存在"中间层最容易被忽略"的注意力特性。但配置文件完全没有这个问题——它的合并是确定性的程序代码逻辑,三层优先级严格线性递增,全局 → 项目 → 本地,不存在"中间塌陷"。
所以"局部覆盖全局"这个宏观结论两类文件都成立;但"越中间越弱"只是指令文件的事,别套到配置文件上。
3.4 和电脑环境变量的类比
如果你用过 Windows 的"系统变量 / 用户变量 / 进程变量",会觉得很眼熟——都是层级配置 + 局部覆盖全局。可进行关联理解:
- 更具体的覆盖更通用的
- 全局放共性,局部放差异
- 敏感的个人配置走最局部的那一层
- 同名设置不生效时,从最局部往外排查
三处错位(不能直接套用):
- 中间层维度:Windows 用户变量 = "哪个登录账户"(身份维度);Claude 项目级 = "哪个目录树"(空间维度)。OS 不感知"项目"概念,最接近的对应物是
git config --local。 - 嵌套语义:Windows 三层是平铺读取顺序,系统/用户变量不构成父子集;Claude 的"作用域 3 ⊂ 2 ⊂ 1"是真子集嵌套。
- 第三层维度:Windows 进程变量 = 时间维度(当前会话,退出即失);Claude
.local.json= 空间维度(永久落盘但不入 git)。
四、配置文件实例
光说规则太抽象,下面用一个个人作品展示网站的例子(技术栈:Next.js + Python API + SQLite)把三个文件串起来看。
4.1 全局.claude/settings.json
注意:标准 JSON 不支持注释,以下
//注释仅用于说明,实际文件中请删除注释行。
{
"model": "claude-opus-4-6", // 默认使用的模型(可选 opus/sonnet 等)
"permissionMode": "workspace-write", // 权限模式:read-only / workspace-write / danger-full-access
"env": { "MY_API_KEY": "..." }, // 注入到环境变量中,AI 和工具可以读取的API KEY
"hooks": { // 生命周期钩子:在工具调用前后自动执行的命令
"PreToolUse": ["lint-check"], // 工具调用前 → 先运行 lint 检查
"PostToolUse": ["auto-test"] // 工具调用后 → 自动运行测试
},
"mcpServers": { // MCP 外部工具服务器配置(给 AI 装"插件")
"my-server": { // 工具名称(自定义,用于标识)
"command": "uvx", // 启动命令(uvx = Python 工具运行器)
"args": ["mcp-server-sqlite", "--db", "data.db"], // 启动参数(SQLite MCP 服务器 + 数据库路径)
"env": { "TOKEN": "..." } // 传给该 MCP 服务器的环境变量
}
},
"sandbox": { // 沙箱隔离配置(限制 AI 的系统访问范围)
"enabled": true, // 是否启用沙箱
"filesystemMode": "workspace-only", // 文件系统限制:只能访问当前工作区
"networkIsolation": true // 网络隔离:禁止 AI 发起外部网络请求
}
}
要点:
- 这个文件在你的用户主目录
~/.claude/下,作用范围是这台机器上、你这个账户的所有项目——不属于任何单个项目,也不进 Git - 它是配置文件最常用、也最该先配好的一层:默认模型、全局权限白名单、状态栏这类"长期不变的个人偏好"都放这里
- 它的优先级最低,但角色是"兜底"——项目级 / 本地没配的字段,最终都会回落到这里生效
- 这里的
model、permissionMode是给所有项目的默认值:设成 Opus 后所有项目默认用 Opus,某个项目想换再去项目级 / 本地单独覆盖 - 因为是"按需覆盖"模式,很多人其实只有这一个文件就够用了——普通项目没特殊需求时,根本不必再建项目级或本地配置
- 例子里
sandbox.enabled设为true,可以理解为给所有项目兜一条通用安全基线;信任的个人项目再在项目级把它关掉(见 4.2)
4.2 项目级 settings.json(会进 Git,团队共享)
{
"model": "claude-sonnet-4-20250514", // 用 Sonnet 模型(更快更便宜,展示网站够用)
"permissionMode": "workspace-write", // 日常开发标准权限
"env": { // 项目级环境变量(会进 Git,不放敏感信息)
"DATABASE_URL": "sqlite:///data/portfolio.db", // 数据库相对路径(团队通用)
"NODE_ENV": "development" // Node.js 环境标识
},
"hooks": { // 生命周期钩子
"PreToolUse": [], // 工具调用前:无额外操作
"PostToolUse": ["npm run lint"] // 工具调用后:自动跑 ESLint 检查代码风格
},
"mcpServers": { // 项目专属的 MCP 工具
"portfolio-db": { // 作品集数据库工具
"command": "uvx", // 用 uvx 启动
"args": ["mcp-server-sqlite", "--db", "data/portfolio.db"], // 指向项目内的 SQLite 文件
"env": {} // 无额外环境变量
}
},
"sandbox": { // 沙箱配置
"enabled": false // 个人项目关闭沙箱(信任自己的代码)
}
}
要点:
- 这个文件会进 Git,团队成员(或你换电脑后)clone 下来就能直接用
model用 Sonnet——更快更便宜,展示网站不需要 Opus 级别的推理能力permissionMode选workspace-write,这是日常开发的标准选择mcpServers配了一个 SQLite 工具,让 AI 能直接查询作品集数据库hooks里配了npm run lint,AI 每次改完代码自动跑代码风格检查- 这里不写任何密码、API Key,因为它会进 Git
4.3 个人本地覆盖 settings.local.json(不进 Git)
同一个项目,你的个人本地配置:
{
"model": "claude-opus-4-6", // 覆盖项目级的 Sonnet → 个人偏好用更强的 Opus
"env": { // 个人私密环境变量(不进 Git,只在本地生效)
"VERCEL_TOKEN": "my-vercel-deploy-token", // Vercel 部署令牌(用于自动部署展示网站)
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx", // GitHub 个人访问令牌(用于 Issues/PR 操作)
"DATABASE_URL": "sqlite:///D:/projects/portfolio/data/portfolio.db" // 覆盖为本机绝对路径
},
"mcpServers": { // 个人额外的 MCP 工具(会与项目级合并)
"github-helper": { // GitHub 操作工具(管理 Issues、创建 PR)
"command": "npx", // 用 npx 启动
"args": ["-y", "@modelcontextprotocol/server-github"], // -y 自动确认安装
"env": { "GITHUB_TOKEN": "ghp_xxxxxxxxxxxx" } // 传入 GitHub token
},
"vercel-deploy": { // HTTP 请求工具(用于调用 Vercel API 部署)
"command": "npx", // 用 npx 启动
"args": ["-y", "mcp-server-fetch"], // MCP fetch 服务器(通用 HTTP 请求能力)
"env": {} // 无额外环境变量(Vercel token 已在上面的 env 中)
}
}
}
要点:
- 这个文件不进 Git,只存在于你本地
model覆盖成claude-opus-4-6——你个人偏好用更强的模型,但不影响团队设置env里放了你的私人 token(Vercel 部署、GitHub),只在本地生效,安全DATABASE_URL把项目级的相对路径覆盖成你本机的绝对路径- 多加了一个
github-helperMCP 工具——这是你的个人需求,不是团队统一需求
4.3 三层叠加后,最终生效的是什么
把全局 + 项目级 + 本地三层合并,最终结果是:
model = claude-opus-4-6 ← 标量字段:三层都有值,按优先级取最高 → 本地 Opus 覆盖项目级 Sonnet
permissionMode = workspace-write ← 标量字段:本地没设,回落到「有值的最高层」→ 项目级生效(哪怕全局也设了也轮不到)
mcpServers = { portfolio-db, github-helper, vercel-deploy } ← 对象字段递归合并:三个 key 互不重复 → 1(项目)+2(本地)=3 个全保留
hooks = { PostToolUse: ["npm run lint"] } ← 数组字段:本例只有项目级配了 → 它是唯一有值的层,并未发生合并
env = { VERCEL_TOKEN, GITHUB_TOKEN, DATABASE_URL(本地路径), NODE_ENV } ← 对象字段递归合并:不同 key 全保留,重复 key(DATABASE_URL)由本地覆盖
看明白这张表,你就真正理解了"深度合并":
model是单个值,本地的 Opus 把项目级的 Sonnet 覆盖掉了;mcpServers是对象,项目级的 1 个 + 本地的 2 个 = 最终 3 个工具全部可用;env同理,不同的 key 全保留,相同的 key(DATABASE_URL)由最高优先级的本地值胜出。
4.4 顺带说说 permissionMode(权限模式)
配置文件里有个字段叫 permissionMode,它决定了 AI 默认能干多少事,普通用户只需理解以下三个模式:
| 模式 | 含义 | 适用场景 |
|---|---|---|
| read-only | 只能读文件,不能改、不能跑命令 | 代码审查、不信任的代码 |
| workspace-write | 能自由读写项目文件,但跑危险命令仍会弹窗确认 | 日常开发标准选择 |
| danger-full-access | 所有操作直接放行,不弹窗 | 最高效也最危险,生产环境务必配合沙箱 |
它和你平时点的弹窗按钮是配套的:
- 点 "Allow Once":只允许这一次,不写进任何文件;
- 点 "Always Allow":把这条命令加进白名单(写入
settings.local.json的permissions.allow),以后不再弹窗。
可以这样理解:permissionMode 是"默认能干什么"的天花板,permissions.allow 是"白名单",可以通过预先声明哪些具体命令跳过弹窗直接放行。
五、配置文件放在哪里
下面这棵目录树标了 ★ 的就是你真正需要关心的文件:
~/ ← 用户主目录(Windows: C:\Users\<name>)
└── .claude/ ← Claude Code 用户级配置目录
├── settings.json ← ★ 全局配置(管所有项目)
├── CLAUDE.md ← 用户级指令文件
├── plugins/ ← 用户级插件
└── projects/ ← 会话历史等运行数据(自动管理,别动)
<某个项目根目录>/
├── .claude/
│ ├── settings.json ← ★ 项目级配置(进 Git,团队共享)
│ ├── settings.local.json ← ★ 本地覆盖(不进 Git,优先级最高)
│ ├── CLAUDE.md ← 项目级指令文件
│ └── commands/ agents/ hooks/ rules/
├── CLAUDE.md ← 项目级指令文件(与 .claude/CLAUDE.md 二选一)
├── CLAUDE.local.md ← 项目本地指令(不进 Git)
└── .gitignore ← 必须包含 settings.local.json
几个容易踩的点:
- 配置文件的本地版
settings.local.json是在.claude/目录里面;而指令文件的本地版CLAUDE.local.md是在项目根目录——两者位置不一样,别记混。 - 凡是带
.local的文件都不进 Git,需要在.gitignore里显式写一行.claude/settings.local.json把它排除掉。 - 用户级的
~/.claude/settings.json是配置文件最常用的一层,模型、全局白名单这类长期偏好都放这里。 - 进阶:环境变量
CLAUDE_CONFIG_HOME可以改掉~/.claude这个默认路径,一般人用不到。
六、普通人使用时需要关注的几点建议
前面都是原理,这一节是给普通用户的实操建议——把握住这几条,基本就不会出问题。
1. 不是每个项目都要建配置文件。 Claude Code 是"按需覆盖"模式,不是"必须存在"模式。没有项目级配置,它会自动回落到用户级配置;没有本地配置,再往上回落。所以普通项目 + 用户级配置已经够用时,什么都不用加。只有在以下情况才值得新建配置文件:项目需要特定模型、项目有私密 token、项目有专属 MCP 工具、项目需要自动跑 typecheck/lint。
2. 密钥永远只放 settings.local.json。
任何 API Key、token、密码——只能写在不进 Git 的本地文件里。项目级 settings.json 会被提交到仓库,写进去等于公开泄露。这是最重要的一条安全红线。
3. 一定要配好 .gitignore。
在 .gitignore 里加上 .claude/settings.local.json(和 CLAUDE.local.md)。否则你的本地私密配置会不小心被提交上去。
4. 想临时换模型 / 权限,改 settings.local.json 最省心。
因为它优先级最高,在里面加一个字段就能临时覆盖;不想要了直接删掉那行,就自动回落到项目级或全局设置,随时可逆,不影响别人。
5. 日常开发用 workspace-write 就好。
别一上来就开 danger-full-access。workspace-write 已经能让 AI 自由读写项目文件,危险命令还会弹窗给你最后一道确认;遇到反复弹窗的常用命令,点"Always Allow"逐步攒白名单即可。
6. 全局放共性,局部放差异。
长期不变的个人偏好(默认模型、常用白名单)放全局 ~/.claude/settings.json;项目专属的东西放项目级;只属于你这台机器的东西放本地。一旦某个设置没生效,从最局部(本地)往外(全局)逐层排查同名字段被谁覆盖了。
小结:配置文件就是一份分三层的"参数表"——全局、项目、本地,范围越小优先级越高,三层会被深度合并成一份最终生效的设置。普通用户记住三件事就够了:密钥只进本地文件、本地文件别忘了写进
.gitignore、没特殊需求就不必新建配置文件。它和上一篇的指令文件一个管"硬开关"、一个管"软约定",配合起来才是完整的 Claude Code 使用姿势。