Claude Code settings.json 改了不生效

改了 ~/.claude/settings.json 或项目 .claude/settings.json,重启后 Claude Code 完全无视 hook、permissions、env。多半是 JSON 语法、scope 选错、或者优先级被覆盖。

你改了 ~/.claude/settings.json 或项目里的 .claude/settings.json,想加 hook、设权限、定义环境变量。重启 Claude Code 之后好像什么都没生效:hook 不触发、permission 还在弹、env 变量是空的。Claude Code 是按分层读 settings 的:项目本地、项目共享、用户全局,再加企业管理那层。一个不起眼的 JSON 语法错误、key 名打错、scope 选错、或者优先级被覆盖,都能让你的改动隐形。只要搞清楚你这个改动该在哪一层赢、实际 Claude Code 在读哪一层,修起来就很快。

常见原因

按命中率从高到低。

1. JSON 语法错误让整个文件失效

末尾多个逗号、key 没加引号、智能引号——任何一个都会让整个 settings 文件解析失败。很多版本下 Claude Code 会静默回落到默认值。

怎么判断:跑 jq . ~/.claude/settings.json。报错就是文件非法。

2. 改错了 scope

至少三个位置:~/.claude/settings.json(用户全局)、<project>/.claude/settings.json(共享、入 git)、<project>/.claude/settings.local.json(本地、gitignore)。用户全局的 hook 会被项目同 key 的 hook 盖掉。

怎么判断:跑 ls -la ~/.claude/settings.json $PWD/.claude/settings*.json。看哪些存在;优先级 local > project > user。

3. 最近版本里 key 改名了

Claude Code 偶尔会改 key 名(比如 permissions.allow 的写法、hook schema)。你旧版的 key 留在文件里没人理。

怎么判断:把你的 key 跟当前文档版本对照。未知 key 会被静默忽略。

4. 环境变量定义在了错的 block 下

env 放错 scope、或者类型不对(只能字符串),Claude Code 就会丢掉它。某些版本下数字和布尔也得写成字符串。

怎么判断:重启后跑 claude --debug,找 env 加载相关的行。没出现就是被拒了。

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. Claude Code 还在用旧的会话

很多 settings 只在会话启动时加载。开着的会话还在用它启动时加载的那份。

怎么判断:你重启 Claude Code 之前真的退了吗(/exit 或关终端)?没退就还是旧会话。

开始前

  • 改 settings.json 之前先备份。
  • 想清楚你这个改动到底要在哪一层(用户全局 vs 项目共享 vs 项目本地)。
  • 想清楚这个改动是只给你自己用、还是给团队用、还是只给这个项目会话用。
  • 装好 jq,要用它来校验。

需要收集的信息

  • Claude Code 版本:claude --version
  • 系统 + 是谁在跑 Claude Code:whoami
  • ls -la ~/.claude/ 和项目根下 ls -la .claude/ 的输出。
  • 所有相关 settings.json 文件的完整内容。
  • jq . ~/.claude/settings.json 的输出(有报错就记下来)。
  • Debug 日志:claude --debug 2>&1 | head -200

一步一步修复

Step 1:校验 JSON 语法

jq . ~/.claude/settings.json
jq . .claude/settings.json 2>/dev/null
jq . .claude/settings.local.json 2>/dev/null

有解析错误就先修这个,别的都没法查。重点盯对象或数组最后一项后面的逗号。

Step 2:确认是哪一层在赢

Claude Code 是按这个优先级合并的(高到低):

  • 企业管理层(如果有)
  • .claude/settings.local.json(项目本地)
  • .claude/settings.json(项目共享)
  • ~/.claude/settings.json(用户)

两个文件定义了同一个 key、只有高优先级那个赢。要么把改动挪到对的那一层、要么把低层那条删掉。

Step 3:开 debug 模式确认加载

claude --debug 2>&1 | grep -i settings

应该能看到 settings 路径和加载的 key。少了哪条就是那个文件被跳过了。

Step 4:核对文件所有权和权限

ls -la ~/.claude/settings.json
chmod 600 ~/.claude/settings.json
chown $USER ~/.claude/settings.json

跑 Claude Code 的用户必须能读这个文件。

Step 5:和已知良好的模板对比

不确定当前 schema 是什么样,就把文档里的示例复制到一个 scratch 文件、用 jq 校验、然后一条一条地把你的自定义搬过去、每搬一条就重启验证一次。

Step 6:彻底重启 Claude Code

输入 /exit、关掉终端窗格、新开一个 shell 启动。某些 shell 会缓存 env、被 CLI 继承走。

Step 7:env 类型仔细看

{
  "env": {
    "MY_API_BASE": "https://api.example.com",
    "DEBUG": "true"
  }
}

布尔和数字也写成字符串,到脚本里再转换。

怎么验证修好了

  • Hook 在对应的工具调用上能触发了。
  • Permission 规则按配置正确地允许或拒绝。
  • 在 Bash 工具调用里跑 printenv MY_VAR 能返回预期值。
  • 重启 Claude Code 后行为不回退,持久生效。

长期预防

  • 每次改 settings.json 都用 jq 校一遍。给项目加个 pre-commit hook 做这事。
  • dotfiles 里维护一份 settings.example.json,注释说明每块是干嘛的。
  • 同一个 hook 不要既放用户全局、又放项目本地,挑一个家。
  • 不入 git 的个人 override 用 .claude/settings.local.json
  • 关注 Claude Code release notes 里的 schema 变更,及时改 key 名。

容易踩的坑

  • 在 JSON 里加注释(// 或 #)。JSON 不支持注释,有些 loader 宽容、Claude Code 不宽容。
  • 数组最后一个元素后面留逗号,严格 JSON 拒收。
  • 用了会自动塞智能引号或 BOM 的编辑器。
  • 把 hook 定义写进 settings.local.json 然后顺手 commit 了。
  • 忘了改动要起新会话才生效。

常见问答

  • 两个 settings 文件冲突谁赢? 企业 > 项目本地 > 项目共享 > 用户全局。同 key 看哪一层最具体。
  • settings.json 能写注释吗? 不行,严格 JSON。要标注就用单独的笔记文件、或者起个 _comment 这样的 key。
  • 为啥 env 变量还是空的? scope 放错了、或者值不是字符串。全部加引号。
  • 改 hook 要重启吗? 要。Hook 在会话启动时加载。
  • schema 文档在哪? Anthropic 有 settings reference,找跟你 claude --version 对得上的那个版本。
  • 不重启能验证吗? 能跑 jq . settings.json。catch 不到未知 key,但能 catch 语法错。

相关

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