Context
Future OpenCLI adapters may need to spawn their own background daemons (analogous to the browser-bridge daemon that bridges CDP traffic). When researching the spawn pattern used by browser-bridge, two documentation-worthy findings surfaced:
- The spawn pattern is simple, correct, and stable — it's worth recording so plugin authors copy it verbatim rather than inventing variations.
- The recently-drafted
docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.md implicitly assumes a single daemon and doesn't cover how opencli daemon status/stop/restart would behave if a second (plugin-side) daemon coexists.
This issue tracks adding docs for (1) and deciding the scope for (2).
1. Verified spawn pattern
src/browser/bridge.ts:102-107:
this._daemonProc = spawn(spawnArgs[0], spawnArgs.slice(1), {
detached: true,
stdio: 'ignore',
env: { ...process.env },
});
this._daemonProc.unref();
Properties worth highlighting in plugin-author docs:
detached: true + .unref() lets the CLI process exit without keeping the daemon as a child — daemon outlives any single invocation.
stdio: 'ignore' is required for .unref() to actually release the pipes; otherwise the parent stays attached until stdio closes.
- No
setsid / explicit pgid management is needed on macOS or Linux for this use case — detached: true + stdio: 'ignore' is sufficient. Plugin authors do not need to reimplement process-group logic.
env: { ...process.env } is intentional: the daemon inherits the caller's env (including adapter-specific OPENCLI_* vars and PATH).
- Spawn happens lazily from the CLI entry point (
bridge.ts), not at module import — important for plugin authors who want the daemon to come up only when their adapter actually runs.
Suggested home for this doc: a new docs/developer/plugin-daemons.md (or extending docs/advanced/remote-chrome.md's daemon section).
2. Multi-daemon gap in the daemon lifecycle redesign spec
docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.md introduces opencli daemon status/stop/restart subcommands. The current /status example returns a single daemon's state:
Daemon: running (PID 12345)
Uptime: 2h 15m
Extension: connected
Last CLI request: 8 min ago
Memory: 12.3 MB
Port: 19825
If plugin-side daemons land later, this shape doesn't generalize cleanly. Two orthogonal questions to settle before the spec is implemented:
- Discovery: should
opencli daemon status auto-enumerate known daemons (via a registry / well-known port range / pidfile convention), or require --name browser-bridge to target one?
- Targeting: should
daemon stop / daemon restart require an explicit target when >1 daemon is running, and default to "all" / "browser-bridge" / error when ambiguous?
Neither needs to be solved immediately — but the spec should at least reserve namespace for multi-daemon (e.g. accept opencli daemon status [name] with today's behavior being name = browser-bridge implicit), so later extension doesn't break existing flags.
Out of scope
This issue is strictly documentation / spec-scope. It does not commit to adding any new plugin daemon; it only records patterns and flags a gap so future work has an easier on-ramp.
Suggested resolution
Context
Future OpenCLI adapters may need to spawn their own background daemons (analogous to the
browser-bridgedaemon that bridges CDP traffic). When researching the spawn pattern used bybrowser-bridge, two documentation-worthy findings surfaced:docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.mdimplicitly assumes a single daemon and doesn't cover howopencli daemon status/stop/restartwould behave if a second (plugin-side) daemon coexists.This issue tracks adding docs for (1) and deciding the scope for (2).
1. Verified spawn pattern
src/browser/bridge.ts:102-107:Properties worth highlighting in plugin-author docs:
detached: true+.unref()lets the CLI process exit without keeping the daemon as a child — daemon outlives any single invocation.stdio: 'ignore'is required for.unref()to actually release the pipes; otherwise the parent stays attached until stdio closes.setsid/ explicit pgid management is needed on macOS or Linux for this use case —detached: true+stdio: 'ignore'is sufficient. Plugin authors do not need to reimplement process-group logic.env: { ...process.env }is intentional: the daemon inherits the caller's env (including adapter-specificOPENCLI_*vars andPATH).bridge.ts), not at module import — important for plugin authors who want the daemon to come up only when their adapter actually runs.Suggested home for this doc: a new
docs/developer/plugin-daemons.md(or extendingdocs/advanced/remote-chrome.md's daemon section).2. Multi-daemon gap in the daemon lifecycle redesign spec
docs/superpowers/specs/2026-03-31-daemon-lifecycle-redesign.mdintroducesopencli daemon status/stop/restartsubcommands. The current/statusexample returns a single daemon's state:If plugin-side daemons land later, this shape doesn't generalize cleanly. Two orthogonal questions to settle before the spec is implemented:
opencli daemon statusauto-enumerate known daemons (via a registry / well-known port range / pidfile convention), or require--name browser-bridgeto target one?daemon stop/daemon restartrequire an explicit target when >1 daemon is running, and default to "all" / "browser-bridge" / error when ambiguous?Neither needs to be solved immediately — but the spec should at least reserve namespace for multi-daemon (e.g. accept
opencli daemon status [name]with today's behavior beingname = browser-bridgeimplicit), so later extension doesn't break existing flags.Out of scope
This issue is strictly documentation / spec-scope. It does not commit to adding any new plugin daemon; it only records patterns and flags a gap so future work has an easier on-ramp.
Suggested resolution