Skip to content

5.5 权限管控

💡 一句话总结:通过权限配置控制 AI 能做什么、不能做什么。

📝 课程笔记

本课核心知识点整理:

权限管控学霸笔记

学完你能做什么

  • 理解三种权限模式
  • 配置全局权限
  • 配置细粒度规则
  • 配置 Agent 级权限
  • 理解 Bash 命令如何被匹配
  • 配置外部目录访问权限(external_directory

你现在的困境

  • 担心 AI 执行危险命令
  • 每次写文件都要确认,太麻烦
  • 想限制某些 Agent 的能力
  • AI 访问项目外的文件时总是弹出确认框

什么时候用这一招

  • 当你需要:精细控制 AI 能做什么
  • 而且不想:让 AI 有太大的自由度

权限模式

模式说明
allow允许执行,不询问
ask每次询问用户确认
deny禁止执行

全局权限配置

opencode.json 中使用 permission(注意是单数):

jsonc
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "*": "ask",          // 默认所有操作需确认
    "bash": "allow",     // Bash 命令自动放行
    "edit": "deny"       // 禁止编辑文件
  }
}

一次性设置所有权限:

jsonc
{
  "permission": "allow"  // 所有操作自动放行
}

细粒度规则(对象语法)

可以根据工具输入应用不同的操作:

jsonc
{
  "permission": {
    "bash": {
      "*": "ask",                    // 默认需确认
      "git *": "allow",              // git 命令放行
      "npm *": "allow",              // npm 命令放行
      "rm *": "deny"                 // 禁止 rm 命令
    },
    "edit": {
      "*": "deny",                   // 默认禁止编辑
      "packages/web/src/content/docs/*.mdx": "allow"  // 只允许编辑文档
    }
  }
}

规则优先级:按模式匹配求值,最后匹配的规则生效

常见模式是把通配符 "*" 规则放在前面,更具体的规则放在后面。


通配符

  • * 匹配零个或多个任意字符
  • ? 匹配正好一个字符
  • 其他字符按字面匹配

可用权限列表

支持细粒度规则的权限

这些权限可以使用对象语法配置不同模式的规则:

权限描述匹配内容
read读取文件文件路径
edit所有文件修改(涵盖 edit, write, patch, multiedit文件路径
glob文件通配符搜索glob 模式
grep内容搜索正则表达式模式
list列出目录文件目录路径
bash运行 shell 命令解析后的命令前缀
task启动子代理子代理名称
skill加载技能技能名称
lsp运行 LSP 查询支持细粒度匹配
external_directory访问项目外路径目录路径

仅支持简单语法的权限

这些权限只能设置为 allow/ask/deny,不支持对象语法:

权限描述
todoread读取待办列表
todowrite更新待办列表
webfetch获取 URL 内容(运行时会传递 URL 用于 always 批准)
websearch网页搜索(运行时会传递查询用于 always 批准)
codesearch代码搜索(运行时会传递查询用于 always 批准)
doom_loop相同工具调用重复 3 次时触发

来源opencode/packages/opencode/src/config/config.ts:418-447


默认值

  • 大多数权限默认为 "allow"
  • doom_loopexternal_directory 默认为 "ask"
  • .env 文件默认被拒绝读取:
jsonc
{
  "permission": {
    "read": {
      "*": "allow",
      "*.env": "deny",
      "*.env.*": "deny",
      "*.env.example": "allow"  // 示例文件允许读取
    }
  }
}

来源opencode/packages/opencode/src/agent/agent.ts:46-57


外部目录访问权限(external_directory)

当 AI 尝试访问项目工作目录之外的文件时,会触发 external_directory 权限检查。

触发场景

以下工具在访问项目外路径时会触发此权限:

工具触发条件
read读取项目外的文件
edit编辑项目外的文件
write写入项目外的文件
patch修补项目外的文件
bash命令涉及项目外路径(如 cd ..rm /tmp/file

检测逻辑

OpenCode 使用相对路径判断文件是否在项目内:

typescript
// 来源:opencode/packages/opencode/src/util/filesystem.ts:25-27
export function contains(parent: string, child: string) {
  return !relative(parent, child).startsWith("..")
}

如果相对路径以 .. 开头,说明文件在项目目录之外。

默认行为

jsonc
{
  "permission": {
    "external_directory": "ask"  // 默认值:每次询问用户确认
  }
}

常用配置:允许访问外部文件夹

如果你希望 OpenCode 访问外部文件夹时不需要每次授权,添加以下配置:

jsonc
// opencode.json
{
  "permission": {
    "external_directory": "allow"
  }
}

这是最常用的配置之一,特别适合以下场景:

  • 需要频繁访问 ~/.config/ 等配置目录
  • 项目依赖其他目录的文件
  • 使用 monorepo 但只在子目录启动 OpenCode

细粒度控制(按路径)

external_directory 支持对象语法,可以按路径配置:

jsonc
{
  "permission": {
    "external_directory": {
      "*": "ask",                    // 默认需确认
      "/tmp/*": "allow",             // /tmp 目录允许
      "/home/user/shared/*": "allow", // 共享目录允许
      "/etc/*": "deny"               // 系统配置禁止
    }
  }
}

配置方式汇总

方式配置位置示例
全局配置~/.config/opencode/opencode.json"external_directory": "allow"
项目配置项目根目录/opencode.json"external_directory": "allow"
环境变量OPENCODE_PERMISSIONexport OPENCODE_PERMISSION='{"external_directory": "allow"}'
Agent 级别agent.xxx.permission见下方示例

Agent 级别配置

jsonc
{
  "agent": {
    "file-manager": {
      "description": "文件管理 Agent,可访问外部目录",
      "permission": {
        "external_directory": "allow"
      }
    },
    "safe-agent": {
      "description": "安全 Agent,禁止访问外部目录",
      "permission": {
        "external_directory": "deny"
      }
    }
  }
}

Bash 命令如何被匹配

OpenCode 会将 Bash 命令解析为可读的命令前缀再进行匹配。解析规则基于命令的"arity"(参数数量)。

解析示例

输入命令解析后的匹配模式
git checkout maingit checkout
npm installnpm install
npm run devnpm run dev
docker compose updocker compose up
rm -rf node_modulesrm

常见命令 Arity

命令前缀Arity说明
git2匹配 git <子命令>
npm2匹配 npm <子命令>
npm run3匹配 npm run <脚本名>
docker2匹配 docker <子命令>
docker compose3匹配 docker compose <子命令>
rm1只匹配 rm

来源opencode/packages/opencode/src/permission/arity.ts

实用配置示例

jsonc
{
  "permission": {
    "bash": {
      "*": "ask",
      "git status": "allow",
      "git diff": "allow",
      "git log*": "allow",
      "npm run*": "allow",
      "rm*": "deny"           // 禁止所有删除操作
    }
  }
}

Ask 的行为

当 OpenCode 提示批准时,提供三种选项:

选项行为
once仅批准此次请求
always批准匹配建议模式的未来请求(当前会话)
reject拒绝请求

always 如何工作

选择 always 时,OpenCode 会使用工具建议的安全模式来批准后续请求。

例如,批准 git status --porcelain 时,建议的模式可能是 git status*,这样后续所有 git status 相关命令都会自动放行。

拒绝时的反馈

用户拒绝时,可以选择:

  • 直接拒绝:AI 收到"用户拒绝了此工具调用",会尝试其他方法
  • 附带反馈:可以告诉 AI 为什么拒绝,引导它调整方向

Agent 级权限

可以按代理覆盖权限,代理规则优先于全局配置:

jsonc
{
  "permission": {
    "bash": {
      "*": "ask",
      "git status": "allow"
    }
  },
  "agent": {
    "deploy": {
      "permission": {
        "bash": {
          "*": "ask",
          "git status": "allow",
          "git push": "allow"     // 仅 deploy agent 可以 push
        }
      }
    }
  }
}

Markdown Agent 配置

在 Markdown 代理中配置权限:

markdown
---
description: 只读代码审查
mode: subagent
permission:
  edit: deny
  bash: ask
  webfetch: deny
---

只分析代码并建议更改,不执行任何修改。

注意:Agent 权限会与全局权限合并,Agent 中的规则优先。


废弃配置迁移

自 v1.1.1 起,旧的 tools 配置已被废弃,迁移到 permission

jsonc
// ❌ 旧语法(已废弃,但仍向后兼容)
{
  "tools": {
    "bash": true,
    "edit": false
  }
}

// ✅ 新语法
{
  "permission": {
    "bash": "allow",
    "edit": "deny"
  }
}

旧配置仍然可用,OpenCode 会自动转换为新格式。


踩坑提醒

现象原因解决
权限配置不生效用了 permissions(复数)permission(单数)
命令被意外拦截规则顺序问题最后匹配的规则生效,把 * 放最前面
无法读取 .env默认被拒绝显式添加 allow 规则
todowrite: {...} 报错只支持简单语法改为 todowrite: "allow"
git push 被匹配为 git没有配置完整命令配置 "git push": "allow"
Agent 权限不生效嵌套层级错误确保在 agent.名称.permission
访问外部文件总是弹确认external_directory 默认 ask设置 "external_directory": "allow"
想禁止访问某些外部路径需要细粒度控制使用对象语法按路径配置

本课小结

你学会了:

  1. 三种权限模式(allow/ask/deny)
  2. 使用 permission 配置(单数)
  3. 区分支持对象语法和简单语法的权限
  4. Bash 命令的 Arity 解析机制
  5. always 的模式匹配行为
  6. Agent 级权限覆盖
  7. 外部目录访问权限external_directory)的配置方法

相关资源


下一课预告

下一课我们将学习主题与快捷键定制。