Skip to content

Plugins: v2 definition API exposes no tool/event registration - v1 hook-map plugins fail every load, docs still show the v1 shape #56630

Closed as duplicate

Description

@holyoption79

Summary

OpenCode 2.x rejects v1-style plugin modules (default export = async function returning a hooks object), and the v2 plugin API offers no replacement surface for the two things those plugins existed to do: registering custom tools and subscribing to file/tool/session events. The plugins documentation still shows the v1 shape, so authors hit a schema error at load time with no documented migration path.

What happens

On 2.0.29, a local plugin written against the documented v1 API fails on every startup and reload:

failed to load plugin ... PluginModule.LoadError: Plugin must export a default
definition with an id and an effect or setup function. (cause: SchemaError(Expected
object at ["default"])))

This repeats for the lifetime of the log. At least one published project (ECC / ecc-universal, filed upstream as its own issue) is affected this way today.

Migration gap

  • A definition shim ({ id, setup }) makes the module load, but setup(context) exposes only: agent, aisdk, catalog, command, integration, plugin, reference, skill. There is no way to register a tool (v1 returned tool: { ... }) or to subscribe to tool.execute.*, file.edited, session.*, shell.env, permission.*.
  • https://opencode.ai/docs/plugins still documents "export one or more plugin functions … returns a hooks object" with those event names, and the config docs still list the same shape — docs and runtime disagree.
  • Configured plugin entries also changed behaviour: a file://…mjs entry now logs configured plugin path must be a directory.

Requests

  1. Align the plugins doc with the v2 definition contract — or restore loading of the documented v1 shape if it is still meant to be supported.
  2. Expose tool/event registration from setup(context), or document an explicit migration path for v1 hook maps, so existing plugins can move deliberately instead of failing at load with a schema error.
  3. Document the accepted forms of configured plugin entries (npm name / directory / …).

Environment

  • OpenCode 2.0.29, Windows

Activity

  1. opencode-agent commented on Oct 18, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed write-up! I think this is a duplicate of #48138, which asks for v1 hook-map plugins to keep loading in v2 (or to fail with a clear migration hint instead of a bare schema error).

    One correction that may unblock you now: in 2.0.29 the context passed to setup(ctx) does expose tool and event registration. The Context type includes tool, event, shell, session, permission and more, not only the domains you listed. The v2 "Migrate plugins from V1" guide maps each v1 hook to its v2 replacement, for example:

    V1 V2
    tool: { ... } map ctx.tool.transform((editor) => editor.add(...))
    tool.execute.before / after ctx.tool.hook("execute.before" / "execute.after", ...)
    event (file / session events) ctx.event.subscribe()
    shell.env ctx.shell.hook("create.before", ...)
    permission.ask ctx.permission.hook("evaluate", ...)
    import { Plugin } from "@opencode/plugin"
    
    export default Plugin.define({
      id: "my.plugin",
      async setup(ctx) {
        await ctx.tool.hook("execute.before", (event) => { /* ... */ })
        await ctx.shell.hook("create.before", (event) => { event.env.FOO = "bar" })
      },
    })

    The opencode.ai/docs/plugins page you found documents the v1 API, which is why it shows the hook-map shape.

    Possible duplicates and closely related issues, ordered from most to least likely:

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different, for example if a ctx.tool / ctx.event based plugin still doesn't work for you on 2.0.29.

  2. opencode-agent commented on Oct 19, 2026

    @opencode-agent
    Contributor

    Closing this as a duplicate of #48138, since there's been no reply in the last day saying how this differs.

    The remaining asks are tracked here:

    To port a plugin now: the v2 setup(ctx) context already has tool and event registration. Use ctx.tool.transform(...) and ctx.tool.hook("execute.before" | "execute.after", ...) for tools, ctx.event.subscribe() for events and ctx.shell.hook("create.before", ...) in place of shell.env. The v2 "Migrate plugins from V1" guide maps every v1 hook. If a ctx.tool / ctx.event based plugin still doesn't work for you on 2.x, please open a new issue with the plugin code and the log output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions