你改了 ~/.claude/settings.json 或项目里的 .claude/settings.json,想加 hook、设权限、定义环境变量,结果 Claude Code 像没看到一样:hook 不触发、permission 还在弹、env 变量是空的。
最快的修法: 在 Claude Code 里跑 /doctor。截至 2026 年 6 月,它会在一屏里告诉你哪些 settings 文件加载了、来自哪一层、以及任何非法条目对应的具体字段名。如果 /doctor 没报问题,就在 shell 里跑 jq . ~/.claude/settings.json,抓那种会让整个文件静默失效的语法错误。这两步能解决绝大多数”settings 不加载”的情况。
Claude Code 是按分层读 settings 的(用户、项目、项目本地,再加企业管理那层),然后按优先级合并。一个 JSON 语法错误、key 名打错、改错了 scope、或者高层把你那层盖掉,都能让你的改动隐形。只要搞清楚你这个改动该在哪一层赢、Claude Code 实际在读哪一层,修起来就很快。
有一点变了、很多老教程还在误导人:多数情况下你不需要重启。 截至当前版本(2026 年 6 月),对 permissions、hooks、apiKeyHelper 的改动会热加载进正在跑的会话里——Claude Code 会监视这些文件,每检测到一次改动就触发一次 ConfigChange hook。只有 model 和 outputStyle 还需要重启(分别用 /model 和 /clear)。
你属于哪一类
| 症状 | 最可能的原因 | 跳到 |
|---|---|---|
/doctor 报非法条目或解析错误 | JSON 语法错误或未知 key | Step 1 |
| 队友能用你不能用(或反过来) | 改错了 scope / 优先级被覆盖 | Step 2 |
/hooks 显示 “No hooks configured” 或 0 个 matcher | 文件不对,或 event/matcher 结构错,或语法错 | Step 3 |
配了 allow 规则还是弹 permission | 有 deny 或 ask 规则在赢;规则跨层合并 | Step 4 |
Bash 工具调用里 env 变量是空的 | scope 放错,或值不是字符串 | Step 6 |
| 什么都不加载、文件看着没问题 | 文件 root 所有 / 读不到 | Step 5 |
常见原因
按命中率从高到低。
1. JSON 语法错误让整个文件失效
末尾多个逗号、key 没加引号、写了 // 注释、智能引号——任何一个都会让整个 settings 文件解析失败,Claude Code 直接回落到默认值。/doctor 现在能报出来,但 jq 能给你具体行。
怎么判断: 跑 jq . ~/.claude/settings.json。报错就是文件非法。JSON 不支持注释——一个误留的 // 或 # 是常见祸首。
2. 改错了 scope
有三个基于文件的 scope,外加管理层:~/.claude/settings.json(用户)、<project>/.claude/settings.json(项目,入 git)、<project>/.claude/settings.local.json(本地,gitignore)。用户层的标量值会被项目层同名 key 盖掉。
怎么判断: 跑 ls -la ~/.claude/settings.json "$PWD"/.claude/settings*.json,看哪些存在。再跑 /doctor 看每个 setting 解析出来的来源。
3. key 改名了,或根本不存在
Claude Code 偶尔会改 key 名,而打错的 key 会被静默忽略。加上 JSON schema,就能拿到自动补全和校验:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json"
}
怎么判断: 配了 $schema 后,编辑器会标出未知 key。/doctor 也会把管理层里的非法条目连同字段名一起报出来。
4. permission 规则跨层合并,按 deny -> ask -> allow 求值
跟多数 setting 不一样,permissions.allow、permissions.ask、permissions.deny 这几个数组不是跨层覆盖——它们会被拼接 + 去重,所以用户层的一条规则会跟项目层的叠加。规则随后按 deny -> ask -> allow 顺序求值(截至 2026 年 6 月),所以任何一处遗留的 deny 或 ask 规则都会盖过你新加的 allow。
怎么判断: 在每一层里搜你要管的那个工具,比如 grep -r '"Bash' ~/.claude/settings.json .claude/settings*.json。别处匹配到的 deny 或 ask 就是在赢的那条。
5. 文件权限挡住了 Claude Code 读文件
你 root 改的、或脚本写的,文件现在可能是 600 root 所有,你以普通用户跑的 Claude Code 进程读不到。
怎么判断: stat -f '%Su %Lp' ~/.claude/settings.json(macOS)或 stat -c '%U %a' ~/.claude/settings.json(Linux)。所有者不是你、或权限太紧,就改回来。
6. 环境变量放错 scope 或类型不对
env key 是一个 string-to-string 的扁平对象,会应用到每个会话和 Claude Code 拉起的每个子进程。数字和布尔也必须写成带引号的字符串;裸的 true 或 5 是非法 JSON,会直接搞坏文件。
怎么判断: 在 Bash 工具调用里跑 printenv MY_VAR。空的就是没加载——回头检查 scope,以及值是不是带引号的字符串。
开始前
- 备份文件。Claude Code 会自动留带时间戳的备份(最近 5 份),但手动复制一份更稳。
- 想清楚你要的到底是哪一层:用户全局、项目共享、还是项目本地。
- 装好
jq,要用它来校验。
需要收集的信息
- Claude Code 版本:
claude --version。 - 是谁在跑 Claude Code:
whoami。 - 项目下的
ls -la ~/.claude/和ls -la .claude/。 - 所有相关 settings 文件的完整内容。
jq . ~/.claude/settings.json(记下任何报错)。/doctor的输出;如果是 hook 问题再加/hooks。
一步一步修复
Step 1:先跑 /doctor,再校验 JSON
在 Claude Code 里跑 /doctor。它会报出哪些 settings 文件加载了、来自哪一层、以及任何非法条目对应的字段名。然后在 shell 里逐个校验:
jq . ~/.claude/settings.json
jq . .claude/settings.json 2>/dev/null
jq . .claude/settings.local.json 2>/dev/null
有解析错误就先修这个,别的都没法查。常见祸首:对象或数组最后一项后面多个逗号、写了 // 或 # 注释、从文档里粘进来的智能引号。
Step 2:确认是哪一层在赢
优先级,高到低(截至 2026 年 6 月):
- 管理层 / 企业层(无法被覆盖)
- 命令行参数(只对当次会话生效,比如
claude --model opus) .claude/settings.local.json(项目本地).claude/settings.json(项目共享)~/.claude/settings.json(用户)
对标量值,定义了这个 key 的最高层赢。把改动挪到对的那一层、或把低层那条删掉。如果存在管理层,它盖过一切,包括命令行参数。管理文件的位置:
- macOS:
/Library/Application Support/ClaudeCode/managed-settings.json - Linux / WSL:
/etc/claude-code/managed-settings.json - Windows:
C:\Program Files\ClaudeCode\managed-settings.json
注意:旧的 Windows 路径 C:\ProgramData\ClaudeCode\managed-settings.json 在 v2.1.75 已废弃。
Step 3:hook 用 /hooks 确认加载
在会话里跑 /hooks。它会列出每个已配置的 hook、它的来源(user / project / managed)、以及 matcher 和 handler 细节。如果你明明配了,它却显示 “No hooks configured” 或 0 个 matcher,那就是 hook 写在了 Claude Code 没读的文件里,或者 event/matcher 结构错了。Hook 嵌三层:event(PreToolUse、PostToolUse、Stop 等)、按工具名过滤的 matcher 组、以及指明 command、HTTP endpoint 或 MCP tool 的 handler。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "echo blocked >&2; exit 2" }
]
}
]
}
}
Step 4:permission 要在每一层都搜
因为 permissions.allow、permissions.ask、permissions.deny 跨层合并、并按 deny -> ask -> allow 求值,别的文件里一条游离的规则就能盖过你的意图:
grep -rn 'permissions' ~/.claude/settings.json .claude/settings*.json
把那条更高优先级的 deny/ask 删掉或改对,或者把 pattern 收紧到不再匹配。
Step 5:核对文件所有权和权限
ls -la ~/.claude/settings.json
chmod 600 ~/.claude/settings.json
chown "$USER" ~/.claude/settings.json
跑 Claude Code 的用户必须能读这个文件。
Step 6:env 类型仔细看
{
"env": {
"MY_API_BASE": "https://api.example.com",
"DEBUG": "true"
}
}
布尔和数字也写成字符串,到脚本里再转。env 这块会应用到每个会话和每个子进程。
Step 7:重载——只在必要时才重启
对 permissions、hooks、apiKeyHelper,存盘就行,正在跑的会话会热加载(可以用 ConfigChange hook 盯着)。只有 model 和 outputStyle 需要动手:会话中途换模型用 /model,换新的 outputStyle 用 /clear 或重启。如果你真想干净地重载一遍,就 /exit 然后新开一个 shell 重启,因为某些 shell 会缓存 env、被 CLI 继承走。
Step 8(可选):抓 debug 日志
如果 /doctor 和 /hooks 都还让你摸不着头脑,跑:
claude --debug 2>&1 | grep -i -E 'settings|hook|permission'
它会打印文件加载顺序、以及每个值来自哪一层。
怎么验证修好了
/doctor不再报非法条目,并把你的文件列为来源。/hooks显示你的 hook,来源和 matcher 都对。- Permission 规则按配置正确地允许或拒绝(不再有意外弹窗)。
- 在 Bash 工具调用里
printenv MY_VAR返回预期值。 - 再改一处存盘能立即生效(针对
permissions/hooks),说明文件确实被监视着。
长期预防
- 每个 settings 文件都加上
"$schema": "https://json.schemastore.org/claude-code-settings.json",让编辑器帮你抓打错的、和未知的 key。 - 改完用
jq校一遍;接到项目的 pre-commit hook 里。 - dotfiles 里维护一份
settings.example.json,注释说明每块是干嘛的。 - 同一个 hook 不要既放用户全局又放项目本地,挑一个家。
- 不入 git 的个人 override 用
.claude/settings.local.json。 - 扫一眼 Claude Code release notes 里改名的 key 和废弃的路径。
容易踩的坑
- 在 JSON 里加
//或#注释。JSON 没有注释,Claude Code 不宽容。 - 数组或对象最后一个元素后面留逗号,严格 JSON 拒收。
- 用了会塞智能引号或 BOM 的编辑器。
- 把带个人 hook 的
settings.local.json顺手 commit 了。 - 以为得重启,却没意识到
model改动才是那个真正需要/model的特例。 - 指望项目层的
allow盖过用户层的deny——permission 列表是合并的,而deny永远赢。
常见问答
- 两个 settings 文件冲突谁赢? 标量值:管理层 > 命令行参数 > 项目本地 > 项目共享 > 用户。同 key 看哪一层最具体。Permission 列表是例外——它们是合并的。
- 改完 settings 要重启 Claude Code 吗? 通常不用。截至 2026 年 6 月,
permissions、hooks、apiKeyHelper会热加载进正在跑的会话。只有model(用/model)和outputStyle(/clear或重启)需要动手。 - 为啥配了
allow还是弹? 规则按deny->ask->allow求值,而且列表跨所有 scope 合并。任何文件里的deny或ask都盖过你的allow。 - settings.json 能写注释吗? 不行,严格 JSON。要标注就用单独的笔记文件、或者起个
_comment这样的 key。 - 为啥 env 变量还是空的? scope 放错了、或者值不是带引号的字符串。每个
env值都得是字符串。 - 怎么看某个 setting 到底来自哪个文件? 跑
/doctor看总览、/hooks看 hook 来源、或claude --debug看原始加载顺序。
相关
- Claude Code hook 莫名拦下 Edit
- Claude Code permissions 弹窗循环
- Claude Code Skill 没被发现
- Claude Code MCP 调用超时
- Claude Code 反复追问
外部参考:
标签: #Claude Code #settings #排查 #CLI