## Summary - package `packages/server` as a standalone desktop executable so Electron and Tauri no longer depend on a system-installed Node runtime in production - align Electron and Tauri startup logic around launching the packaged server, resolving binaries from the user shell, and bundling the same server resources into both desktop apps - replace the workspace instance proxy path that used `@fastify/reply-from` with a direct streaming proxy so packaged standalone builds can talk to spawned `opencode` instances correctly ## Why Desktop production builds were still depending on a user-provided Node runtime to launch `packages/server`, which made packaging less self-contained and created different behavior across machines. While moving to a standalone server executable, we also found that Bun-compiled standalone builds could start `opencode` successfully but failed when proxying requests to those instances through `reply-from`. The goal of this change is to make desktop production startup self-contained, keep Electron and Tauri behavior aligned, and restore correct communication with local `opencode` instances in packaged builds. ## What Changed - added a standalone build path for `packages/server` and bundle `codenomad-server` into desktop resources - updated Electron production startup to resolve and launch the standalone server executable - updated Tauri production startup to resolve and launch the standalone server executable with matching cwd and shell behavior - added runtime path helpers so the packaged server can reliably find its bundled UI, auth templates, config template, and package metadata - improved bare binary resolution so commands like `opencode` can be resolved from the user's login shell environment - upgraded the server stack to newer Fastify-compatible packages needed for the standalone/runtime work - replaced the workspace instance proxy implementation with a direct streaming proxy for requests to spawned `opencode` instances - updated Electron and Tauri build/prebuild scripts to generate and package the standalone server, while also repairing missing platform-specific optional binaries during packaging ## Benefits - desktop production builds no longer require Node to be installed on the user's system - Electron and Tauri now use the same packaged server model in production, reducing platform drift - packaged desktop apps can successfully create workspaces, launch `opencode`, and proxy health/session traffic to those instances - the server bundle is more self-contained and resilient to different launch environments - desktop packaging is more predictable because the required server executable is built and bundled as part of the app build flow
opencode-config
TLDR
Template config + plugins injected into every OpenCode instance that CodeNomad launches. It provides a CodeNomad bridge plugin for local event exchange between the CLI server and opencode.
What it is
A packaged config directory that CodeNomad copies into ~/.config/codenomad/opencode-config for production builds or uses directly in dev. OpenCode autoloads any plugin/*.ts or plugin/*.js from this directory.
How it works
- CodeNomad sets
OPENCODE_CONFIG_DIRwhen spawning each opencode instance (packages/server/src/workspaces/manager.ts). - This template is synced from
packages/opencode-config(packages/server/src/opencode-config.ts,packages/server/scripts/copy-opencode-config.mjs). - OpenCode autoloads plugins from
plugin/(packages/opencode-config/plugin/codenomad.ts). - The
CodeNomadPluginreadsCODENOMAD_INSTANCE_ID+CODENOMAD_BASE_URL, connects toGET /workspaces/:id/plugin/events, and posts toPOST /workspaces/:id/plugin/event(packages/opencode-config/plugin/lib/client.ts). - The server exposes the plugin routes and maps events into the UI SSE pipeline (
packages/server/src/server/routes/plugin.ts,packages/server/src/plugins/handlers.ts).
Expectations
- Local-only bridge (no auth/token yet).
- Plugin must fail startup if it cannot connect after 3 retries.
- Keep plugin entrypoints thin; put shared logic under
plugin/lib/to avoid autoloaded helpers. - Keep event shapes small and explicit; use
type+propertiesonly.
Ideas
- Add feature modules under
plugin/lib/features/(tool lifecycle, permission prompts, custom commands). - Expand
/workspaces/:id/plugin/*with dedicated endpoints as needed. - Promote stable event shapes and version tags once the protocol settles.
Pointers
- Plugin entry:
packages/opencode-config/plugin/codenomad.ts - Plugin client:
packages/opencode-config/plugin/lib/client.ts - Plugin server routes:
packages/server/src/server/routes/plugin.ts - Plugin event handling:
packages/server/src/plugins/handlers.ts - Workspace env injection:
packages/server/src/workspaces/manager.ts