5 种权限模式
用户可通过 Shift+Tab 在模式间循环切换,每种模式对工具调用有不同的处理策略。
💬
default
默认交互模式
未明确允许的操作
向用户弹出确认框
📝
acceptEdits
自动接受工作目录
内的文件编辑操作
其余仍需确认
📋
plan
计划模式
用户先审查执行计划
再批准实际操作
bypassPermissions
自动允许所有操作
需 Statsig 门控
tengu_iron_gate
🤖
auto
AI 分类器决策
ANT 内部 A/B 测试
TRANSCRIPT_CLASSIFIER

⌨️ 模式切换顺序(Shift+Tab 循环)

default acceptEdits plan bypassPermissions auto → ...
12 步权限决策管道
每次工具调用都经过 hasPermissionsToUseToolInner() 的完整决策链,顺序不可更改(来自 permissions.ts 1158-1319行)。
1a

整个工具被 Deny Rule 拒绝?

检查 alwaysDenyRules 中是否存在整个工具名称(如 Bash)的拒绝规则。

→ 返回 DENY
1b

整个工具有 Ask Rule?

检查 alwaysAskRules 中是否有整个工具的规则。若有且不可沙箱化,强制弹出确认框。

→ 返回 ASK
1c

工具自身的 checkPermissions()

调用工具实现中的 checkPermissions(input, context) 方法,工具可自定义额外权限检查逻辑。

1d

工具实现返回 DENY?

若 checkPermissions 返回 deny 决策,立即中止,不再继续后续检查。

→ 返回 DENY
1e

工具需要用户交互?

若工具声明 requiresUserInteraction(),即使在 bypassPermissions 模式下也必须弹出确认(免疫绕过)。

→ 返回 ASK(免疫绕过)
1f

内容级 Ask Rules 匹配?

检查是否有针对特定内容的 Ask 规则,如 Bash(npm publish:*)。若匹配,强制确认(免疫绕过)。

→ 返回 ASK(免疫绕过)
1g

安全检查触发?

硬编码的安全保护路径:.git/.claude/、shell 配置文件(.bashrc/.zshrc等)的写操作强制确认(免疫绕过)。

→ 返回 ASK(免疫绕过)
2a

bypassPermissions 模式?

若当前权限模式为 bypassPermissions,且未被上述免疫保护拦截,自动放行。

→ 返回 ALLOW
2b

整个工具在 Allow 白名单?

检查 alwaysAllowRules 是否包含整个工具名称(无内容约束),若是则自动放行。

→ 返回 ALLOW
2c

内容级 Allow Rules 匹配?

检查 alwaysAllowRules 中带内容模式的规则,如 Bash(git status:*),匹配则自动放行。

→ 返回 ALLOW
3

passthrough → ask 转换

若工具未返回明确的 allow/deny,将其视为"需要询问",进入 useCanUseTool.tsx 的交互流程。

→ 返回 ASK

useCanUseTool.tsx 处理 ASK

弹出交互式确认框,记录用户决策,支持"记住此选择"将规则写入 alwaysAllowRules / alwaysDenyRules。

规则系统(Allow / Deny / Ask Rules)
三类规则列表,支持工具级和内容级精确匹配。来自多个来源(本地设置、用户设置、项目设置、CLI 参数、会话)。
alwaysAllowRules

自动放行规则

匹配时跳过用户确认,直接执行。

示例:

  • Bash — 允许所有 Bash 命令
  • Bash(git status:*) — 只允许 git status
  • Read — 允许所有文件读取
  • Edit(/src/**:*) — 允许 src 下所有编辑
alwaysDenyRules

硬拒绝规则

匹配时立即拒绝,模型无法绕过(除 bypassPermissions 模式下的非免疫检查)。

示例:

  • Bash(rm -rf:*) — 禁止删除命令
  • Bash(npm publish:*) — 禁止发包
  • WebSearch — 完全禁用搜索
alwaysAskRules

强制确认规则

即使在 bypassPermissions 模式下也会强制弹出确认框(免疫绕过)。用于高风险但需要用户知情的操作。

示例:

  • Bash(git push:*) — 所有 push 需确认
  • Bash(curl * | bash:*) — 管道执行需确认
BashTool/bashPermissions.ts — 规则匹配逻辑
// Bash 规则匹配:去除安全包装器后进行命令比较 // 1. stripSafeWrappers() — 移除 timeout/time/nice/nohup 等 // 2. 处理复合命令 (&&, |, ;) — 逐个子命令检查 // 3. 三种匹配类型: // - 精确规则: "git status" → 仅匹配 git status // - 前缀规则: "git:*" → 匹配所有 git 命令 // - 通配规则: Bash → 匹配所有 Bash 调用 function bashToolHasPermission(command, rules) { const stripped = stripSafeWrappers(command) // 去掉timeout等 const subCmds = splitCommandWithOperators(stripped) // 拆分复合命令 return subCmds.every(cmd => matchWildcardPattern(cmd, rules)) }
AI 分类器决策 + 拒绝跟踪
在 auto 权限模式下,AI 分类器通过分析命令语义来决定是否自动批准。内置拒绝次数上限防止无限循环。

🤖 Classifier 决策流程

  1. dontAsk 模式 → 直接拒绝
  2. 检查 acceptEdits 快速路径
  3. 查询安全工具白名单(classifierDecision.ts)
  4. 调用 YOLO 分类器 API 判断
  5. 分类器拒绝 → 计入连续/累计拒绝次数
  6. 超限 → 降级为交互式确认框

📊 拒绝次数限制(denialTracking.ts)

3
连续拒绝上限
20
累计拒绝上限

任一触发 → 自动降级到交互式弹窗,避免 Agent 被无限循环拒绝卡死。

🔒 Bypass 免疫保护层级

以下检查在所有模式下都强制执行,包括 bypassPermissions:

安全路径保护(1g)
.git/, .claude/, ~/.bashrc, ~/.zshrc 等的写操作
内容级 Ask 规则(1f)
Bash(npm publish:*) 类形式,用户主动设置的 always-ask
需要用户交互工具(1e)
requiresUserInteraction() 返回 true 的工具(如确认框)

🏖️ 沙箱集成

通过 SandboxManager 检测是否启用沙箱。若命令在沙箱中执行且 autoAllowBashIfSandboxed 开启,ask-rule 会被自动升级为 allow。

排除条件:dangerouslyDisableSandbox=true + 策略允许,或命令在排除列表中。

Headless Agent 权限路径
当 shouldAvoidPermissionPrompts = true 时(异步子 Agent、SDK 非交互会话),权限决策走特殊的无头路径。
无头路径

跳过交互式弹窗

异步子 Agent 无法显示确认框,因此:

  • 先尝试 PermissionRequest hooks(工具可挂钩处理)
  • Hooks 允许 → 自动放行
  • 无 Hook 响应 → 自动拒绝(不弹框)
  • 分类器连续拒绝超限 → AbortError
PermissionRequest Hooks

Hooks 系统

权限检查前后支持外部 hooks:

  • pre-tool-use:工具调用前,可修改输入或阻止
  • post-tool-use:工具完成后,可检查输出
  • user-prompt-submit:用户提交前处理
  • Hook 以 shell 命令形式配置,通过 stdin/stdout 交互
权限模式在 plan 模式下

Plan 模式特殊行为

Plan 模式下,Claude 首先生成完整计划(仅读操作可执行),用户审查后一次性批准所有待执行操作。批准后切换为 acceptEdits 模式执行。大型任务时默认使用 Claude Opus(超 200k token 时自动切换)。