Skip to content

[FEATURE]: backward compatibility for v1 plugins in v2 #48138

Open

Description

@f15u

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

Problem

v2 rejects plugins written for the old API. The loader decodes each module
against a schema that requires export default { id, setup | effect }
(packages/core/src/plugin/module.ts). Pre-v2 plugins export a bare function,
named or default, that returns a hooks object:

export const RtkOpenCodePlugin = async ({ $ }) => ({
  "tool.execute.before": async (input, output) => { /* rewrite output.args */ },
})

These stop loading on upgrade and the only fix is a full rewrite.
Every existing plugin (eg. rtk, herdr, and others) breaks at once.

Using v2 then is pretty annoying as every plugin breaks.

Proposal

Treat this as missing standard behavior: an upgrade path for old plugins,
behind a flag. Add experimental.legacy_plugins, default false.

  • false (default): same reject as today, but the warning names the flag and
    the migration target instead of a bare schema error.
  • true: the plugin loads through a compat adapter. The adapter maps the v1
    hooks that have a v2 equivalent (tool.execute.before, tool.execute.after,
    event) onto ctx.tool.hook / ctx.event.subscribe, and warns about any
    hook it cannot map so the author knows what to change.

It runs only when the modern decode fails, so modern plugins are untouched. The
adapter sits in one file (plugin/legacy.ts) and can be dropped once plugins
move over.

Scope

Full: tool.execute.*. Best effort: event. Warned and skipped: hooks with no
v2 equal. tui-only default plugins stay rejected.

I have a branch off v2 with the change, config wiring, and tests (unit plus
loader integration for both flag states) ready if the approach is approved at
https://github.com/f15u/opencode/tree/feat/legacy-plugin-compat

Activity

  1. imarshallwidjaja commented on Sep 13, 2026

    @imarshallwidjaja

    Porting a large V1 plugin now. The documented dual export (server for V1, setup/effect for V2) is a workable migration path, and I'd argue for keeping it supported rather than requiring a flag day. What's missing is the surrounding contract: loading rules for V1-style plugins under the V2 schema (#48365), whether the object-entrypoint floor is guaranteed, and migration docs so authors can verify instead of guessing. Exact-version testing against packed artifacts is the only way I've found to be sure; docs would make that cheaper for everyone.

  2. lowlyocean commented on Sep 24, 2026

    @lowlyocean

    We need a compatibility layer - there are going to be plugins that aren't maintained and won't be ported to v2 interface but are still useful

  3. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed proposal, @f15u! You're asking for an opt-in experimental.legacy_plugins flag. With it on, v1-style plugins (a factory returning a hooks map) would load through an adapter that maps tool.execute.* and event onto the v2 ctx.tool.hook / ctx.event.subscribe APIs. With it off, the load error would point to the flag and the migration path instead of a bare schema error.

    Right now v2 rejects v1 plugin exports on purpose, so whether to add a compatibility layer is a design decision for the maintainers. They'll consider it. Several other reports have already been folded into this issue, so it's the main place this is tracked.

    Related issues:

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions