Claude Code settings.json 改了不生效

改了 ~/.claude/settings.json 但 Claude Code 无视你的 hook、permission 或 env?先跑 /doctor。多半是 JSON 语法、scope 选错、或优先级被覆盖。

你改了 ~/.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 月),对 permissionshooksapiKeyHelper 的改动会热加载进正在跑的会话里——Claude Code 会监视这些文件,每检测到一次改动就触发一次 ConfigChange hook。只有 modeloutputStyle 还需要重启(分别用 /model/clear)。

你属于哪一类

症状最可能的原因跳到
/doctor 报非法条目或解析错误JSON 语法错误或未知 keyStep 1
队友能用你不能用(或反过来)改错了 scope / 优先级被覆盖Step 2
/hooks 显示 “No hooks configured” 或 0 个 matcher文件不对,或 event/matcher 结构错,或语法错Step 3
配了 allow 规则还是弹 permissiondenyask 规则在赢;规则跨层合并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.allowpermissions.askpermissions.deny 这几个数组不是跨层覆盖——它们会被拼接 + 去重,所以用户层的一条规则会跟项目层的叠加。规则随后按 deny -> ask -> allow 顺序求值(截至 2026 年 6 月),所以任何一处遗留的 denyask 规则都会盖过你新加的 allow

怎么判断: 在每一层里搜你要管的那个工具,比如 grep -r '"Bash' ~/.claude/settings.json .claude/settings*.json。别处匹配到的 denyask 就是在赢的那条。

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 拉起的每个子进程。数字和布尔也必须写成带引号的字符串;裸的 true5 是非法 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(PreToolUsePostToolUseStop 等)、按工具名过滤的 matcher 组、以及指明 command、HTTP endpoint 或 MCP tool 的 handler。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "echo blocked >&2; exit 2" }
        ]
      }
    ]
  }
}

Step 4:permission 要在每一层都搜

因为 permissions.allowpermissions.askpermissions.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:重载——只在必要时才重启

permissionshooksapiKeyHelper,存盘就行,正在跑的会话会热加载(可以用 ConfigChange hook 盯着)。只有 modeloutputStyle 需要动手:会话中途换模型用 /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 月,permissionshooksapiKeyHelper 会热加载进正在跑的会话。只有 model(用 /model)和 outputStyle/clear 或重启)需要动手。
  • 为啥配了 allow 还是弹? 规则按 deny -> ask -> allow 求值,而且列表跨所有 scope 合并。任何文件里的 denyask 都盖过你的 allow
  • settings.json 能写注释吗? 不行,严格 JSON。要标注就用单独的笔记文件、或者起个 _comment 这样的 key。
  • 为啥 env 变量还是空的? scope 放错了、或者值不是带引号的字符串。每个 env 值都得是字符串。
  • 怎么看某个 setting 到底来自哪个文件?/doctor 看总览、/hooks 看 hook 来源、或 claude --debug 看原始加载顺序。

相关

外部参考:

标签: #Claude Code #settings #排查 #CLI