Skip to content

[Bug]: Grok ACP never connects on Windows when grok is a .cmd shim, and opens a blank console every health check #29088

Description

@ElliotDrel

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server (code lives in packages/provider-acp and packages/provider-grok)

Root cause

On Windows, if grok resolves to a .cmd shim, T3 starts the Grok ACP process with shell: true and detached: true. In that combination grok.exe does not inherit T3's stdio pipes. It ends up attached to its own new console, so:

  • initialize never reaches Grok, and the probe times out after 20 seconds.
  • The console is visible, which is the blank window.

The chain:

  1. grokAcpRuntimeProcessOwnership always returns ownDetachedProcessGroup: true, including on win32 (packages/provider-grok/src/server/acpSupport.ts:83).
  2. AcpSessionRuntime turns that into detached: true (packages/provider-acp/src/server/AcpSessionRuntime.ts:1447).
  3. resolveSpawnCommand runs .cmd and .bat files with shell: true, so cmd.exe is the detached process and grok.exe is its child.
  4. Effect's buildSpawnOptions sets windowsHide: options.windowsHide ?? !detached, so detached also means not hidden.

The grok --version and model probes don't set detached, so they pass. That is why T3 reports "Grok CLI is installed but ACP initialize failed. Model options may be incomplete."

Both files above are from main at 333f7a6, so this looks unfixed there. I confirmed the same behavior in the 0.1.6 bundle.

Steps to reproduce

  1. On Windows, make grok resolve to a .cmd shim that is ahead of grok.exe on PATH. For example, %USERPROFILE%\.local\bin\grok.cmd:
    @echo off
    "C:\path\to\.grok\bin\grok.exe" %*
  2. Leave the Grok provider binaryPath as grok and enable the provider.
  3. Wait for a provider health check, which runs about every 5 minutes.

Expected behavior

The probe finishes hidden, initialize succeeds, and no window appears.

Actual behavior

  • A blank Windows Terminal window opens, titled "...\.grok\bin\grok.exe" agent stdio.
  • After 20 seconds T3 kills it. The window stays open showing [process exited with code 1 (0x00000001)].
  • The provider status changes to the ACP initialize failed warning.
  • This repeats on every health check.
  • From reading the code, Grok sessions use the same makeGrokAcpRuntime spawn path, so they should fail the same way. I did not test a Grok thread directly.

Impact

Major degradation or frequent failure

Version or commit

T3 Code 0.1.6 (desktop). Same code on main at 333f7a6.

Environment

Windows 11 Pro 10.0.26200, Grok CLI 1.0.70, Windows Terminal installed.

Logs or stack traces

Spawn matrix. Same initialize payload as T3 (including clientInfo and _meta), with a 22 second limit, run outside T3 under Node:

Case Target detached windowsHide Result
A grok.exe false true OK, 545 ms
B grok.cmd (shell: true) false true OK, 630 ms
C grok.exe true true OK, 657 ms
D grok.cmd (shell: true) true true Timeout
E grok.exe true false OK, 777 ms
F grok.cmd (shell: true) true false (T3 today) Timeout

Only shell: true plus detached: true fails. windowsHide makes no difference to the hang, so setting windowsHide: true alone would not fix it (case D).

Stdio proof. A throwaway .cmd shim runs a Node script that reports what kind of stdio it received:

not-detached: cmd exit=0 grandchild={"stdin":"Socket","stdout":"Socket","stderr":"Socket"} pipeReceivedOutput=true
detached:     cmd exit=0 grandchild={"stdin":"ReadStream(TTY)","stdout":"WriteStream(TTY)","stderr":"WriteStream(TTY)"} pipeReceivedOutput=false

This takes Grok out of the picture: under a detached cmd.exe, the grandchild gets a console instead of the pipes.

T3 server trace:

checkGrokProviderStatus: "Grok ACP initialize probe failed or timed out." { errorTag: "Timeout" }
initialize span: ~20000 ms, exit Interrupted

~/.grok/logs/unified.jsonl. In failing runs Grok boots normally, then never handles initialize. Each one stops here, with no built auth_methods for ACP response line:

last line: "model catalog: auth refresh watcher started"

Cases D and F produced this same log signature, which ties the matrix to the failures inside T3.

Timing on my machine:

  • Every ACP probe in the traces before a reboot at 11:42 PM succeeded in 1-4 seconds.
  • All 4 ACP probes after the reboot failed.
  • The T3 process tree now has .local\bin at PATH index 4 and .grok\bin at index 27, so grok resolves to the .cmd.
  • I can't prove what the PATH order was before the reboot, so why it flipped is unconfirmed. The bug itself doesn't depend on that, since it reproduces from the spawn options alone.

Suggested fix

Don't pass detached: true on Windows in AcpSessionRuntime, while keeping ownDetachedProcessGroup so process-tree cleanup still runs. Windows has no POSIX process groups to own, and cleanup there already appears to go by PID through the Windows tree terminator.

// packages/provider-acp/src/server/AcpSessionRuntime.ts
...(options.ownDetachedProcessGroup === undefined
  ? {}
  : { detached: options.ownDetachedProcessGroup && hostPlatform !== "win32" }),

This gives case B above, which passes. It also fixes the window, because windowsHide then defaults to true. I tested those spawn options, but not this patch in a T3 build.

Avoid setting ownDetachedProcessGroup: false for win32 in acpSupport.ts instead. terminateOwnedProcessGroupImpl returns early when it is not true, so that would skip tree cleanup.

A regression test could assert that a win32 ACP spawn with ownDetachedProcessGroup: true doesn't pass detached: true. apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts already covers this option.

Workaround

Either of these should avoid it. Neither has been tested inside T3:

  • Set the Grok provider binaryPath to the full path of grok.exe. That skips the shell, which is case E above. checkGrokProviderStatus will still run.
  • Disable the Grok provider. checkGrokProviderStatus returns before spawning anything when it's disabled.

Activity

  1. ElliotDrel commented on Nov 4, 2026

    @ElliotDrel
    ContributorAuthor

    Note

    🤖 gpt-6.1-sol responding on behalf of Elliot

    Reviewed candidate: #30544

    Recommended over #29098 : both make the same non-Windows detachment gate while retaining ownership; this candidate additionally asserts retained PID cleanup and reports an actual Windows Grok .cmd ACP handshake. No unresolved inline review threads found. Console-window disappearance was not visually checked, so that portion of the report remains a verification gap. Avoid merging both duplicate production changes.

    Source/patch and GitHub review audit only in this pass; no new runtime verification. The candidate remains open and unmerged.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions