Claude Code 六种权限模式:auto mode 到底和 bypassPermissions 差在哪
想让 agent 挂着跑很久不被打断,正确的选择通常是 auto mode,不是 --dangerously-skip-permissions。
两者的区别不是「宽松程度不同」,是机制不同:auto mode 有一个分类器(classifier)在逐条判断每个操作的风险,判断结果分四档处理;bypassPermissions 是把整个权限判断层关掉。前者仍然存在硬边界,后者没有边界。
| 模式 | 行为 |
|---|---|
default(CLI 里显示为 Manual) | 每个需要权限的操作都问你 |
acceptEdits | 文件编辑自动通过,其他操作照常问 |
plan | 只读探索与方案撰写,不执行改动 |
auto | 分类器逐条判断,低风险自动放行,高风险仍然拦 |
dontAsk | 不弹提示,被拦的操作直接失败而非询问 |
bypassPermissions | 不做权限判断 |
切换方式有两种:会话内按 Shift+Tab 循环,或启动时用 --permission-mode <mode>。也可以在 settings.json 里写 permissions.defaultMode 设默认值。
manual 是 default 的别名,需要 v2.1.200 或更高版本。
auto mode 的分类器
Section titled “auto mode 的分类器”auto mode 的核心是一个分类器,它读取即将执行的命令,判断它属于哪一档。配置项是 autoMode,四个数组:
| 数组 | 含义 |
|---|---|
environment | 描述运行环境的散文规则,给分类器提供判断背景 |
allow | 明确放行 |
soft_deny | 拦下来但可以问你 |
hard_deny | 直接拒绝 |
这些规则是散文(prose),不是模式匹配。写法像这样:
{ "autoMode": { "soft_deny": ["$defaults", "Never run terraform apply"], "environment": ["This is a staging environment, data loss is recoverable"] }}字面字符串 "$defaults" 表示在该位置继承内置规则。不写 $defaults 就是完全替换掉内置规则——这几乎总不是你想要的,因为内置规则里包含了一批基础的危险操作识别。
environment 数组容易被忽略但很有用。分类器判断风险时需要背景:在一次性的容器里 rm -rf 某个目录和在生产机上做同样的事,风险等级完全不同。把环境性质写进 environment,分类器的判断会更贴合实际。
一个默认行为:shell 命令的 allow 规则会被绕过吗
Section titled “一个默认行为:shell 命令的 allow 规则会被绕过吗”autoMode.classifyAllShell 默认为 false。这个默认值的含义需要拆开说。
auto mode 激活时,Claude Code 会挂起那些「匹配到任意代码执行模式」的 Bash / PowerShell allow 规则,让它们走分类器。但不匹配这类模式的 allow 规则仍然直接生效。
把 classifyAllShell 设为 true 则挂起全部 Bash 和 PowerShell allow 规则,所有 shell 命令一律经过分类器。需要 v2.1.193 或更高版本。
什么时候需要开:你的 permissions.allow 里有一批看起来安全的具体命令(比如 Bash(npm run build)),但你不确定这些命令内部会不会做别的事情。开启后这些命令也会被分类器过一遍。
为什么项目配置不能给自己开 auto mode
Section titled “为什么项目配置不能给自己开 auto mode”在 .claude/settings.json 或 .claude/settings.local.json 里写 "defaultMode": "auto" 不生效,也不报错。
原因是威胁模型:如果项目层配置能设 auto mode,那么克隆任意一个仓库、在里面启动 Claude Code,这个仓库就自动获得了「大部分操作不问你」的权限。仓库里的 CLAUDE.md、hook 脚本、MCP 配置都是仓库作者写的,等于把决策权交给了一个你还没审查过的代码库。
所以 auto 这个值只从 ~/.claude/settings.json、--settings 标志和 managed 设置读取。v2.1.142 之前项目设置可以设,是被收紧的。
autoMode 的分类器规则同理,只从用户层、--settings、managed 层读。否则仓库可以往自己的 allow 里加规则,等价于自我提权。v2.1.207 之前 .claude/settings.local.json 也在读取范围内。
plan 模式与 auto mode 的交叉
Section titled “plan 模式与 auto mode 的交叉”useAutoModeDuringPlan 默认为 true:auto mode 可用时,plan 模式会采用 auto mode 语义。
这个设计的用意是让方案撰写阶段的探索更顺畅——plan 模式本来就不改文件,探索性的只读命令(看目录结构、读配置、查 git 历史)不需要逐条确认。
这个字段不从共享的项目设置读取,同样是防止仓库影响你的权限行为。
关掉这两个模式
Section titled “关掉这两个模式”组织侧或个人侧都可以禁用:
{ "disableAutoMode": "disable", "permissions": { "disableBypassPermissionsMode": "disable" }}disableAutoMode 会把 auto 从 Shift+Tab 循环里移除,并在启动时拒绝 --permission-mode auto。
disableBypassPermissionsMode 同时禁用 --dangerously-skip-permissions 命令行标志。这两个字段在任何作用域都能用,但典型位置是 managed 设置。
还有一个相关字段 skipDangerousModePermissionPrompt,跳过进入 bypass 模式前的确认提示。它在项目设置里被忽略——防止一个不受信任的仓库让你在无感知的情况下进入 bypass 模式。
权限规则的判定顺序
Section titled “权限规则的判定顺序”权限规则的格式是 Tool 或 Tool(specifier),判定顺序是 deny → ask → allow,第一个匹配的规则决定结果,与规则的具体程度无关。
最后半句是最容易踩的地方。写了一条宽泛的 deny 和一条精确的 allow,精确的那条不会因为「更具体」而胜出——deny 先被检查,匹配上就结束了。
几个例子:
| 规则 | 匹配 |
|---|---|
Bash | 所有 Bash 命令 |
Bash(npm run *) | 以 npm run 开头的命令 |
Read(./.env) | 读 .env 文件 |
WebFetch(domain:example.com) | 请求 example.com |
工具名通配只在 mcp__<server>__ 这个字面前缀之后的工具位置支持,比如 mcp__github__get_*;server 段本身不能带通配。deny 规则里工具名可以用通配:* 拒绝全部工具,mcp__* 拒绝全部 MCP 工具。
deny 规则不能在其他工具仍然可用的情况下移除 EndConversation。
按「出错后果的可逆性」选,不按「想少点几次确认」选:
- 代码在 git 里、改动可回滚、命令不碰外部系统 → auto mode 够用,是长时间挂机的默认选择
- 只想让文件编辑免确认,其他照常 →
acceptEdits - 一次性容器、跑完即弃、没有任何持久化后果 → 才考虑 bypassPermissions
- 生产环境凭据在环境变量里、有能力调用外部 API → 不要用 bypassPermissions,用 auto mode 配
hard_deny明确列出禁止操作
dontAsk 是一个容易被误选的模式。它不弹提示,但被拦的操作是直接失败而不是询问。这在无人值守的脚本里是合理的(没人能回答提示),在交互式使用里通常不是你想要的。
- 在
autoMode.hard_deny里加一条你所在项目最不能容忍的操作(比如Never modify files under migrations/),然后让模型尝试做这件事,看拦截信息是什么样的。 - 对比 auto mode 和
acceptEdits在同一个任务上的确认次数。这能让你对分类器实际放行的范围有直观感受。 - 写一条宽泛的
permissions.deny和一条更精确的allow,验证 deny 确实先胜出,加深对「第一个匹配决定结果」的印象。
还没确认的点
Section titled “还没确认的点”- auto mode 的账户与版本要求。文档提到它对账户类型有要求,具体哪些订阅层级可用没有核实清楚。
- 分类器判断在多大程度上是确定性的。同一条命令在同一配置下是否总得到相同结论,文档未见说明。
- 分类器与 sandbox 的具体交互。两者都在限制命令行为,谁先生效、判断结果如何叠加,没有查到明确描述。
soft_deny被触发时呈现给用户的确认界面与 default 模式的权限提示是否相同。