@openai/codex-sdk opens a visible codex.exe console window on Windows

Open 💬 2 comments Opened May 21, 2026 by yanxiyue

What is the problem?

When using @openai/codex-sdk from a GUI/background app on Windows, starting a Codex task opens a visible black console window. The window title is the bundled native Codex binary path, for example:

E:\git\github\..\node_modules\@openai\codex-win32-x64\vendor\x86_64-pc-windows-msvc\codex\codex.exe

This appears to be the TypeScript SDK's direct codex.exe child process, not the separate PowerShell helper window tracked in other Windows issues.

Why this matters

@openai/codex-sdk is useful from Electron apps, editor integrations, background workers, and daemons. In those hosts, SDK calls should be able to run non-interactively without flashing or leaving a visible terminal window on the user's desktop.

Environment

  • OS: Windows 10
  • Host: Node/Electron background worker
  • Observed with: @openai/codex-sdk@0.129.0
  • Latest checked: @openai/codex-sdk@0.132.0
  • Native binary package: @openai/codex-win32-x64

Evidence

The latest published @openai/codex-sdk@0.132.0 still spawns the native binary without windowsHide:

const child = spawn(this.executablePath, commandArgs, {
  env,
  signal: args.signal
});

The command is the SDK's JSON exec path, so it is already non-interactive/stdin-stdout based. On Windows, Node will create a visible console window for a console subsystem executable unless the parent passes windowsHide: true.

Expected behavior

When the TypeScript SDK launches Codex in its non-interactive JSON exec mode on Windows, it should not create a visible console window.

Actual behavior

A visible black console window titled with the bundled codex.exe path appears while the task is running.

Suggested fix

Set windowsHide: true on the SDK's child_process.spawn call that launches this.executablePath, or expose a SDK option that allows hosts to pass it through. Since this SDK path uses exec --experimental-json with piped stdio, hiding the console seems like the expected default on Windows.

Related but distinct issues

  • #18984 tracks PowerShell parser child windows spawned by native codex.exe.
  • #20510 tracks long-lived PowerShell helper windows spawned by codex.exe even when the parent launches Codex hidden.

This issue is one level earlier: the TypeScript SDK currently launches codex.exe itself without windowsHide.

View original on GitHub ↗

2 Comments

voyagi · 3 months ago

Two additional spawn sites in the JS layer that also need windowsHide: true:

1. CLI entry point (@openai/codex/bin/codex.js, line ~176)

const child = spawn(binaryPath, process.argv.slice(2), {
  stdio: "inherit",
  env,
});

This is the npm wrapper that launches codex.exe for interactive CLI use. Missing windowsHide: true.

2. Broker lifecycle (scripts/lib/broker-lifecycle.mjs, spawnBrokerProcess)

const child = spawn(process.execPath, [scriptPath, ...], {
  detached: true,
  stdio: ["ignore", logFd, logFd]
});

This spawns a detached background broker process. detached: true without windowsHide: true allocates a new visible console window. This one fires intermittently (when broker sessions need refreshing), producing the "once in a while" flash symptom.

Other spawn sites in the same codebase already use windowsHide: true correctly (app-server.mjs, process.mjs, codex-companion.mjs:spawnDetachedTaskWorker), so this looks like an oversight rather than a deliberate choice.

The fix for both is adding windowsHide: true to the spawn options. It only suppresses console window allocation via CREATE_NO_WINDOW and does not affect stdio piping or inheritance.

Found while debugging on Windows 11 with Codex @openai/codex@0.132.0 and the Claude Code plugin (openai-codex-plugin-cc v1.0.2).

voyagi · 3 months ago

Additional evidence from WMI process tracing on Windows 11 — the native codex.exe and Codex Desktop app (Codex.exe) both spawn child processes without CREATE_NO_WINDOW, producing dozens of conhost.exe console window flashes per minute during active use:

[18:27:16.825] gh.exe    parent=Codex(31000) -> conhost.exe (flash)
[18:27:17.242] git.exe   parent=Codex(31000) -> conhost.exe (flash)
[18:27:17.820] git.exe   parent=Codex(31000) -> conhost.exe (flash)
[18:27:18.232] git.exe   parent=Codex(31000) -> conhost.exe (flash)
[18:27:19.015] gh.exe    parent=Codex(31000) -> conhost.exe (flash)
[18:27:19.400] gh.exe    parent=Codex(31000) -> conhost.exe (flash)
[18:27:19.775] gh.exe    parent=Codex(31000) -> conhost.exe (flash)
[18:27:21.853] node_repl.exe  parent=codex(55732)
[18:27:21.853] pysemgrep.exe  parent=codex(55732)
[18:27:22.051] node.exe       parent=codex(55732)
[18:27:35.789] powershell.exe parent=Codex(31000) -> conhost.exe (flash)

Every child process spawned by the native binary gets its own conhost.exe — that's the visible console window. This is separate from the JS-layer spawn sites I reported earlier (those are now patched locally). The native binaries (codex.exe and Codex.exe) need CREATE_NO_WINDOW (or equivalent Rust CommandExt::creation_flags(0x08000000)) on their Command::new() calls for gh, git, powershell, node, taskkill, etc.

Captured with Win32_ProcessStartTrace WMI event subscription (no polling gaps). Full log has 3500+ entries in ~3 minutes of active Codex use.