权限

更新时间:
复制 MD 格式

了解 Qoder CN CLI 的权限模式、规则配置和工具调用审批流程。

权限模式

权限模式决定了 Qoder CN CLI 如何处理工具调用——每种模式在"自动化程度"和"安全宽松度"两个维度上定位不同。

模式

适用场景

行为

default

常规交互式使用

安全读取和内部动作可自动执行;敏感操作请求确认。

accept_edits

日常编码任务

自动批准工作目录内的安全文件编辑。Shell 命令、外部动作和敏感路径仍走正常检查。

auto

自动化运行、Goal 执行

零弹窗。安全读取和工作区内编辑自动批准;风险动作被拒绝或交给 AI 分类器判断。

bypass_permissions(YOLO)

仅用于可信本地实验

跳过所有批准提示。所有工具调用自动放行。

dont_ask

必须不弹窗的 headless 流程

从不询问。任何原本需要询问的动作都会被拒绝。

Plan 模式

Plan 是独立的工作状态(非权限策略),可与上述任意权限模式共存。通过 /plan 命令进入/退出(toggle)。进入后 Qoder CN CLI 只读探索代码并输出方案,写入受限于计划文件。退出时可选择后续权限模式或直接进入 Goal 执行。

Goal 模式

Goal 是自主执行状态。通过 /goal set <目标> 进入——自动切换到 auto 模式并锁定 Shift+Tab 切换,确保执行过程零打扰。Goal 可与 Plan 共存(先规划再执行)。使用 /goal clear/goal pause 退出。

模式循环切换

在交互式会话中,按 Shift+Tab 在所有权限模式间循环切换。按 Ctrl+Y 可直达 YOLO 模式。

启动参数

使用 --permission-mode 选择当前会话的默认行为:

qoderclicn --permission-mode default
qoderclicn --permission-mode accept_edits
qoderclicn --permission-mode plan           # 兼容旧版本,实际转译为 default + 进入 Plan 工作状态
qoderclicn --permission-mode auto
qoderclicn --permission-mode bypass_permissions
qoderclicn --permission-mode yolo           # 等价于 bypass_permissions
qoderclicn --permission-mode dont_ask

# 快捷方式
qoderclicn --yolo                         # 等价于 --permission-mode bypass_permissions
qoderclicn --dangerously-skip-permissions # 同上

在交互式会话中,还可以通过 Ctrl+Y 快速切换到 YOLO 模式。

支持多种命名格式(大小写不敏感):

标准值 (snake_case)

camelCase

别名

accept_edits

acceptEdits

bypass_permissions

bypassPermissions

yolo, YOLO

dont_ask

dontAsk

示例:

# 以下写法等价
qoderclicn --permission-mode bypass_permissions
qoderclicn --permission-mode bypassPermissions
qoderclicn --permission-mode yolo
qoderclicn --yolo
qoderclicn --dangerously-skip-permissions

非默认模式只会在可信目录中生效。如果当前目录未被信任,Qoder CN CLI 会回退到 default

权限如何决策

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

  • allow:立即执行工具。

  • ask:需要外部确认后才能执行。

  • deny:阻止这次工具调用。

权限适用于文件读取和编辑、Bash 命令、Web 抓取、MCP 工具、Subagent 以及其他内置工具。

决策顺序

Qoder CN CLI 按固定顺序评估权限:

  1. 先检查 deny 规则——命中即拒绝。

  2. 工具自身的安全检查(如危险命令检测、敏感路径检测)。

  3. ask 规则——命中则标记为需要确认。

  4. 工具级 allow 规则和模式带来的自动允许行为。

  5. 如果最终结果仍是 ask,由运行环境决定如何消费。

宽泛 allow 规则并不等于所有动作都会静默执行——安全检查和 ask 规则优先级更高。

不同运行环境下 ask 的消费方式

运行环境

ask 的归宿

说明

TUI(交互式终端)

弹窗确认

用户在终端中选择允许/拒绝。

Headless-p/--prompt

自动拒绝

无人交互,ask 转为 deny

SDK(stdio 协议)

发送 canUseTool 回调给宿主

宿主程序决定 allow/deny。

ACP(IDE 集成)

发送 requestPermission RPC 给 IDE

IDE 弹窗或自动决策。

Headless 模式(-p/--prompt)下,可以搭配权限模式使用:

# Headless + accept_edits:文件编辑自动通过,Bash 被拒绝
qoderclicn -p "refactor the utils module" --permission-mode accept_edits

# Headless + bypass_permissions:全部放行(仅限可信场景)
qoderclicn -p "run the migration" --yolo

# Headless + 精确 allow 规则:只放行特定工具
qoderclicn -p "check status" --allowed-tools 'Read,Bash(git status)'

权限配置

配置来源(8 层优先级)

规则从多个来源合并,按优先级从低到高:

层级

来源

说明

1

userSettings

~/.qoder-cn/settings.json(用户全局)

2

projectSettings

<project>/.qoder/settings.json(项目级,团队共享)

3

localSettings

<project>/.qoder/settings.local.json(本机个人,加入 .gitignore

4

flagSettings

--settings <path> CLI 参数指定的文件

5

cliArg

--allowed-tools / --disallowed-tools 命令行参数

6

command

/allow/deny 会话中命令

7

session

运行时临时规则(弹窗中"本次会话允许")

高优先级来源的规则覆盖低优先级。如果组织策略开启了 allowManagedPermissionRulesOnly,则只使用策略托管的规则。

各来源的配置方式:

  • 层级 1-3(settings 文件):在对应路径的 JSON 文件中写入 permissions.allow / permissions.deny / permissions.ask 数组。settings.local.json 适合存放本机个人审批规则,建议加入 .gitignore

  • 层级 4(flagSettings)qoderclicn --settings ./custom-settings.json,指定额外的 settings 文件路径。该文件格式与标准 settings.json 相同。

  • 层级 5(cliArg):通过 --permission-mode--allowed-tools--disallowed-tools--tools 等命令行参数配置,仅作用于当前会话。

  • 层级 6(command):会话中输入 /allow Bash(npm test)/deny WebFetch,持久化到 settings.local.json

  • 层级 7(session):弹窗中选择"本次会话允许"产生的临时规则,进程退出后失效。

模式配置

设置默认模式——在 settings 中配置 general.defaultPermissionMode

{
  "general": {
    "defaultPermissionMode": "accept_edits"
  }
}

禁用 YOLO 模式——组织管理员可通过以下配置阻止用户进入 bypass_permissions 模式:

{
  "security": {
    "disableYoloMode": true
  }
}

设置后,--yolo--permission-mode bypass_permissions 和 Ctrl+Y 均不可用,Shift+Tab 循环也会跳过该模式。子 agent 声明 bypass 时也会被降级为 acceptEdits。

禁用 Plan 模式——如果不需要 Plan 工作流,可以关闭:

{
  "general": {
    "plan": {
      "enabled": false
    }
  }
}

设置后,/plan 命令不可用,--permission-mode plan 回退为 default,EnterPlanMode/ExitPlanMode 工具不注册。

Auto 模式分类器配置——可以通过自然语言规则引导 AI 分类器的判断倾向:

{
  "autoMode": {
    "allow": [
      "running npm/yarn/pnpm scripts defined in package.json",
      "creating or editing test files"
    ],
    "soft_deny": [
      "deleting files outside the test directory",
      "modifying CI/CD configuration"
    ],
    "environment": [
      "This is a Node.js monorepo with pnpm workspaces",
      "The project uses Vitest for testing"
    ]
  }
}

字段

作用

allow

分类器倾向于自动批准的操作描述

soft_deny

分类器倾向于拒绝的操作描述

environment

提供给分类器的环境上下文信息

这些规则是软引导——注入到分类器 prompt 作为参考,最终决策仍由 AI 分类器做出。出于安全考虑,autoMode 配置只从可信来源(用户全局 settings 和 localSettings)读取,项目 settings 被排除以防止恶意权限提升。

权限规则配置

规则按 allowaskdeny 分组:

{
  "permissions": {
    "allow": [
      "Read(/src/**)",
      "Edit(/src/**)",
      "Bash(npm run test:*)"
    ],
    "ask": [
      "Bash(npm publish:*)",
      "WebFetch"
    ],
    "deny": [
      "Read(*.pem)",
      "Bash(rm -rf:*)"
    ]
  }
}

规则语法

形式

含义

ToolName

作用于整个工具。

ToolName(content)

作用于某个路径、命令、agent 类型,或工具支持的其他特定内容。

*

匹配所有工具。

使用规范工具名:ReadEditWriteBashGrepGlobWebFetchWebSearchAgent,以及 mcp__github__create_issue 这类 MCP 工具名。

如果内容中包含括号,需要转义:

{
  "permissions": {
    "allow": [
      "Bash(python -c \"print\\(1\\)\")"
    ]
  }
}

ToolName(*) 等同于 ToolName(工具级规则)。

命令行覆盖

qoderclicn --allowed-tools 'Read,Grep,Bash(git status)'
qoderclicn --disallowed-tools 'Bash(rm -rf:*),mcp__github__delete_repo'
qoderclicn --tools 'Read,Grep,Edit'

--allowed-tools--disallowed-tools 使用与 settings 相同的规则语法。--tools 限制本次运行可用的内置工具集(未列出的工具会被拒绝)。

信任目录

Qoder CN CLI 将启动时的当前工作目录(CWD)视为主信任目录。在信任目录内:

  • 文件读取默认 allow

  • 文件写入在 accept_editsauto 模式下可自动批准

  • 非默认权限模式(auto、bypass 等)才能生效

如果当前目录不被信任,Qoder CN CLI 会强制回退到 default 模式。

扩展信任范围

通过 --add-dir/add-dir 命令或 permissions.additionalDirectories 增加额外可信工作目录:

qoderclicn --add-dir ../shared
{
  "permissions": {
    "additionalDirectories": ["../shared"]
  }
}

也可以在全局 settings 中配置 permissions.trustDirectories 将常用目录永久信任。

受保护路径

部分路径受到保护,因为编辑它们可能改变执行行为、凭据或工具行为。例如 .git.vscode.idea.husky、大多数 .qoder 配置文件、.bashrc/.zshrc 等 shell 启动文件、Git 配置、.mcp.json.ripgreprc。在常规交互式模式下,这些路径需要明确批准;在 auto 模式下会被拒绝。

文件访问规则

带路径范围的读取规则使用 Read(...)。带路径范围的写入规则使用 Edit(...);它覆盖 EditWriteNotebookEdit 的文件写入检查。某个路径上的 Edit(...) allow 规则也会隐含允许读取同一路径。

文件规则使用 gitignore 风格匹配。

模式

含义

/src/**

基于规则来源根目录的路径。在 project/local settings 中相对于项目根目录;在 user settings 中相对于 home 目录。

~/Documents/**

基于 home 目录的路径。

//tmp/data/**

从系统 / 开始的绝对路径。绝对路径需要使用双斜杠。

*.secret

不带根目录的文件名模式,可在任意位置匹配。

示例:

{
  "permissions": {
    "allow": [
      "Read(/src/**)",
      "Edit(/src/**)",
      "Read(~/Documents/specs/**)"
    ],
    "ask": [
      "Edit(/package.json)",
      "Read(~/Downloads/**)"
    ],
    "deny": [
      "Read(*.pem)",
      "Edit(/.git/**)",
      "Edit(//etc/**)"
    ]
  }
}

Bash 规则

Bash(...) 规则可以匹配精确命令、命令前缀或通配模式。

规则

匹配内容

Bash(npm run build)

精确匹配 npm run build

Bash(npm run test:*)

匹配 npm run test 以及以 npm run test 开头的命令。

Bash(git log *)

使用 glob 风格通配匹配。

Bash(git status)

精确匹配 git status

示例:

{
  "permissions": {
    "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 匹配是保守的:

  • denyask 规则会穿透常见 wrapper 和环境变量前缀,因此 Bash(rm -rf:*) 仍能拦截被包装过的破坏性命令。

  • 前缀和通配 allow 规则不会静默批准复合命令,除非每个顶层命令片段都能独立被允许。

  • 部分可证明只读的 shell 命令,在 deny、ask 和路径检查之后可以被自动允许。

  • 危险命令(如破坏性删除或 force push),即使存在宽泛 allow 规则,也可能强制确认。在 auto 模式下,危险 Shell 命令会被拒绝。

除非你完全信任当前会话,否则避免使用 BashBash(*) 这类宽泛规则。

Web 和 MCP 规则

Web 工具可以用工具级规则控制。若所有 web fetch 都需要确认,用 ask;若某个会话或项目应禁用网络访问,用 deny

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

MCP 工具使用完整限定名:

mcp__<server>__<tool>

支持的 MCP 模式包括:

规则

含义

mcp__github__create_issue

单个 MCP 工具。

mcp__github__*

github MCP server 下的所有工具。

mcp__github

github MCP server 下的所有工具。

mcp__*

所有 MCP 工具。

示例:

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

MCP server 配置也可以通过 alwaysAllow 为该 server 的工具设置自动允许。如果一次运行只想启用指定 MCP server,可以使用 --allowed-mcp-server-names

qoderclicn --allowed-mcp-server-names context7,github

Hook 与权限

Qoder CN CLI 的 钩子系统在权限决策链路中有两个注入点,可以通过自定义脚本影响工具的允许/拒绝行为。

影响权限的 Hook 事件

Hook 事件

触发时机

可产生的权限影响

PreToolUse

工具执行前(权限检查阶段)

可返回 permissionDecision: "allow" | "deny" | "ask" 直接覆盖权限管道结果

PermissionRequest

权限管道产出 ask 后、弹窗前

可返回 decision.behaviorallowdeny,代替用户交互

其他 Hook 事件(PostToolUseSessionStartStop 等)不参与权限决策。

PreToolUse Hook

在工具执行前触发。Hook 脚本可以检查工具名和参数,返回权限决策:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python ./scripts/check-bash-command.py"
          }
        ]
      }
    ]
  }
}

Hook 脚本通过 stdin 接收 JSON 输入(含 tool_nametool_inputsession_id 等),通过 stdout 输出 JSON 结果:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Command blocked by security policy"
  }
}

permissionDecision 可选值:

  • "allow":跳过权限管道,直接批准

  • "deny":跳过权限管道,直接拒绝

  • "ask":继续走正常权限管道(默认行为)

PermissionRequest Hook

在权限管道产出 ask 之后、弹窗/回调之前触发。适合用于自动化审批系统或外部通知(如 Slack/邮件提醒):

{
  "hooks": {
    "PermissionRequest": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node ./scripts/auto-approve-safe-ops.js"
          }
        ]
      }
    ]
  }
}

输出格式:

{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedInput": {},
      "updatedPermissions": []
    }
  }
}

Hook 与权限模式的优先级

Hook 的权限决策优先级高于权限模式——即使在 bypass_permissions 模式下,PreToolUse Hook 返回 deny 仍然会阻止执行。这为组织级安全策略提供了不可绕过的拦截能力。

执行顺序:

  1. Hook PreToolUse → 如果返回 allow/deny,短路

  2. 权限管道(规则 + 模式 + 安全检查)

  3. 如果结果是 ask → Hook PermissionRequest → 如果返回 allow/deny,短路

  4. 最终由运行环境消费 ask(弹窗/deny/回调)