From fe506f201dfbea926456cfbf9152aa4606378893 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Sun, 6 Sep 2026 11:08:09 -0400 Subject: [PATCH] docs: explain supporting v1 and v2 plugins --- .../src/docs/content/build/plugins/index.mdx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/www/src/docs/content/build/plugins/index.mdx b/packages/www/src/docs/content/build/plugins/index.mdx index f12c7fe4576..e42ddb684fa 100644 --- a/packages/www/src/docs/content/build/plugins/index.mdx +++ b/packages/www/src/docs/content/build/plugins/index.mdx @@ -1499,3 +1499,39 @@ Use versions compatible with the OpenCode release you target and test the installed package, not only a workspace-linked copy. Because the plugin API is beta, publish compatible plugin updates when V2 entrypoints or contracts change. + +## Support V1 + +A plugin can support V1 and V2 from the same package entrypoint. Default export +one object with a V1 `server()` function and a V2 `setup()` function: + +```ts title="src/index.ts" +import { Plugin } from "@opencode-ai/plugin" + +export default { + ...Plugin.define({ + id: "example", + async setup(ctx) { + await ctx.tool.hook("execute.before", () => { + console.log("A tool is about to run") + }) + }, + }), + async server() { + return { + "tool.execute.before": async () => { + console.log("A tool is about to run") + }, + } + }, +} +``` + +- V1 calls `server()` and uses the returned hooks. +- V2 reads the default export's `id` and `setup()` (or `effect()` for Effect plugins), ignoring `server()`. +- Keep each implementation on its own API; sharing an export does not translate V1 hooks into V2 hooks. +- Spread `Plugin.define(...)` into the exported object so it type-checks the V2 definition separately from `server()`. + +The V1 object form is supported in OpenCode `1.18.29`. Older V1 releases may +expect function exports instead; test the installed package with the oldest V1 +release you intend to support and with V2.