The official guide: Migrate V1 plugins. There is no automatic conversion. Summary of the mechanical steps:
@opencode/plugin instead of @opencode-ai/plugin.export default Plugin.define({ id: "my.plugin", async setup(ctx) { ... } }); the id is required.directory/project from ctx.location, options from ctx.options, and use domain methods instead of client.setup (table below); the callback gets one mutable event.plugin to plugins; ["pkg", {opts}] becomes { "package": "pkg", "options": {opts} }.| V1 | V2 (closest equivalent) |
|---|---|
event | ctx.event.subscribe() |
dispose | cleanup function returned by setup |
config | transforms on the affected domains |
tool | ctx.tool.transform(...) |
auth | ctx.integration.transform(...) |
provider | ctx.provider.transform(...) and ctx.model.transform(...) |
chat.message | ctx.session.hook("prompt", ...) |
chat.params | ctx.session.hook("context", ...) |
chat.headers | ctx.session.hook("model.request", ...) or "http.request" |
permission.ask | ctx.permission.hook("evaluate", ...) |
command.execute.before | ctx.command.transform(...) or the prompt hook |
tool.execute.before | ctx.tool.hook("execute.before", ...) |
tool.execute.after | ctx.tool.hook("execute.after", ...) |
shell.env | ctx.shell.hook("create.before", ...) |
tool.definition | ctx.tool.transform(...) |
experimental.chat.system.transform | ctx.session.hook("context", ...), edit event.system |
experimental.chat.messages.transform | ctx.session.hook("context", ...), edit event.messages |
experimental.session.compacting | ctx.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).