Files
hub/docs/decisions/ADR-015-dev-spoke-not-opencode.md
glm-5.1 2d7f9c11cb Resolve 22 open questions via 4 ADRs; add dev spoke questions (OQ-61, OQ-62)
ADR-014 (Docker-first deployment): resolves OQ-21, OQ-22, OQ-23,
OQ-34, OQ-35, OQ-36, OQ-37. Docker is the primary deployment model.
Redis/Postgres in same network. Config via mounted volumes. Single-
container restart for v1. Migrations block startup.

ADR-015 (Dev spoke, not opencode): resolves OQ-16, OQ-17, OQ-26,
OQ-28, OQ-51, OQ-55. Replaces opencode integration with a compiled
dev spoke binary. Hub owns session format. Opencode compat is an
import tool, not an architectural constraint. Adds OQ-61 (dev spoke
operations) and OQ-62 (dev spoke distribution).

ADR-016 (Hub-own schema): resolves OQ-18, OQ-19. Hub defines its own
canonical message/part format. JSONB is implicitly versioned. Flat
parts for v1. Compaction is a hub concern (pruning), not opencode's.

ADR-017 (Hub-first roles): resolves OQ-26, OQ-28, OQ-51 (overlapping
with ADR-015). Hub is database-first for roles. Seeded by migrations.
No file sync needed. hub.createRole for custom roles.

Also narrowed: OQ-04 (service accounts), OQ-05 (git SSO out of scope),
OQ-08 (spoke-side concern), OQ-09 (v1: reconnect only), OQ-11 (dev
spoke replaces container spoke), OQ-29 (hub-only concern), OQ-41
(gitea ops are optional spoke concern).

Deferred: OQ-52 (memory), OQ-55 (anthropic import).

Net result: 15 resolved, 7 narrowed, 2 deferred out of 62 total.
39 remain open, down from 60 in the original tracker.
2026-05-26 05:40:54 +00:00

87 lines
5.9 KiB
Markdown

# ADR-015: Dev spoke instead of opencode integration
- **Status**: Accepted
- **Date**: 2026-05-26
- **Deciders**: alkdev
## Context
The original hub architecture included tight integration with opencode (an external tool) for several capabilities:
- Agent sessions were modeled on opencode's session/message format
- Coordination operations called `opencode.sessionCreate`, `opencode.sessionPromptAsync`, etc.
- Agent roles were defined in `.opencode/agents/*.md` files
- The `ai-sdk-provider-opencode-sdk` package wrapped opencode as an AI SDK model
- Opencode's SQLite database was the reference format for message storage
This created a two-left-hand problem: the hub's architecture was shaped by opencode's data model and conventions, but the hub is a generalized platform that other users won't run opencode on. The integration surface was large (sessions, messages, roles, tools, git operations) and the conceptual overhead was significant (understanding opencode's model to understand the hub).
Meanwhile, the hub already has the spoke model for extending capabilities. A "dev env spoke" that exposes bash, file operations, git, and other development tools would provide the same functionality as opencode's tool suite, but connected to the hub via the standard call protocol over WebSocket — just like any other spoke.
## Decision
Replace the opencode integration with a purpose-built **dev spoke**. The dev spoke is a compiled Deno binary that connects to the hub via WebSocket and exposes development operations (bash, file ops, git, web search) as hub operations. This sits alongside the existing spoke types (client spoke, GPU compute spoke) as just another spoke.
The hub owns sessions, messages, and roles in its own format. Opencode is no longer a core dependency or a shaping force on the hub's architecture. If opencode compatibility is needed in the future, it comes through an **opencode-spoke** — an optional spoke that wraps an opencode instance and exposes its operations through the standard call protocol, just like any other spoke.
### What changes
- **Session model**: Hub defines its own canonical message/part format (based on AI SDK `UIMessage` + parts), not opencode's format. The hub's format stays close to opencode's for import compatibility, but this is a compat concern, not an architectural constraint.
- **Agent roles**: Hub defines roles in the database (see ADR-017). No `.opencode/agents/*.md` file import is needed. The hub is database-first from day one.
- **Coordination operations**: `coord.spawn`, `coord.message`, etc. no longer call `opencode.*` operations. They call hub operations that create sessions, send messages, and manage worktrees — implemented by the dev spoke or hub-native logic.
- **Dev tools**: bash, file operations, git commands come from the dev spoke, not from opencode. The dev spoke is a small, focused binary that does one thing well.
- **Session hosting**: Agent sessions run via the AI SDK directly in the hub (for architect, decomposer, etc.) or via the dev spoke (for implementation specialist). No opencode container required.
### What doesn't change
- The call protocol, call graph, and operation graph are unchanged
- WebSocket spoke transport is unchanged (dev spoke is just another spoke)
- Session/message storage in Postgres is unchanged (just simpler without opencode import compat shaping the schema)
- Auth model, config system, startup sequence — all unchanged
- `hub.list`/`hub.search`/`hub.schema`/`hub.call` — unchanged
- The hub never "spoke opencode" — it spoke the call protocol
### Future: opencode-spoke
An optional opencode-spoke can be built later that:
- Connects to the hub via WebSocket (standard spoke protocol)
- Wraps an opencode instance
- Exposes opencode's operations through FromOpenAPI (opencode's REST spec → typed operations)
- Imports opencode's SQLite session data into the hub's Postgres
This is a spoke-level concern, not a hub architecture concern.
## Consequences
**Positive**: The hub is self-contained and doesn't depend on opencode's data model, conventions, or implementation. The dev spoke is a bounded, implementable component. The hub's session format, role model, and coordination operations are designed for the hub's needs, not adapted from another project. Opencode users can still integrate via an optional spoke.
**Negative**: The dev spoke needs to be built. It replaces the "install opencode and connect it" model with "download a binary and connect it." The dev spoke needs its own implementation of bash, file ops, git, and web search — these are well-understood operations but still need implementation. The `ai-sdk-provider-opencode-sdk` package is no longer a dependency.
### Open questions resolved by this decision
| OQ | Resolution |
|----|-----------|
| OQ-16 | Hub defines its own canonical message/part format. Opencode's format is an import concern, not an architectural constraint. The format stays close for compat but the hub owns it. |
| OQ-17 | Compaction is a hub concern (pruning/summarization for long sessions), not an opencode "compaction agent" concern. For v1, full message history is served. |
| OQ-26 | No `roles.sync` from `.opencode/agents/*.md` needed. Hub is database-first for roles (see ADR-017). |
| OQ-28 | No `Agent.generate()` support needed. The hub creates sessions with DB-defined roles. |
| OQ-29 | Per-session role switching is a hub-only concern. No opencode agent model to reconcile. |
| OQ-51 | No file→DB role migration needed. Hub is database-first from day one. |
| OQ-55 | Anthropic conversation import is deferred. Not shipped with the codebase. |
### Open questions narrowed by this decision
| OQ | Narrowing |
|----|-----------|
| OQ-11 | Container spoke is now "dev spoke" — a compiled binary, not an opencode container. Simpler scope, no opencode integration needed. |
### New open questions
| ID | Question |
|----|----------|
| OQ-61 | What operations does the dev spoke expose? |
| OQ-62 | How is the dev spoke distributed and configured? |