You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
OpenCode 2.x introduced a new plugin API. The OpenCode adapter installed by engram setup opencode targets the 1.x plugin API, so on OpenCode 2.x it fails to load at startup and every plugin feature is silently inactive:
level=WARN message="failed to load plugin" target=~/.config/opencode/plugins/engram.ts
cause="PluginModule.LoadError: Plugin must export a default definition with an id and an effect or setup function.
(cause: SchemaError(Missing key at [\"default\"]))"
OpenCode's migration guide is explicit: "V1 plugin implementations do not run in V2." A V2 plugin must export default Plugin.define({ id, setup }) (from @opencode/plugin) instead of exporting an async function from @opencode-ai/plugin. The current adapter does export const Engram: Plugin = async (ctx) => ({ event, "chat.message", "tool.execute.after", "experimental.chat.system.transform", "experimental.session.compacting" }), so the V2 loader finds no default export and rejects the module.
Impact on OpenCode 2.x: no Memory Protocol injection, no prompt capture, no session registration/tracking, no save nudges, no compaction context, no passive capture. The MCP server still connects (engram mcp), so manual memory tools keep working — which is why the regression is quiet.
Reproduced on opencode 2.0.4 (stable channel) / engram 1.20.0, at every server start and for every project location.
💡 Proposed Solution
Add a V2 adapter and a dedicated setup command, leaving the 1.x path untouched:
New adapter at plugin/opencode-v2/engram.ts, embedded through internal/setup/plugins/opencode-v2/ (same go:embed pattern as the current one).
New agent entry: engram setup opencode-v2, installed to the same destination ~/.config/opencode/plugins/engram.ts — OpenCode auto-discovers that path in both 1.x and 2.x. MCP registration needs a V2-aware injector: V2 config uses mcp.servers.<name> with disabled: false, while the current injectOpenCodeMCP() writes the 1.x shape (mcp.<name> with enabled: true).
engram setup opencode stays as-is for 1.x. Nice-to-have: each command detects the installed OpenCode version (opencode --version) and hints at the other command when it does not match.
Add @opencode/plugin (matching the target OpenCode release, 2.0.4 today) as the adapter's type dependency.
Behavior parity to preserve: ensureSession(), prompt capture (truncate 2000, <private> stripping), ENGRAM_TOOLS filtering, Memory Protocol appended to the last system entry (single-system-block compatibility), nudge debounce, compaction context, passive capture, ENGRAM_PORT / ENGRAM_BIN / ENGRAM_NUDGE_COOLDOWN_SECS overrides, sub-agent session suppression (#116), and the ENGRAM_BIN absolute-path patch applied by the installer.
📦 Affected Area
CLI (commands, flags)
🔄 Alternatives Considered
One adapter supporting both APIs: OpenCode 1.18.29+ accepts a default export with both setup() (V2) and server() (V1), but the two hook APIs are different domains and do not translate automatically — both implementations would still be needed in one file, and OpenCode < 1.18.29 would stop working. Two files + two commands is clearer and keeps the 1.x path frozen.
Auto-detect inside engram setup opencode: no new command, but it silently changes the installed adapter for everyone; a dedicated command is more explicit and lets the V2 adapter evolve at its own pace.
Do nothing: not viable; OpenCode 2.x is the current stable line and the V1 adapter already fails on every start.
Server log evidence from a fresh 2.0.4 start shows discovery still works (msg="loading plugin" entrypoint=file://<home>/.config/opencode/plugins/engram.ts) and only the module shape is rejected.
🔍 Problem Description
OpenCode 2.x introduced a new plugin API. The OpenCode adapter installed by
engram setup opencodetargets the 1.x plugin API, so on OpenCode 2.x it fails to load at startup and every plugin feature is silently inactive:OpenCode's migration guide is explicit: "V1 plugin implementations do not run in V2." A V2 plugin must
export default Plugin.define({ id, setup })(from@opencode/plugin) instead of exporting an async function from@opencode-ai/plugin. The current adapter doesexport const Engram: Plugin = async (ctx) => ({ event, "chat.message", "tool.execute.after", "experimental.chat.system.transform", "experimental.session.compacting" }), so the V2 loader finds nodefaultexport and rejects the module.Impact on OpenCode 2.x: no Memory Protocol injection, no prompt capture, no session registration/tracking, no save nudges, no compaction context, no passive capture. The MCP server still connects (
engram mcp), so manual memory tools keep working — which is why the regression is quiet.Reproduced on opencode 2.0.4 (stable channel) / engram 1.20.0, at every server start and for every project location.
💡 Proposed Solution
Add a V2 adapter and a dedicated setup command, leaving the 1.x path untouched:
plugin/opencode-v2/engram.ts, embedded throughinternal/setup/plugins/opencode-v2/(samego:embedpattern as the current one).engram setup opencode-v2, installed to the same destination~/.config/opencode/plugins/engram.ts— OpenCode auto-discovers that path in both 1.x and 2.x. MCP registration needs a V2-aware injector: V2 config usesmcp.servers.<name>withdisabled: false, while the currentinjectOpenCodeMCP()writes the 1.x shape (mcp.<name>withenabled: true).engram setup opencodestays as-is for 1.x. Nice-to-have: each command detects the installed OpenCode version (opencode --version) and hints at the other command when it does not match.export const Engram: Plugin = async (ctx) => ...export default Plugin.define({ id: "engram", async setup(ctx) { ... } })eventctx.event.subscribe()(cleanup via AbortController)chat.messagectx.session.hook("prompt", ...)— text comes fromevent.prompt.texttool.execute.afterctx.tool.hook("execute.after", ...)experimental.chat.system.transformctx.session.hook("context", ...)— append toevent.systemexperimental.session.compactingctx.session.hook("compaction", ...)— exact injection point to validatectx.directoryctx.location.directoryBun.spawn,Bun.spawnSync,Bun.file,Bun.which) — usenode:child_process/node:fsinstead. See Plugin assumes a Bun runtime, but opencode's plugin host has no Bun global (plugin is silently inert) #1218: OpenCode's plugin host has noBunglobal, so a Bun-based adapter would load but stay inert.@opencode/plugin(matching the target OpenCode release,2.0.4today) as the adapter's type dependency.Behavior parity to preserve:
ensureSession(), prompt capture (truncate 2000,<private>stripping), ENGRAM_TOOLS filtering, Memory Protocol appended to the last system entry (single-system-block compatibility), nudge debounce, compaction context, passive capture,ENGRAM_PORT/ENGRAM_BIN/ENGRAM_NUDGE_COOLDOWN_SECSoverrides, sub-agent session suppression (#116), and theENGRAM_BINabsolute-path patch applied by the installer.📦 Affected Area
CLI (commands, flags)
🔄 Alternatives Considered
setup()(V2) andserver()(V1), but the two hook APIs are different domains and do not translate automatically — both implementations would still be needed in one file, and OpenCode < 1.18.29 would stop working. Two files + two commands is clearer and keeps the 1.x path frozen.engram setup opencode: no new command, but it silently changes the installed adapter for everyone; a dedicated command is more explicit and lets the V2 adapter evolve at its own pace.📎 Additional Context
msg="loading plugin" entrypoint=file://<home>/.config/opencode/plugins/engram.ts) and only the module shape is rejected.Bunglobal).opencode-v2setup entry once this issue is approved.