feat(pi-plugin): add user pi_binary override for embedded Pi hosts
Refs #851
What this changes
pi_binary (user config only) names the Pi executable Magic Context spawns for its child processes. When set, resolvePiInvocation returns it immediately and skips the argv[1] / execPath / bundled-package / PATH detection chain. This is the escape hatch for embedded hosts where Pi runs in a process whose execPath is the host binary (a VS Code extension hosting the SDK, embedded web servers) — the case in #851 — without changing the default detection order.
resolvePiInvocationacceptspiBinary;~/expands, a bare command name stays a PATH lookup, and a path-shaped value that is not a readable file is reported throughfallbackDiagnosticinstead of being spawned blindly.- When an embedded host shape is still spawned as Pi, spawn and non-zero-exit errors carry a hint naming
pi_binary. - Wired into historian (
resolveHistorianFromConfig),/ctx-recomp,/ctx-wrapup, and the Dreamer runner factory. It is listed inLIVE_RELOAD_CONFIG_PATHS, so fixing the value applies on the next run without a restart. - Stripped from project config in
stripUnsafeProjectConfigFields, the same tier rule asauto_update: a repository must not choose which executable the machine runs. - Schema, config reference,
CONFIGURATION.md, and the dashboard coverage manifest regenerated.
What this does not change
The default execPath classification is untouched. An embedded host that does not set pi_binary still spawns the host binary as Pi and exits with a bad-option error; that half of #851 is left for maintainers to decide (rename detection, host adapters, or in-process child sessions).
Tests
packages/pi-plugin/src/subagent-runner.test.ts: five new cases — short-circuit over an embedded-hostexecPath, unreadable configured path diagnostic,~/expansion, embedded-host failure hint, and no hint for a renamed packaged Pi binary.packages/plugin/src/config/project-security.test.ts: project-config stripping.- Ran:
packages/plugintypecheck andbun test src/config(334 pass, including the live-schema drift check);packages/pi-plugintypecheck,bun test src/config(48 pass),src/subagent-runner.test.ts(168 pass, 2 failures unrelated to this change: this machine's Bun reportsos.userInfo().username === "unknown", so the redaction fixtureunknown-providerbecomes<USER>-provider; Node reportstrim21),src/dreamer+src/index-in-process-latch.test.ts(159 pass); dashboardConfigEditortests (63 pass); biome on the touched files.
Harness coverage (required)
- OpenCode 1: not applicable — the OpenCode lane creates child sessions through the host SDK client; it never spawns a Pi executable.
- OpenCode 2: not applicable — same reason.
- Pi: covered — resolver short-circuit, historian/recomp/wrapup wiring, Dreamer factory, failure hint, tests.
- OMP: covered — shares the same
resolvePiInvocationpath;pi_binarynames the OMP binary through the shared basename detection. - Rust module: not applicable — the ck-mc module handles transforms and does not spawn Pi children.
Summary by cubic
Adds a user-level pi_binary config setting that overrides Pi executable detection, so embedded hosts (VS Code extensions or web servers hosting the SDK) can tell Magic Context which Pi executable to spawn for historian, dreamer, recomp, and wrapup child processes. Without it, those hosts are misdetected as Pi binaries and fail with bad-option exits (#851).
pi_binaryskips theexecPath/ bundled-package / PATH detection chain;~/expands, bare command names stay PATH lookups, and unreadable explicit paths surface a fallback diagnostic.- Errors hint at
pi_binarywhen an embedded host is still spawned as Pi. - Wired into the reloadable config paths so a fix applies on the next run; project configs cannot set it.
Bug Fixes
- Embedded editor/SDK hosts no longer need workarounds to run Pi child processes.