Native OpenCode v2 adapter as a sibling package
Summary
I have a working native v2 adapter for OMO running against opencode2, built as a package sibling to omo-codex / omo-senpi rather than as a compatibility bridge inside omo-opencode. Before investing in splitting it into reviewable PRs, I would like to know whether this shape is one you would accept.
Related: #6169 (v2 migration timeline, open since July, acceptance question unanswered), #7847 (v2 loader rejects the { id, server } shape).
Why a new issue rather than a comment on #6169
#6169 asks for a timeline. This asks a narrower and more actionable question: is an independent sibling adapter package the right shape for v2 support, and would you review one? Two prior attempts (#7104, #7570) took the opposite approach and were both withdrawn by their author within two hours, without review, so there is no precedent to read either way.
Approach: sibling adapter, not a bridge
Both #7104 and #7570 placed v2 support inside packages/omo-opencode/src/plugin/v2/ as a compat facade replaying the v1 init pipeline. #7570's own description lists the resulting cost: todo/boulder continuation degrade to no-ops, compaction hooks have no v2 surface, and the host contract is validated by QA rather than by the compiler.
This adapter instead registers natively against the v2 API and consumes only the Core layer:
- 13 workspace core dependencies (
model-core,prompts-core,rules-engine,team-core,omo-config-core,boulder-state,hashline-core,delegate-core,comment-checker-core,agents-core,shared-skills,utils, plus the plugin/schema pins) - zero dependency on
omo-opencode
That is the dependency direction ROADMAP.md specifies for adapters, so it adds a harness without adding a reverse edge or a second consumer of the v1 pipeline.
Pinned to @opencode-ai/[email protected].
Registered surface today
| Surface | Detail |
|---|---|
| Agents | 11 (4 primaries, sisyphus default) + delegation categories, via agent.transform |
| Tools | 10 base + 19 config-gated, including 12 team_* |
| MCP | 4 built-ins (context7, grep_app, lsp, codegraph) via ctx.mcp.transform; websearch deliberately omitted because v2 ships ctx.websearch natively |
| Skills | 17 shared SKILL.md via skill.transform |
| Hooks | tool guards, comment-checker, rules injection, hashline read+edit pairing, and one ordered session.hook("context") composer |
| Features | Team Mode (mailbox), monitor, BTW side conversations, reactive model fallback, goal/todo/boulder idle continuation |
Gates: bun test → 354 pass / 0 fail across 62 files; tsgo --noEmit clean. Per-increment QA against the real binary is recorded as 38 evidence bundles, asserted from OMO_SPIKE_TRACE NDJSON rather than CLI prose.
Correction to #7847
That issue is currently the most visible statement of what v2 can do, and one of its conclusions is not correct. It states that prompt mutation (chat.message, messages.transform, system.transform) and tool interception (tool.execute.*) "have no v2 equivalents to bind to".
They do:
session.hook("context")exposesevent.system,event.messagesandevent.toolstogether. It is the prompt-rewrite and tool-stripping surface. The adapter uses exactly one of these as an ordered composer: sisyphus prompt rebake, skill catalog, command catalog, rules, then keyword mode last.tool.hook("execute.before" / "execute.after")covers interception.agent.transform,mcp.transform,skill.transformandcatalog.transformare the other high-leverage surfaces the issue's "portable subset" omits.
So the harness is portable to v2 in substance, not only loadable.
Real v2 constraints worth recording
These are genuine and shaped the design:
- The model catalog is empty at setup and populates asynchronously via
catalog.updated. A setup-time snapshot silently drops every agent onto its first fallback. agent.transformcallbacks stay lazy until first registry materialization;agent.reload()forces them.SessionDomainhas nolistand nomessages, so session-history tools cannot be built onctx.sessionand must read the SQLite store read-only.session.hook("model.request")has a readonly model field, so model fallback has to be reactive offsession.execution.failed+switchModel, never proactive.ctx.shellis{ hook("create.before") }and nothing more; the fullShellApihangs off the HTTP client surface, which the pluginContextnever hands out.aisdkhooks only fire for models the native map cannot resolve, so they are not a viable interception point for the major providers.
Questions
- Is an independent sibling adapter package the shape you would accept for v2, or do you want that surface handled differently (or reserved)?
- If yes, would you review it split per milestone — agents+prompts, then tools/orchestration, then hooks/context, then MCP, then features?
- Given LazyCodex and the Senpi edition, is the OpenCode plugin line still one you intend to extend to v2? A plain "not planned" is a genuinely useful answer and would save everyone the PR work.
Happy to sign the CLA if there is interest.
Source: code-yeongyu/oh-my-openagent