# Monorepo 全景

> 36 个 workspace 包的职责与规模、schema → protocol → server 的依赖方向、V1 与 V2 各住在哪些包，以及撑起这一切的关键外部依赖。

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

## 工作区

根 `package.json` 声明 `packageManager` 为 `bun@1.3.14`，工作区是 `packages/*`、`packages/console/*`、`packages/stats/*`、`packages/sdk/js` 与 `packages/slack`，合计 36 个包。版本统一钉在 `workspaces.catalog` 里，各包用 `catalog:` 引用；`patchedDependencies` 还给 `effect`、`solid-js` 和一批 `@ai-sdk/*` 打了补丁（见根目录 `patches/`）。类型检查走 `bun turbo typecheck`，根目录的 `test` 脚本直接 `exit 1`——测试只能进各包目录跑。

## 规模

按各包 `src/` 下的 TS/TSX 统计（不含测试与 `.d.ts`），与 agent 直接相关的包如下：

| 包 | 行数 | 职责 |
| --- | --- | --- |
| `packages/opencode` | 81180 | 命令 `opencode`：CLI、现役 HTTP 服务端、V1 会话主循环、工具、提供方、配置、插件宿主 |
| `packages/core` | 32970 | Effect 化的新内核：V2 会话、事件、数据库与迁移、LayerNode、models.dev；V1 契约的 facade |
| `packages/tui` | 27035 | 终端界面：OpenTUI + SolidJS，领域数据只经 SDK 获取 |
| `packages/llm` | 9533 | Schema 优先的模型协议层 |
| `packages/codemode` | 6878 | Code Mode：受限的代码执行，只能经 schema 描述的工具与外界交互 |
| `packages/client` | 4643 | 由 HttpApi 生成的新客户端（Promise 与 Effect 两个入口） |
| `packages/schema` | 3387 | 浏览器安全的 wire 与存储契约 |
| `packages/effect-drizzle-sqlite` | 3238 | Effect 与 Drizzle 的 SQLite 适配 |
| `packages/server` | 1682 | 新 HttpApi 的具体实现：handlers、中间件、鉴权 |
| `packages/plugin` | 1612 | 插件 API `@opencode-ai/plugin` |
| `packages/protocol` | 1582 | `/api/...` 端点契约 |
| `packages/cli` | 670 | 新 CLI，可执行文件名 `lildax` |
| `packages/sdk/js` | 30090 | 旧 JS SDK，主体是生成代码 |
| `packages/sdk-next` | 68 | 组合 Client、Core、Server 的新 SDK |

其余是产品外围：`packages/app`（Web 界面，SolidJS，约 13.9 万行）、`ui` 与 `session-ui`（共享组件）、`desktop`（Electron）、`web`（Astro Starlight 官网与文档）、`console/*`（opencode.ai 控制台）、`stats/*`、`enterprise`、`function`、`slack`、`storybook`，以及测试基础设施 `http-recorder`（录制与回放 HTTP 流量）和客户端代码生成器 `httpapi-codegen`。

## 依赖方向

根 `AGENTS.md` 把方向写成了规则：

> Keep runtime dependencies directed from Schema to Core and Protocol, then from Core and Protocol to Server. Client runtime code may depend on Schema and Protocol but never Core or Server; `sdk-next` composes Client, Core, and Server.

照各包 `package.json` 的运行时依赖画出来（只画 agent 相关的包）：

```mermaid
flowchart TB
    schema["schema<br/>契约"]
    llm["llm<br/>模型协议层"]
    protocol["protocol<br/>/api 端点契约"]
    core["core<br/>Effect 内核"]
    server["server<br/>HttpApi 实现"]
    client["client<br/>生成的客户端"]
    sdknext["sdk-next"]
    sdk["sdk/js<br/>旧 SDK"]
    plugin["plugin"]
    tui["tui"]
    opencode["opencode<br/>CLI 与现役服务端"]
    cli["cli<br/>lildax"]

    llm --> schema
    protocol --> schema
    core --> schema
    core --> llm
    core --> plugin
    server --> core
    server --> protocol
    client --> schema
    client --> protocol
    sdknext --> client
    sdknext --> core
    sdknext --> server
    plugin --> sdk
    tui --> sdk
    tui --> plugin
    tui -.少量基础设施.-> core
    opencode --> server
    opencode --> tui
    opencode --> llm
    opencode --> protocol
    opencode -.devDependencies.-> core
    cli --> server
    cli --> tui
    cli --> core
```

三处值得留意：

1. **清单与 import 不完全一致**。`packages/opencode/package.json` 把 core 列在 `devDependencies`，源码却大量 import `@opencode-ai/core/...`。读依赖关系要看 import，不能只看清单。
2. **TUI 与 core 的边界还没收干净**。`specs/tui-package.md` 的目标是 TUI 只以 SDK 为边界、不依赖 core，十个迁移小节都已勾选完成；但 v1.18.30 的 `packages/tui` 仍依赖 core，源码里还有十几处从 core 取 `Global`、`Flag`、`InstallationVersion` 之类基础设施的 import（如 `packages/tui/src/context/sdk.tsx:3`）。领域数据则确实只走 SDK。
3. **两条 SDK 线**。旧的 `packages/sdk/js` 由 `openapi.json` 生成（`./packages/sdk/js/script/build.ts`），TUI、插件、`run` 命令用的都是它；新的 `packages/client` 从 `@opencode-ai/server/api` 这份 HttpApi 定义生成（在 `packages/client` 里跑 `bun run generate`），`sdk-next` 在其上组合。

## V1 与 V2 各住在哪

| | V1（现役） | V2（迁移中） |
| --- | --- | --- |
| 会话主循环 | `packages/opencode/src/session`：`prompt.ts`、`llm.ts`、`processor.ts` | `packages/core/src/session`：`execution`、`runner`、`run-coordinator.ts`、`context-epoch.ts` |
| HTTP 路由 | `packages/opencode/src/server/routes/instance/httpapi`：`/session/...` 等 | `packages/protocol` 定义、`packages/server` 实现：`/api/...` |
| 客户端 | `packages/sdk/js` | `packages/client`、`packages/sdk-next` |
| CLI | `opencode` | `lildax`（守护进程模式） |
| 数据契约 | `packages/schema/src/v1`（`SessionV1`、`PermissionV1` 等） | `packages/schema` 根导出的当前契约 |

两代并不是各跑各的。V1 的持久化已经交给 core：`Session.updatePart` 发布的 `message.part.updated` 是带 `durable` 声明的事件，由 core 的 `SessionProjector` 写进 SQLite 的 `PartTable`（`packages/core/src/session/projector.ts:310`）。现役服务端也已经挂上了 V2：`HttpApiApp.createRoutes` 把旧路由与 `serverRoutes` 合在一起，并提供换上本地执行实现的 `SessionV2` 层（`packages/opencode/src/server/routes/instance/httpapi/server.ts:276`，删减后）：

```ts
return Layer.mergeAll(
  rootApiRoutes,
  eventApiRoutes,
  ptyConnectApiRoutes,
  instanceRoutes,
  serverRoutes,
  docRoute,
  uiRoute,
).pipe(
  // ...
  Layer.provide(
    AppNodeBuilderV1.build(SessionV2.node, [
      [LocationServiceMap.node, locationServiceMapV2],
      [SessionExecution.node, SessionExecutionLocal.node],
    ]),
  ),
  // ...
)
```

`serverRoutes` 就是 `HttpApiBuilder.layer(Api)`，`Api` 来自 `@opencode-ai/server/api`（同文件第 177 行）。一个 `opencode serve` 进程同时提供旧的 `/session/...` 与新的 `/api/...`。V2 内核见 [V2 会话内核](https://daiw.org/manual/opencode/session-v2)。

存储同样收拢到 core：SQLite + Drizzle，表定义分散在 `packages/core/src` 下的 `*.sql.ts` 与 `sql.ts` 里（`packages/core/drizzle.config.ts` 两种文件名都收），迁移在 `packages/core/src/database/migration/`，数据库默认是全局数据目录下的 `opencode.db`，可用 `OPENCODE_DB` 改（`packages/core/src/database/database.ts:44`）。旧的 `packages/opencode/src/storage/db.ts` 已删除，细节见[存储：SQLite 与事件投影](https://daiw.org/manual/opencode/storage)。

## 关键外部依赖

| 依赖 | 版本 | 用在哪 |
| --- | --- | --- |
| `effect`、`@effect/platform-node` | 4.0.0-beta.83 | 全仓的服务组织、Schema、HTTP 服务端（`effect/unstable/httpapi`） |
| `ai` 与 `@ai-sdk/*` | `ai` 6.0.168 | 默认的模型调用链路；opencode 与 core 都直接依赖一批 provider 包 |
| `@opentui/core`、`@opentui/solid`、`@opentui/keymap` | 0.4.5 | TUI 渲染、布局与键位 |
| `solid-js` | 1.9.10 | TUI 与 Web 界面的响应式 |
| `drizzle-orm` | 1.0.0-rc.2 | SQLite 表定义与查询（core 另依赖 `@effect/sql-sqlite-bun`） |
| `tree-sitter-bash`、`tree-sitter-powershell`、`web-tree-sitter` | 0.25.x | Shell 工具解析命令（`packages/opencode/src/tool/shell.ts`） |
| `vscode-jsonrpc` | 8.2.1 | LSP 客户端（`packages/opencode/src/lsp/client.ts`） |
| `@parcel/watcher` | 2.5.1 | 文件监听（`packages/core/src/filesystem/watcher.ts`） |
| `@modelcontextprotocol/sdk` | 1.29.0 | MCP 客户端 |
| `@agentclientprotocol/sdk` | 0.21.0 | `opencode acp` |
| `bonjour-service` | 1.3.0 | mDNS 服务发布（`packages/opencode/src/server/mdns.ts`） |
| `yargs` | 18.0.0 | 旧 CLI 的命令解析 |

一个细节：服务端没有用 Hono 或 Express，而是 Effect 自带的 `effect/unstable/httpapi` 加 `@effect/platform-node` 的 Node HTTP 服务器——路由、校验、OpenAPI 生成都出自同一份 HttpApi 定义。这是后面[HTTP 服务端](https://daiw.org/manual/opencode/server)一篇的主角。

下一篇：[怎么读这份源码](https://daiw.org/manual/opencode/reading-the-source)——Effect 的 Service、Layer 与 LayerNode，实验开关，以及一条推荐的阅读路线。
