Repository navigation
Windows: app-server daemon opens a visible console window for every hook and shell command it runs #44768
Description
Summary
On Windows, once the shared app-server daemon is running (codex app-server daemon start), any Codex TUI session in the same CODEX_HOME silently attaches to it. From then on every hook (pre_tool_use, post_tool_use, user_prompt_submit, …) and every shell command of that session is spawned by the daemon instead of by the TUI — and each one opens a visible console window for as long as the child runs. With per-tool-call hooks configured, that is several windows per tool call, i.e. dozens per minute during normal agent work.
The same session without the daemon (embedded app-server inside the TUI) shows no windows at all.
Environment
- Windows 11 Pro 10.0.26200, Windows Terminal 1.24.11911 set as default terminal
- codex-cli 0.154.0 (standalone install,
~/.codex/packages/standalone/current/bin/codex.exe) - Source referenced below: commit
ddea03ad049142943bdbf13e937b1d67e8c1ba0c(2026-09-10) - Hooks configured in
<project>/.codex/hooks.json(PreToolUse/PostToolUse command hooks), shellpwsh
Reproduction
codex app-server daemon start- Open a Codex TUI in a project that has command hooks (or just run any shell command); make sure the TUI attaches to the daemon (default launch, no
-c/--worktree/--oss). - Send a prompt that runs a shell command.
Observed: for each hook and for the shell command a console window flashes up (Windows Terminal, "OpenConsole.exe -Embedding"), visible for the lifetime of the child (typically 0.5–2 s; longer for long-running commands). Process chain captured with a monitor:
window "C:\Program Files\PowerShell\7\pwsh.exe"
<- OpenConsole.exe -Embedding
<- conhost.exe
<- pwsh.exe -Command "..." (the hook / the command)
<- codex.exe app-server --listen unix:// (the daemon; its parent has exited)
codex app-server daemon stop makes the windows stop immediately; the TUI falls back to its embedded server.
Cause (from the source)
- The daemon is launched with no console at all:
codex-rs/app-server-daemon/src/backend/pid_start.rs:207command.creation_flags(DETACHED_PROCESS | CREATE_BREAKAWAY_FROM_JOB);
- Hook and command children are console programs spawned with only
CREATE_SUSPENDED— noCREATE_NO_WINDOW:
codex-rs/hooks/src/engine/command_runner.rs:234-241(JobObject::spawn_contained, fallbackcreation_flags(0)), and
codex-rs/utils/pty/src/win/job.rs:126A console application whose parent has no console gets a fresh one from Windows, and with Windows Terminal as the default terminal that fresh console is a visible window.command.creation_flags(CREATE_SUSPENDED).kill_on_drop(true);
Other daemon-side spawns already avoid this correctly, e.g. managed_install.rs:79,106 and update_loop.rs:448 use CREATE_NO_WINDOW. The hook/command path does not.
What did not help
Starting the daemon process with CREATE_NO_WINDOW instead of DETACHED_PROCESS (so it owns a hidden console) keeps the daemon and its long-lived children (MCP servers, codex-code-mode-host.exe) invisible, but the hook/command pwsh children still get visible windows. So inheriting the parent's hidden console is not sufficient; the flag has to be set on the hook/command spawn itself.
Expected
Hooks and shell commands run by the app-server daemon should not create visible console windows — i.e. spawn them with CREATE_NO_WINDOW (as the updater and installer paths already do), or otherwise ensure they attach to a hidden console.
Impact
Any Windows user who starts the shared daemon (needed for codex agents, remote control, or any external client of the control socket) and has command hooks configured gets a window storm proportional to the agent's tool-call rate, and the only remedy is to stop the daemon.
Activity
argszero commentedon Sep 11, 2026
Thanks — this is a well-instrumented report, and your diagnosis of the mechanism (spawn-flags) is essentially right. I verified every line you cited on current
mainand they all check out. Two things may still be missing from the fix list, both of which matter for the "every hook and every shell command" half of the symptom.Your citations, re-verified
app-server-daemon/src/backend/pid_start.rs:169—creation_flags(DETACHED_PROCESS | CREATE_BREAKAWAY_FROM_JOB): confirmed (imports at:110-111). The daemon really does launch with no console.hooks/src/engine/command_runner.rs:234-241—JobObject::create(),job.spawn_contained(&mut command), fallbackcommand.creation_flags(0): confirmed (:234/:237/:241).utils/pty/src/win/job.rs:126—prepare_suspended_spawn→creation_flags(CREATE_SUSPENDED): confirmed.So the hook path is exactly as you describe, and your negative control (starting the daemon with
CREATE_NO_WINDOWleaves thepwshchildren visible) is the right experiment — it correctly locates the fix on the child spawn rather than on the daemon.1. The fix belongs in
prepare_suspended_spawn, not per-callerCREATE_SUSPENDEDis applied by the shared job helper (utils/pty/src/win/job.rs:126), which is reached throughspawn_contained(:169-185). Every caller that goes through that helper has the same gap, and the ones you cited are not the whole set:hooks/src/engine/command_runner.rs:237(your case)git-utils/src/git_process.rs:44-50rmcp-client/src/stdio_server_launcher.rs:290-295(MCP stdio servers)rmcp-client/src/http_headers.rs:464-468A per-caller edit fixes the instance; editing
prepare_suspended_spawntoCREATE_NO_WINDOW | CREATE_SUSPENDEDfixes the class, and the combination is already the in-repo precedent for a suspending spawn —windows-sandbox-rs/src/setup_launch.rs:30does exactlycreation_flags(CREATE_NO_WINDOW | CREATE_SUSPENDED).2. The shell-command path does not use that helper at all
This is the part I think is missing. For
exec_commandthe agent tool'sttyargument defaults tofalse(core/src/tools/handlers/unified_exec.rs:70-72), so a default shell command does not go through a ConPTY. It goes:core/src/unified_exec/process_manager.rs:1337→sandboxing/src/spawn.rs:110-139→ for the non-tty branchutils/pty/src/pipe.rs(spawn_process:330,spawn_process_no_stdin:353, both exported atutils/pty/src/lib.rs:17-19).And in
pipe.rsthe creation flags are simply never set — the job containment there is created around an already-started child:prepare_suspended_spawn/spawn_containedare not called on this route, so addingCREATE_NO_WINDOWto the job helper alone would not silence the shell-command windows — the second half of your symptom would survive the fix. This also explains why yourCREATE_NO_WINDOW-on-the-daemon experiment left thepwshchildren visible: they are not inheriting a console through a job-assigned suspended spawn, they are being created by a path that has no console flags whatsoever.Two notes on this route:
spawn_containedis not used, there is an explicit accepted race betweencommand.spawn()(:192) and the job assignment on the returned handle (:200-205; the comment at:195-196says as much). For a hook the job matters for tree termination; doingCREATE_NO_WINDOWhere would need to keep the post-spawn assignment semantics intact.windows-sandbox-rs/src/process.rs:109-114only mapsCREATE_NO_WINDOWwhen stdio is supplied ((Some(_), ConsoleMode::NoWindow) => CREATE_NO_WINDOW, all other arms0), and the one non-helper caller passesConsoleMode::Inherit(windows-sandbox-rs/src/unified_exec/backends/legacy.rs:120, reached fromspawn_process_with_pipes:109). TheNoWindowcase is currently reserved for the FS helper (windows-sandbox-rs/src/bin/command_runner/win.rs:359-361). Note also that the defaultWindowsSandboxLevel::Disabled(protocol/src/config_types.rs:297-299) means the unsandboxedpipe.rsroute is the one most users actually hit.Suggested split
CREATE_NO_WINDOW | CREATE_SUSPENDEDinutils/pty/src/win/job.rs:126— covers hooks, git, MCP stdio and the HTTP-headers helper in one edit.CREATE_NO_WINDOWon the non-suspending spawn inutils/pty/src/pipe.rs:192(and the no-stdin sibling if it is a separate body) — covers agent shell commands.ConsoleMode::Inheritatlegacy.rs:120should follow the same policy.A regression test is awkward without a real console, but a Windows-only unit assertion that the built
Command's creation flags includeCREATE_NO_WINDOWfor each of the three spawn sites would at least lock the policy in.JerrySkywalker commentedon Sep 14, 2026
I investigated this further on native Windows and built a local implementation to validate the spawn-flag diagnosis at runtime.
A few findings may be useful for the internal fix:
CREATE_NO_WINDOWneeds to reach the final child CreateProcess boundary. Applying it only to an intermediate shellCommanddoes not cover unified execution.CREATE_SUSPENDED; setting the no-window flag earlier is insufficient if a latercreation_flags(...)replaces it.I validated the local implementation with:
I also manually tested the resulting Windows UX: the positive control produced an intentional console window, while the patched background workload and TUI shell commands produced no window flash and no focus steal.
Two existing ConPTY failures were reproduced against baseline source and were unchanged by the fix.
The implementation that tested cleanly used a flag-aware JobObject spawn path that composes caller flags with
CREATE_SUSPENDED, plusCREATE_NO_WINDOWat the separate non-suspending pipe-backed spawn boundary. Hook/Git/MCP fallback paths retained the no-window flag as well.The fully validated version was tested before my final upstream rebase. The same patch subsequently rebased cleanly onto current
main(374c4b2d828321cfa3d3fc69ce66870f8b7fd01f), but I did not rerun the full suite after that last rebase.I have the exact tested diff and detailed runtime evidence locally if maintainers want any specific part of it reproduced or shared.
i-dedova commentedon Sep 15, 2026
Reproduced on 0.154.0 standalone (Windows 11 Pro, Windows Terminal as the default terminal) — adding one manifestation and two data points I don't think are captured above.
cua_node hosted runtimes: with the daemon running, a TUI session immediately spawns visible consoles for
AppData\Local\OpenAI\Codex\runtimes\cua_node\<hash>\bin\node_repl.exeand...\bin\node.exe. A Win32_Process parent walk shows both are children of the daemon process itself (node_repl.exe→ the daemon'snode.exe→ daemon), created right at TUI session start — so the daemon-hosted code-mode/REPL runtimes hit the same flag gap as the paths enumerated above.Severity during agent turns: during tool-call-heavy work the spawns repeat per tool call at 10+ visible windows per second, which makes the machine effectively unusable until
daemon stop.Control: the same TUI session performs the same tool calls with zero visible windows once the daemon is stopped, so the running daemon is the necessary condition for the storm in interactive use — consistent with the daemon-side spawn sites rather than TUI-local spawning.
JerrySkywalker commentedon Sep 16, 2026
Follow-up after completing the Windows runtime validation and deploying the local compatibility build. I also found and corrected one flaw in my earlier acceptance harness, so this supersedes the presentation-specific part of my previous comment.
Final root-cause / implementation model
The reliable rule I ended up with is: background presentation state is not transitive on Windows;
CREATE_NO_WINDOWhas to reach each finalCreateProcessboundary that creates a console-subsystem child.The implementation that held up in testing uses two distinct patterns:
CREATE_SUSPENDEDrather than replacing them. In practice the suspended launch needsCREATE_NO_WINDOW | CREATE_SUSPENDEDwhen the caller is a background/non-interactive path. If containment setup falls back and suspension is removed, the no-window bit must remain.CREATE_NO_WINDOWdirectly on the actualCommand::spawn()boundary. The JobObject assignment happens after process creation on this route, so fixing onlyprepare_suspended_spawndoes not cover ordinary non-TTY shell execution.That same policy had to be preserved across rebuilt/fallback commands rather than applied only at one higher-level caller.
The audited spawn families included redirected/pipe-backed shell execution, command hooks, internal Git, automatic/plugin Git, local stdio MCP, the HTTP-header helper path, Code Mode host launch, and relevant Windows helper/fallback paths. Interactive/PTY paths were intentionally left interactive.
Correction to my earlier runtime evidence
I later performed a separate provenance audit of the acceptance harness. It found one real problem: the harness began the root app-server
startupobservation phase and then launchedcodex.exe app-server --stdiowith harness-suppliedDETACHED_PROCESS.That means my earlier root app-server startup presentation result was not authoritative: the harness itself suppressed that root console. Specifically, the old
legacy-background/startupandcode-mode/startuppresentation claims had to be withdrawn/qualified.The provenance audit also established that this did not substitute the wrong Codex binary or production daemon: source→binary binding, daemon identity, isolated control state, package coherence, and phase attribution were all independently proven. It also did not invalidate the independently attributed product-created shell/hook/Git/MCP/Code Mode-host/fallback child evidence.
I rebuilt the relevant acceptance path so that the harness applies no presentation-changing flags (
DETACHED_PROCESS,CREATE_NO_WINDOW,SW_HIDE, etc.) to the product process being measured.Decisive unmasked A/B on 0.154.0
With that corrected harness I ran the same real daemon-backed workload against two isolated 0.154.0 subjects:
Official 0.154.0:
Patched R4C 0.154.0:
Direct
app-server --stdiostartup was also rerun unmasked for both subjects and initialized successfully. The key bug-control result, however, is the real daemon-backed official-vs-patched shell/hook A/B above.I then activated the complete managed 0.154.0 patched package on the Windows machine used for testing. The running shared daemon resolves to the patched managed release and its executable hash matches the active
currentrelease. A normal TUI production smoke (including a real PowerShell command with a deliberate delay and the existing hook path) completed without popup/focus-steal behavior.Forward applicability
I also semantically forward-ported the same source-level policy rather than treating the built 0.154 binary as reusable across versions.
A validated port was frozen on an upstream-main base at
83dc7d11e873f43533dc898d50fae71cf4d55dc5. Subsequent drift through8f38d5a877da8c5c2c0b5158e72bb5f2290a3157had zero direct changes to the patch-touched source paths, and the exact sealed patch applied cleanly without manual production-source edits.Focused clean-vs-patched checks at
8f38…completed as follows:One limitation: I could not complete the
8f38…Code Mode runtime execution because the matching localrusty_v8build artifact required bycodex-code-mode-host.exewas unavailable, and I deliberately did not substitute a mismatched host/archive or start a V8-from-source build just to make the matrix green. The selected app-server Code Mode tests consequently failed on the common missing host binary prerequisite, not on observed patched behavior. I therefore classify current-main Code Mode runtime coverage there as build-prerequisite-blocked, not passed.cua_node/node_repl.exereportI also tried to qualify the later
cua_node/node_repl.exemanifestation reported in this thread. On my machine no realcua_noderuntime existed in either expected local runtime root, so I did not synthesize or install one just for the test.Therefore my result for that manifestation is explicitly:
I am not claiming this patch covers the
cua_nodedescendant path described by @i-dedova. Their report remains useful evidence of another final-boundary manifestation that should be checked where that hosted runtime is available.Practical takeaway
For an upstream fix, I would still recommend treating this as a spawn-policy class rather than a one-off hook fix:
CREATE_NO_WINDOWwithCREATE_SUSPENDEDin the shared JobObject path;CREATE_NO_WINDOWat the non-suspending pipe-backed spawn boundary;I have kept the exact validated source patch and detailed process/window evidence in a public fork/local evidence set and can provide a smaller diff or reproduce a particular spawn family if maintainers want one. I am not opening a PR because the repository's contribution guidance does not accept external code PRs.
ncuJack12 commentedon Sep 25, 2026
Confirming a continuing report on a newer release from Windows 11 Home 25H2 (OS build 26200.9457).
codex-cli 0.157.0(global npm installation).0.157.0-x86_64-pc-windows-msvc.1.24.11911.0.26.917.9434.0is also installed, but the process chain below belongs to the active CLI session.During normal Codex use, the user sees terminal windows repeatedly popping up. Read-only process inspection while this session executes shell tools shows the active
codex.exe --yoloCLI attached to acodex.exe app-server --listen unix:// --managed-daemonchild. The shell tool'spowershell.exeis a child of that daemon and has aconhost.exechild:This matches the daemon-side spawn path described in this issue and shows the symptom is still relevant on 0.157.0. I did not stop the daemon or run a daemon-off control, since that would interrupt the active session. No personal paths or raw logs are included.
tnisizawa commentedon Sep 26, 2026
Confirming this is still reproducible in the Windows Codex Desktop app:
26.917.9434.00.157.1-x86_64-pc-windows-msvc7.6.5Microsoft Windows NT 10.0.26200.0 x64Every shell tool call opens a visible console window titled
C:\Program Files\PowerShell\7\pwsh.exe. In repeated controlled tests, five separate trivial shell calls produced five visible windows. Process inspection showed thepwsh.exeparent is the managedcodex.exe app-server --listen unix:// --managed-daemonprocess.Controls tested, each followed by a full app restart where applicable:
[features] unified_exec = true: no changesandbox_mode = "workspace-write"withwindows.sandbox = "elevated"andsandbox_private_desktop = true: no changeAll experimental settings were restored afterward. This confirms the daemon-side child-window behavior remains present in
0.157.1and is not specific to an old PowerShell version or the selected terminal host.GinnieII commentedon Sep 26, 2026
Same issue on Windows 11 Pro (26200), Codex CLI 0.157.1 via npm, launched inside Orca terminal panes.
app-server --listen unix:// --managed-daemon, detached, no console), every hookcommandWindowsentry (run aspowershell.exe -NoProfile -Command "...") opens a new console. Windows Terminal is the default terminal app, so each one becomes a WT window showing error2147942632 (0x800700e8)(pipe closed) because the hook has already exited.--no-daemonand runningcodex app-server daemon stop→ 0 new console windows for the same prompt and hook set.CREATE_NO_WINDOW(or equivalent), as the in-process TUI path effectively did.Seamless switching and AFK for Claude Code and Codex
fidonan commentedon Sep 26, 2026
Adding a native Windows 0.157.1 reproduction, one additional sandbox-helper spawn site, and a small locally tested patch.
Environment and reproduction
0.157.1, initially installed via npm.26200; Windows Terminal1.24.11911.0as the default terminal.Write-Output helloandgit --versioncaused transient console windows even when the commands succeeded.A process/window trace captured a visible
PseudoConsoleWindowbelonging tocodex-windows-sandbox-setup.exe, alongside a new Windows Terminal window, before the command runner and PowerShell started:Additional source finding
In run_setup_refresh_payload at rust-v0.157.1, stdin/stdout/stderr are redirected to null, but the helper is started without
CREATE_NO_WINDOW. This refresh path is distinct from the setup launch path that already supplies the no-window flag.The same refresh omission exists in the source tags 0.155.0 and 0.156.0. Separately,
daemon_auto_startis absent in 0.155.0, experimental/default-off in 0.156.0, and stable/default-on in 0.157.1. That is consistent with this becoming noticeable after upgrading; I did not run the older binaries.Local patch and observed results
The attached patch, based on
rust-v0.157.1(36650394c5b38c2990ccf2a3457165ca3e9d9726), changes four files: 8 insertions, 5 deletions.CREATE_NO_WINDOWto sandbox refresh.CREATE_NO_WINDOW | CREATE_BREAKAWAY_FROM_JOB.Validation:
initialize+command/execcomparison reproduced visible Terminal/Git windows with a harness-suppliedDETACHED_PROCESSlaunch; theCREATE_NO_WINDOWlaunch returned the expected output without a new terminal window. This is a controlled launch-mode experiment, not independent proof of production daemon startup behavior.This does not establish that changing the daemon flag alone fixes every descendant. In particular, the hook/MCP/fallback paths discussed above were not covered by our acceptance check, and I am not claiming to invalidate the earlier final-spawn-boundary findings.
Test limitations: a broader sandbox library run had 244 passed, 1 failed, 5 skipped. Its elevated setup test failed in an incomplete local fixture (missing helper;
ShellExecuteExWreturned 1223), so that suite is not claimed as passing. Full workspace tests were not run. The patch has not been rebased onto or tested against currentmain.Locally tested source patch against rust-v0.157.1
Datakeysystems commentedon Sep 26, 2026
Additional Windows 0.157.1 reproduction with a failed rollback/stop path (26 Sep 2026):
@openai/codex@0.155.0(npm ls -g @openai/codex --depth=0andcodex --versionboth confirm it).codex app-server daemon versionstill reportsstatus: running,cliVersion: 0.155.0,appServerVersion: 0.157.1, andmanagedCodexVersion: null. Two livecodex.exeprocesses resolve to~/.codex/packages/app-server-daemon/releases/0.157.1-x86_64-pc-windows-msvc/bin/codex.exe.powershell.exechildren. A timed process snapshot observed newOpenConsole.exeprocesses during the same burst.codex app-server daemon stopexits 1 withError: app server is running but is not managed by codex app-server daemon. The immediately following version query still reports the 0.157.1 app-server running.This leaves command-heavy Codex sessions effectively unusable even after the npm CLI rollback. The unmanaged-server error also resembles #46468 and #37893. A supported way to stop or replace the unmanaged app-server, plus the child-process no-window fix discussed here, would help. I have not edited Codex configuration or binaries.
6 remaining items
ThisCCL commentedon Sep 28, 2026
Additional reproduction from a Windows 11 user running Codex CLI 0.157.1 with the OmO/LazyCodex 5.0.1 plugin (2026-09-28).
.../.codex/packages/app-server-daemon/releases/0.157.1-x86_64-pc-windows-msvc/bin/codex.exe app-server --listen unix:// --managed-daemon(observed PID 35408).plugin_hooks = true, andomo@sisyphuslabsis enabled.pwsh.exe.codexthrough the global Node/pnpm entry point, then launched the same 0.157.1 package'sbin/codex.jswith an absolute Bun executable path. The visible-window symptom persisted. This comparison changes the JavaScript launcher runtime but keeps the native Codex version,CODEX_HOME, managed daemon, and plugin; it does not establish a clean Bun installation or an independent daemon comparison.pre-tool-use-recommending-git-bash-mcp.jsonandpost-tool-use-checking-lsp-diagnostics.json. Both usepowershell -NoProfile -ExecutionPolicy Bypass -File .../node-dispatch.ps1 ...viacommandWindows; the configured Git Bash executable (D:\Git\bin\bash.exe) is only for the Git Bash MCP and does not replace these hook commands. This increases the number of daemon child launches per tool call.Source checked against current
openai/codexmain (1cc7e2361237ce7244430ee1d581c77f95c57ac8):pid_start.rs:209still usesDETACHED_PROCESS | CREATE_BREAKAWAY_FROM_JOB;command_runner.rs:227-231usesspawn_containedand resets creation flags to zero on fallback. Current LazyCodex source (8cbc467bb3845f0ec74c80a6e0dd573204909ff1) retains the two PowerShell hook declarations: pre-tool, post-tool.The local screenshots establish the visible symptom, but this report did not capture each window's process parent at creation time or run a
--no-daemoncontrol. The managed-daemon spawn path is a strong match to the process traces already in this issue; this comment does not claim that every visible window on the machine came from a hook.This issue or PR was generated by LazyCodex.
Tag: lazycodex-generated
SinkaiZhang commentedon Sep 28, 2026
Additional confirmed A/B reproduction on Windows 11 Pro (OS build 26100) with Codex CLI 0.157.1, launched from the VS Code integrated terminal using PowerShell:
codexmode (shared background server), the agent ranWrite-Output POPUP_TEST. The command succeeded and printedPOPUP_TEST, but a separate, blank black console window visibly popped up.codex --no-daemon, the same command succeeded and printedPOPUP_TESTwithout any popup.codex --no-daemon resume;Write-Output RESUMED_SESSION_EXEC_OKcompleted with exit code 0 and no popup..codexdirectory ACL problem. Commands then executed successfully in both modes, so this is not the earlier sandbox setup failure.This comparison narrows the popup to the shared-daemon execution path in this setup; it does not prove the exact child process or process-creation flags responsible. Expected: agent-run, noninteractive shell commands should not open a visible console window.
--no-daemonis an effective workaround here. No raw logs, private paths, or account details are attached.Always start Codex with --no-daemon on Windows
genebukh-npm commentedon Sep 28, 2026
I can reproduce this on Windows 11. When my Codex session uses the shared daemon, each
pwshcommand opens a visible console window. Running Codex with--no-daemonavoids the popups while the same commands still work. I now use--no-daemonfor my Windows Codex sessions.Started with 0.157, now on 0.158
ScienHAC commentedon Sep 28, 2026
Same root cause as #48826:
JobObject::prepare_suspended_spawnincodex-rs/utils/pty/src/win/job.rs(used by the hooks command runner) only setsCREATE_SUSPENDED, neverCREATE_NO_WINDOW, so hook/shell commands spawned viaspawn_containedon Windows always show a console window. Full diagnosis + fix: #48826 (comment)brunocouri commentedon Sep 29, 2026
Additional confirmation from another Windows 11 system.
I originally noticed this while using Codex through Orca, so I first suspected Orca hooks / terminal integration. I then reproduced the same visible console flashing with Codex launched directly from PowerShell, outside Orca.
Environment:
10.0.262007.6.5A/B result on the same machine:
During affected runs I observed short-lived process chains such as:
With the managed app-server path there were also additional helper / command child processes receiving console hosts.
The key finding for me was the rollback test: after uninstalling the newer build and installing:
the flashing stopped immediately on the same Windows environment.
sonofsmog commentedon Sep 29, 2026
Follow-up from the Windows machine in my earlier 0.157.1 report: updating the npm CLI to 0.158.0 has not fixed the daemon-associated terminal-window spawning. During ordinary interaction with Codex—even simply sending a message—roughly five extra terminal windows flicker across the screen as Codex runs its background processes. This makes normal use disruptive; it is not confined to a special command-heavy task. Another Windows user in this thread also reports the symptom persisting on 0.158.
Read-only checks on 2026-09-28:
The live
codex.exe app-server --listen unix:// --managed-daemonprocess resolves to~/.codex/packages/app-server-daemon/releases/0.157.0-x86_64-pc-windows-msvc/bin/codex.exe; itspid-update-loopcompanion is from that same release. Thus the 0.158.0 CLI upgrade left the symptom in place and left an older app-server process running. This local check does not isolate how a freshly started 0.158.0 app-server behaves. The version mismatch also continues the daemon lifecycle problem in my earlier rollback/stop report.Please keep this issue open and test an ordinary interactive turn on Windows, including the background child processes it starts, along with daemon version replacement after a CLI upgrade.
ScienHAC commentedon Sep 29, 2026
#48826 (comment) pls check
yushizhan commentedon Sep 29, 2026
Still reproducible on codex-cli 0.159.0 (npm install, Windows 11 Enterprise 10.0.26200, Windows Terminal 1.24.11911, default terminal = "Let Windows decide"). Adding a concrete trigger and a verified workaround.
Symptom
Just launching
codexfrom PowerShell (no prompt submitted) flashes 3 console windows during startup.What flashes
I hooked
EVENT_OBJECT_SHOW(SetWinEventHook) and resolved each shown window's owning process and parent:44460is the managed daemon, not the TUI:At the same instant the daemon logs (
logs_2.sqlite) show the TUI asking it to run the status-line branch probe:So even
command/execone-off commands (not only hooks / shell tool calls) spawned by the daemon get a fresh console. The daemon has no console of its own, so each console-subsystem child (git.exe) is allocated a new one, which gets handed off to Windows Terminal via default-terminal delegation → visible flash.Workaround (verified)
codex --no-daemon→ same window hook captures zero git/console windows on startup (the embedded app-server inherits the TUI's console).Expected
Children spawned by the daemon on Windows (
command/exec, hooks, shell tools, stdio MCP servers) should useCREATE_NO_WINDOW(or be attached to a hidden console / ConPTY), matching the TUI-embedded behavior.Related: #48074 (same CLI+daemon scenario, root cause not identified there), #48023 (stdio MCP servers), #46949.
action-control commentedon Sep 29, 2026
Additional data point from a Windows user (Codex app 26.924, app-server-daemon 0.157.1, Windows 11 26200, Windows Terminal as default terminal).
Measured with a 15 ms poll of top-level visible windows, correlated with a process-creation log (parent = the resident
codex.exe app-server --managed-daemon):rev-parse --git-dir,rev-parse HEAD,rev-parse --abbrev-ref HEAD,remote get-url origin), more during work (status --porcelain,remote -v).pwsh.exe -NoProfile -Command "node -e ..."windows in ~7 minutes (plugin hooks), plus one for astop-review-gatehook per turn end.notifyexecutable (codex-computer-use.exe turn-ended), see also [bug] Computer Use helper's black console briefly appears when a turn completes #33254. It is started by absolute path, so it is not covered by fixes that only touch git or shell commands.Switching the default terminal to Windows Console Host only turned Windows Terminal windows into classic console windows.
Workarounds that removed windows for us (not a fix, and they do not cover hooks):
git.exewrapper placed next tocodex.exe(Windows searches the application directory first), which runs the real git with CREATE_NO_WINDOW and passes stdio, args and the exit code through. Startup windows went from 4 to 0. It stops working when the daemon package directory changes on update.The hook
pwsh.exewindows remain, which matches the analysis above.Rcarraway3 commentedon Sep 29, 2026
Additional Windows reproduction with process-parent evidence and mitigation results.
Environment:
Observed:
Submitting a prompt causes many visible PowerShell windows. During the initial capture, eight hook PowerShell processes were started in the same second, all parented directly to the managed Codex app-server process. Each had its own conhost.exe child. Sanitized example:
The other captured hook commands included prompt checks, skill synchronization, and lifecycle dispatch. Ordinary assistant shell-tool execution also appeared as a PowerShell child of that same daemon.
Mitigation attempted:
This supports investigating console suppression on the daemon's outer hook/shell child spawn: hiding grandchildren cannot suppress a console already created for the outer PowerShell process. CREATE_NO_WINDOW is a candidate fix for non-interactive launches, consistent with the investigation above; we have not patched or independently verified the native launcher implementation.
Expected: background command hooks and non-interactive shell tools should preserve stdin/stdout/stderr and exit status without opening visible console windows. The current repeated popups significantly disrupt normal use.
tstager commentedon Sep 30, 2026
Remaining console window: persistent PowerShell parser
Thanks for #49164 and #49308. After comparing a locally verified Windows console-suppression patch against current
main, the persistent PowerShell parser is the one remaining launch path from that patch that is still missing suppression.Verified base:
bd5185820d(currentmainwhen tested), Windows 11 build 26200, using Windows PowerShell (powershell.exe) as selected by the existing test helper.In
PowershellParserProcess::spawn, the code constructs a plainstd::process::Commandand callsspawn()withoutCREATE_NO_WINDOW. It does not use the new background-command or Job Object helpers.Reproduction and results
I added the regression below to the existing Windows-only tests module in that file. It starts an isolated test process with
DETACHED_PROCESS, launches the actual persistent parser, verifies that parsingGet-Locationworks, and checks the parser console window from the isolated process.On the unchanged production code, the test failed on both nextest attempts with:
Adding a Windows-only
CREATE_NO_WINDOWflag immediately beforecommand.spawn()made the same regression pass. The full affected unit suite then passed:The minimal local fix is:
Reusing the new shared
background_commandhelper would also fit the upstream implementation if preferred. This parser is a background helper with piped stdin/stdout; interactive ConPTY creation is separate.Detached-parent regression added to the existing Windows test module
The test intentionally checks
GetConsoleWindow()rather than requiringAttachConsole()to fail: a headless PowerShell process can still expose an attachable console with no window.This is a focused reproduction on the source commit above, not a full runtime validation of the official 0.159.2 binary. Sharing it here in accordance with the contribution guide's request for issue reports and root-cause analysis instead of external PRs. Related: #48074.
babelllll commentedon Sep 30, 2026
Windows Console Popup Fix for Codex App-Server Daemon
This note records a local workaround for the Windows console windows opened by the Codex app-server daemon. It is a technical summary, not an upstream patch.
Verified result
The useful verified result is narrower than
--no-daemon:This was verified without disabling
daemon_auto_start. A normally launched console remained visible in the control test, while the daemon-owned console stayed hidden and the visible-console count returned to zero during hook and command execution.Environment
openai/codex#44768#46949,#48074,#18984#48138,#48238,#48483Timeline
September 27: first diagnosis
After updating Codex, every user message caused a burst of visible
pwsh.exewindows.The first suspected causes were scheduled health checks, terminal-host settings, and hook commands. Those checks found a separate once-per-minute popup source, but disabling it did not remove the burst caused by sending a message.
Process tracing showed that the app-server daemon launched the console processes. The relevant behavior was:
CREATE_NO_WINDOW.pwsh -Command ....UserPromptSubmitandStophook batches together.Stopping the daemon removed the windows but also dropped the active app-server session, so that was rejected as the normal fix.
The 0.159 alpha contained upstream fixes for some MCP, code-mode, and pipe subprocesses, but the hook path still flashed. The local workaround was a small Node launcher that respawns every configured hook with both
windowsHideandCREATE_NO_WINDOW(0x08000000) while preserving stdio and exit codes. All hook entries were routed through it.Verification showed that the hook-process burst disappeared. A single-flash remained: the app-server still created an outer PowerShell process for command execution, and that process was outside the hook configuration.
September 29: regression after the stable update
The CLI on
PATHwas updated to stable 0.158.0 while the manually deployed daemon remained 0.159.0-alpha.9.Two failures returned:
spawn()cannot directly launch.cmdfiles on Windows (spawn EINVAL).cmd /C.The launcher was changed so
.cmdand.batcommands go throughcmd.exe /d /s /c, while still usingCREATE_NO_WINDOW. Both affected hooks then returned exit code 0.That fixed the hook layer only. The remaining outer PowerShell window required a different boundary: the daemon needed its own hidden console so its children could share it instead of allocating new visible consoles.
Hidden daemon console
The daemon startup was changed from the detached/no-console mode to a hidden-console process:
codex app-server --listen unix:// --managed-daemonwith a hidden window.EnumWindows,GetClassName,IsWindowVisible) rather thanProcess.MainWindowHandle, which is unreliable for console windows.After this change, the previously visible console burst was no longer observed during hook and command execution.
Verification record
nowinrouting: no new visible terminal in the test window..cmdforwarding: both previously failing hooks returned 0.Operational caveat
The hidden daemon must remain running for this workaround. Starting Codex with
--no-daemon, or disablingdaemon_auto_start, avoids one popup path but also removes the shared daemon used by the rest of the local workflow. It is not the fix used here.Suitable upstream report
The useful report for Codex is narrow:
No credentials, local paths, or private configuration are required for that report.
etraut-openai commentedon Sep 30, 2026
This should now be fixed as of hotfix release
0.159.2. Your daemon (background app server) should update automatically, but you can also update it manually using the/daemonslash command in the CLI.