fix(packaged): isolate headless MCP runtime namespace - #7494
Conversation
Prevent MCP bootstrap from starting a second packaged daemon on the desktop IPC socket while preserving the shared project data root.
|
🧪 Queued for QA validation — this PR has changes that need a manual QA pass before it's merged. Nothing needed from you; we'll update here once it's validated. Thanks for the contribution! 🙏 |
mrcfps
left a comment
There was a problem hiding this comment.
@VaiYav Thanks for the focused namespace-isolation patch and the clear regression coverage around runtime/data path separation. I traced the full desktop → daemon → installed MCP bootstrap lifecycle and found one main-path discovery mismatch that prevents the newly isolated daemon from being observed after it launches. The concrete fix is described inline; once the bootstrap target follows the new socket, this approach should be much safer.
🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.| const activeConfig = launcherRuntime.config; | ||
| const paths = launcherRuntime.paths; | ||
| const stamp = createHeadlessStamp(config.namespace); | ||
| const stamp = createHeadlessStamp(runtimeNamespace); |
There was a problem hiding this comment.
Blocking — switch post-bootstrap discovery to the isolated daemon socket.
This changed stamp moves the headless daemon from the data namespace socket (for example, release-stable/daemon) to the new runtime namespace socket (release-stable-headless/daemon). However, the installed MCP environment is still built in apps/daemon/src/mcp-routes.ts::computeInstallPayload from the current desktop daemon's SIDECAR_ENV.IPC_PATH, and apps/daemon/src/mcp-bootstrap.ts::ensureMcpDaemonUrl uses that same unchanged environment both before spawning and throughout its post-spawn polling loop. Therefore, when the desktop socket is unavailable, the packaged headless process can start successfully here while the invoking MCP process keeps polling the old desktop socket until the 60-second timeout. That breaks the primary headless-bootstrap flow this PR is intended to fix.
Please carry a distinct normalized bootstrap daemon IPC target through the install payload and switch discovery to it after spawning (while retaining the desktop socket for the initial fast-path probe), or otherwise update the polling environment to the socket derived from runtimeNamespace. Add a lifecycle fixture covering unavailable desktop IPC → isolated headless spawn → discovery of the headless daemon, including the explicit namespace override.
|
@VaiYav The current blocker is the one @mrcfps called out: after the headless daemon moves onto the isolated runtime namespace, the MCP bootstrap still keeps polling the old desktop socket after spawn. Once that post-spawn discovery follows the isolated namespace and the lifecycle coverage is in place, this path should be in much better shape. Also, the PR template parser is still reading 💡 To drive this PR to merge hands-free, paste this to your AI coding agent (Claude Code / Codex / opencode / Cursor …): |
Carry the packaged headless IPC target through MCP install metadata so post-bootstrap discovery follows the new runtime namespace.
Pass the isolated runtime namespace to spawned headless clients so the bootstrap process binds the socket that post-spawn discovery polls.
Fixes #7154
Why
Agent/MCP bootstrap can launch packaged Open Design headlessly while the desktop runtime is already active. Both modes currently resolve the same release-stable IPC namespace, so the second daemon fails with EADDRINUSE and the desktop enters a restart loop.
This was reproduced locally on macOS arm64 with Open Design 0.20.2 outer bundle and 0.21.0 payload. Open MCP sessions must not require closing the desktop or each other.
What users will see
Open Design desktop and MCP/headless sessions can run at the same time. Headless bootstrap uses a separate runtime namespace/socket while continuing to use the desktop namespace data root, so existing projects remain visible.
Surface area
Screenshots
None — lifecycle/runtime fix.
Bug fix verification
apps/packaged/tests/headless-runtime.test.ts,paths.test.ts, andsidecars.test.ts.Validation
pnpm --filter @open-design/packaged exec vitest run tests/headless-runtime.test.ts tests/paths.test.ts tests/sidecars.test.ts— 86 passedpnpm --filter @open-design/packaged typecheck— passedpnpm --filter @open-design/packaged build— passedgit diff --check— passedImplementation notes
OD_PACKAGED_NAMESPACEremains backward compatible.OD_PACKAGED_RUNTIME_NAMESPACEis an optional override; headless defaults to<data-namespace>-headless. The existing sidecar stamp contract is unchanged. Desktop keeps its existing namespace and behavior.