Why
src/main/installer/index.ts discovers harnesses via which() then falls back to the npm-global root. On macOS when the user installed via Homebrew the claude binary lives in /opt/homebrew/bin — already on PATH for most users but not in npm-global. On Linux with NVM-flipping users, the resolution gets fragile.
OpenCode reads ~/.config/opencode/opencode.json for everything: providers, plugins, MCP servers. It supports installing community plugins via the plugin[] array. A small OpenCode plugin installed via opencode plugin install @hoist/discover could run at OpenCode's startup and:
- Read
/usr/bin/env + ~/.bashrc/~/.zshrc paths to discover installed harness binaries
- Compare against the hoist catalog (
src/main/providers/harnesses.ts shape)
- Report back to hoist via a local Unix socket or
~/.cache/hoist/discovery.json
This is an OpenCode-side affordance, not hoist-side — but it's the cleanest way to feed accurate detection back into the GUI's "Installed · v2.1.204" cards.
Scope
- New repo under
packages/opencode-plugin-hoist/ (or just in src/opencode-plugin/ until we publish).
- Small plugin with no deps: spawns
which for each catalog binary, writes ~/.cache/hoist/discovery.json with { path, version } per tool.
installer/discoverInstalled() reads that file first (if newer than 5 minutes), then falls back to the current which + npm-global probe.
- Renderer keeps showing the discovered status without a UI change.
- CLI
hoist install/hoist list picks it up via the same shared discoverInstalled.
Acceptance criteria
Non-goals
- Real-time signalling (file mtime is fine for v1)
- Auto-install from the plugin (that's hoist's job — keep the boundary clean)
- Cross-platform notification (linux/macOS only for v1)
Why
src/main/installer/index.tsdiscovers harnesses viawhich()then falls back to the npm-global root. On macOS when the user installed via Homebrew theclaudebinary lives in/opt/homebrew/bin— already on PATH for most users but not in npm-global. On Linux with NVM-flipping users, the resolution gets fragile.OpenCode reads
~/.config/opencode/opencode.jsonfor everything: providers, plugins, MCP servers. It supports installing community plugins via theplugin[]array. A small OpenCode plugin installed viaopencode plugin install @hoist/discovercould run at OpenCode's startup and:/usr/bin/env+~/.bashrc/~/.zshrcpaths to discover installed harness binariessrc/main/providers/harnesses.tsshape)~/.cache/hoist/discovery.jsonThis is an OpenCode-side affordance, not hoist-side — but it's the cleanest way to feed accurate detection back into the GUI's "Installed · v2.1.204" cards.
Scope
packages/opencode-plugin-hoist/(or just insrc/opencode-plugin/until we publish).whichfor each catalog binary, writes~/.cache/hoist/discovery.jsonwith{ path, version }per tool.installer/discoverInstalled()reads that file first (if newer than 5 minutes), then falls back to the currentwhich+ npm-global probe.hoist install/hoist listpicks it up via the same shareddiscoverInstalled.Acceptance criteria
~/.cache/hoist/discovery.jsonwithin 200 ms of OpenCode startup.which+ npm-global).discoverInstalledreads the cache file when present and fresh, otherwise falls back.opencode plugin install @hoist/discover(or equivalent local-path install during dev).Non-goals