Summary
On Windows, the codex-companion plugin fails to start the codex app-server because
child_process.spawn("codex", ...) at scripts/lib/app-server.mjs:188 is invoked
without { shell: true }. Node on Windows does not auto-resolve PATHEXT (.cmd,
.ps1) extensions for spawn unless shell: true is set, so the npm-installed
codex.cmd wrapper is invisible. Result: spawn codex ENOENT.
This causes two user-visible failure modes downstream:
codex-audit / direct review invocations fail fast with spawn codex ENOENT.
codex:rescue (task mode) blocks the foreground for an extended period
(observed ~50 minutes) and /codex:status blocks ~2 hours before erroring,
apparently retrying the failed spawn without surfacing the underlying ENOENT.
Environment
- OS: Windows 11 Home (10.0.26200)
- Node: v22.14.0
- npm: 10.9.2
- codex-cli: 0.131.0 (installed globally via
npm i -g)
- Claude Code with
openai-codex plugin (latest as of 2026-05-19)
- Shell: PowerShell 5.1 (main session); subagent dispatches use Bash via Git for Windows
Reproduction
From PowerShell, codex --version succeeds:
PS> (Get-Command codex).Source
C:\Users\<user>\AppData\Roaming\npm\codex.ps1
PS> codex --version
codex-cli 0.131.0
But Node spawn without shell fails:
PS> node -e 'const{spawn}=require("child_process");const p=spawn("codex",["--version"]);p.on("error",e=>console.log(e.code));'
ENOENT
With shell: true, it succeeds:
PS> node -e 'const{spawn}=require("child_process");const p=spawn("codex",["--version"],{shell:true});p.stdout.on("data",d=>process.stdout.write(d));'
codex-cli 0.131.0
Root cause
scripts/lib/app-server.mjs:188:
this.proc = spawn("codex", ["app-server"], {
cwd: this.cwd,
env: this.options.env,
stdio: ["pipe", "pipe", "pipe"]
});
The plugin already uses the correct pattern elsewhere — scripts/lib/process.mjs:11
sets shell: process.platform === "win32" for its runCommand spawns. The
app-server spawn was missed.
Proposed fix
One-line addition:
this.proc = spawn("codex", ["app-server"], {
cwd: this.cwd,
env: this.options.env,
- stdio: ["pipe", "pipe", "pipe"]
+ stdio: ["pipe", "pipe", "pipe"],
+ shell: process.platform === "win32"
});
Verified locally: applying this patch unblocks the codex-rescue dispatch path
(smoke test completed end-to-end in 53s vs. indefinitely hanging before).
Why this matters
The hang failure mode is particularly costly because it masquerades as Codex
"still working" rather than a config error — users wait for hours before
realizing the task is wedged. A clean ENOENT surface would be better than the
current silent-hang behavior.
Summary
On Windows, the codex-companion plugin fails to start the codex app-server because
child_process.spawn("codex", ...)atscripts/lib/app-server.mjs:188is invokedwithout
{ shell: true }. Node on Windows does not auto-resolve PATHEXT (.cmd,.ps1) extensions forspawnunlessshell: trueis set, so the npm-installedcodex.cmdwrapper is invisible. Result:spawn codex ENOENT.This causes two user-visible failure modes downstream:
codex-audit/ directreviewinvocations fail fast withspawn codex ENOENT.codex:rescue(taskmode) blocks the foreground for an extended period(observed ~50 minutes) and
/codex:statusblocks ~2 hours before erroring,apparently retrying the failed spawn without surfacing the underlying ENOENT.
Environment
npm i -g)openai-codexplugin (latest as of 2026-05-19)Reproduction
From PowerShell,
codex --versionsucceeds:But Node spawn without shell fails:
With
shell: true, it succeeds:Root cause
scripts/lib/app-server.mjs:188:The plugin already uses the correct pattern elsewhere —
scripts/lib/process.mjs:11sets
shell: process.platform === "win32"for itsrunCommandspawns. Theapp-serverspawn was missed.Proposed fix
One-line addition:
this.proc = spawn("codex", ["app-server"], { cwd: this.cwd, env: this.options.env, - stdio: ["pipe", "pipe", "pipe"] + stdio: ["pipe", "pipe", "pipe"], + shell: process.platform === "win32" });Verified locally: applying this patch unblocks the codex-rescue dispatch path
(smoke test completed end-to-end in 53s vs. indefinitely hanging before).
Why this matters
The hang failure mode is particularly costly because it masquerades as Codex
"still working" rather than a config error — users wait for hours before
realizing the task is wedged. A clean ENOENT surface would be better than the
current silent-hang behavior.