Port an OpenCode plugin from V1 to V2

The official guide: Migrate V1 plugins. There is no automatic conversion. Summary of the mechanical steps:

  1. Depend on @opencode/plugin instead of @opencode-ai/plugin.
  2. Replace the exported function with export default Plugin.define({ id: "my.plugin", async setup(ctx) { ... } }); the id is required.
  3. Read directory/project from ctx.location, options from ctx.options, and use domain methods instead of client.
  4. Register hooks inside setup (table below); the callback gets one mutable event.
  5. In opencode.json rename plugin to plugins; ["pkg", {opts}] becomes { "package": "pkg", "options": {opts} }.

Hook map

V1V2 (closest equivalent)
eventctx.event.subscribe()
disposecleanup function returned by setup
configtransforms on the affected domains
toolctx.tool.transform(...)
authctx.integration.transform(...)
providerctx.provider.transform(...) and ctx.model.transform(...)
chat.messagectx.session.hook("prompt", ...)
chat.paramsctx.session.hook("context", ...)
chat.headersctx.session.hook("model.request", ...) or "http.request"
permission.askctx.permission.hook("evaluate", ...)
command.execute.beforectx.command.transform(...) or the prompt hook
tool.execute.beforectx.tool.hook("execute.before", ...)
tool.execute.afterctx.tool.hook("execute.after", ...)
shell.envctx.shell.hook("create.before", ...)
tool.definitionctx.tool.transform(...)
experimental.chat.system.transformctx.session.hook("context", ...), edit event.system
experimental.chat.messages.transformctx.session.hook("context", ...), edit event.messages
experimental.session.compactingctx.session.hook("compaction", ...)

Using an AI agent? Give it SKILL.md (port-opencode-plugin-v2), also shipped in the opencode-v2-ready package: opencode-v2-ready skill.

To stay compatible with both for a while, export { ...Plugin.define({...}), async server() { return { /* V1 hooks */ } } } (V1 object entrypoints work from OpenCode 1.18.29).