Repository navigation
Description
Summary
@vectorize-io/hindsight-coding-agents 0.8.2 is reported as failed by opencode 2.2.x when the plugin is registered as a directory path (install opencode does exactly that):
Server plugin error
Plugin: ~/.hindsight/coding-agents
Status: failed
Runtime: server
Source: ~/.hindsight/coding-agents
Error: Plugin must export a default definition with an id and an effect or setup function.
Reference: err_83624a09
The server log shows which module opencode actually loaded, and why it rejected it:
msg="loading plugin" id=/home/adamadmin/.hindsight/coding-agents entrypoint=file:///home/adamadmin/.hindsight/coding-agents/dist/index.js
message="failed to load plugin" target=/home/adamadmin/.hindsight/coding-agents cause="Cause([Fail(PluginModule.LoadError: Plugin must export a default definition with an id and an effect or setup function. (cause: SchemaError(Expected object\n at [\"default\"])))])"
Root cause
opencode v2 resolves a plugin that is registered as a directory path through that directory's package.json exports map, preferring the ./server subpath export and otherwise falling back to ".". It does not fall back to <dir>/index.js once a manifest exists.
coding-agents/index.js is your v2 entrypoint and its own header documents the assumption that broke:
v1 follows package.json
main(→ dist/index.js, the v1 plugin), while v2 ignoresmainand loads<dir>/index.js
In 2.2.x that is no longer true. package.json has exports["."].default = "./dist/index.js", i.e. the v1 plugin, whose default export is a function (input, options) => Hooks. opencode's v2 plugin definition schema requires an object ({ id, effect } or { id, setup }), so validation fails with Expected object at ["default"].
How the resolution rule was confirmed
Controlled experiment with a minimal plugin package registered by absolute path:
{"name":"fake-plugin","version":"1.0.0","type":"module",
"main":"./a-main.js",
"exports":{".":{"default":"./b-exports.js"},"./server":"./c-server.js"}}a-main.js→export default function V1Plugin(ctx) { return {} }b-exports.js→export default { id: "fake-exports", setup() {} }c-server.js→export default { id: "fake-server", setup() {} }
Observed:
| package.json exports | entrypoint opencode 2.2.0 loaded |
|---|---|
"." + "./server" |
file:///tmp/.../fake/c-server.js |
"." only |
file:///tmp/.../fake/b-exports.js |
main only, no exports |
<dir>/index.js |
main was never used while exports was present. The same rule explains why @cortexkit/aft-opencode (which ships exports["./server"] = "./dist/entry/server.js") loads correctly on the same machine.
Fix
Expose the v2 entrypoint as the ./server subpath export, leaving "." (the v1 entry) untouched:
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./server": "./index.js",
"./dsh": "./dist/dsh.js",
"./cordis.patch.yml": "./cordis.patch.yml",
"./package.json": "./package.json",
"./dist/*": "./dist/*"
}With this single added line, a fresh opencode 2.2.0 process resolves:
msg="loading plugin" id=~/.hindsight/coding-agents entrypoint=file:///.../coding-agents/index.js
and the plugin then runs normally — from its own diagnostics log:
{"event":"skill_registered","id":"hindsight-coding-agent"}
{"event":"session_start","bank":"opencode::trade-schwab","pages":7}
{"event":"pages_ok","count":7}
{"event":"retain_ok","turns":1,"trigger":"idle"}
No load failure appears in the server log. main remains dist/index.js, so v1 hosts are unaffected by the change (they read main, not exports).
Note for anyone applying this by hand: a long-lived opencode server that already resolved this path keeps the old entrypoint cached and will still report the failure until it is restarted; a new process picks up the fixed manifest immediately.
Second, related issue: the installer registers the plugin twice
hindsight-coding-agents install opencode writes the same path under both the v2 key plugins and the legacy key plugin. opencode 2.2 normalizes the legacy key into plugins, so opencode debug config reports the target twice in one document:
"plugins": [
"/home/adamadmin/.hindsight/coding-agents",
"@cortexkit/[email protected]",
"@cortexkit/[email protected]",
"/home/adamadmin/.hindsight/coding-agents",
"/opencode/opencode-beads"
]The supervisor dedupes by target string, so this does not raise Duplicate plugin ID, but the target is resolved and loaded on every activation cycle redundantly. Dropping the legacy plugin array (2.x-only hosts) leaves a single plugins entry.
Environment
- opencode v2.2.0 (
opencode --version), Linux x64; the desktop UI reports the build as 2.2.2.0 @vectorize-io/hindsight-coding-agents0.8.2, installed vianpx @vectorize-io/hindsight-coding-agents install opencode- plugin registered as
~/.hindsight/coding-agentsunderpluginsin~/.config/opencode/opencode.jsonc
AI disclosure
This report was written by an AI coding agent (OpenCode, model deepseek-v4.1-flash) operating on the reporter's machine, under their direction. The root-cause analysis, the controlled resolution experiment, the one-line manifest patch, and the verification run were all performed by that agent. Log excerpts are verbatim from the reporter's machine; paths are the reporter's home directory.
Activity
nicoloboschi commentedon Oct 29, 2026
Fixed in
@vectorize-io/hindsight-coding-agents0.8.3. It addsexports["./server"]→./index.js, which OpenCode 2.2 reads first when it resolves the plugin folder, so it loads the v2 entry. I checked it on a real OpenCode 2.2.1: the plugin loadsindex.js, adds memory to the prompt and saves the session. OpenCode 1.18.9 still loads the v1 plugin. To update:npx @vectorize-io/hindsight-coding-agents@latest install opencode2, or wait for auto-update.