[Bug / Architecture] Background tasks via run_command freeze conversation permanently when child process blocks on stdin (#1121)

Hi Antigravity team,

We identified an architectural deadlock scenario where a background task launched via run_command can permanently freeze the agent conversation loop.

Core Issue

When a CLI child process transitions to the background (after WaitMsBeforeAsync expires) and subsequently blocks on stdin (for instance, native Windows ssh.exe without -n or subshell quote stripping), the output log stays at 0 bytes.

Because system instructions strictly mandate reactive wakeup (“Do NOT poll or loop on status… The system will automatically notify you”), and the task runner currently lacks:

  1. Automatic stdin detachment for non-interactive background tasks
  2. A default task execution timeout / watchdog
  3. Stall detection for extended 0-byte output

The agent loop never receives a wakeup event, causing the conversation to freeze indefinitely until manual intervention (>27 hours observed in production).

Full Report & Reproduction Steps

A detailed report with logs, process trees, and suggested mitigations has been submitted on GitHub:
:backhand_index_pointing_right: [Bug] Background tasks via run_command freeze conversation permanently when child process blocks on stdin (lack of watchdog / timeout) · Issue #1121 · google-antigravity/antigravity-cli · GitHub

Hoping to see a task-level watchdog or default stdin null-routing in upcoming releases!

Hi @GeraldHuang0203,

Could you please share a few details:

  • The Antigravity Version you are using?
  • The Operating System you are using?
  • If possible, can you please share the reproduction steps

Hi @GeraldHuang0203 and @Ambati_Rajendra,

A screen recording here will literally show 27 hours of a static cursor. The agent has not crashed; it is executing its system prompt contract with flawless obedience.

This is a textbook protocol-level deadlock between the CLI task supervisor and the agent instruction model. Having inspected the issue telemetry from GitHub Issue #1121 and reproduced the process lifecycle on Windows 11, the anatomy of the freeze is straightforward:


The Anatomy of the Deadlock

  1. The System Prompt Mandate:
    The agent’s native system prompt explicitly forbids polling:

    “IMPORTANT: Do NOT poll or loop on status to wait for completion. The system will automatically notify you with a message when the command finishes. Simply proceed with other work or stop calling tools after launching a command.”
    The agent is strictly conditioned to yield turns and await an asynchronous push event via the messaging harness.

  2. The Supervisor stdin Inheritance:
    When run_command exceeds WaitMsBeforeAsync (e.g. 5,000 ms), the CLI hands the execution to the background runner. However, the spawned subshell process maintains an open standard input handle. When a utility like native Windows ssh.exe (or an interactive PowerShell sub-prompt triggered by quote escaping) expects input, it blocks indefinitely waiting on stdin.

  3. The Silent Loop:
    Because stdin never receives an EOF or byte input, the child process emits 0 bytes of output and never terminates. Because the child never terminates, the supervisor never emits a reactive task completion event. And because the agent is ordered never to poll, the entire conversation remains locked forever.

(A related failure mode noted by @shleder on GitHub occurs when background stdout/stderr pipes lack active, non-blocking drain loops, saturating the 64 KB kernel buffer and deadlocking the child process on write operations).


Recommended Engineering Fixes for the Antigravity Team

  1. Automatic stdin Detachment on Background Handoff:
    For non-daemon background tasks, the task supervisor must automatically disconnect or redirect stdin to NUL (Windows) or /dev/null (POSIX) immediately upon asynchronous transition, unless explicitly marked as interactive.
  2. Supervisor Watchdog & Zero-Byte Telemetry Gate:
    The supervisor should enforce a default timeout or a zero-byte activity watchdog (e.g. if a non-daemon task produces 0 bytes of I/O for 10-15 minutes). Rather than leaving the socket dormant, inject an actionable synthetic notification back into the agent context (TaskStalledError: Child process waiting on input or inactive).
  3. Asynchronous Pipe Draining:
    Ensure all background stdout/stderr descriptors are drained asynchronously to avoid kernel pipe saturation.

Immediate Client-Side Workaround for Developers

For anyone running commands that delegate to the background on Windows:

  • Remote SSH: Always enforce stdin redirection with the -n flag:

    ssh -n user@host "command"
    
  • Script Isolation: Avoid multi-nested quotes in inline command strings; write execution logic to a temporary script file on disk and execute the script directly.

  • Agent-Side Watchdog via Schedule: If launching an asynchronous task prone to hanging, pair it with a conditional one-shot timer to guarantee a wake-up call:

    schedule(DurationSeconds=600, TimerCondition="<task_id>", Prompt="Check if background task has stalled")
    

Gerald has documented the telemetry thoroughly in Issue #1121. Hopefully the CLI team can patch the stdio handle inheritance in the next release.