第 11 章

权限系统

六种模式 + 细粒度规则,安全地把活交给 AI

权限不是束缚,是让你敢放手让 AI 干活的底气

扩展篇到此为止。进入控制篇 —— 权限系统是安全地把 AI 交出去的基础:六种模式 + 细粒度规则,让你敢放手让 AI 干活。

怕它乱来

AI 能改文件、能跑命令——万一改坏或删错怎么办

担心删库

AI 跑 shell 命令时,万一执行了 rm -rf 或 git push --force,损失不可逆。

担心改坏配置

AI 修改 .git、.env、CI 配置这类敏感文件,可能让项目直接挂掉。

自动化时没人盯

在 CI 跑 AI,没人能确认每一步——既想让它自主,又怕失控。

权限系统就是为"既敢放手又不失控"设计的:它给每一次工具调用三选一的裁决——允许、询问、拒绝。配合六种模式和细粒度规则,你能在任何场景精确控制 AI 的行为边界。

三种结果

每次工具调用前,权限系统给出三种裁决之一

Qoder CLI 在每次工具调用前做权限检查,结果只有三种:

结果含义行为
allow允许立即执行工具
ask询问交互式会话弹确认;非交互式转为拒绝
deny拒绝阻止这次工具调用

权限适用于所有工具:文件读写、Bash 命令、Web 抓取、MCP 工具、子代理调用等。

核心理念:不是"AI 能干什么由 AI 决定",而是"由你的权限规则决定"。AI 想做的每个动作,都要先过权限这道闸。

六种模式

用 --permission-mode 选择会话的默认行为

模式适用场景行为
default 常规交互式使用 安全读取自动执行;敏感操作请求确认
accept_edits 日常编码任务 自动批准工作目录内的安全文件编辑
plan 评审、排查、规划 偏规划,写入需批准
auto 不弹确认的自动化 不弹窗,安全操作自动批,风险操作拒
bypass_permissions 仅可信本地实验 跳过大多数批准(仍非无条件放行)
dont_ask 必须不弹窗的 headless 从不询问,需询问的一律拒绝
新手记住三个就够:日常用 default,嫌确认烦用 accept_edits,做 CI 自动化用 auto 或 dont_ask。其余两个进阶再用。

模式怎么选

不同场景下的推荐选择

本地开发(default)

新手默认。读取自动通过,写文件和跑命令要确认。最安全,适合学习阶段和敏感项目。

日常编码(accept_edits)

写代码时最常用。文件编辑不再逐个确认,但危险 shell 命令仍会问。效率与安全的平衡点。

代码审查(plan)

只想让 AI 看和分析,不想它改东西。读取顺畅,写入受控。review 场景首选。

CI 自动化(auto / dont_ask)

无人值守。auto 自动批准安全操作、拒绝风险操作;dont_ask 更严格,需询问的一律拒。第 14 章详解。

关于 bypass_permissions:它等价于 --dangerously-skip-permissions(也叫 --yolo)。只在完全可信的沙盒环境用,且部分安全检查仍会拦截危险操作——它不是无条件放行。

设置默认

不想每次启动都带参数,就持久化配置

用 --permission-mode 只对本次会话生效。想持久默认值,在 settings 里配置:

{
  "general": {
    "defaultPermissionMode": "accept_edits"
  }
}
重要约束:非默认模式(accept_edits/plan/auto 等)只在可信目录中生效。如果当前目录未被信任,Qoder 会回退到 default。bypass_permissions 还可能被安全设置禁用。
settings 建议值:default、accept_edits、plan、auto。需要 bypass 时,通过命令行参数启动而非写进默认配置——避免你忘了自己开着 bypass。

决策顺序

权限判定的优先级,理解它才能写对规则

Qoder 按固定顺序评估权限,早判断的优先:

  1. 先检查 deny 规则——命中直接拒
  2. 在 auto 模式下,必须直接得到 allow 或 deny,不弹窗
  3. ask 规则和工具自身检查,先于宽泛 allow 执行
  4. 安全检查仍可能中断宽泛规则或 bypass 模式
  5. 再应用工具级 allow 规则和模式自动允许
  6. 非交互式会话中,结果仍是 ask 会转为 deny
关键含义:宽泛的 allow 规则不等于所有动作都静默执行。例如危险 shell 命令仍可能要求确认,可疑路径仍可能被阻止——deny 和安全检查永远优先。

配置规则

持久权限规则写在 settings 文件中

规则按 allow、ask、deny 三组组织,写在以下文件:

~/.qoder/settings.json              # 用户级(所有项目)
${project}/.qoder/settings.json     # 项目级(团队共享,提交 Git)
${project}/.qoder/settings.local.json  # 本地级(个人,不提交)
{
  "permissions": {
    "allow": [
      "Read(/src/**)",
      "Edit(/src/**)",
      "Bash(npm run test:*)"
    ],
    "ask": [
      "Bash(npm publish:*)",
      "WebFetch"
    ],
    "deny": [
      "Read(*.pem)",
      "Bash(rm -rf:*)"
    ]
  }
}
三级文件分工:用户级放个人偏好;项目级随 Git 提交供团队共享;本地级(settings.local.json)放个人审批,加进 .gitignore。

规则语法

三种形式,覆盖从粗到细的需求

形式含义示例
ToolName作用于整个工具WebFetch
ToolName(content)作用于特定路径/命令/模式Read(/src/**)
*工具级匹配所有工具*

规范工具名:Read、Edit、Write、Bash、Grep、Glob、WebFetch、WebSearch、Agent,以及 mcp__github__create_issue 这类 MCP 工具名。

括号转义:内容里含括号要转义,否则会被当成规则语法:
"Bash(python -c \"print\\(1\\)\")"
ToolName(*) 会被视为工具级规则,等同于 ToolName。

文件规则

用路径模式精确控制读写范围

读取规则用 Read(...),写入规则用 Edit(...)(覆盖 Edit/Write/NotebookEdit)。某路径的 Edit allow 会隐含允许读取同路径。路径用 gitignore 风格匹配:

模式含义
/src/**相对规则源根目录的路径(项目级相对项目根)
~/Documents/**相对 home 目录
//tmp/data/**从系统根 / 开始的绝对路径(双斜杠)
*.secret不带根的文件名模式,任意位置匹配
"deny": [
  "Read(*.pem)",          // 禁止读密钥
  "Edit(/.git/**)",       // 禁止改 git 内部
  "Edit(//etc/**)"        // 禁止改系统配置
]
受保护路径:.git、.vscode、.idea、.husky、.mcp.json、.bashrc 等会改变执行行为或凭据的路径,默认模式下需明确批准,auto 模式下直接拒绝。

Bash 规则

最需要细控的工具——精确匹配、前缀、通配

规则匹配内容
Bash(npm run build)精确匹配这条命令
Bash(npm run test:*)匹配 npm run test 及以其开头的命令
Bash(git log *)glob 风格通配
"allow": ["Bash(git status)", "Bash(git log:*)", "Bash(npm run test:*)"],
"ask":    ["Bash(npm publish:*)", "Bash(git push:*)"],
"deny":   ["Bash(rm -rf:*)", "Bash(sudo:*)"]
Shell 匹配是保守的:
  • deny 和 ask 穿透 wrapper 和环境变量前缀——Bash(rm -rf:*) 能拦截被包装的破坏性命令
  • 前缀/通配 allow 不会静默批准复合命令,除非每个片段都能独立允许
  • 危险命令(破坏性删除、force push)即使有宽泛 allow 仍可能强制确认;auto 模式下直接拒
别用 Bash 或 Bash(*) 这种宽泛规则——等于把整个 shell 开放,极其危险。

Web 与 MCP

网络访问和外部工具的权限控制

Web 工具

用工具级规则控制。所有 fetch 都确认用 ask,禁网用 deny:

{
  "ask": ["WebFetch"],
  "deny": ["WebSearch"]
}

某些项目或会话要完全断网,deny WebFetch 即可。

MCP 工具

用完整限定名 mcp__<server>__<tool>:

{
  "allow": ["mcp__context7__*"],
  "ask": ["mcp__github__create_issue"]
}

支持 mcp__github__*(某 server 全部)、mcp__*(所有 MCP)。

按需启用 server:某次运行只用指定 MCP server,用 --allowed-mcp-server-names context7,github。或在 server 配置里用 alwaysAllow 自动放行。

覆盖与 CI

命令行一次性覆盖 + 非交互式场景

命令行覆盖(一次性会话):

qodercli --permission-mode accept_edits
qodercli --allowed-tools 'Read,Grep,Bash(git status)'
qodercli --disallowed-tools 'Bash(rm -rf:*),mcp__github__delete_repo'
qodercli --tools 'Read,Grep,Edit'   # 限制本次可用工具

非交互式会话(print mode、CI)的特殊处理:

  • 无法弹确认,任何 ask 都转为 deny
  • 自动化时优先配置精确的 allow 规则,而非依赖模式
  • 需要编辑文件用 accept_edits
  • 要严格 fail-closed 用 dont_ask
  • 可信环境确需宽泛执行才用 bypass_permissions
CI 最佳实践:用项目级 settings 配精确 allow 规则(只允许需要的命令和路径)+ auto 或 dont_ask 模式。这是"既自主又安全"的标准组合,第 14 章会完整演示。

排错指南

权限相关的高频问题

accept_edits 没生效

原因:当前目录未受信任,回退成了 default。修复:先信任该目录;或在可信目录运行。

allow 规则没放行

原因:规则语法错(括号没转义)、路径模式不对、或被 deny/安全检查优先拦截。修复:核对语法;用 /config 看生效规则;deny 优先于 allow,检查是否冲突。

CI 里 AI 啥都做不了

原因:非交互式 ask 转 deny,没配 allow 规则。修复:在项目 settings 加精确 allow;或用 accept_edits/auto 模式。

危险命令还是被拦

这是设计如此,不是 bug。即使 bypass 模式,危险 shell 仍可能被安全检查拦截。如确需执行,在可信环境手动跑。

动手练习

为你的项目搭一套合理的权限配置

练习 1:体验不同模式

  • 分别用 default 和 accept_edits 启动
  • 让 AI 改同一个文件,感受确认次数的差异

练习 2:写项目权限规则

  • 在 .qoder/settings.json 配置:allow 常用测试命令、deny 危险命令
  • 禁止读写 *.pem 和 .env

练习 3:只读会话

  • 用 --permission-mode plan 启动
  • 让 AI 分析项目,观察它无法改文件
  • 体会 plan 模式在 review 中的价值

本章回顾

带走的三个核心认知

三种结果六种模式

allow/ask/deny 三种裁决,default/accept_edits/plan/auto/bypass/dont_ask 六种模式。

规则可细到路径和命令

Read/Edit 按路径,Bash 按命令前缀,MCP 按 server/tool。deny 永远优先。

CI 用精确 allow + auto

非交互式 ask 转 deny,所以自动化要预先配好 allow 规则。

核心结论:权限系统是 Qoder CLI 安全的基石。它让你敢把活交给 AI——因为你知道,AI 能做的事,永远在你画的圈里。

下一章,学习 Quest 模式——在权限保护下,把一个完整需求端到端委派给 AI。

延伸阅读

继续本课程

官方资源