OpenCode¶
OpenCode integrates via a TypeScript plugin instead of shell hooks. The plugin holds a persistent WebSocket connection to the daemon for the lifetime of the session.
What gets installed¶
| Path | What |
|---|---|
~/.config/opencode/plugins/repowire.ts |
Global plugin (default) |
The plugin uses the current OpenCode plugin API (@opencode-ai/plugin). It hooks into session lifecycle events from inside the OpenCode runtime — not via external shell hooks — and bridges them to the Repowire daemon over WebSocket. OpenCode calls the plugin's dispose hook on reload or shutdown so connections and pending requests are released without process-level signal handlers.
OpenCode's session.status event is the authoritative status source:
busy sends status=busy, turn_state=working, and idle sends
status=idle, turn_state=idle. Query timeouts also clear the plugin's local
busy flag so a failed injected prompt does not strand the peer.
Why a plugin instead of hooks¶
OpenCode does not expose Claude-style stdout hooks. The plugin model gives the integration:
- Direct access to session state without parsing a transcript file.
- Persistent WebSocket connection (no spawn-on-each-event overhead).
- Tool-call interception in-process (used for the dashboard's tool-call detail view).
The trade-off: the plugin runs inside OpenCode's process, so a plugin crash takes the OpenCode session with it. Repowire's plugin is small and defensive on purpose.
Verifying¶
Open an OpenCode session, submit its first prompt, and watch repowire peer list. The peer registers from the first live session event. The plugin deliberately does not mark every historical session returned by session.list() online at startup. If the active peer does not appear, check OpenCode's plugin log for the error.
repowire setup installs globally in OpenCode's canonical plural plugins directory. It removes the old Repowire file from ~/.opencode/plugin/ after the new file is written, preventing the plugin from loading twice during migration.
Outside tmux, the plugin reads the local daemon token from ~/.repowire/config.yaml, pre-registers its pane-less identity over authenticated HTTP, and uses the same stable project-derived circle as Pi. Inside a Repowire-spawned tmux pane, verified tmux/spawn placement remains authoritative.
Troubleshooting¶
- Peer never appears → the plugin didn't load. Check that
~/.config/opencode/plugins/repowire.tsexists and is non-empty; check OpenCode's log for plugin load errors. - WebSocket errors in the plugin log → daemon is unreachable. See Daemon unreachable.
- Tool calls missing from the dashboard → confirm the plugin version matches the installed
repowirepackage. Re-runrepowire setupto refresh.