Repository navigation
Description
Summary
OpenCode v2.2.0 loads local plugins via Node.js ESM resolution (package.json exports) instead of directly loading the directory's index.js file as documented. This breaks plugins like hindsight-coding-agents that provide dual v1/v2 compatibility by exporting the v1 plugin from dist/index.js (via package.json main) and the v2 plugin from the root index.js.
Environment
- opencode version: 2.2.0
- OS: Darwin 27.0.0 (darwin arm64)
- Terminal: TERM_PROGRAM=ghostty, TERM=xterm-256color, COLORTERM=truecolor
- Shell: /bin/zsh
- Install/channel: latest (release)
- Active plugins: /Users/seppa/.hindsight/coding-agents, opencode-plugin-litellm@latest
Reproduction
- Install the hindsight-coding-agents plugin:
npx @vectorize-io/hindsight-coding-agents install opencode2 - Verify opencode.json contains:
"plugin": ["/Users/seppa/.hindsight/coding-agents"] - Start opencode:
opencode - Observe plugin load failure in logs
Expected Behavior
Per the OpenCode v2 documentation: "Configured local paths must be directories. OpenCode loads the directory's server or index module, such as index.ts."
OpenCode should load /Users/seppa/.hindsight/coding-agents/index.js (the root index.js) which exports the v2 plugin with { id: 'hindsight-opencode2', setup: [AsyncFunction] }.
Actual Behavior
OpenCode loads /Users/seppa/.hindsight/coding-agents/dist/index.js (via Node.js ESM resolution using package.json exports field) which exports the v1 plugin factory function.
Error in server log:
failed to load plugin target=/Users/seppa/.hindsight/coding-agents ref=err_8fbc317d cause="Cause([Fail(PluginModule.LoadError: Plugin must export a default definition with an id and an effect or setup function. (cause: SchemaError(Expected object at ["default"])))])"
The v1 plugin factory function doesn't match the v2 plugin schema (which requires { id, setup } or { id, effect }).
Additional Context
The hindsight-coding-agents plugin (v0.8.2) is designed for dual v1/v2 compatibility:
- v1/Node.js: resolves via
package.json main→dist/index.js(v1 plugin) - v2: should resolve via
<dir>/index.js→ rootindex.js(v2 plugin re-exporting fromdist/opencode2.js)
This worked in earlier OpenCode versions but broke in v2.2.0.
The plugin's package.json has:
{
"main": "dist/index.js",
"exports": { ".": { "default": "./dist/index.js" } }
}OpenCode v2.2.0 appears to be using the exports field for resolution instead of directly loading the directory's index.js.
Related hindsight issues (already filed upstream):
- opencode 2.2.2.0 config definition change/break vectorize-io/hindsight#6148
- opencode v2.2.0: plugin fails to load — "Plugin must export a default definition with an id and an effect or setup function" vectorize-io/hindsight#6146
- Hermes plugin: option to skip auto-recall in cron runs (recall_cron) vectorize-io/hindsight#6145
Activity
opencodejr commentedon Oct 28, 2026
Thanks for the detailed report!
This comes from a deliberate change in 2.2.0 to how local plugin directories are resolved, so it isn't a loader bug. If a local directory's
package.jsonhas bothnameandexports, OpenCode now loads it through those fields, the same way as a published package: it tries the./serverexport first, then.. The rootserver/indexfiles are only used when those fields are missing. The Load section of the plugin docs describes this: "A local plugin directory with apackage.jsonnameandexportsloads its parts through them, like the published package. Without them, it uses file names at its root."hindsight-coding-agents only exports
.→./dist/index.js(the v1 factory), so v2 ends up with that module and the schema check fails. The plugin can support both versions by adding a./serverexport for its v2 entry:Node and v1 keep resolving
., and OpenCode v2 picks up./server. That's probably worth passing on to the upstream issues you linked.I've logged this as a feature request: either prefer a local directory's root
index/serverfile overexports, or make this case easier to diagnose (for example, an error that names the file it resolved and suggests a./serverexport). Maintainers will consider it.Related:
package.jsonmain