---
title: "管理权限"
description: "理解 OpenCode 的 allow、ask、deny、外部目录和 Agent 级权限边界。"
verifiedAt: "2026-05-09"
---

权限配置是 OpenCode 新手最应该认真理解的一页。它决定模型能不能读文件、改文件、跑命令、访问外部目录、调用工具或加载 Skill。

> [!NOTE]
> **这一篇用 10 分钟换什么**：你会知道 `allow` / `ask` / `deny` 怎么选，为什么不要一开始全开，外部目录怎么收口，以及审查 Agent 为什么应该用权限禁止写入。

## 先给结论：真实项目从 ask 开始

新手的目标不是把所有弹窗关掉，而是让高风险动作必须经过确认，让低风险动作不要打断工作流。

```mermaid
flowchart LR
  Action["Agent 想执行动作"] --> Risk{"动作风险"}
  Risk -->|只读搜索| Allow["allow"]
  Risk -->|写文件 / shell / web| Ask["ask"]
  Risk -->|密钥 / 删除 / 发布 / 外部敏感目录| Deny["deny"]
  Ask --> Explain["看命令和影响范围"]
  Explain --> Approve["一次性批准或拒绝"]

  style Allow fill:#dcfce7,stroke:#22c55e
  style Ask fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
  style Deny fill:#fee2e2,stroke:#ef4444
```

真实项目里不要依赖默认值。OpenCode 默认相对宽松——多数权限默认 `allow`、`doom_loop` 和 `external_directory` 默认 `ask`、`.env` 类文件默认禁读。但项目仍然应该显式写出权限边界。

`.env` 默认规则的精确写法是：

```jsonc
{
  "permission": {
    "read": {
      "*": "allow",
      "*.env": "deny",
      "*.env.*": "deny",
      "*.env.example": "allow"
    }
  }
}
```

这条规则同时覆盖了 `.env`、`.env.production`、`.env.local` 等所有变体，但放行 `.env.example`（公开的示例文件）。

## 三种动作怎么选

| 动作 | 含义 | 适合场景 |
| --- | --- | --- |
| `allow` | 直接执行 | 低风险、高频、你完全理解的只读动作 |
| `ask` | 执行前询问 | 写文件、跑命令、联网、外部工具 |
| `deny` | 直接拒绝 | 密钥、生产、删除、危险外部目录 |

读文件、搜索、查看项目结构，可以先允许。改文件、跑命令、访问网页，先设置为 `ask`。删除文件、访问敏感外部目录、运行危险 shell，一开始应该拒绝或至少询问。

## 完整的 permission key 列表

OpenCode 把权限按工具或安全场景分成下面这些 key。每个 key 可以单独设 `allow` / `ask` / `deny`，部分 key 还支持用对象 + glob/pattern 做更细粒度控制（标 ✅ 的）：

| Key | 控制什么 | 细粒度 | 默认 |
| --- | --- | --- | --- |
| `read` | 读文件（按路径匹配） | ✅ | allow（`.env*` 默认 deny）|
| `edit` | 所有文件修改（覆盖 `edit`/`write`/`apply_patch`） | ✅ | allow |
| `glob` | glob 文件匹配（按 pattern） | ✅ | allow |
| `grep` | 正则内容搜索（按 pattern） | ✅ | allow |
| `list` | 列目录（按路径） | ✅ | allow |
| `bash` | shell 命令（按解析后命令匹配如 `git status --porcelain`） | ✅ | allow |
| `task` | 启动 subagent（按 subagent 名匹配） | ✅ | allow |
| `external_directory` | 工具触碰工作区外路径时触发 | ✅ | **ask** |
| `todowrite` | 维护 todo 列表 | — | allow |
| `webfetch` | 抓取 URL（按 URL 匹配） | — | allow |
| `websearch` | 网页搜索（按 query 匹配） | — | allow |
| `lsp` | LSP 查询（暂不支持细粒度） | — | allow |
| `skill` | 加载 SKILL.md（按 skill 名匹配） | ✅ | allow |
| `question` | agent 中途反问用户 | — | allow |
| `doom_loop` | 同一工具同输入连续 3 次时触发 | — | **ask** |

新手要记住的是这 4 个：`read` / `edit` / `bash` / `external_directory`——它们覆盖 95% 的安全场景。剩下的等遇到具体需求再翻这张表。

## 一个保守起点

项目级权限可以先从这类基线开始：

```jsonc title="opencode.json"
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "read": "allow",
    "grep": "allow",
    "glob": "allow",
    "edit": "ask",
    "bash": {
      "*": "ask",
      "git status*": "allow",
      "git diff*": "allow",
      "rm *": "deny",
      "git push*": "deny"
    },
    "webfetch": "ask",
    "websearch": "ask",
    "skill": "ask",
    "external_directory": "ask"
  }
}
```

这不是唯一正确配置，但体现了原则：只读可以更开放，写入和 shell 要确认，危险动作先拒绝。

> [!IMPORTANT]
> **规则顺序很重要——最后匹配的规则胜出**。所以惯例是把 `"*"` 兜底规则放在**最前面**，把具体规则放在**后面**。如果你把 `"git status*": "allow"` 写在 `"*": "ask"` 之前，`*` 会再次匹配 `git status` 并把它改回 `ask`。`bash` 段里的写法（`*` 在前、具体命令在后）就是这个原因。

> [!WARNING]
> `bash: allow` 不适合作为默认配置。安装依赖、删除文件、发布、数据库操作都可能从 shell 触发。

路径模式支持 `~` 和 `$HOME` 开头展开到 home 目录（`~/projects/*` 等价于 `/Users/<你>/projects/*`）。这是 OpenCode 内部展开的，和 shell 是不是支持 `~` 没关系。

## 文件修改统一看 `edit`

不要只盯着某一个工具名。文件修改能力包括 `edit`、`write`、`apply_patch` 等，应该统一按 `edit` 权限治理。

如果你真的不希望某个 Agent 改文件，不能只在提示词里写“不要修改”。要在权限里写清楚：

```yaml
permission:
  edit: deny
  bash: ask
```

提示词是意图，权限是边界。审查、规划、安全检查这类 Agent，默认应该比 Build Agent 更保守。

## 外部目录要单独批准

OpenCode 默认工作在启动目录内。访问工作区外路径时，会触发 `external_directory`。

不要为了省事允许整个 home 目录。更稳的写法是允许少数可信路径，并单独限制写入：

```jsonc title="opencode.json"
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "external_directory": {
      "~/projects/shared-docs/**": "allow"
    },
    "edit": {
      "~/projects/shared-docs/**": "deny"
    }
  }
}
```

允许读取不代表允许修改。这个区分对团队知识库、公共素材目录和凭据目录尤其重要。

## 审批弹窗怎么判断

OpenCode 的审批弹窗给三个选项：

| 选项 | 行为 | 适合什么时候选 |
| --- | --- | --- |
| **once** | 只批准这一次 | 默认起点；除非你完全理解后果，否则用这个 |
| **always** | 批准所有匹配建议 pattern 的同类请求（**仅当前 OpenCode 会话**有效，重启不保留） | 你已经看清这条规则覆盖什么、且能接受会话内自动放行 |
| **reject** | 拒绝这一次 | 命令看不懂、影响范围不明、不该让 agent 跑 |

`always` 不是永久 allow——它只在本次会话生效，关掉 OpenCode 就失效。如果想永久放行，应该写进 `opencode.json` 的 `permission` 配置。

如果你看不懂命令，不要批准。让 OpenCode 解释：

- 它要做什么。
- 为什么需要这个动作。
- 会影响哪些文件。
- 有没有只读替代方案。
- 不执行会阻塞什么。

如果请求访问外部目录，先问清它为什么不能在当前工作区完成。

### 看到 `doom_loop` 弹窗怎么办

`doom_loop` 是 OpenCode 的反卡死机制：当同一个工具用同样的输入连续调用 3 次时触发。这通常意味着模型卡在循环里、自己也意识不到。看到这个弹窗时**不要默认批准**——先看 agent 在做什么，多半要打断它、换个角度提问，或者切到 Plan mode 让它先列计划再继续。

## 和 Agent 配合

权限可以按 Agent 覆盖。审查 Agent 应该只读；执行 Agent 才允许改文件；联网研究 Agent 可以访问 web，但不一定能 `edit`。

常见分工：

- `review`：`edit: deny`，`bash: ask`。
- `docs`：`edit: ask`，只允许文档目录。
- `security`：`edit: deny`，外部目录和 web 默认 ask。
- `build`：按项目默认权限执行。

这比在提示词里写“不要修改文件”更可靠。

## 新手常见坑

- 为了省弹窗直接全开 `allow`。
- 只限制 `bash`，忘记 `edit` 也能改文件。
- 允许外部目录后忘记限制编辑权限。
- 把宽泛命令当安全命令，例如允许所有 `git *`。
- 只靠 Agent 提示词约束行为，没有配权限。
- 看不懂审批内容却点 always。

## 怎么验收

用这些动作检查权限是否符合预期：

- 让 OpenCode 读一个普通文件，应该不打断。
- 让它改一个文件，应该出现审批或按规则拒绝。
- 让它运行只读命令，应该符合你的 bash 规则。
- 让它访问工作区外路径，应该触发 external directory 规则。
- 让审查 Agent 尝试改文件，应该被拒绝。

## 接下来去哪

<Cards>
  <Card title="工具总览" description="理解 read、grep、edit、bash、apply_patch、web 和 MCP 工具如何受权限治理。" href="/docs/opencode/official/04-tools-mcp/tools" />
  <Card title="安全、分享与团队使用" description="把权限放到密钥、share、provider、MCP 和 CI 的整体边界里看。" href="/docs/opencode/understanding/08-security-share-team" />
  <Card title="配置 Agents" description="为 review、docs、security 等 Agent 设置更窄的权限边界。" href="/docs/opencode/official/02-agents-skills/agents" />
  <Card title="分享会话" description="权限之外，还要单独处理公开分享和会话数据边界。" href="/docs/opencode/official/00-getting-started/share" />
</Cards>

## 官方资料

- Permissions：[https://opencode.ai/docs/permissions](https://opencode.ai/docs/permissions)
- Tools：[https://opencode.ai/docs/tools](https://opencode.ai/docs/tools)
- Agents：[https://opencode.ai/docs/agents](https://opencode.ai/docs/agents)
