这一章解释 Claude Code 的设置从哪里来、按什么顺序叠加,以及为什么 policy / managed settings 会被单独当成一类源。
Claude Code 的设置系统不是单文件配置,而是多来源合并系统。当前快照里至少存在:
- user settings
- project settings
- local settings
- flag settings
- policy settings
- plugin settings base
其中 policy settings 又不是单一文件,而是 remote managed settings、MDM、文件型 managed settings、HKCU 的“首个非空源优先”链路。
- 设置主逻辑:src/utils/settings/settings.ts
- 来源与优先级定义:src/utils/settings/constants.ts
- managed file 路径:src/utils/settings/managedPath.ts
- remote managed settings:src/services/remoteManagedSettings/index.ts
- 迁移脚本目录:src/migrations/
flowchart TD
A["plugin settings base"] --> B["userSettings"]
B --> C["projectSettings"]
C --> D["localSettings"]
D --> E["flagSettings"]
E --> F["policySettings"]
F --> G["effective settings"]
F --> H{"policy 来源"}
H --> H1["remote managed"]
H --> H2["MDM: HKLM / plist"]
H --> H3["managed-settings.json + drop-ins"]
H --> H4["HKCU"]
src/utils/settings/constants.ts 里把来源顺序写成:
userSettingsprojectSettingslocalSettingsflagSettingspolicySettings
注释直接说明 later sources override earlier ones。也就是说,settings merge 的语义不是推断出来的,而是常量层面就固定了。
src/utils/settings/settings.ts 对 policySettings 单独分支处理,并明确写明优先级:
- remote managed settings
- MDM (
HKLM/ macOS plist) managed-settings.json+managed-settings.d/*.jsonHKCU
这和普通 settings source 不同。普通源是 merge;policy 源是先选出“赢者”,再并入总配置。
loadManagedFileSettings() 说明:
- 基础文件是
managed-settings.json - drop-in 目录是
managed-settings.d/ - 基础文件先 merge
- drop-in 文件按文件名字典序排序后覆盖
这是典型的系统级配置 drop-in 设计,和 systemd / sudoers 的管理习惯很像,方便多团队分别下发策略片段。
src/services/remoteManagedSettings/index.ts 说明这套服务具备:
- 用户 eligibility 检查
- OAuth / API key 两套认证头
- checksum / sha256 级别的内容校验
- 重试与轮询
- 安全检查
- fail-open 行为
其中最关键的是 fail-open。源码注释直接说明远程托管设置获取失败时不会阻断主流程,而是继续运行。
settingsMergeCustomizer() 表明:
- 数组会 concat + dedupe
- 普通对象走 lodash 深合并
同时 updateSettingsForSource() 又对写回做了额外规则:
- 数组写回时直接替换
- 显式
undefined表示删除键 localSettings写回后会异步加到.gitignore
这说明“读取时的合并策略”和“写回时的编辑语义”是分开的。
同一个 settings.ts 里,像 hasSkipDangerousModePermissionPrompt()、hasAutoModeOptIn()、getUseAutoModeDuringPlan() 这类函数都会刻意排除 projectSettings,注释还直接提到 malicious project 风险。
这很重要。它说明 Claude Code 不认为所有 settings source 都同等可信。项目目录中的共享配置可以影响行为,但不能自动替用户接受高风险授权。
src/migrations/ 目录中能看到大量“旧模型 / 旧选项迁移到新 setting”的脚本,例如:
- 旧模型名迁移
- 自动更新设置迁移
- remote control 启动项迁移
这说明 settings 体系是长期演化的,Anthropic 预期用户配置会跨版本存活,因此必须维护迁移层。
这套 settings 系统体现出几个工程判断:
- Claude Code 已经不是单机玩具配置,而是企业可治理配置。
- policy 与 user/project/local 被明确区分。
- 远程托管、MDM、本地 managed 文件被整合进统一策略层。
- 某些高风险行为只接受“可信源”授权。
Claude Code 的 settings 系统本质上是“多源 merge + 托管策略优先 + 可信边界控制”的配置治理系统,而不是一个普通的 settings.json 读取器。