Repository navigation
Description
Summary
Local plugins written with the documented V2 pattern — import { Plugin } from "@opencode/plugin" plus export default Plugin.define(...) — fail to load in OpenCode 2.0.12 with Cannot find package '@opencode/plugin'. Node and Bun resolve the same import from the same directories without issue, so the server's plugin module resolver is at fault.
Environment
- opencode version: 2.0.12 (channel=latest)
- OS: Linux (Ubuntu, kernel 7.0.0-31-generic, x86_64, glibc)
- Terminal: xterm-256color, truecolor
- Shell: /bin/bash
- Install/channel: Homebrew tap
anomalyco/tap/opencode-v2 - Active plugins:
vexp-guard(local; kept working via the no-import workaround below). Earlier local plugins (rtk.ts) and the V1 package pluginopenslimedit@latestalso failed to load with the same resolution error after porting to the documented V2 pattern.
Reproduction
- Create a project with
.opencode/plugins/probe.js:
import { Plugin } from "@opencode/plugin"
export default Plugin.define({
id: "probe",
setup() {},
})- Run a headless session with server logs:
opencode run --print-logs "hi"(or just open the TUI and inspect~/.local/share/opencode/log/opencode.log). - Observe the load failure:
failed to load plugin target=<project>/.opencode/plugins/probe.js
cause="Cause([Die(ResolveMessage: Cannot find package '@opencode/plugin' imported from <project>/.opencode/plugins/probe.js)])"
Expected Behavior
Local plugins using the documented @opencode/plugin import load and appear in the plugin list with source: local and status: active (visible via opencode api get /api/plugin).
Actual Behavior
@opencode/plugin cannot be resolved by the server's plugin bundler, so every local plugin written with the documented pattern fails to load. Isolation findings:
- Node resolves the same import from the same file:
node -e "import('@opencode/plugin').then(() => console.log('ok'))"works. - Bun resolves it too:
bun -e "import('@opencode/plugin').then(() => console.log('ok'))"works. - Installing
@opencode/plugin@2.0.12(and its@opencode/*dependencies) intonode_modules— both as an ancestor of the plugin file and in the global config dir~/.config/opencode/node_modules— does not help. - Unscoped bare imports DO resolve from the plugin directory (
import { parse } from "yaml"from the config-dirnode_modulesloaded fine), so the loader itself is healthy. - Scoped and subpath imports fail even when the target files exist:
@opencode/ai/schema,yaml/dist/yaml.mjs, and — inside@opencode/plugin's own dist —@opencode/schema/agent,effect/unstable/httpapi, and the peer@opencode/theme. - Plugins with no bare imports load fine: a plain
export default { id, setup(ctx) }using onlynode:builtins is accepted by the loader and receives the full context (ctx.tool.hook("execute.before", ...)works).
This looks like a resolver that mishandles package exports/subpath resolution for local plugin files, separate from the LOADER (the loader's shape validation of the default export works).
Additional Context
- Frequency: reproducible consistently (100%).
- Also reproduced with the official npm build:
npm install -g @opencode/cli@2.0.12→ native binary@opencode/cli-linux-x64has the same BuildID as the brew binary and fails identically, so this is a runtime defect, not an installer quirk. - Recent change: migrated from OpenCode 1.x to 2.0.12. The V1 plugin API breakage is expected, but the documented V2 replacement pattern for local plugins does not work either.
- Workaround currently in use (works, but bypasses the type-checked
Plugin.define): omit the bare import and export a plain object —
export default {
id: "vexp-guard",
async setup(ctx) {
await ctx.tool.hook("execute.before", (event) => {
// ...
})
},
}
Activity
alexrs-cohere commentedon Sep 25, 2026
Still reproduces on 2.0.16 (channel=latest), and also for plugins auto-discovered from the global config dir (
~/.config/opencode/plugins/), so it isn't limited to project.opencode/plugins/or configpluginsentries.Environment
TERM=xterm-256color,COLORTERM=truecolor@opencode/pluginfine from the same directory, so the failure is in the server's plugin resolverReproduction
~/.config/opencode/plugins/_probe.ts:Nothing surfaces in the session; the plugin's hooks and tools are simply absent.
Workaround that works on 2.0.16: export the definition object directly, with no import —
Plugin.defineappears to be a typed identity helper, so the runtime object is equivalent. Both plugins I ported this way load and register their tools/hooks correctly on 2.0.16.holny commentedon Sep 28, 2026
Gentle nudge — this has been open for a week with checks green and no review. The fix is contained: the resolve hook reads scoped
@opencode/*imports from the project directory (found by walking back to the.opencodesegment of the entrypoint) instead of the plugin file's own directory, and files inside node_modules skip tracking as before. Happy to rebase or adjust.CarlosCorreaB9 commentedon Sep 30, 2026
Confirmed on the current stable release — adding occurrence evidence from a different platform (Windows) and a managed-plugin set.
Occurrence
@opencode/plugindist-taglatest= 2.0.20, i.e. current stable)~/.config/opencode/plugins/(auto-discovered, nopluginsentry inopencode.json).tsfiles in that directoryObserved log lines (verbatim, path redacted to the documented location)
The same
ResolveMessageappears for every loose plugin in the directory, on every boot. Cumulative count observed in the persisted server log: 23–50 occurrences per plugin since 2026-09-19, still reproducing in the most recent boot.Isolation checks performed
package.jsonand nonode_modulesexist in the global config dir. Consistent with the docs statement that local files "are imported directly" and their dependencies are not installed for you.@opencode/pluginresolves on npm at 2.0.20, an exact match for the installed runtime. It is not a typo for the 1.18.x line (@opencode-ai/plugin, latest 1.18.33).import { Plugin } from "@opencode/plugin"plusexport default Plugin.define({ id, setup }).This matches the isolation findings already in this thread, including the report that installing the package into
node_modulesdoes not help.Related upstream work
PR #49097 ("fix(plugin): serve bundled SDK to loose plugin files on Bun") describes this as the Bun server side missing the module shim that the Node prelude already installs, and proposes registering the host's own
@opencode/pluginspecifiers as Bun virtual modules.As of this report that PR is still open and unmerged (
mergedAt: null, basev2), so no released build contains it. The workaround documented in this thread — dropping the bare import and exporting a plain object withid+setup— avoids the defect but gives up the type-checkedPlugin.definesurface.DennisBecker commentedon Oct 6, 2026
I have the same issue when running opencode with a local plugin. Starting opencode v2 it shows
1 plugin failedand/pluginsselecting the one plugin shows this error:Fresh clean install of v2.0.23 - updated to v2.0.24
mgajda commentedon Oct 18, 2026
Confirmed, and I think the mechanism is specific: it depends on the working directory.
Bun resolves the bare specifier by walking up from the importing file. The repo tool files live at
<repo>/.opencode/tool/*.ts, and<repo>/node_modules/@opencode/pluginis a workspace symlink topackages/plugin. So inside the opencode repo the import resolves to the repo's own v2 source,packages/plugin/src/promise/index.ts, which does not exporttool— it was dropped in v2(
f28c10aa4d). The dynamic import throws:Outside the repo the files aren't loaded at all, which is why it looks working-directory dependent.
Two things worth noting for the fix:
.opencode/opencode.jsoncsets"tools": { "github-triage": false, "github-pr-search": false }and the error still fires — theregistry imports the module to enumerate before the enabled flag applies.
.opencode/node_modules/@opencode-ai/plugin@1.18.31does exporttool, and it sits closerto the importing file, so the same import spelled
@opencode-ai/pluginwould resolve to it.On my machine this is 18 of 790 ERROR lines (2.3%), and it fires once per launch inside the
repo — 8 times in a single day, every launch, deterministically.
Context: #35325, #36582.
fix(plugin): resolve scoped packages from project directory in local …
opencodejr commentedon Oct 28, 2026
Thanks for the detailed report. I reproduced this on 2.0.12: a local
.opencode/plugins/probe.jsthat doesimport { Plugin } from "@opencode/plugin"andexport default Plugin.define(...)fails withCannot find package '@opencode/plugin', and itssetup()never runs.With the same setup on the latest release, 2.2.0, the plugin loads and
setup()runs. I couldn't test the latestdevfrom source here, so this result is from the published 2.2.0 release. The likely fix is #53422, which makes OpenCode's own@opencode/pluginandeffectmodules available to plugins. It first shipped in 2.0.25. Upgrading (opencode upgrade, ornpm i -g @opencode/cli@latest/ your Homebrew tap) should let you go back to the typedPlugin.definepattern. The script below reproduces it.The bot will close this issue in 1 day unless you reply that it still happens on 2.0.25 or newer.
opencodejr commentedon Oct 29, 2026
I'm closing this because there has been no reply since my last comment. I reproduced the
Cannot find package '@opencode/plugin'failure for a localPlugin.defineplugin on 2.0.12. On the latest release, 2.2.0, the same plugin loads and itssetup()runs. The likely fix is #53422, which first shipped in 2.0.25, so upgrading should let you use the typedPlugin.definepattern again instead of the plain-object workaround.If it still happens on 2.0.25 or newer, please comment here or open a new issue with your version and the log line, and we'll look again. Thanks for the detailed report!