Skip to content

Windows: every child cmd.exe (git probes, MCP spawns) flashes a visible console window and steals focus despite windowsHide being set #52281

Closed as duplicate

Description

@beyondrocks

Summary

On Windows 11, opencode-cli (v2.0.20, serve --service, Bun-compiled) spawns short-lived child processes through cmd.exe (cmd /d /s /c "git rev-parse --git-common-dir", git rev-parse --show-toplevel, git config user.email, MCP npx ...). Each spawn creates a visible console window that takes foreground focus, then disappears. During active sessions this happens at ~1.5??/sec for 30??5 second bursts (100+ windows per burst), making the app nearly unusable ??focus is ripped away from the editor continuously.

Environment

  • Windows 11, x64
  • OpenCode Desktop 2.0.20 ??opencode-cli.exe serve --service (v2.0.20, built with Bun 1.4.2)
  • Default terminal application: Windows Console Host (reproduced with both Console Host and Windows Terminal as default)

Reproduction

  1. Open OpenCode Desktop on Windows with a git repository project.
  2. Send messages / run sessions normally.
  3. Observe bursts of cmd.exe console windows flashing and stealing focus.

Captured command lines (parent = opencode-cli.exe serve --service):

cmd /d /s /c "git rev-parse --git-common-dir"
cmd /d /s /c "git rev-parse --show-toplevel"
cmd /d /s /c "git config user.email"
cmd /d /s /c "npx -y obsidian-mcp-server@latest"

Observed via a WinEvent hook (EVENT_OBJECT_SHOW, EVENT_SYSTEM_FOREGROUND): each spawn produces SHOW + FOREGROUND events on a ConsoleWindowClass window at a fixed rhythm (~500??00ms apart, ~100 windows per 45s burst).

Expected behavior

Child processes spawned for internal git probes/MCP must not create visible windows or steal focus.

Analysis

  • packages/util/src/cross-spawn-spawner.ts (at tag v2.0.20) does pass windowsHide: process.platform === "win32" to child_process.spawn, and the string windowsHide:!0 is present in the shipped opencode-cli.exe.
  • However the windows still appear. Suspected cause: windowsHide is ineffective for this spawn path on Windows ??likely the combination with the cmd.exe wrapper / shell option / Bun's node:child_process compat layer. Known upstream references: child_process - windowsHide not working with detached: true nodejs/node#21825 (windowsHide ignored with detached), and the distinct observation that detached: command.options.detached ?? process.platform !== "win32" interacts with the hide flag.
  • Control experiment on the same machine: a Bun 1.4.2 compiled binary (GUI subsystem, no console) spawning cmd.exe with windowsHide: true does not create a window; windowsHide: false does. So Bun honors the flag in isolation ??the effective spawn path in opencode-cli must be dropping it (or spawning with a flag combination that defeats it).
  • Also observed: git rev-parse probes run at ~1.5??/sec for 30??5s at a time during active sessions. Regardless of window visibility, this polling rate for git discovery seems high; caching Repository.discover results might reduce the spawn volume substantially.

Suggested fix

  • Ensure CREATE_NO_WINDOW (not just STARTF_USESHOWWINDOW/SW_HIDE) is applied to every internal child spawn on Windows, including the cmd.exe /d /s /c wrapper path and MCP server spawns.
  • Alternatively avoid the cmd.exe wrapper entirely for git (it is a native .exe; spawning it directly needs no shell).
  • Consider caching git repository discovery instead of re-running rev-parse per operation.

Related

Workaround currently used

A local WinEvent hook script hides each console window immediately on EVENT_OBJECT_SHOW and returns focus to the app. Users should not need this.

Activity

  1. github-actions commented on Sep 30, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    • #52266: Windows child processes, including git and MCP spawns, flash visible console windows on v2.0.20.
    • #51887: OpenCode 2 repeatedly opens foreground console windows on Windows from spawned processes.
    • #42440: Console windows flash on every subprocess spawn in a Windows v2 build.
  2. a2belugin commented on Oct 1, 2026

    @a2belugin

    Confirming this on the Desktop build too — the problem is still present in 1.18.34.

    Environment: Windows x64, opencode desktop 1.18.34 (Electron, %LOCALAPPDATA%\Programs\@opencode-aidesktop\OpenCode.exe).

    Repro: launch desktop, open a git working copy → burst of console windows at startup and again on changes/refresh.

    Captured live (Win32_Process polling loop). Parent of every line below = the OpenCode.exe node utility process (--type=utility --utility-sub-type=node.mojom.NodeService):

    git rev-parse --git-dir
    git rev-parse --show-toplevel
    git rev-parse --git-common-dir
    git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false for-each-ref --format=%(refname:short) refs/heads
    git --no-optional-locks ... symbolic-ref --quiet --short HEAD
    git remote get-url origin
    git --no-optional-locks ... diff --no-ext-diff --no-renames --name-status -z HEAD -- .
    git --no-optional-locks ... diff --no-ext-diff --no-renames --numstat -z HEAD -- .
    git --no-optional-locks ... status --porcelain=v1 --untracked-files=all --no-renames -z -- .
    

    Worth noting: this is the VCS status/diff discovery path, not snapshots. Setting top-level "snapshot": false removed the snapshot git init / git config / write-tree spawns, but the windows above remained.

    Second, independent source — the codegraph MCP server. codegraph.js serve --mcp --path <repo> (parent = its own node.exe) also spawns git without hiding:

    git -C <repo> config --get core.excludesFile
    git -C <repo> ls-files -z -o -i --exclude-standard --directory
    git rev-parse HEAD
    

    Why this is desktop-specific (CLI/TUI is not affected): the desktop is a GUI Electron process with no console. Every console child (git.exe/cmd.exe) spawned without CREATE_NO_WINDOW allocates a new console window. The TUI runs inside a console, so its git children inherit that console and no new window appears.

    In resources/app.asar, @opencode/Git runs git via the process service with options that omit windowsHide:

    appProcess.run(make58("git", [...cfg, ...args], {
      cwd, env, extendEnv: true,
      stdin: opts.stdin ?? "ignore", stdout: "pipe", stderr: "pipe"
      // no windowsHide
    }))

    and the central spawner never sets it either:

    const handle2 = NodeChildProcess.spawn(command.command, command.args, spawnOptions);

    …while the MCP spawn path does set windowsHide: process.platform === "win32". So the flag is applied inconsistently.

    Can confirm the problem still exists on 1.18.34 desktop.

  3. xxmisaoxx commented on Oct 6, 2026

    @xxmisaoxx

    Additional data point: still present on OpenCode Desktop 2.0.24 (bundled opencode-cli 2.0.24). I captured the full parent chain and exact command lines with a process monitor, which may help confirm the call site.

    Environment

    • opencode version: Desktop 2.0.24 (bundled opencode-cli 2.0.24, serve --service)
    • OS: Windows 10 Pro, build 19045 (win32 x64)
    • Shell: cmd.exe (%ComSpec%), default terminal application: Windows Console Host
    • Install/channel: Desktop, latest channel
    • Active plugins: opencode-supermemory@latest only (no third-party plugins; snapshots disabled in config)

    Observation

    While using the app I get bursts of visible cmd.exe console windows (they briefly take focus). Captured during a single burst (local time 14:18:04–14:18:21, ~17 s):

    • 53 × cmd.exe spawned with parent = opencode-cli.exe serve --service (PID observed)
    • 46 of them were the shell wrapper: cmd.exe /d /s /c "git ..."
    • 56 × git.exe children of those cmd.exe
    • Rate ≈ 3 windows/second

    Command lines seen (parent = ...\ai.opencode.desktop\cli\2.0.24\opencode-cli.exe serve --service):

    cmd.exe /d /s /c "git rev-parse --git-common-dir"
    cmd.exe /d /s /c "git rev-parse --show-toplevel"
    cmd.exe /d /s /c "git config user.email"
    

    Additional Context

    • The burst lines up with location services booted for each open project in the server log. With multiple projects open, the probe burst multiplies per location.
    • This is consistent with the analysis in this issue: the shipped binary contains windowsHide:!0 (e.g. spawn(..., { detached: !0, windowsHide: !0, ... }) and the process-options helper defaults windowsHide = !detached on win32), yet the cmd.exe /d /s /c wrapper path still produces a visible console window.
    • Reproduced with no third-party plugins and snapshots disabled, so this appears to be the internal git-discovery call site rather than a plugin/MCP path.
    • No client-side workaround found; reducing the number of open projects only reduces the burst size.

    Happy to provide more detail or run additional captures if useful.

  4. xxmisaoxx commented on Oct 8, 2026

    @xxmisaoxx

    Correction to my earlier comment on this issue.

    I originally wrote "no third-party plugins", but I later isolated the real source on the same machine: the remaining cmd.exe /d /s /c "git ..." spawns come from the opencode-supermemory plugin (v2.0.15, which is also the current latest on npm) — not from core.

    Its dist/index.js (source src/services/tags.ts) runs git via execSync without windowsHide:

    execSync("git rev-parse --git-common-dir", { cwd: directory, encoding: "utf-8", stdio: ["pipe","pipe","pipe"] });
    execSync("git rev-parse --show-toplevel",  { cwd: directory, encoding: "utf-8", stdio: ["pipe","pipe","pipe"] });
    execSync("git config user.email",           { cwd: base,      encoding: "utf-8", stdio: ["pipe","pipe","pipe"] });
    execSync("git remote get-url origin",       { cwd: directory, encoding: "utf-8", stdio: ["pipe","pipe","pipe"] });

    These match the captured lines exactly. execSync always runs through a shell, so on Windows it becomes cmd.exe /d /s /c "git ...". Because plugins execute inside the console-less opencode-cli serve --service process, each call without windowsHide allocates a visible console window — which is why the parent process in my capture showed as opencode-cli.exe. Disabling the plugin stopped the bursts on my machine.

    This is consistent with the "plugins run inside the console-less service" line of investigation (see also #53730), and supports adding the windowsHide guidance/helper for plugin authors that is being requested — core can't fix third-party call sites.

    Filed against the plugin: supermemoryai/opencode-supermemory#105

  5. hxbb00 commented on Oct 10, 2026

    @hxbb00

    Confirmed still reproducible on v2.0.26 (latest release channel, Windows 11).

    Environment

    • opencode version: 2.0.26 (@opencode/cli, installed globally via npm)
    • OS: Windows 11, Windows_NT 10.0.26300 (win32 x64)
    • Terminal: Windows Terminal (WT_SESSION set), TERM=xterm-256color
    • Shell: PowerShell 7.6.6 (pwsh.exe)
    • Install/channel: release (latest)
    • Active plugins: superpowers@git+https://github.com/obra/superpowers.git
    • Git: 2.55.0.windows.5 at C:\Program Files\Git\cmd\git.exe

    What I see

    Flashing git.exe console windows (sometimes stealing focus / popping new Windows Terminal tabs) during normal TUI use. Matches the pattern described above: the managed background service (serve --service, detached, no console) spawns console-subsystem children, so the kernel allocates a fresh visible console per spawn.

    Log evidence

    %USERPROFILE%\.local\share\opencode\log\opencode.log, all role=server, 21 git spawns within a short session — e.g.:

    timestamp=2026-10-10T14:33:55.446Z level=INFO message="spawning process" command="C:\\Program Files\\Git\\cmd\\git.EXE" args="[\"rev-parse\",\"--git-dir\",\"--git-common-dir\",\"--show-toplevel\"]" cwd="D:\\...\\project" role=server
    timestamp=2026-10-10T14:33:55.508Z level=INFO message="spawning process" command="C:\\Program Files\\Git\\cmd\\git.EXE" args="[\"remote\",\"get-url\",\"origin\"]" role=server
    timestamp=2026-10-10T14:33:55.911Z level=INFO message="spawning process" command="C:\\Program Files\\Git\\cmd\\git.EXE" args="[\"--no-optional-locks\",\"-c\",\"core.autocrlf=false\",...,\"symbolic-ref\",\"--quiet\",\"--short\",\"HEAD\"]" role=server
    

    Shell tool calls also spawn visible pwsh.EXE consoles from the same detached service.

    Workaround status

    • opencode --standalone avoids the flashes (service inherits the TUI console), as previously reported by @ramagdev — confirms the detached-service root cause.

    Happy to test a fix build (next channel) if one lands.

  6. Forrest-Gump0927 commented on Oct 13, 2026

    @Forrest-Gump0927

    Still reproducible on OpenCode Desktop 2.0.27 (Windows 11) — data from a 12-hour process-creation monitor

    Environment

    • OpenCode Desktop 2.0.27 — bundled opencode-cli.exe serve --service (%APPDATA%\ai.opencode.desktop\cli\2.0.27\opencode-cli.exe)
    • Windows 11 x64 (zh-CN); default terminal application: Windows Terminal
    • Workspace: not a git repository — so the git probes seen here are not repo-driven
    • Third-party plugins: still being audited (a leftover oh-my-opencode folder exists under %LOCALAPPDATA%)

    Method

    Continuous WMI subscription to __InstanceCreationEvent on Win32_Process (0.3 s polling), logging every new process with its parent PID/name and full command line, ~12 h.

    Parent -> child counts (my own interactive shell excluded)

    663  opencode-cli.exe -> cmd.exe
    207  ?               -> cmd.exe
    105  ?               -> git.exe
     29  opencode-cli.exe -> powershell.exe
     12  opencode-cli.exe -> rg.exe
     25  chrome.exe      -> cmd.exe     (unrelated: Adobe Acrobat Chrome-extension native messaging host)
    
    • Console-host window creations in the same period: WindowsTerminal.exe 289 + OpenConsole.exe 291, all reported with parent svchost.exe (console handoff) — i.e. one visible console per spawn.
    • User-visible symptom: black console windows at roughly 0.5 s intervals in bursts, matching the ~500-1000 ms rhythm in the original report. Screenshots and recordings usually miss them because the window is gone before capture completes.

    Notes

    • WMI snapshot polling undercounts very short-lived processes, so the real spawn rate is likely higher than the counts above.
    • Because the workspace is not a git repository, the git.exe spawns are most likely the plugin-update / MCP-related probes discussed in server: unpinned plugin update check flashes visible git console window on Windows #50868. Exact cmd.exe command lines were not captured in this run — happy to add them if useful.
    • Setting the default terminal application to Windows Console Host does not remove the flashes here either, consistent with the OP's note that both defaults reproduce.
  7. Forrest-Gump0927 commented on Oct 13, 2026

    @Forrest-Gump0927

    Follow-up — exact command lines captured (Desktop 2.0.27, Windows 11)

    I extracted the command line of every opencode-cli.exe -> cmd.exe spawn from the same ~12 h monitor log (379 total, parent = opencode-cli.exe serve --service):

    294  C:\WINDOWS\system32\cmd.exe /d /s /c "git rev-parse --git-common-dir"
     36  C:\WINDOWS\system32\cmd.exe /d /s /c "git config user.email"
      3  C:\WINDOWS\system32\cmd.exe /d /s /c "git remote get-url origin"
     46  cmd.exe with empty/unavailable command line (parent had already exited when polled)
    

    Additional data points:

    • npx / MCP spawns in the entire log: 0 — no MCP server is started through a shell on this machine, so MCP is not a factor here.
    • No plugins involved: the only local plugin is a small user-written token-usage-toast.js that contains no spawn/exec/child_process usage, and the config file has no plugins entries. So these git probes come from the core.
    • The workspace is not a git repository, yet git rev-parse --git-common-dir is spawned roughly 24×/hour, in tight bursts during active sessions — consistent with the per-session/per-message git probe path.
    • This machine had a V1 install upgraded to V2 (shared ~/.config/opencode), whereas a clean V2 install on another machine shows no flashing at all — which suggests the trigger frequency may depend on session/state carried over, but the spawn itself is core behavior.
  8. neriousy commented on Oct 20, 2026

    @neriousy
    Member

    Thanks for the report and the process captures. We're tracking this same Windows child-process console flashing in #52266, so I'm closing this as a duplicate. Please follow that issue for updates.

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