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:
-
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" }).
-
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.
-
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
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
bashtool invocation in opencode — each spawn ofpowershell.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.exeallocates and draws the console window during process initialization inkernelbase.dll— before the application entry point runs and before any-WindowStyle Hiddenflag orShowWindow(SW_HIDE)call can execute. The window is on screen for a frame or two before being hidden.Three specific failure modes:
Node.js
child_process.spawn(Desktop app): MissingwindowsHide: true+stdio: "pipe". Without these, Node passesCREATE_NEW_CONSOLE(or omitsCREATE_NO_WINDOW), forcing a visible console allocation. Fix:spawn(cmd, args, { windowsHide: true, stdio: "pipe" }).Go
os/exec.Cmd(CLI/TUI, any Go-based tool spawn): MissingSysProcAttr.HideWindow = trueand/orCREATE_NO_WINDOW(0x08000000) inProcAttr.SysProcAttr.CreationFlags. Without these, Go'sexec.Commandinherits or allocates a visible console.Scheduled Task launched as Interactive logon:
powershell.exe -WindowStyle Hiddenunder 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: useconhost.exe --headless <cmd>as the task action for persistent runtime hosts.Why
-WindowStyle HiddenIs Not Sufficient-WindowStyle Hiddenis a runtime flag that PowerShell processes AFTERconhost.exehas 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
wscript.exe+CreateObject("WScript.Shell").Run(cmd, 0, False)): Does hide the console, but triggers aVBScriptDeprecationAlert(Event ID 4096) on every execution on modern Windows — a desktop dialog the user did not ask for. Deprecated approach.Affected surfaces in opencode
bashtool (every PowerShell invocation)gitoperations (diff, status, commit, etc.).cmdscriptsos/execorchild_processcall to console-subsystem binariesRecommended Fix Strategy
child_process.spawn{ windowsHide: true, stdio: "pipe" }on every spawnos/exec.CmdSysProcAttr.HideWindow = trueon every command, or setCREATE_NO_WINDOWin CreationFlagsconhost.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
windowsHide: truepassesCREATE_NO_WINDOWtoCreateProcessWsyscall.SysProcAttr.HideWindow/syscall.CREATE_NO_WINDOWon Windows