跳转到内容

Claude Code 六种权限模式:auto mode 到底和 bypassPermissions 差在哪

约 18 分钟 难度:进阶 理解章

想让 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 设默认值。

manualdefault 的别名,需要 v2.1.200 或更高版本。

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 也在读取范围内。

useAutoModeDuringPlan 默认为 true:auto mode 可用时,plan 模式会采用 auto mode 语义。

这个设计的用意是让方案撰写阶段的探索更顺畅——plan 模式本来就不改文件,探索性的只读命令(看目录结构、读配置、查 git 历史)不需要逐条确认。

这个字段不从共享的项目设置读取,同样是防止仓库影响你的权限行为。

组织侧或个人侧都可以禁用:

{
"disableAutoMode": "disable",
"permissions": {
"disableBypassPermissionsMode": "disable"
}
}

disableAutoMode 会把 autoShift+Tab 循环里移除,并在启动时拒绝 --permission-mode auto

disableBypassPermissionsMode 同时禁用 --dangerously-skip-permissions 命令行标志。这两个字段在任何作用域都能用,但典型位置是 managed 设置。

还有一个相关字段 skipDangerousModePermissionPrompt,跳过进入 bypass 模式前的确认提示。它在项目设置里被忽略——防止一个不受信任的仓库让你在无感知的情况下进入 bypass 模式。

权限规则的格式是 ToolTool(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 确实先胜出,加深对「第一个匹配决定结果」的印象。
  • auto mode 的账户与版本要求。文档提到它对账户类型有要求,具体哪些订阅层级可用没有核实清楚。
  • 分类器判断在多大程度上是确定性的。同一条命令在同一配置下是否总得到相同结论,文档未见说明。
  • 分类器与 sandbox 的具体交互。两者都在限制命令行为,谁先生效、判断结果如何叠加,没有查到明确描述。
  • soft_deny 被触发时呈现给用户的确认界面与 default 模式的权限提示是否相同。
这一节有错或讲不清? 提个 Issue 直接改文档 请作者催更