Skip to content

Windows: secondary Codex session spawns visible console windows for child executable calls #44856

Open

Description

@rbleattler

Summary

On Windows, a primary Codex terminal/session behaves normally, but a second Codex tab/session appears to launch child executable calls in separate visible console windows.

This is reproducible specifically in the secondary session. The primary session does not exhibit the behavior.

Environment

  • Windows 11
  • Codex running in terminal tabs
  • Multiple Codex sessions open concurrently
  • Windows Terminal used as the terminal host

Reproduction

  1. Start a Codex session in one terminal tab.
  2. Run normal work involving shell/tool calls (pwsh, git, gh, etc.).
  3. Open a second terminal tab and start a second Codex session.
  4. In the second session, run work that triggers shell/tool calls.
  5. Observe that many child executable calls spawn their own visible console/terminal windows.

Actual behavior

  • In the first/main Codex session, child commands execute without spawning visible external console windows.
  • In the second Codex session, many executable calls open a separate visible terminal/console window.
  • The windows typically show a successful exit, e.g.:
[process exited with code 0 (0x00000000)]
You can now close this terminal with Ctrl+D, or press Enter to restart.
  • Changing Windows Terminal's setting to close automatically on clean exit reduces the symptom from accumulated windows to a brief visible flicker, but the secondary-session child consoles are still being created and remain disruptive.

Expected behavior

Child executable calls in additional Codex sessions should behave like those in the primary session: remain attached to/contained within the existing terminal/PTY (or otherwise run hidden) rather than creating visible transient console windows.

Important differentiator

This does not happen in the main/first Codex tab. It appears tied specifically to running a second concurrent Codex session/tab.

That suggests this may involve secondary-session console/PTY inheritance or Windows process creation flags rather than a generic Windows shell configuration issue.

Impact

The behavior is especially disruptive for autonomous/agent-style workflows that execute many short-lived commands, since each subprocess can cause a visible window flash.

A screenshot is available showing multiple short-lived terminal windows created by the secondary session.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    windows-osIssues related to Codex on Windows systems
    tool-callsIssues related to tool calling
    on Sep 11, 2026
  2. rbleattler commented on Sep 11, 2026

    @rbleattler
    Author

    Additional reproduction detail: one child process spawned by the secondary Codex session was not ephemeral. A separate visible window remained open while running:

    C:\Users\Robert Bleattler\.codex\packages\standalone\releases\0.154.0-x86_64-pc-windows-msvc\bin\codex-code-mode-host.exe
    

    This makes the issue look less like generic short-lived shell flashing and more like the secondary session is causing Codex child/host processes themselves to be launched into separate visible console windows. The behavior is still specific to the second concurrent Codex tab/session; the primary session does not do this.

  3. github-actions commented on Sep 11, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  4. argszero commented on Sep 12, 2026

    @argszero

    Your differentiator is the whole clue, and it points at the shared app-server daemon. It explains both halves of the symptom, including the non-ephemeral codex-code-mode-host.exe window.

    The two sessions are not running the same server:

    • A session that starts before any background server exists runs an embedded app-server inside the TUI process (AppServerClient::InProcess), i.e. inside the Windows Terminal tab that already owns a console.
    • Once a managed daemon exists, later sessions attach to it instead: maybe_probe_default_daemon_socket (tui/src/lib.rs:461), app_server_target_for_launch (:929-956, the LocalDaemon arm at :948-954), can_reuse_implicit_local_daemon (:990-1001). If the socket is missing or the handshake fails, that session silently falls back to embedded (lib.rs:520-525).

    That daemon is a separate, console-less process: it is launched with DETACHED_PROCESS | CREATE_BREAKAWAY_FROM_JOB and all three stdio streams detached (app-server-daemon/src/backend/pid_start.rs:91-95 and :207). It is started by codex agents (cli/src/main.rs:2735-2747) or from inside the TUI.

    So the same tool call behaves differently depending on which session runs it:

    • child of the TUI process → inherits that tab's console → invisible;
    • child of the detached daemon → there is no console to inherit, so Windows allocates a new one for any console-subsystem child spawned without CREATE_NO_WINDOW → visible window. With Windows Terminal as the default terminal host that is a new terminal window, which is exactly what your screenshot shows.

    The parent executable is the same codex.exe in both cases; only its console state differs. This is not hypothetical in this repo: the identical spawn was already observed and shim-validated on Windows in #37599 — codex-code-mode-host.exe (PE subsystem 3) is started by code-mode/src/remote_session/connection.rs:156-169, which pipes stdio and sets no Windows creation flags, and a CREATE_NO_WINDOW shim removed the window with the protocol unchanged. That report is still accurate on current main (:157), and it is the non-ephemeral window you saw.

    Sites that spawn a console-subsystem child without that flag (fixing only one of them leaves the rest flashing):

    1. utils/pty/src/win/job.rs:125-126 prepare_suspended_spawn — sets only CREATE_SUSPENDED; shared by the hooks runner (hooks/src/engine/command_runner.rs:237), the git helper (git-utils/src/git_process.rs:45), and both MCP launchers (rmcp-client/src/stdio_server_launcher.rs:299, rmcp-client/src/http_headers.rs:467). CREATE_NO_WINDOW | CREATE_SUSPENDED is already used in-tree (windows-sandbox-rs/src/setup_launch.rs:30).
    2. utils/pty/src/pipe.rs:192 — a plain command.spawn() with no creation_flags at all. This is the route ordinary agent shell commands take: the tool's tty defaults to false (core/src/tools/handlers/unified_exec.rs:70-72) → sandboxing/src/spawn.rs:122/:132.
    3. code-mode/src/remote_session/connection.rs:157 — the code-mode host (item 1 of Windows: codex-code-mode-host opens a visible Windows Terminal window #37599).
    4. app-server-daemon/src/backend/pid_start.rs:103 — the app-server --managed-daemon --help capability probe, also a console-subsystem child with null stdio and no flag.

    The repo already treats this as a requirement for its own daemon-side helpers: app-server-daemon/src/managed_install.rs:79/:106, app-server-daemon/src/update_loop.rs:448 (powershell.exe), and the elevated sandbox maps it deliberately (windows-sandbox-rs/src/process.rs:109-114 — CREATE_NO_WINDOW only when stdio is supplied and the mode is NoWindow).

    Cheap checks that separate this from a generic terminal-settings theory, run in the session that pops windows:

    1. /status — this hypothesis predicts a background-service row (unix://…codex.sock; tui/src/status/remote_connection.rs:19-43 → status/card.rs:832-838), and none in the first session.
    2. Parent PID of one popped window's child (Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,Name) — the predicted parent is a standalone codex.exe app-server --listen unix:// … process (app-server-daemon/src/backend/pid.rs:354-363), not the TUI's own PID.
    3. Fresh state: stop the daemon (codex app-server daemon stop; state is visible in codex doctor), start both tabs before any daemon exists → both should be silent; then start the background server (codex agents) and open a new tab → from then on the new tab pops windows.

    If those three hold, this is the daemon's child-spawn flags rather than terminal configuration. I can prepare a patch plus a Windows-only assertion that no console is allocated for the freshly spawned child — but I cannot exercise the Windows path from my side, so your read-back on those checks would be worth more than my guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingtool-callsIssues related to tool callingwindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions