Repository navigation
[Bug] OpenCode V2 integration broken: plugin ships the V1 plugin API and both DB readers target the V1 schema #654
Description
中文摘要(TL;DR)
OpenCode V2 下 Memmy 集成完全失效,存在两个根因:
- 插件仍使用 OpenCode V1 插件 API:
memmy-opencode-plugin.ts模板导入@opencode-ai/plugin并导出 V1 钩子函数;OpenCode V2 已改为{ id, setup(ctx) }定义(@opencode/plugin),官方迁移指南明确 "V1 plugin implementations do not run in V2",因此插件加载直接失败:Cannot find package '@opencode-ai/plugin'。- 两处数据库读取器仍按 V1 表结构:插件捕获路径(
readOpencodeHookSourceTurn)与桌面历史扫描(Memory/src/agent-source/adapters/opencode/db-reader.ts)都要求session/message/part三张表;OpenCode V2 已迁移为session_v2+session_message(消息内容内联在data.content[]),因此扫描器会静默忽略整个 OpenCode V2 数据库。后果:无自动召回注入、无回合捕获、无
memmy_memory_*工具、/memmy-resume失效(记忆服务本身健康)。下方 gist 是已验证的社区 PoC,在 OpenCode V2 + Memory 2.1.4 上完整恢复了上述功能。修复思路:V2 插件模板 + 兼容
session_v2的读取器,可同时修复插件与桌面扫描两条链路。如有需要我可以直接提 PR。
OpenCode V2 integration is broken: plugin ships the V1 plugin API and both DB readers target the V1 schema
Environment
- Memmy desktop 1.2.x with Memory service 2.1.4 (macOS arm64, local mode)
- OpenCode V2 (current stable, client-server architecture)
- Integration installed via the desktop app (
opencodeagent source → plugin + skill + command)
Symptom
OpenCode V2 refuses to load the installed plugin on every start:
Plugin failed: /Users/<user>/.config/opencode/plugins/memmy-memory.js
Run /plugins to view details.
Server log (~/.local/share/opencode/log/opencode.log):
level=WARN message="failed to load plugin" target=.../plugins/memmy-memory.js
cause="Cause([Die(ResolveMessage: Cannot find package '@opencode-ai/plugin'
imported from /Users/<user>/.config/opencode/plugins/memmy-memory.js)])"
Consequences: no automatic recall injection, no turn capture, no memmy_memory_* tools, and /memmy-resume does nothing. The memory service itself is healthy (/api/v1/health → ok).
Root cause 1 — the plugin template uses the OpenCode V1 plugin API
Memory/src/agent-source/integration/templates/memmy-opencode-plugin.ts (and the copy under App/backend/src/adapters/outbound/skill-writer/templates/) renders a plugin that:
- imports
{ tool } from "@opencode-ai/plugin"(the V1 SDK package), and - exports a V1-style async function returning the V1 hooks map (
chat.message,tool.execute.before,tool.execute.after,experimental.text.complete,event,dispose).
OpenCode V2 intentionally broke the plugin API. From the official V1→V2 migration guide (https://opencode.ai/v2/docs/build/plugins/migrate-v1):
V1 plugin implementations do not run in V2. Moving a file or renaming its config entry is not enough.
A V2 plugin must default-export a definition (id + setup(ctx)) built on @opencode/plugin, register tools through ctx.tool.transform, use ctx.session.hook("prompt", ...), and subscribe to events via ctx.event.subscribe(). Installing the old @opencode-ai/plugin package does not fix anything because the entrypoint shape itself is no longer invoked.
Root cause 2 — both OpenCode DB readers target the V1 schema, V2 renamed the tables
OpenCode V2 also migrated its SQLite database. V1 tables session, message, part are gone; V2 stores:
session_v2(same useful columns:id,parent_id,directory,agent,revert, plusproject_id,time_*)session_message(id,session_id,type=user|assistant|system|synthetic|idle|model-switched,seq,data) with message parts inline indata.content[]({type:"text"|"tool"|"reasoning", ...}; tool state carries{status, input, output})
Two code paths require the old tables:
- Plugin capture path —
readOpencodeHookSourceTurnin the bridge preparesSELECT ... FROM session/message/part, so everysession.idlecapture fails with "no such table". - Desktop historical scan —
Memory/src/agent-source/adapters/opencode/db-reader.ts:
function createSource(db) {
if (!hasTable(db, "session") || !hasTable(db, "message") || !hasTable(db, "part")) return null;so the scanner silently ignores an OpenCode V2 database entirely — no episodes, no L1, nothing from OpenCode.
Verified working proof of concept
To confirm the service side is fine and only the integration layer is stale, I wrote a community V2 port that:
- keeps
memmy-workspace-bridge.mjsunchanged (runtime session,startRuntimeTurn,completeSourceTurn, L3), - registers
memmy_memory_search/get/addviactx.tool.transform, - injects the recall packet through
ctx.session.hook("prompt", ...)(persisted text is later unwrapped via the existing<current_user_request>convention, sounwrapUserRequestsemantics are preserved), - captures turns on
session.idle+ a flush-on-next-prompt fallback, using asession_v2/session_messagereader that maps V2 rows onto the sameSourceTurnpayload (turnId= usersession_message.id, which matches the prompt-admissionmessageIDexactly; tool calls/results recovered from inlinecontent[].state; compaction and revert handling ported), - ports the
/memmy-resumeflow unchanged.
Results on OpenCode V2 + Memory 2.1.4: recall injection works on every prompt, turns are captured with correct identity, queries are stored unwrapped, tool calls are paired, and episodes appear in the viewer. Capture works for parallel sessions too.
The port is published here: https://gist.github.com/kristhianmanue1/f2048c3b578ce14c2839327b87c492e8 (memmy-opencode-v2-plugin.js, MIT, derived from the official template). It is a stopgap: an official V2 template + a V2-aware db-reader would fix both the plugin and the desktop scan.
Suggested fix
- Ship a V2 plugin template (default-exported
{id, setup}on@opencode/plugin) alongside the V1 one, choosing per detected OpenCode version, or a single dual-entry file (setup()for V2 +server()for V1, supported since OpenCode 1.18.29 per the migration guide). - Extend
AgentSourceCore'sOpencodeSourceimplementation with asession_v2/session_messagereader (fallback when the V1 tables are absent). Useful mapping notes: user text lives atdata.text(norolefield; the rowtypeis the role), assistantparentIDno longer exists so turns must be grouped byseqorder (user row → following assistant rows), assistant completion isdata.time.completed, andsession_v2.revertkeeps the same{messageID}JSON shape.
Happy to turn the attached port into a PR against either the template or AgentSourceCore if maintainers prefer.
— Kris Nóva
Activity
kristhianmanue1 commentedon Oct 27, 2026
Resolved by v1.2.4 (2026-10-22) — verified live on v1.2.401. Closing with a point-by-point mapping:
@opencode-ai/plugin,chat.messagehooks)export default { id, server, setup }:setup(ctx)is the V2 entrypoint with feature-detected context APIs; V1 hosts keepserver(). The SDK import is gone entirely — the schema helper is bundled in the bridge (opencodeTool), so neither host generation needs the other package. Regenerated plugin identifies itself as revisionopencode-v2-3.session/messagetables)AgentSourceCore/src/opencode-database-source.ts, which handles thesession_v2/session_messageschema; the workspace-bridge runtime was updated accordingly, with a dedicated test atMemory/tests/service/session/source-turn-opencode-v2.test.ts.session.compactednever fires on OpenCode V2 (live tally on 2.0.29–2.0.30)session.compaction.endedto the internalsession.compactedhook, and the regenerated plugin shipsreadOpencodeCompactionBoundaryfor boundary reads.Local verification: upgraded 1.2.2 → 1.2.401 (darwin-arm64, checksummed DMG). The installer regenerated the OpenCode plugin automatically, the memory service came up as 2.1.7 (schema 9 preserved), and recall/capture work end-to-end on OpenCode v2.0.30.
TL;DR(中文):v1.2.4 起官方已原生支持 OpenCode V2 插件 API 与 session_v2 数据库架构(含 compaction 事件映射),已在 v1.2.401 上实测通过,本 issue 关闭。