Background Bash processes can run indefinitely with no visibility to user or model

Status Open
Reported on v2.1.146
Maintainer reply None cached
Activity 4 comments · opened May 22, 2026

Summary

Bash invocations started with run_in_background: true have no upper-bound duration and no built-in way for the user or the model to see what's currently running. A faulty exit condition in a polling loop can leave a background process running for hours undetected. The status bar shows that something is running but doesn't expose what it is or how long it's been alive.

Repro

In an interactive Claude Code session, I asked Claude to push a branch and wait for the pre-push integration suite to finish. Claude (Opus 4.7) ran:

git push -u origin <branch>   # run_in_background: true  → task id A

Then, redundantly, started a polling loop to wait for it:

until grep -E "(Passed|Failed|done|Everything up-to-date|To github\.com)" \
  /tmp/.../tasks/A.output | tail -1 | grep -q "github.com\|done\|Everything"; do
  sleep 5
done; cat /tmp/.../tasks/A.output      # run_in_background: true → task id B

The push completed within ~1 minute. The loop's exit predicate matched only the last line of the push output — which was the branch set up to track message, not the github.com URL line — so the loop never exited. Task B kept polling every 5 seconds for several hours until the user noticed an unexplained shell in their status bar.

Expected

One or more of:

  1. The status bar (or a /jobs-style command) exposes the list of currently-running background Bash tasks with command and elapsed time.
  2. Background Bash tasks have an opt-in max_duration parameter that auto-terminates if exceeded.
  3. The harness emits a system-reminder to the model when a background task exceeds some threshold (e.g., 10 min), so the model can investigate or kill it.
  4. The harness emits a user-visible warning for the same.

Actual

  • No user-facing affordance to see what's running. User had to ask the assistant, who then had to ps -ef | grep ... to find the offending PID.
  • No notification to the model after the foreground push completed that a redundant background poller was still alive.
  • The task stayed alive for ~several hours of wall time before the user investigated.

Why this matters

  • Resource waste (process and shell snapshot per task).
  • User confusion ("what's that shell my status bar shows running?").
  • Model drift: the assistant said it had "learned a lesson" about this, which is hollow — the model is stateless across sessions. The harness is the durable layer; if it doesn't guard against this, the same class of bug recurs every session.
  • Headless mode never completes: this problem has caused Claude Code running in headless mode to hang and never exit. A headless invocation that finishes its real work but leaves a background polling loop alive will sit there until the orchestrator times it out (or never, if there's no orchestrator timeout) — making Claude Code unusable in CI, scripted pipelines, and any automation that expects the process to exit cleanly when work is done.

Suggested fix

Cheapest viable surface: add max_duration_seconds to the Bash tool's run_in_background parameter (default None = no cap, opt-in cap). Pair it with a /jobs command users can run to inspect active background tasks. In headless mode, also consider auto-terminating background tasks at session-end rather than blocking on them.

Environment

  • Claude Code version: 2.1.146
  • Model: claude-opus-4-7 (1M context)
  • Platform: Linux

View original on GitHub ↗

4 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/51932
  2. https://github.com/anthropics/claude-code/issues/61416
  3. https://github.com/anthropics/claude-code/issues/51760

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

730alchemy · 3 months ago

The main difference between this issue and the others is the mechanism that caused the Claude Code background task to get stuck in an infinite loop. In my case, Claude Code generated logic on the fly for detecting the end of a process (the git push command) and the logic was wrong; the logic failed to detect the end of the command). I know this logic is generated on the fly because I have seen several instances of this exact problem (background test failing to determine a process has ended) each with different logic.

tristan666666 · 2 months ago

This is close to the problem that made me build Agent Island.

It is not a fix for the run_in_background internals or /jobs, but for Mac users running long Claude/Codex sessions it adds a small external status layer in the MacBook notch:

  • running session -> logo breathes
  • waiting for me -> logo spins
  • stuck/interrupted -> logo turns red + beeps
  • selected long run can auto-resume when it is allowed to continue again

Repo, in case useful to anyone following this class of "agent is doing something but I cannot tell what state it is in" issues: https://github.com/tristan666666/agent-island

timothyshores · 1 month ago

+1, same root issue for me — a multi-hour background script, polled via Monitor. The underlying task ran fine and finished on schedule, but the polling/session-tracking side hung and the session froze. Being unable to distinguish "my long job is still running" from "the harness lost track of it" is the core pain point here.