你改了 ~/.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 hook 莫名拦下 Edit
- Claude Code permissions 弹窗循环
- Claude Code Skill 没被发现
- Claude Code MCP 调用超时
- Claude Code 反复追问
标签: #Claude Code #settings #排查 #CLI