# OpenCode 是什么

> 产品全貌：安装方式、七个内置 Agent 与各自的权限、从 TUI 到 ACP 的多种入口、不写死的模型提供方，以及与另外四本专栏的对照。

- 作者：David（道雾轩）
- 专栏：OpenCode 源码解读（https://daiw.net/manual/opencode.md）
- 最后更新：2026-09-19
- 原文：https://daiw.net/manual/opencode/what-is-opencode
- 转载与引用：请注明出处并附原文链接（https://daiw.net/about/copyright）

OpenCode 的 README 只有一句自我介绍：“The open source AI coding agent.”——开源的 AI 编码 Agent。这一篇先把它当成一个**产品**来看：怎么装、有哪些 Agent、从哪些入口用、模型从哪来。实现细节留给后面各篇。

## 开源与仓库

- 许可证是 MIT（根目录 `LICENSE`，根 `package.json` 的 `license` 字段）。
- 仓库已从 `sst/opencode` 迁到 `anomalyco/opencode`：README 的徽章、Homebrew tap（`anomalyco/tap/opencode`）和根 `package.json` 的 `repository` 字段都指向新地址。默认分支是 `dev`（根 `AGENTS.md`）。
- npm 包名是 `opencode-ai`，命令名是 `opencode`。本专栏基准为 `v1.18.30`。

## 安装

README 列了一长串安装方式，常用的是这几种：

```bash
curl -fsSL https://opencode.ai/install | bash    # 官方安装脚本
npm i -g opencode-ai@latest                      # 或 bun / pnpm / yarn
brew install anomalyco/tap/opencode              # macOS 与 Linux，更新最及时
scoop install opencode                           # Windows
```

另有 choco、pacman / paru、mise、nix 等渠道。安装脚本按 `$OPENCODE_INSTALL_DIR`、`$XDG_BIN_DIR`、`$HOME/bin`、`$HOME/.opencode/bin` 的优先级选安装目录。

npm 装下来的 `opencode` 并不是程序本体。`packages/opencode/bin/opencode` 是一个 Node 小脚本：按操作系统与 CPU 架构拼出包名（形如 `opencode-linux-x64`，x64 还区分是否支持 AVX2 的 `baseline` 版，Linux 还区分 `musl`），在 `node_modules` 里找到对应的预编译二进制，`spawn` 它并转发 `SIGINT`、`SIGTERM`、`SIGHUP`。二进制由 `packages/opencode/script/build.ts` 调用 `Bun.build` 的 `compile` 选项生成——发行版是自带 Bun 运行时的独立可执行文件。

## 内置 Agent

README 说有两个可用 `Tab` 切换的主 Agent（build 与 plan），外加一个 `general` 子代理。`packages/opencode/src/agent/agent.ts` 里实际定义了七个：

| Agent | mode | 用途与权限要点 |
| --- | --- | --- |
| `build` | primary | 默认 Agent，按配置的权限执行工具；额外放开 `question` 与 `plan_enter` |
| `plan` | primary | 计划模式：`edit` 一律 `deny`，只放行 `.opencode/plans/*.md` 与数据目录下的计划文件；禁止调用 `general` 子代理 |
| `general` | subagent | 通用子代理，适合并行执行多个任务；禁用 `todowrite` |
| `explore` | subagent | 只读探索：先 `"*": "deny"`，再放行 `grep`、`glob`、`list`、`bash`、`webfetch`、`websearch`、`read` |
| `compaction`、`title`、`summary` | primary（隐藏） | 分别负责上下文压缩、生成会话标题、生成摘要，工具全部 `deny` |

`Tab` 与 `Shift+Tab` 的绑定在 `packages/tui/src/config/keybind.ts:130`（`agent_cycle` 与 `agent_cycle_reverse`）；子代理可以在消息里用 `@general` 这样的写法点名。

所有 Agent 先共享一套默认规则，再各自叠加（`packages/opencode/src/agent/agent.ts:119`）：

```ts
const defaults = Permission.fromConfig({
  "*": "allow",
  doom_loop: "ask",
  external_directory: {
    "*": "ask",
    ...Object.fromEntries(whitelistedDirs.map((dir) => [dir, "allow"])),
  },
  question: "deny",
  plan_enter: "deny",
  plan_exit: "deny",
  // mirrors github.com/github/gitignore Node.gitignore pattern for .env files
  read: {
    "*": "allow",
    "*.env": "ask",
    "*.env.*": "ask",
    "*.env.example": "allow",
  },
})
```

兜底是 `"*": "allow"`——OpenCode 默认是放开的，危险面靠几处收口：同一工具连续三次以相同参数调用会触发 `doom_loop` 询问；访问工作区之外的目录要问（截断输出目录、临时目录、Skills 目录等白名单除外）；读 `.env` 要问。用户配置里的 `permission` 与 `agent` 字段会在此之上合并（`agent.ts:138`、`agent.ts:267`）：可以改内置 Agent 的模型、提示词、温度与步数上限，`disable: true` 能删掉一个内置 Agent，也能新增自定义 Agent。细节分别见[权限系统](https://daiw.net/manual/opencode/permission)与 [Agent、命令与 Skills](https://daiw.net/manual/opencode/agents-and-commands)。

## 入口一览

`packages/opencode/src/index.ts` 用 yargs 注册了二十多个命令，与“怎么用它”直接相关的是这些：

| 入口 | 形态 |
| --- | --- |
| `opencode [project]` | 默认命令：全屏 TUI，服务端跑在 Worker 线程里 |
| `opencode --mini` | 精简的交互界面（split-footer 直出模式），服务端在进程内 |
| `opencode run [message..]` | 非交互：发一条消息，把结果打到 stdout 后退出；`--format json` 输出原始事件 |
| `opencode serve` | 无界面服务端，端口默认先试 4096 |
| `opencode web` | 启动服务端并打开浏览器里的 Web 界面 |
| `opencode attach <url>` | 用 TUI 连接一个已在运行的服务端 |
| `opencode acp` | 作为 ACP（Agent Client Protocol）服务，经 stdin 与 stdout 接入编辑器 |
| `opencode github install`、`run` | 安装、运行 GitHub agent |
| `opencode pr <number>` | 拉取并检出 GitHub PR 分支，然后启动 opencode |

其余是管理类命令：`mcp`、`providers`、`models`、`agent`、`session`、`export`、`import`、`stats`、`db`、`plugin`、`upgrade`、`uninstall`、`debug`，以及把 OpenAPI 规格打到 stdout 的 `generate`（另有隐藏的 `console`，管账号登录与组织）。

命令行之外还有几种形态，复用同一套服务端 API：

- **Web 界面**：`opencode web` 起的服务端优先返回内嵌的 Web UI 资源，没有内嵌时把页面请求代理到 `https://app.opencode.ai`（`packages/opencode/src/server/shared/ui.ts`）。界面代码在 `packages/app`（SolidJS）。
- **桌面端**：`packages/desktop` 是 Electron 应用，包装 `packages/app`；主进程用 `utilityProcess.fork` 拉起本地服务端 sidecar（`packages/desktop/src/main/server.ts`）。
- **VS Code 扩展**：在仓库根的 `sdks/vscode`。
- **GitHub Action**：仓库根的 `github/action.yml` 先用安装脚本装好 opencode，再执行 `opencode github run`。
- **Slack**：`packages/slack`，基于 `@slack/bolt` 与 SDK。

这些入口的启动差异见[启动链路](https://daiw.net/manual/opencode/startup)，ACP 与 GitHub 见 [ACP、GitHub 与其他入口](https://daiw.net/manual/opencode/frontends)。

## 模型：不写死提供方

CONTRIBUTING 里有一句很能说明取向的话：

> New providers shouldn't require many if ANY code changes, but if you want to add support for a new provider first make a PR to: https://github.com/anomalyco/models.dev

新增一家提供方，原则上不该改 OpenCode 的代码，而是去开放目录 models.dev 提 PR。客户端由 `packages/core/src/models-dev.ts` 取目录：

- 数据源默认是 `https://models.opencode.ai`（可用 `OPENCODE_MODELS_URL` 改），拉取其下的 `api.json`；
- 缓存为全局缓存目录里的 `models.json`，5 分钟内视为新鲜，后台每 60 分钟刷新一次；
- 构建时还把一份目录快照编译进二进制（`OPENCODE_MODELS_DEV` 这个 define）：读不到磁盘缓存就先用快照，两者都没有才联网拉取；`OPENCODE_DISABLE_MODELS_FETCH` 可以关掉联网。

真正发请求默认交给 Vercel AI SDK：`packages/opencode/package.json` 直接依赖 `ai` 与近二十个 `@ai-sdk/*` 包（Anthropic、OpenAI、Google、Bedrock、Azure、Groq、Mistral、xAI 等），外加 OpenRouter、GitLab 等第三方 provider。各家差异由适配层抹平，自研的 `packages/llm` 则作为实验开关后的原生链路，见[提供方目录与 models.dev](https://daiw.net/manual/opencode/provider-catalog)、[提供方适配层](https://daiw.net/manual/opencode/provider-transform)与[模型调用层：AI SDK 与原生双轨](https://daiw.net/manual/opencode/llm-bridge)。

## 和另外四本对照

- 相比[《从 LLM 到 Coding Agent》](https://daiw.net/manual/llm-to-agent)的教学最小实现，OpenCode 多出的是“产品化”的那一圈：权限规则、多入口、提供方适配、会话持久化与事件同步。
- [《Kimi Code 源码解读》](https://daiw.net/manual/kimi-code)同为 TypeScript 生产实现，也经历了两代引擎（`agent-core` 与 `agent-core-v2`），而且已经走完换代、删掉了 v1，正好对照两个团队怎么做迁移。
- [《MiMo Code 源码解读》](https://daiw.net/manual/mimo-code)拆的是小米从 OpenCode v1.14.19 分叉出来的 MiMo Code：底座相同，另加了检查点、分层记忆、Actor 子智能体与 Workflow 编排，正好看一个团队怎样在 OpenCode 之上做二次开发。
- [《Grok Build 源码解读》](https://daiw.net/manual/grok-build)是 Rust 实现，适合对照同一类问题在另一种语言生态里的解法。

下一篇：[Monorepo 全景](https://daiw.net/manual/opencode/monorepo-map)——36 个 workspace 包各管什么，依赖怎么流，V1 与 V2 各住在哪里。
