Agent shell hangs on rg invocations without an explicit path (stdin not a TTY)

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

When Cursor’s agent runs rg (ripgrep) via its shell tool without an explicit path argument, the process hangs indefinitely instead of completing in seconds.

Root cause: rg’s stdin heuristic. When no path argument is given, ripgrep checks whether stdin is a TTY. If it is, it searches the current working directory; if it isn’t, it reads from stdin instead. The agent’s shell wraps every command in cursorsandbox with stdin connected to a Unix domain socket, so the TTY check fails and rg silently waits forever for input on stdin that never arrives.

Symptoms:

  • The rg process sits at ~0.0% CPU in state S (sleeping), accumulating essentially no CPU time, while the agent’s shell tool reports it as “still running” and eventually backgrounds it.
  • lsof shows FD 0 as a Unix socket, not a TTY.
  • The exact same command run in a regular interactive Terminal in the same directory finishes in ~1–2 seconds.
  • Appending . (or any explicit path) to the rg invocation fixes the hang.

This is a high-frequency footgun in real agent sessions because the agent often shells out to rg directly (which Cursor’s tool docs actively recommend over grep). The built-in Grep tool is unaffected because it implicitly passes the workspace root as the path.

Steps to Reproduce

  1. Open Cursor in a moderately sized repo (I reproduced in a ~100k-file Node monorepo, but any non-trivial repo works).

  2. In an Agent chat, ask the agent to run an rg command without a path argument, e.g.:

    rg -c "assert\.ok\(" --type js -g "*.spec.js"
    
  3. Observe that the command never returns. The shell tool reports it as still running and eventually moves it to background.

  4. Open a regular macOS Terminal, cd to the same directory, and run the exact same command. It completes in ~1–2 seconds.

  5. (Optional) While the agent’s rg is hung, inspect it:

    ps -o pid,pcpu,time,stat -p <rg_pid>     # ~0.0% CPU, state S, ~0:00.00 CPU time
    lsof -p <rg_pid> | awk '$4 ~ /^0/'       # FD 0 is "unix", not a TTY
    
  6. Re-run the same command via the agent but with . appended:

    rg -c "assert\.ok\(" --type js -g "*.spec.js" .
    

    It completes immediately with correct results, confirming the hang is rg’s stdin fallback, not anything else about how the agent runs the command.

Expected Behavior

rg invoked by the agent should behave the same as rg invoked from a normal terminal: when no path argument is given, it should search the current working directory and return results in seconds, not block forever on a stdin that will never produce data.

Any of the following would resolve it:

  • Wire stdin to /dev/null (or close it) for commands run by the shell tool, so rg sees EOF immediately and falls through to searching cwd.
  • Allocate a pty for the shell tool so rg’s TTY check succeeds.
  • Update the agent’s tool documentation/system prompt to instruct it to always pass an explicit path when invoking rg directly. (The shell tool docs already steer the agent toward rg over grep; adding a sentence about always passing a path would be a small change.)

Operating System

MacOS

Version Information

Version: 3.3.30 (Universal)
VSCode Version: 1.105.1
Commit: 3dc559280adc5f931ade8e25c7b85393842acf30
Date: 2026-05-09T18:28:42.332Z
Layout: editor
Build Type: Stable
Release Track: Default
Electron: 39.8.1
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Darwin arm64 25.5.0

For AI issues: which model did you use?

Most recent issue seen on claude-opus-4-7-thinking-xhigh, but I’m almost 100% certain I’ve seen this across many different models

Additional Information

Environment

  • ripgrep: 15.1.0
  • Default shell: zsh

Evidence the process is blocked on stdin, not slow

A stuck rg invoked by the agent had been running for 19 minutes when inspected; it had accumulated essentially no CPU time:

PID    ELAPSED  %CPU  TIME      STAT
3096   19:23    0.0   0:00.01   S

lsof on the same PID confirms FD 0 is a Unix domain socket, not a TTY:

rg  3096  user  0u  unix 0x7a1c8e2ecfa67e52  ->0x1be40e439438bbc

For comparison, the same rg invocation run by hand in an interactive Terminal in the same cwd completed in 1.81s and produced the expected results.

Process tree (from ps)

The agent’s command is wrapped roughly like this (truncated):

/Applications/Cursor.app/.../helpers/cursorsandbox --policy /var/folders/.../sandbox-policy-xxx -- /bin/zsh -c "<wrapper script> -- <user command>"
 └─ /bin/zsh -c "..."
     └─ rg -c "assert\.ok\(" --type js -g "*.spec.js" -g "integration-tests/**"

Stdin to the inner zsh (and therefore to rg) is a unix socket inherited from the cursorsandbox wrapper, which is what trips rg’s “stdin is not a TTY → read from stdin” heuristic.

Why this is more than a minor papercut

  • The shell tool’s own description tells the agent to use rg instead of grep, but doesn’t tell it to pass a path. So the agent reaches for rg constantly and falls into this trap.
  • Each hang typically wastes ~minutes per occurrence (the agent waits, then backgrounds, then sometimes retries), and consumes a model turn slot in the meantime.
  • The built-in Grep tool is unaffected because it implicitly passes the workspace root as the path, which suggests the cleanest fix is either matching that behavior at the shell-tool layer (e.g. close/redirect stdin to /dev/null) or instructing the agent in the tool description.

Workaround currently used
A workspace rule telling the agent to always append . (or another explicit path) when shelling out to rg.

Does this stop you from using Cursor

No - Cursor works, but with this issue

3 posts were merged into an existing topic: Shell tool hangs indefinitely when running rg (ripgrep) recursive directory search