权限模式决定「多久问你一次」,权限规则决定「哪些操作预先放行或封死」,沙箱决定「命令跑起来之后能碰到什么」。三层各司其职,搭配得当,才能既少被打断又不裸奔。
为什么这天学这个
D1 里我们拆过 agentic loop:收集上下文 → 行动 → 验证,循环推进。其中「行动」这一环——编辑文件、跑 shell 命令、发网络请求——每一步都要先过 Claude Code 的授权闸门。不搞清楚它,你要么被弹窗打断到烦躁,要么图省事一路放行、把安全交给运气。
本课也是后面几课的地基:D5 要讲的 plan mode 本身就是一种权限模式;D13 的 Headless 与 CI 场景依赖 dontAsk 这类「永不等待输入」的模式。
概念讲清楚
权限模式:决定多久问你一次
官方当 Claude 想编辑文件、运行 shell 命令或发起网络请求时,它会暂停并请你批准;权限模式控制这个暂停出现的频率。官方共提供六种模式,每种在「便利」与「监督」之间做不同取舍:
| 模式 | 免询问能跑什么 | 适合场景 |
|---|---|---|
default(界面里叫 Manual) | 只有读取类操作 | 上手阶段、敏感工作 |
acceptEdits | 读取、文件编辑,以及 mkdir、touch、mv、cp 等常见文件系统命令 | 自己会 review diff 的日常迭代 |
plan | 读取;auto mode 可用时,还有 classifier 批准的命令 | 改代码前先摸清代码库 |
auto | 几乎全部,由后台 classifier 逐个安全审查 | 长任务、减少询问疲劳 |
dontAsk | 只有预先 allow 过的工具,其余直接拒绝 | 锁死的 CI 与脚本 |
bypassPermissions | 全部 | 只用于隔离的容器 / VM |
官方几个细节:default 在界面里显示为 Manual,配置值仍写 default(v2.1.200 起 CLI 也接受 manual 别名);acceptEdits 的自动批准只覆盖工作目录和 additionalDirectories 内的路径;对受保护路径(.git、.claude、~/.zshrc 等)的写入,除 bypassPermissions 外任何模式都不自动批准。auto mode 需账号满足条件才会出现,其 classifier 会拦截超出请求范围、指向陌生基础设施、或疑似被恶意内容带偏的动作;bypassPermissions 则没有任何后台检查,不防 prompt injection,只应在容器、VM 等隔离环境使用。
怎么切换模式
官方模式通过这些控制切换,在聊天里「让 Claude 自己改」是无效的:
- 会话中:按
Shift+Tab循环default→acceptEdits→plan,状态栏显示当前模式徽章(如accept edits on)。auto 满足条件时加入循环;bypassPermissions只有启动时用--dangerously-skip-permissions等 flag 启用后才进循环;dontAsk从不进循环,只能启动时指定。 - 启动时:传 flag,例如
claude --permission-mode plan,配-p的非交互运行同样适用。 - 持久默认:在 settings 文件里设
permissions.defaultMode:
{
"permissions": {
"defaultMode": "acceptEdits"
}
}
权限规则:allow / ask / deny 写在哪、怎么写
官方模式定的是基线,规则叠在模式之上做细粒度控制:allow 免询问放行,ask 每次强制询问,deny 直接禁止。用 /permissions 可以查看全部规则以及每条来自哪个 settings 文件。规则可以写在五级来源里,优先级从高到低:managed 托管设置 → 命令行参数 → .claude/settings.local.json(个人本地)→ .claude/settings.json(项目共享,可提交进 git)→ ~/.claude/settings.json(用户全局)。任何一级 deny 了某工具,其它级都无法再放行。
官方规则格式是 Tool 或 Tool(specifier)。Bash 规则支持 * 通配符,一个 * 能跨空格匹配多个参数;文件规则用 gitignore 语法;WebFetch 用 domain: 前缀;MCP 工具用 mcp__服务器__工具。一个典型的项目配置:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)",
"WebFetch(domain:github.com)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Bash(curl *)"
]
}
}
官方评估顺序是固定的:deny → ask → allow,第一个命中的规则决定结果,规则写得多具体都不改变这个顺序。所以宽的 Bash(aws *) deny 会盖过窄的 Bash(aws s3 ls) allow——deny 规则上打不了「例外的洞」。三类规则都没命中时,才落到当前权限模式的默认行为。另有一个内置只读命令集(ls、cat、grep、pwd 及 git 的只读形式等)在任何模式下都免询问。
官方在权限弹窗里选「Yes, don't ask again」,Bash 批准会永久存进仓库根的 .claude/settings.local.json,对该仓库未来会话生效(文件编辑的批准只活到会话结束)。另外,权限规则由 Claude Code 强制执行,不靠模型自觉——CLAUDE.md 里写「不要 git push」只影响 Claude 想不想,不改变能不能,这条边界 D4 还会用到。
沙箱:OS 级的硬边界
官方沙箱是内置在 Claude Code 里的操作系统级隔离:macOS 用系统自带的 Seatbelt,Linux 和 WSL2 用 bubblewrap(需要安装 bubblewrap 和 socat 两个包),原生 Windows 不支持。在会话里运行 /sandbox 打开面板即可启用,选择的模式保存到项目的 .claude/settings.local.json;想全局启用则在 ~/.claude/settings.json 里设 sandbox.enabled: true。
官方沙箱有两层默认边界,由 OS 对 Bash 命令及其所有子进程强制执行:
- 文件系统:默认只能写工作目录和会话临时目录;读取默认几乎全盘可读——注意
~/.ssh、~/.aws/credentials等凭据默认仍读得到,要挡需配sandbox.credentials或denyRead。 - 网络:走沙箱外的代理,默认零预允许域名;命令第一次要连新域名时弹批准,同意后本会话内记住(v2.1.191 起),也可用
allowedDomains预先放行。
官方沙箱自身有两种审批模式:auto-allow(能进沙箱的命令免询问直接跑)和 regular permissions(照常走权限流程),两者隔离边界完全相同,差别只在是否自动批准。即便 auto-allow,deny 规则、内容级 ask 规则(如 Bash(git push *))、指向 / 或 home 的 rm 仍会拦。命令因沙箱限制失败时,Claude 可能带 dangerouslyDisableSandbox 参数在沙箱外重试并走常规权限流程;设 allowUnsandboxedCommands: false 可关掉这个逃生舱。
官方划重点:沙箱只覆盖 Bash 命令及其子进程。Read、Edit、WebFetch 走权限系统,MCP 服务器和 hooks 是宿主机上不受约束的独立进程。要把整个进程都关进边界,官方还提供 sandbox runtime(无需 Docker)、dev container、自建容器、VM,以及 Anthropic 托管 VM 的 Claude Code on the web,隔离强度与搭建成本递增。
权限和沙箱是什么关系
官方两者是互补的两道闸门,拦的东西不同:权限在命令运行前评估,依据是命令字符串(auto mode 下再加一层 classifier 判断);沙箱在命令运行时由操作系统在进程上强制,哪怕被放行的命令「名不副实」,或 Claude 被文件里的恶意内容 prompt injection 带偏,OS 边界依然拦得住。
官方两层配置还会合并:sandbox.filesystem 与 Read/Edit deny 规则合并成最终文件边界,WebFetch 域名规则与 allowedDomains/deniedDomains 合并成网络边界。开沙箱且 autoAllowBashIfSandboxed 保持默认 true 时,沙箱化命令即使有裸 Bash ask 规则也免询问——沙箱边界替代了那次整工具级询问。
安全与效率怎么取舍
本站观点取舍的核心原则只有一句:每放松一层「询问」,就要有另一层「硬边界」顶上。询问是最后的人肉防线,拿掉它之前,先确认 classifier、沙箱或容器至少有一个在场。按场景对照:
- 陌生仓库、敏感操作:Manual 或 plan 模式,逐条过目,慢就是快。
- 日常迭代、事后 review diff:
acceptEdits+ 沙箱 auto-allow。文件编辑和工作目录内的命令都不打断,出圈的操作(新域名、git push、受保护路径)照样询问。 - 长时间无人值守:auto mode(classifier 逐动作兜底),或在容器 / VM 里跑
bypassPermissions——官方明确后者没有任何检查兜底,隔离环境不是建议而是前提。 - CI 流水线:
dontAsk+permissions.allow白名单,永不等待输入,名单之外一律拒绝。
本站观点常见误区:把「开沙箱」当成一种权限模式。它不是——模式决定是否询问,沙箱决定能碰什么,两者独立开关、可任意组合。想系统性减少询问而不牺牲安全,配方见 Tip 《怎么让权限少打断我》。
当天能做完的实操
以下步骤在自己任意一个 git 项目里做,30 分钟内能跑完:
- 认识模式循环:启动
claude,连按Shift+Tab。预期:状态栏在 Manual →accept edits on→plan mode on之间循环;账号满足条件时还会出现auto mode on。 - 查看现有规则:输入
/permissions。预期:看到 Allow / Ask / Deny 三类规则列表,以及每条规则来自哪个 settings 文件。 - 写两条规则:在项目根新建或编辑
.claude/settings.json,放入上文「权限规则」小节的 JSON(可按自己项目替换命令)。预期:重启会话后首次会弹 workspace trust 对话框列出这些 allow 规则,接受后npm run build类命令直接放行,git push --dry-run命中 ask 规则强制弹窗。 - 体验「不再询问」:让 Claude 跑一条无害但不在只读集的命令(如
npm --version),在弹窗里选「Yes, don't ask again」。预期:.claude/settings.local.json里多出一条对应 allow 规则,未来会话直接放行。 - 开沙箱:运行
/sandbox,在 Mode 页选 auto-allow(macOS 开箱即用;Linux/WSL2 若面板只显示 Dependencies 页,先sudo apt-get install bubblewrap socat再重启)。预期:Claude 在工作目录内跑写文件的命令不再弹询问;访问一个从没允许过的域名,会弹出域名批准。 - 整体验证:把下面的 prompt 原样贴给 Claude Code:
帮我验证当前会话的权限配置,依次执行:
1. 运行 ls 和 git status(内置只读命令,应该不询问);
2. 运行 npm run build(如果我配了 allow 规则,应该直接放行);
3. 尝试 git push --dry-run(应该命中 ask 或 deny 规则,被询问或拦下)。
做完后逐条告诉我:每条命令分别走了哪条路径——
内置只读集、allow 规则、ask 规则,还是模式默认询问。
预期:三条命令的授权表现各不相同,Claude 的复盘能和你在 /permissions 里看到的规则一一对上。
验收标准
- 能不看文档说出六种权限模式的名字,以及每种「免询问能跑什么」。
- 能解释 deny → ask → allow 的评估顺序,并说清为什么宽 deny 不能被窄 allow 打洞。
- 能用一句话讲清权限与沙箱的分工:权限在运行前决定能不能跑,沙箱在运行时用 OS 限制能碰什么,且沙箱只覆盖 Bash 及其子进程。
- 实操跑通:
/permissions里能看到自己写的规则;沙箱 auto-allow 下工作目录内命令免询问、新域名会弹批准。 - 自测题:同时存在 allow 规则
Bash(aws s3 ls)和 deny 规则Bash(aws *),Claude 跑aws s3 ls会怎样?(答案:被拒绝——deny 先于 allow 评估,且规则具体程度不改变顺序。)