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 v2 (2.0.x) hard-breaks the plugin API: plugins must now be defined with Plugin.define({ id, setup(ctx) }) from the new @opencode/plugin package. v1-style function-export plugins built on @opencode-ai/plugin no longer load under v2. This plugin currently targets v1 (recent fixes #3 / PR #4 target 1.18.x), which makes it unusable on opencode 2.x installations (e.g. 2.0.15).
Ships as loose .ts files for config-dir auto-discovery (no @opencode-ai/plugin dependency in package.json)
Port checklist (v2)
Plugin shape: import from @opencode/plugin and wrap in Plugin.define({ id: "opencode-vision", async setup(ctx) { ... } }). v2 still auto-loads .opencode/plugins/*.ts; the config key is now plugins (v1 plugin is gone). The plugin id is required.
tool.definition → removed in v2: use ctx.tool.transform((editor) => editor.update("vision", (t) => { t.description = ... })).
tool.execute.before → ctx.tool.hook("execute.before", (event) => ...): same concept; v2 event is { tool, sessionID, agent, messageID, id, input }; mutate event.input (the native-vision block args go here).
Both experimental.chat.*.transform hooks → ctx.session.hook("context", ...): edit event.system (SystemParts) / event.messages. Fires per model request — the existing "clean injected hints each pass" discipline becomes mandatory. The native-multimodal check moves here (event.model: Model.Ref).
Image part reads: v1 base64 FilePart.url → v2 MediaPart (media.source.data, media.source.mediaType, part.filename). The compaction skip via msg.info.summary needs the v2 equivalent from event/message metadata.
vision custom tool: Zod args → JSON-Schema input; execute(input, context) returns { content }; register via ctx.tool.transform((editor) => editor.add({ name: "vision", ... })). context.signal / context.progress are available for the external VLM call.
Subagent mode: good news — the shipped agents/image-reader.md file is exactly the v2-compatible pattern. v2 plugins cannot define agents in code anymore (AgentEditor has no add), so file-based agents remain the way to go; the installer just needs to keep placing the file where v2 discovers it.
Install script (bin/install.js): update for v2 discovery paths, the plugins config key, and add the @opencode/plugin dependency.
No structural blockers
Every hook used by this plugin maps onto an existing v2 surface (tool.definition via the transform editor, the rest directly) — the port is mostly mechanical.
Why
OpenCode v2 (2.0.x) hard-breaks the plugin API: plugins must now be defined with
Plugin.define({ id, setup(ctx) })from the new@opencode/pluginpackage. v1-style function-export plugins built on@opencode-ai/pluginno longer load under v2. This plugin currently targets v1 (recent fixes #3 / PR #4 target 1.18.x), which makes it unusable on opencode 2.x installations (e.g. 2.0.15).v1 API surface used by this plugin today
plugins/vision-helper.ts: v1 function-export plugin (export default (async () => ({...})) satisfies Plugin) with hookstool.definition,tool.execute.before,experimental.chat.system.transform,experimental.chat.messages.transformtools/vision.ts: v1tool()helper from@opencode-ai/pluginwith Zodtool.schema.*argsBun.file/Bun.write) — PR fix: replace Bun globals with Node fs APIs for OpenCode 1.18 compatibility #4 already proposes replacing them with Nodefs.tsfiles for config-dir auto-discovery (no@opencode-ai/plugindependency in package.json)Port checklist (v2)
@opencode/pluginand wrap inPlugin.define({ id: "opencode-vision", async setup(ctx) { ... } }). v2 still auto-loads.opencode/plugins/*.ts; the config key is nowplugins(v1pluginis gone). The pluginidis required.tool.definition→ removed in v2: usectx.tool.transform((editor) => editor.update("vision", (t) => { t.description = ... })).tool.execute.before→ctx.tool.hook("execute.before", (event) => ...): same concept; v2 event is{ tool, sessionID, agent, messageID, id, input }; mutateevent.input(the native-vision block args go here).experimental.chat.*.transformhooks →ctx.session.hook("context", ...): editevent.system(SystemParts) /event.messages. Fires per model request — the existing "clean injected hints each pass" discipline becomes mandatory. The native-multimodal check moves here (event.model: Model.Ref).FilePart.url→ v2MediaPart(media.source.data,media.source.mediaType,part.filename). The compaction skip viamsg.info.summaryneeds the v2 equivalent from event/message metadata.visioncustom tool: Zodargs→ JSON-Schemainput;execute(input, context)returns{ content }; register viactx.tool.transform((editor) => editor.add({ name: "vision", ... })).context.signal/context.progressare available for the external VLM call.fs(building on PR fix: replace Bun globals with Node fs APIs for OpenCode 1.18 compatibility #4).agents/image-reader.mdfile is exactly the v2-compatible pattern. v2 plugins cannot define agents in code anymore (AgentEditorhas noadd), so file-based agents remain the way to go; the installer just needs to keep placing the file where v2 discovers it.bin/install.js): update for v2 discovery paths, thepluginsconfig key, and add the@opencode/plugindependency.No structural blockers
Every hook used by this plugin maps onto an existing v2 surface (
tool.definitionvia the transform editor, the rest directly) — the port is mostly mechanical.Reference implementations already on v2
Plugin.define,ctx.tool.transform,ctx.tool.hook("execute.before"),ctx.session.hook("context")hindsight-integrations/coding-agents/src/harness/opencode2.tsdocuments the same v1→v2 mappingHappy to help test a v2 port against opencode 2.0.15.