Skip to content

Windows: Console window flash on subprocess spawn — root cause analysis and solutions (CREATE_NO_WINDOW, S4U, conhost --headless) #38715

Description

@Nabaatxaneh

Summary

On Windows, spawning console-subsystem processes (powershell.exe, pwsh.exe, cmd.exe, git.exe, etc.) causes a brief console window flash. This affects every bash tool invocation in opencode — each spawn of powershell.exe (and every child it launches) flashes a window. The Board has raised this repeatedly; root cause analysis below.

Root Cause

The fundamental mechanism: when Windows creates a console-subsystem process, conhost.exe allocates and draws the console window during process initialization in kernelbase.dll — before the application entry point runs and before any -WindowStyle Hidden flag or ShowWindow(SW_HIDE) call can execute. The window is on screen for a frame or two before being hidden.

Three specific failure modes:

  1. Node.js child_process.spawn (Desktop app): Missing windowsHide: true + stdio: "pipe". Without these, Node passes CREATE_NEW_CONSOLE (or omits CREATE_NO_WINDOW), forcing a visible console allocation. Fix: spawn(cmd, args, { windowsHide: true, stdio: "pipe" }).

  2. Go os/exec.Cmd (CLI/TUI, any Go-based tool spawn): Missing SysProcAttr.HideWindow = true and/or CREATE_NO_WINDOW (0x08000000) in ProcAttr.SysProcAttr.CreationFlags. Without these, Go's exec.Command inherits or allocates a visible console.

  3. Scheduled Task launched as Interactive logon: powershell.exe -WindowStyle Hidden under Interactive logon still flashes. The "Hidden" flag only hides the window AFTER conhost has drawn it. Fix: set the task Principal to S4U ("Run whether user is logged on or not", LogonType S4U). Session-0 tasks never draw a window. Alternative: use conhost.exe --headless <cmd> as the task action for persistent runtime hosts.

Why -WindowStyle Hidden Is Not Sufficient

-WindowStyle Hidden is a runtime flag that PowerShell processes AFTER conhost.exe has already allocated the console window. The window is drawn, then hidden — but the flash has already occurred. This is a Windows architectural limitation, not a PowerShell bug (see microsoft/terminal#249 for the full discussion).

What "works" but has side effects

  • VBScript shim (wscript.exe + CreateObject("WScript.Shell").Run(cmd, 0, False)): Does hide the console, but triggers a VBScriptDeprecationAlert (Event ID 4096) on every execution on modern Windows — a desktop dialog the user did not ask for. Deprecated approach.

Affected surfaces in opencode

  • bash tool (every PowerShell invocation)
  • git operations (diff, status, commit, etc.)
  • MCP tools using .cmd scripts
  • LSP server subprocesses
  • File watchers and polling
  • Any os/exec or child_process call to console-subsystem binaries

Recommended Fix Strategy

Layer Mechanism Fix
Node.js (Desktop) child_process.spawn { windowsHide: true, stdio: "pipe" } on every spawn
Go (CLI/TUI/server) os/exec.Cmd SysProcAttr.HideWindow = true on every command, or set CREATE_NO_WINDOW in CreationFlags
Scheduled Tasks Task Scheduler Use S4U principal ("Run whether user logged on or not"), not Interactive logon
Persistent runtime hosts Any conhost.exe --headless <cmd>

The key insight: this must be a default on Windows, not an opt-in per-call. Every shell-out to a console-subsystem binary that does not need a visible terminal should suppress the window at the OS level.

References

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions