1. 为什么 settings.json 才是 Claude Code 的真正控制台很多人装完 Claude Code 之后第一反应是去翻官方文档找命令或者到处问“怎么让它别每次都问我”。但真正用久了你会发现Claude Code 的行为几乎全部由配置文件驱动而settings.json就是那个最核心的开关面板。它决定了模型走哪个通道、哪些命令不用二次确认、哪些目录允许被读写、环境变量怎么注入、钩子脚本在什么时机触发。你可以把它理解成 Claude Code 的“注册表”——不改它你永远只能用默认那一套改对了它才真正变成贴合你工作流的工具。我最初用 Claude Code 的时候最烦的就是每次执行一个ls或者git status都要弹一次确认。后来把权限规则写进settings.json整个世界清净了。再后来接入自定义模型通道、配置项目级指令、加钩子做格式化才发现这个文件的潜力远不止“少点几次确认”。它其实是你和 AI 编程助手之间的契约你告诉它什么能做、什么不能做、用什么做、做完之后还要干什么。这篇文章面向的是已经装好 Claude Code、但还没认真折腾过配置的人。如果你还在纠结怎么安装那可以先去看安装教程但如果你已经能跑起来只是觉得“差点意思”那问题大概率就出在settings.json上。下面我会从文件结构讲起把权限、模型、环境变量、钩子、项目级配置这几块拆开说清楚每个配置项都告诉你为什么这么写、不这么写会怎样。中间会穿插我自己踩过的坑和实测有效的方案你可以直接抄也可以按自己的习惯改。2. settings.json 的文件结构与加载优先级2.1 三个层级用户级、项目级、本地级Claude Code 的配置不是只有一个文件而是分层的。理解这个分层比记住任何单个配置项都重要。它决定了你的配置会不会被覆盖、会不会被提交到 Git、会不会影响同事。用户级配置路径通常在~/.claude/settings.json。这是你个人的全局配置对所有项目生效。适合放模型通道、通用权限、个人偏好的环境变量。项目级配置路径在项目根目录的.claude/settings.json。这个文件通常会被提交到版本控制团队共享。适合放项目相关的权限规则、钩子脚本、项目指令。本地级配置路径在项目根目录的.claude/settings.local.json。这个文件应该被.gitignore忽略只对你本机生效。适合放你个人的临时覆盖比如本地调试用的环境变量。加载顺序是用户级 → 项目级 → 本地级。后面的会覆盖前面的。但注意不是所有字段都是简单覆盖有些是合并。比如权限的 allow 列表多个层级的规则会叠加而模型设置这种单值字段后面的直接覆盖前面的。我一般这样分配用户级放模型通道和全局权限白名单项目级放这个项目特有的钩子和指令本地级放我本机才有的路径和密钥。这样换项目不用改全局换机器也不用改项目。2.2 一个最小可用的配置骨架先看一个最基础的settings.json长什么样。很多人第一次打开这个文件是空的或者只有一对花括号完全不知道从哪下手。下面这个骨架你可以直接复制到用户级配置里{ model: claude-sonnet-4-20250514, permissions: { allow: [ Bash(git status), Bash(git diff:*), Bash(ls:*), Read ], deny: [ Bash(rm -rf:*), Bash(curl:*) ] }, env: { EDITOR: code --wait } }这个骨架里model指定默认模型permissions.allow列出不需要确认的命令permissions.deny列出直接拒绝的命令env注入环境变量。就这么几行已经能解决大部分“每次都要确认”的烦恼。但这里有个细节Bash(git status)和Bash(git status:*)的区别。前者只匹配完全等于git status的命令后者匹配所有以git status开头的命令比如git status --short。我建议对只读命令用:*通配对写操作保持精确匹配避免误放行。2.3 配置合并的坑为什么你的规则没生效我遇到过好几次“明明写了 allow为什么还问我”的情况。排查下来基本都是合并逻辑没搞对。比如你在用户级写了Bash(ls:*)在 allow 里在项目级写了Bash(ls:*)在 deny 里那最终是 deny 优先。Claude Code 的权限判断顺序是先看 deny再看 allow都没有才问用户。还有一个坑是路径写法。项目级配置里的相对路径是相对于项目根目录的但用户级配置里的相对路径是相对于你启动 Claude Code 时的工作目录。如果你在用户级配置里写了Read(./src/**)换一个项目就完全不对了。所以用户级配置里尽量用绝对路径或者~开头的路径项目级配置里才用相对路径。另外JSON 本身不支持注释但 Claude Code 的配置解析器对尾随逗号比较宽容。不过我还是建议你保持严格的 JSON 格式因为有些工具链会校验。如果你实在想写注释可以在项目里放一个settings.md说明文件别在 JSON 里硬塞。3. 权限系统让 AI 该放手时放手该刹车时刹车3.1 allow 和 deny 的匹配规则详解权限系统是settings.json里最值得花时间打磨的部分。它的核心就两个列表allow和deny。但匹配规则比看起来复杂。每条规则的基本格式是工具名(参数模式)。工具名可以是Bash、Read、Write、Edit、WebFetch等。参数模式支持通配符*但通配符的位置很关键。Bash(git:*)匹配所有以git开头的命令。Bash(* --help)匹配所有以--help结尾的命令。Read(~/projects/**)匹配~/projects下所有文件。Write(./src/**/*.ts)匹配src下所有 TypeScript 文件。注意**和*的区别*匹配单层路径**匹配多层。这个和 glob 规则一致。我自己的 allow 列表分三类只读命令、版本控制命令、构建测试命令。只读命令比如ls、cat、grep、find这些放行没有风险。版本控制命令比如git status、git diff、git log放行能省很多确认。构建测试命令比如npm test、npm run build、pytest这些虽然会写文件但都是预期内的放行也合理。deny 列表我放三类破坏性命令、网络请求、敏感文件读取。破坏性命令比如rm -rf、git reset --hard、git push --force。网络请求比如curl、wget除非我明确知道要干什么。敏感文件比如.env、*.pem、id_rsa。3.2 用 deny 兜底那些绝对不能碰的操作allow 是效率工具deny 是安全底线。我建议每个人都在用户级配置里放一份“绝对禁止”列表不管项目怎么变这些命令永远不放行。{ permissions: { deny: [ Bash(rm -rf /:*), Bash(rm -rf ~:*), Bash(rm -rf .:*), Bash(git push --force:*), Bash(git reset --hard:*), Bash(chmod 777:*), Bash(curl:* | sh), Bash(wget:* | sh), Read(.env), Read(.env.*), Read(**/*.pem), Read(**/id_rsa*) ] } }这里有几个我特意加的curl:* | sh和wget:* | sh是防止从网络下载脚本直接执行这是供应链攻击的常见入口。chmod 777是防止权限被改得一塌糊涂。.env和*.pem是防止密钥泄露。注意deny 列表里的规则优先级最高即使 allow 里写了同样的规则deny 也会赢。所以不要在两个列表里放冲突的规则否则你会困惑为什么 allow 不生效。3.3 权限规则的调试方法写完权限规则怎么知道它到底匹配不匹配Claude Code 没有内置的规则测试命令但你可以用一个小技巧故意执行一个应该被 allow 的命令看它还问不问。如果还问说明规则没匹配上。更系统的做法是看 Claude Code 的日志。启动时加--verbose参数它会打印每次权限判断的详细过程包括匹配了哪条规则、为什么放行或拒绝。这个日志在排查复杂规则时非常有用。我一般会先用一个宽松的 allow 列表跑一段时间观察哪些命令经常被问然后逐步加进去。不要一上来就写一大堆规则因为你可能写错而写错的规则要么太宽有风险要么太窄没效果。渐进式收紧比一次性写完更靠谱。还有一个经验把权限规则按项目类型分组。比如前端项目的 allow 列表和后端项目不一样你可以把公共部分放用户级项目特有的放项目级。这样切换项目时不用改全局配置。4. 模型与通道配置不只是换个名字4.1 model 字段的取值与切换逻辑model字段决定 Claude Code 默认用哪个模型。取值可以是模型 ID比如claude-sonnet-4-20250514也可以是别名比如sonnet、opus、haiku。用别名更省心因为官方会维护别名到最新版本的映射。但这里有个常见误区很多人以为改了model就万事大吉其实还要看你的接入方式。如果你用的是官方通道model直接生效。如果你用的是自定义通道model的值可能被通道配置覆盖。我一般这样配用户级设一个默认模型项目级根据项目复杂度覆盖。比如简单脚本项目用haiku省钱复杂重构项目用opus保质量。切换项目时自动切换模型不用手动改。{ model: sonnet }如果你在项目级想临时用更强的模型{ model: opus }4.2 自定义通道与 Router 配置Claude Code 支持通过环境变量或配置指定自定义 API 端点。这是很多人接入其他模型服务的方式。配置通常在env字段里{ env: { ANTHROPIC_BASE_URL: https://your-endpoint.example.com, ANTHROPIC_API_KEY: your-key-here } }但把密钥直接写在settings.json里不安全尤其是项目级配置可能被提交。更好的做法是用本地级配置或者用环境变量引用{ env: { ANTHROPIC_BASE_URL: https://your-endpoint.example.com, ANTHROPIC_API_KEY: ${MY_API_KEY} } }这样密钥从系统环境变量读取不落在文件里。如果你用 Claude Code Router 这类工具做多通道切换配置通常在 Router 自己的配置文件里而不是settings.json。但你可以通过settings.json的env字段指定 Router 的地址让 Claude Code 走 Router。这样切换通道时只改 Router 配置不用动 Claude Code。我实测下来自定义通道的稳定性取决于端点质量。如果经常超时可以在env里加超时设置{ env: { ANTHROPIC_TIMEOUT: 60000 } }单位是毫秒60000 就是 60 秒。默认值通常够用但网络慢的时候调大一点能减少失败。4.3 模型参数微调temperature 与 max_tokenssettings.json里还可以配一些模型参数比如temperature和max_tokens。不过这两个字段的支持情况取决于 Claude Code 版本和接入方式不是所有版本都认。{ temperature: 0.2, max_tokens: 8192 }temperature控制随机性编程场景建议低一点0.1 到 0.3 之间让输出更确定。max_tokens控制单次输出长度如果你经常处理大文件可以调大但注意不要超过模型上限。我的经验是这两个参数不要频繁改。默认值通常是经过调优的除非你有明确需求否则保持默认。改多了反而容易出怪问题比如输出截断或者重复。5. 环境变量与钩子把重复劳动自动化5.1 env 字段的实用配置env字段用来注入环境变量Claude Code 执行命令时会带上这些变量。这个功能看起来简单但用好了能省很多事。我常用的几个{ env: { EDITOR: code --wait, PAGER: cat, GIT_PAGER: cat, NODE_OPTIONS: --max-old-space-size4096 } }EDITOR设成code --wait是为了让 Claude Code 调用编辑器时用 VS Code 并等待关闭。PAGER和GIT_PAGER设成cat是为了避免分页器卡住输出因为 Claude Code 是非交互环境分页器会导致命令挂起。NODE_OPTIONS调大内存是为了处理大项目时不爆内存。还有一个实用技巧把项目相关的路径加到PATH里。{ env: { PATH: ${PATH}:/your/custom/bin } }这样 Claude Code 能直接调用你自定义的工具不用写全路径。5.2 钩子机制在关键节点插入自动化钩子是 Claude Code 比较高级的功能允许你在特定事件发生时执行脚本。常见的事件有PreToolUse、PostToolUse、Notification等。比如你想在每次文件被修改后自动格式化{ hooks: { PostToolUse: [ { matcher: Edit|Write, command: npx prettier --write ${file} } ] } }这个配置的意思是当Edit或Write工具执行后对修改的文件跑 Prettier。${file}是 Claude Code 传入的变量代表被操作的文件路径。再比如你想在 Claude Code 需要确认时发个通知{ hooks: { Notification: [ { command: notify-send Claude Code 需要你的确认 } ] } }这个在 Linux 上用notify-sendmacOS 上可以用osascriptWindows 上可以用 PowerShell 脚本。钩子的坑在于命令执行失败会阻塞后续流程。所以钩子脚本一定要加错误处理别让一个格式化失败导致整个操作卡住。我一般会在命令后面加|| true让失败不影响主流程。{ hooks: { PostToolUse: [ { matcher: Edit|Write, command: npx prettier --write ${file} || true } ] } }5.3 项目指令与 CLAUDE.md 的配合settings.json管行为CLAUDE.md管知识。这两个要配合用。CLAUDE.md放在项目根目录里面写项目结构、编码规范、常用命令Claude Code 启动时会自动读取。我一般把CLAUDE.md分成几块项目概述、目录结构、开发命令、编码规范、注意事项。这样 Claude Code 一上来就知道这个项目是干什么的、怎么跑、代码怎么写。# 项目概述 这是一个 Node.js 后端服务用 Express 框架。 # 开发命令 - 安装依赖npm install - 启动开发npm run dev - 跑测试npm test - 构建npm run build # 编码规范 - 用 TypeScript不用 JavaScript - 缩进用 2 空格 - 函数名用 camelCase类名用 PascalCase - 提交信息用 conventional commits 格式 # 注意事项 - 不要修改 src/config 下的文件 - 数据库迁移文件在 migrations 目录不要手动改settings.json里可以指定CLAUDE.md的路径如果不在默认位置{ projectDoc: ./docs/CLAUDE.md }这个字段不是所有版本都支持如果不生效就把文件放在默认位置。6. 常见问题与排查技巧实录6.1 配置不生效的排查顺序配置写了没效果按这个顺序查文件位置对不对用户级在~/.claude/settings.json项目级在.claude/settings.json本地级在.claude/settings.local.json。路径错了文件等于没写。JSON 格式对不对用jq . settings.json校验一下有语法错误会直接报出来。字段名对不对Claude Code 的字段名是大小写敏感的permissions不是Permissionsallow不是Allow。优先级对不对本地级覆盖项目级项目级覆盖用户级。如果你在用户级改了但项目级有覆盖那用户级的改动看不到效果。版本支持不支持有些字段是新版本才加的旧版本不认。用claude --version看版本对照文档确认。我遇到最多的是第 2 和第 4 条。JSON 里多一个逗号或者项目级配置覆盖了用户级都会让人困惑半天。6.2 权限规则写错的典型症状权限规则写错通常有两种症状要么该放行的还问要么不该放行的直接跑了。该放行的还问一般是匹配模式写错了。比如你写了Bash(git status:*)但实际执行的是git status --short理论上应该匹配但如果 Claude Code 把命令拆分了可能匹配不上。这时候用--verbose看日志确认实际匹配的命令字符串是什么。不该放行的直接跑了一般是通配符太宽。比如你写了Bash(git:*)那git push --force也会被放行。这种规则很危险一定要用精确匹配或者更窄的通配。提示写完权限规则后用claude --verbose跑几个典型命令确认匹配行为符合预期。不要等到出了事再回头查。6.3 钩子脚本失败的常见原因钩子脚本失败最常见的原因是路径和权限。钩子命令是在 Claude Code 的工作目录下执行的如果你用了相对路径可能找不到脚本。建议用绝对路径或者在命令里先cd到脚本目录。第二个原因是环境变量。钩子执行时的环境变量可能和你终端里不一样尤其是PATH。如果钩子调用了某个工具但报“command not found”就在钩子命令里写全路径。第三个原因是输出处理。钩子的 stdout 和 stderr 会被 Claude Code 捕获如果输出太多可能影响性能。建议钩子脚本只输出必要信息或者重定向到日志文件。{ hooks: { PostToolUse: [ { matcher: Edit|Write, command: /absolute/path/to/format.sh ${file} /tmp/claude-hook.log 21 || true } ] } }这样输出进日志不干扰主流程失败也不阻塞。6.4 常见问题速查表问题可能原因解决方法配置完全不生效文件路径错误确认文件在正确层级目录下部分配置不生效被高层级覆盖检查项目级和本地级是否有冲突JSON 解析报错语法错误用jq校验修复逗号或引号权限规则不匹配通配符写法错误用--verbose看实际匹配字符串钩子不执行matcher 不匹配确认工具名和 matcher 正则一致钩子执行失败路径或权限问题用绝对路径检查执行权限模型切换无效通道配置覆盖检查自定义通道的模型映射环境变量不生效变量名拼写错误对照文档确认变量名大小写这张表是我自己排查时总结的覆盖了八成以上的常见问题。遇到新问题先按这个表过一遍大部分都能解决。7. 我的配置演进过程与实战建议7.1 从默认配置到个性化配置的迭代路径我刚开始用 Claude Code 的时候配置就是默认的什么都没改。用了两周被确认弹窗烦得不行才开始研究settings.json。第一版配置只加了 allow 列表把常用的只读命令放进去。第二版加了 deny 列表把危险命令禁掉。第三版加了环境变量解决分页器卡住的问题。第四版加了钩子做自动格式化。第五版开始分项目级配置不同项目用不同规则。这个迭代路径我觉得比较合理先解决最痛的问题再逐步优化。不要一上来就追求完美配置因为你不知道哪些规则真正有用。用一段时间观察哪些命令经常被问、哪些操作经常重复然后针对性地加配置。7.2 团队协作中的配置管理如果你在团队里用 Claude Code配置管理要注意几点。项目级配置提交到 Git但不要放个人密钥和本地路径。本地级配置加到.gitignore每个人自己维护。用户级配置不共享每个人按自己习惯来。团队共享的部分主要是项目指令CLAUDE.md、通用权限规则、钩子脚本。这些能保证团队成员用 Claude Code 时行为一致。个人部分主要是模型偏好、本地路径、个人密钥。我建议在项目里放一个.claude/settings.json模板新成员克隆项目后复制成settings.local.json填上自己的密钥就能用。这样既统一了基础配置又保留了个性化空间。7.3 几个我踩过的坑和最终方案第一个坑在用户级配置里写了相对路径的权限规则换项目后完全失效。后来改成绝对路径或者把相对路径规则放项目级。第二个坑钩子脚本没加|| true一次格式化失败导致整个编辑操作回滚。后来所有钩子都加错误容忍。第三个坑deny 列表里写了Bash(curl:*)结果连正常的 API 调试都不行了。后来改成只 denycurl:* | sh这种管道执行普通 curl 放行。第四个坑项目级配置覆盖了用户级的模型设置导致我在某个项目里一直用错模型。后来养成习惯项目级只覆盖必要的字段不整体替换。第五个坑JSON 里写了注释虽然 Claude Code 能解析但 CI 里的校验工具报错。后来注释都移到CLAUDE.md里JSON 保持纯净。这些坑说到底都是“想当然”导致的。配置这东西写的时候多花五分钟确认用的时候能省五小时排查。我现在改配置的习惯是改完先用jq校验再用--verbose跑几个典型场景确认没问题才正式用。最后分享一个小技巧把settings.json纳入版本控制但用不同的分支或目录管理不同场景的配置。比如configs/minimal.json、configs/full.json、configs/team.json需要时复制到对应位置。这样切换配置就像切换主题一样简单不用每次手动改。