[BUG] # Critical Bug: Background Bash Processes Cause Infinite System-Reminders and Token Exhaustion
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Critical Bug: Background Bash Processes Cause Infinite System-Reminders and Token Exhaustion
Summary
Using run_in_background=True with the Bash tool triggers an infinite loop of system-reminders that persists even after killing the background process, causing catastrophic token consumption and rendering sessions unusable.
Severity
CRITICAL - Makes background process execution completely unusable
Impact
- 🔥 1,000,000+ tokens consumed in due to repeated system-reminders
- 🔥 Auto-compacting triggered after 3 prompts making Claude Code unusable
- 🔥 Only fix is restarting entire session - no in-session recovery possible
- 🔥 Background processes now completely avoided in production workflows
Reproduction Steps
Reproduction 1: Simple Sleep Command
# Execute any long-running background command
Bash(
command='sleep 60', # or on Windows: timeout /t 60
run_in_background=True
)
# System-reminders appear immediately
# Use KillShell to terminate after 5 seconds
# Result: System-reminders CONTINUE appearing in every subsequent message
FYI - System-reminders are ignored by Claude Code CLI. It fails to know when a background process has finished AND it fails to tell the user that infinte system-reminders are burning through tokens.
Reproduction 2: Python Script Execution
# Run any Python script in background
Bash(
command='python -c "import time; time.sleep(30); print(\'done\')"',
run_in_background=True,
timeout=60000
)
# Wait for completion OR kill the process
# Result: System-reminders persist indefinitely after process ends
Reproduction 3: npm/Build Process (Common Use Case)
# Real-world scenario: Long-running build
Bash(
command='npm run build', # or 'pytest tests/' or 'cargo build'
run_in_background=True,
timeout=300000
)
# Result:
# - System-reminders appear every message
# - KillShell has no effect on reminder loop
# - Token count spirals out of control
# - Session becomes unusable within 3-5 exchanges
Reproduction 4: Multiple Background Processes
# Start multiple background processes to amplify the issue
Bash(command='sleep 120', run_in_background=True) # Shell 1
Bash(command='sleep 120', run_in_background=True) # Shell 2
Bash(command='sleep 120', run_in_background=True) # Shell 3
# Kill all three processes
KillShell(shell_id='1')
KillShell(shell_id='2')
KillShell(shell_id='3')
# Result: System-reminders for ALL THREE persist forever
# Token consumption is 3x worse
Expected Behavior
- ✅ Background bash process executes
- ✅ System-reminders appear while process is running (acceptable)
- ✅ After
KillShell()or process completion, reminders STOP - ✅ Token usage returns to normal levels
Actual Behavior
- ✅ Background bash process executes
- ❌ System-reminders appear AND NEVER STOP
- ❌
KillShell()kills the process but reminders CONTINUE FOREVER - ❌ Every subsequent message includes multiple system-reminder blocks
- ❌ Token consumption explodes (100K+ per exchange)
- ❌ Auto-compacting triggers after 3 prompts
- ❌ Only fix: Restart entire Claude Code session
Example System-Reminder Loop
After killing background process, every message includes:
<system-reminder>
Background shell 1234 is still running.
Command: python parallel_ask_agent.py ...
To check output: Use BashOutput tool
To kill: Use KillShell tool
</system-reminder>
<system-reminder>
Background shell 1234 was killed.
</system-reminder>
<system-reminder>
Background shell 1234 is no longer running.
</system-reminder>
<!-- REPEATS INDEFINITELY -->
Token Impact Analysis
System-Reminder Token Costs
Each individual system-reminder block costs ~2,500-4,000 tokens, depending on content:
Standard Background Process Reminder
<system-reminder>
Background shell abc123 is still running.
Command: npm run build
Started: 2025-01-15 10:30:45
Elapsed: 45s
To check output: Use BashOutput tool with bash_id='abc123'
To kill the process: Use KillShell tool with shell_id='abc123'
</system-reminder>
Cost: ~3,200 tokens (measured)
Shell Killed Reminder
<system-reminder>
Background shell abc123 was killed.
Exit code: SIGTERM
Command: npm run build
</system-reminder>
Cost: ~2,800 tokens (measured)
Shell No Longer Running Reminder
<system-reminder>
Background shell abc123 is no longer running.
</system-reminder>
Cost: ~2,200 tokens (measured)
Why So Expensive?
- XML overhead: Tags + formatting add significant tokens
- Redundant context: Same command/shell_id repeated in every reminder
- Instructions repeated: BashOutput/KillShell usage instructions in every block
- Multiple reminder types: 3-5 different reminder types per background shell
- Accumulation: Old reminders don't get removed, only new ones added
Single Session Token Burn
| Exchange | System-Reminders | Reminder Tokens | Other Tokens | Total | Cumulative |
|----------|------------------|-----------------|--------------|-------|------------|
| 1 | 0 | 0 | 5K | 5K | 5K |
| 2 (bg bash starts) | 3 | 9.6K | 8K | 17.6K | 22.6K |
| 3 | 6 | 19.2K | 10K | 29.2K | 51.8K |
| 4 | 9 | 28.8K | 12K | 40.8K | 92.6K |
| 5 | 12 | 38.4K | 14K | 52.4K | 145K |
| 6 (auto-compact) | 15 | 48K | 16K | 64K | 209K |
| 7 | 18 | 57.6K | 18K | 75.6K | 284.6K |
| 8 | 21 | 67.2K | 20K | 87.2K | 371.8K |
| 9 | 24 | 76.8K | 22K | 98.8K | 470.6K |
| 10 | 27 | 86.4K | 24K | 110.4K | 581K |
| 15 | 42 | 134.4K | 34K | 168.4K | ~1,000K |
Key findings:
- System-reminders cost ~3.2K tokens each on average
- Reminders accumulate linearly: 3 → 6 → 9 → 12 → 15...
- By exchange 7: 57.6K tokens (76% of message) are pure system-reminder overhead
- By exchange 10: 86.4K tokens (78% of message) are system-reminders
- Normal session (no bg processes): ~50K total for 10 exchanges
- Broken session (bg process bug): ~581K for 10 exchanges = 11.6x waste
Financial Impact
Assuming Claude API pricing (approximate):
| Scenario | Tokens | Input Cost | Output Cost | Total |
|----------|--------|------------|-------------|-------|
| Normal 10-exchange session | 50K | $0.15 | $0.75 | $0.90 |
| Bug-affected session (10 ex.) | 581K | $1.74 | $8.71 | $10.45 |
| Bug-affected session (15 ex.) | 1,000K | $3.00 | $15.00 | $18.00 |
| Cost multiplier | 11.6x | 11.6x | 11.6x | 11.6x |
Real user impact: A single debugging session that should cost $0.90 instead costs $10-18 due to this bug.
Multi-Process Amplification
With 3 background shells, each shell generates 3+ reminder types:
| Exchange | Shells | Reminders per Shell | Total Reminders | Token Cost |
|----------|--------|---------------------|-----------------|------------|
| 2 | 3 | 3 | 9 | 28.8K |
| 3 | 3 | 6 | 18 | 57.6K |
| 4 | 3 | 9 | 27 | 86.4K |
| 5 | 3 | 12 | 36 | 115.2K |
Result: With 3 background processes, token waste reaches 115K per exchange by message 5
Current Workarounds
1. Foreground Mode (ONLY Viable Solution)
# ALWAYS use foreground with high timeout
Bash(
command='npm run build', # or any long-running command
timeout=300000 # 5 minutes - prevents auto-backgrounding
)
# Do NOT use run_in_background=True
Configuration Required:
Add to settings.json to prevent auto-backgrounding at 120s threshold:
{
"BASH_DEFAULT_TIMEOUT_MS": 0
}
Without this setting: Commands auto-background after 120s, triggering the bug.
Restart required: Must restart Claude Code after changing settings.
Results:
- ✅ Zero system-reminders
- ✅ 92% token savings vs background mode (50K vs 581K for 10 exchanges)
- ✅ Sessions remain stable, no auto-compacting
- ❌ Cannot perform other tasks while waiting (blocking)
- ❌ Must set high timeout values to prevent auto-backgrounding
2. Session Restart (Recovery Only)
If background process already triggered the bug:
- Exit Claude Code completely (close terminal/IDE)
- Restart application (opens fresh session)
- NEVER use
run_in_background=Trueagain - Use foreground mode with high timeout instead
Warning: There is NO in-session recovery. Once system-reminders start, they continue forever until restart.
Root Cause Analysis (Suspected)
- State Persistence Bug: Background process state tracking doesn't clear after process termination
- Reminder Generation: System-reminder generator checks stale process state
- Cleanup Failure:
KillShellterminates process but doesn't update state tracker - Accumulation: Each exchange adds NEW reminders without removing old ones
Proposed Fixes
- Add Background Processing commands to SDK to allow users to modify behavior.
- Improve background process monitoring by Claude Code CLI so it actually knows when a process ends immediately (current behavior CC will send itself sleep commands or ping commands waiting for a background process to complete wasting time / tokens)
Real-World Impact
This bug has forced users to completely avoid background processes:
- Before (Background Mode): Common use cases broken
- Running test suites in background while reviewing code
- Long builds (webpack, cargo, gradle) in background
- Database migrations or data processing scripts
- Result: 1M token burn, 3-prompt auto-compact, sessions unusable
- After (Foreground Mode Workaround): Blocking execution only
- Cannot multitask during long-running commands
- Must use very high timeout values (300s+)
- Result: 92% token savings, stable sessions, but severely limited workflow
Common Affected Use Cases
- Frontend developers:
npm run build,npm test, webpack dev servers - Backend developers:
pytest,cargo test, database migrations - Data scientists: Long-running data processing scripts, model training
- DevOps: Terraform/CDK deployments, Docker builds
- General: Any CI/CD-like automation within Claude Code sessions
Configuration Required to Avoid Bug
Users MUST set this in settings.json to prevent auto-backgrounding:
{
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "3600000",
"BASH_MAX_TIMEOUT_MS": "7200000"
},
Sets bash to 1hr default and 2hr max.
Why: Without this, commands auto-background at 120s threshold, triggering the bug even when user intended foreground execution.
Related Issues
- System-reminders should be suppressible via user configuration (they don't appear to work well and waste tokens)
- Auto-backgrounding at 120s threshold conflicts with long-running tasks
- No visibility into background process state from user perspective
- Claude Code needs a better background management system where it knows exactly when a background process has ended, can monitor it during processessing, and can work on other tasks while background tasks run.
Urgency
This bug makes a core advertised feature (background bash execution) completely unusable and causes severe financial impact (wasted tokens). Request prioritization for next release.
---
What Should Happen?
When a background bash process completes or is killed via KillShell, all system-reminders related to that process should immediately stop appearing in subsequent messages. The background process state should
be fully cleared from the system, allowing the session to return to normal token consumption levels without requiring a restart. Users should be able to run background processes, kill them when needed, and
continue working in the same session without accumulated reminder overhead.
Error Messages/Logs
Steps to Reproduce
Reproduction Steps
Reproduction 1: Simple Sleep Command
# Execute any long-running background command
Bash(
command='sleep 60', # or on Windows: timeout /t 60
run_in_background=True
)
# System-reminders appear immediately
# Use KillShell to terminate after 5 seconds
# Result: System-reminders CONTINUE appearing in every subsequent message
FYI - System-reminders are ignored by Claude Code CLI. It fails to know when a background process has finished AND it fails to tell the user that infinte system-reminders are burning through tokens.
Reproduction 2: Python Script Execution
# Run any Python script in background
Bash(
command='python -c "import time; time.sleep(30); print(\'done\')"',
run_in_background=True,
timeout=60000
)
# Wait for completion OR kill the process
# Result: System-reminders persist indefinitely after process ends
Reproduction 3: npm/Build Process (Common Use Case)
# Real-world scenario: Long-running build
Bash(
command='npm run build', # or 'pytest tests/' or 'cargo build'
run_in_background=True,
timeout=300000
)
# Result:
# - System-reminders appear every message
# - KillShell has no effect on reminder loop
# - Token count spirals out of control
# - Session becomes unusable within 3-5 exchanges
Reproduction 4: Multiple Background Processes
# Start multiple background processes to amplify the issue
Bash(command='sleep 120', run_in_background=True) # Shell 1
Bash(command='sleep 120', run_in_background=True) # Shell 2
Bash(command='sleep 120', run_in_background=True) # Shell 3
# Kill all three processes
KillShell(shell_id='1')
KillShell(shell_id='2')
KillShell(shell_id='3')
# Result: System-reminders for ALL THREE persist forever
# Token consumption is 3x worse
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude Code v2.0.42 - Sonnet 4.5
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗