用 Claude Code 的第一周,你大概率会在两件小事上耗掉不少耐心。
一是弹窗。改个文件问一次,跑个命令问一次,一天下来你点了三十几次“Yes, allow”,手指已经形成了肌肉记忆。某天屏幕上弹出一个你没细看的请求,你顺手点了“不再询问”——事后才反应过来,刚才放行的是什么。
二是重复劳动。你在一台机器上把 Claude Code 调教得服服帖帖:允许哪些命令、拦掉哪些文件、用哪个模型。换了台电脑或者拉了个新项目,一切从零开始,又回到见什么点什么的原始状态。
这两个问题的根源是同一件事:放权没有章法。该写进配置的尺度,被你留在了每次弹窗的临场判断里。这篇就讲 Claude Code 的门禁系统——settings.json,它管的就是“AI 可以干什么、要问谁、绝对不许碰什么”。
先建立直觉:一套分层的门禁
把 Claude Code 想象成一个新来的员工。他进门第一天,你需要告诉他的事情分好几种:有些是公司的红线(谁都不能碰生产库),有些是部门的规定(发版必须走 CI),有些是你个人的习惯(提交信息用英文)。这些规矩不能混在一张纸上——层级不同,效力不同,维护的人也不同。
settings.json 就是这套规矩的载体,而且 Claude Code 给了它五个层级,从高到低:
- Managed settings:组织统一下发(MDM、注册表或
managed-settings.json),公司红线,任何人都覆盖不了,包括你自己用命令行参数也不行; - 命令行参数:
claude --settings指定,只影响本次会话,临时实验用; .claude/settings.local.json:你在这个项目里的私人配置,不进 git;.claude/settings.json:项目团队共享,提交进 git,人手一份生效;~/.claude/settings.json:你的全局默认,所有项目通用。
规则很简单:同一项配置,高层覆盖低层。你全局里设了用 pnpm,某个老项目偏偏要 npm,就在那个项目的 local 层写一条,互不打架。这和第 2 篇讲记忆分层是同一个思想——不同范围的信息放不同层,只是那边管“AI 记什么”,这边管“AI 能干什么”。
还有一个容易忽略的细节:数组类的配置是跨层合并的,不是覆盖。比如 permissions.allow 名单,全局写了三条、项目写了两条,实际生效的是五条的并集。这让分层真正好用起来——公司给基础白名单,项目补自己的,个人再加私货,谁也不用抄谁的作业。少数例外(比如 fallbackModel)取最高层级的完整值,遇到行为奇怪时先想到这点。
三张名单:allow、ask、deny
门禁的核心是 permissions 对象,就三张名单:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Edit(src/**)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(.env)",
"Bash(curl *)"
]
}
}
每条规则的写法是 工具(范围):Bash(npm run *) 放行所有 npm 脚本,Read(.env) 禁止读环境变量文件,Edit(src/**) 允许改 src 下所有代码。范围里支持通配符,还有几个讲究的细节:
Bash(ls *)带空格才匹配ls -la,不会误伤lsof;- 复合命令是拆开逐段检查的:
Bash(safe-cmd *)挡不住safe-cmd && rm -rf /,后半段照样要过审; - 路径前缀有四种:
//开头是绝对路径,~/是家目录,/是项目根,不带前缀是相对路径。
三张名单的求值顺序是 deny → ask → allow,第一条命中的规则说了算。这个顺序意味着 deny 拥有最高安全优先级:你在 deny 里写死的东西,任何低层级的 allow 都救不回来。这是整个门禁系统的安全底线——公司红线写在 deny 里,就真的谁也放不了行。
Shift+Tab 背后的权限模式
按 Shift+Tab 能循环切换的“权限模式”,其实是给整套门禁调总闸。常用的四档:
- default:标准模式,名单之外的都问你;
- acceptEdits:工作目录内的文件编辑免确认(
mkdir、touch这类常见文件操作也顺带放行),写代码最顺手的一档; - plan:只读探索,连显式的
Editallow 规则都会被压住——规划阶段谁也别想动代码; - auto:自动模式,读操作和文件编辑由分类器直接放行,拿不准的动作做后台安全检查,连拦三次就退回人工询问。研究预览阶段,但方向很清楚:弹窗会越来越少。
还有一档 bypassPermissions(跳过全部检查),存在但我不打算推荐——它连 .git、.claude 这类敏感目录的写入都不再询问,只适合一次性脚本环境。日常工程里,“权限弹窗烦”的正解是花十分钟写好 allow 名单,而不是把门禁整个拆了。
这里藏着一个我很欣赏的安全设计:auto 和 bypassPermissions 这两个模式,写在项目或项目的 local 设置里是不生效的,只能在用户或组织层设置。道理不复杂:.claude/settings.json 是随仓库走的文件,你 clone 了一个来路不明的仓库,它的配置文件不该有权力给自己的内容解锁全权限。仓库不能给自己提权,这条防线值得单独记一笔。
可抄的配置:从最小集开始
给一套我实际在用、可以直接抄的最小配置。团队共享层(.claude/settings.json,进 git):
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git status)",
"Bash(git diff *)",
"Edit(src/**)",
"Read(//Users/*/Documents/GitHub/*)"
],
"deny": [
"Read(.env)",
"Read(./secrets/**)"
]
}
}
思路是三句话:日常无风险的操作(跑测试、看 diff、改源码)放进 allow,把弹窗消灭在 90% 的场景;敏感文件(环境变量、密钥目录)写死在 deny,谁来了也读不了;剩下的交给默认询问——真正的判断题才值得打断你。
Hooks 的挂载也住在这份文件里(第 6 篇的事件配置就写在 hooks 字段下)。配套的组织方式和第 2 篇的思路一致:团队共享的进这份文件,个人想覆盖的进 settings.local.json——比如我嫌某个提示音吵,就在 local 层关掉那一个事件,不动大家的配置。
env:环境变量的统一入口
settings.json 里还有一个 env 对象,专门给 Claude Code 及其子进程注入环境变量。能配的东西比想象中多——按素材仓库的整理,环境变量有几百个,从模型选择到代理设置都有官方开关。不必背,遇到“这行为能不能配”的问题时先查官方 settings 文档,大概率有对应的键。
两个容易踩的坑
坑一:以为 deny 了,其实只是匹配得不够严。 通配符的边界比直觉严格:Bash(ls *) 挡不住 lsof 这种前缀粘连的命令;反过来,safe-cmd 的 allow 规则也拦不住 safe-cmd && something-else 的后半段。写规则前后,用一条真实的边界命令试一下,比对着文档想象靠谱得多。
坑二:把个人偏好写进了团队文件。 settings.json 是进 git 的,你写进去的每一条同事都会继承。个人机器路径、私有代理地址、你自己的模型偏好——这些进 local 层。判断标准和第 2 篇的 CLAUDE.md 一样:这条规矩是“这个项目所有人的”还是“我这个人的”?
坑三:sandbox 时代快来了,但别急着裸奔。 Claude Code 还有文件系统和网络的沙箱能力,能把 AI 的活动范围限制在指定目录和域名内。这块配置项还在快速演进,细节我不在这篇展开(避免写成快照说明书),只提一个方向:未来“防 AI 误伤”的主力会从名单匹配逐步转向运行时沙箱,值得关注官方文档的更新。
收工清单
- 五个层级,高层覆盖低层;数组类配置跨层合并,白名单大家一起攒
- 求值顺序 deny → ask → allow;deny 是安全底线,写在组织层最稳
- 规则语法
工具(范围),通配符的边界用真实命令验证过再信 - 日常顺手的事进 allow,敏感文件进 deny,判断题留给默认询问
auto/bypassPermissions不能从项目文件生效——仓库不能给自己提权,这是特性不是 bug- 团队共享进
.claude/settings.json,个人覆盖进settings.local.json - 遇到“能不能配”的问题,先查官方 settings 文档,几百个环境变量大概率有答案
门禁装好了,地基打完了,系列的前半程到此收官。下一篇我们换一个视角:不再讲“怎么配”,而是讲“怎么用得久”——上下文为什么越用越钝、40% 法则是什么、什么时候该 /clear 什么时候该 /compact。前面所有的配置,最终都是为了让你能长时间、高质量地用下去。
