claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

Background shell reminders persist after KillShell, causing context exhaustion

Open diegocconsolini opened this issue 2 weeks ago • 2 comments

Bug Description

When a background shell is started with run_in_background: true and later killed with KillShell, the system continues to inject reminder messages on every single turn for the rest of the conversation. This rapidly exhausts context and makes long sessions unusable.

Steps to Reproduce

  1. Start a background shell:
{
  "command": "npm run dev",
  "run_in_background": true
}
  1. Receive response: Command running in background with ID: f0f238

  2. Kill the shell:

{
  "shell_id": "f0f238"
}
  1. Receive confirmation: Successfully killed shell: f0f238

  2. Bug: On every subsequent turn, system injects reminders like:

Shell f0f238 has new output available. Use BashOutput to retrieve it.

Impact

  • Context exhaustion: Each reminder adds ~150-200 chars per zombie shell
  • Accumulates rapidly: With multiple background shells, adds 1000+ chars per message
  • Cannot be cleared: No way to stop reminders without starting new conversation
  • Session unusable: Long debugging sessions become impossible

Root Cause Analysis

Investigated the issue thoroughly:

  1. Background shell state is stored in conversation context (JSONL file)
  2. KillShell kills the process but doesn't update conversation state
  3. Conversation is append-only - past entries cannot be modified
  4. Reminder system checks conversation history, finds backgroundTaskId, sends reminder
  5. Even though shell is dead, the historical reference triggers reminders forever

Evidence from Conversation Log

// Shell started
{"backgroundTaskId":"f0f238"}

// Shell killed (success)
{"message":"Successfully killed shell: f0f238","shell_id":"f0f238"}

// But reminders continue on EVERY turn after this

Expected Behavior

After KillShell succeeds:

  • No more reminders for that shell ID
  • Shell should be marked as terminated in tracking state
  • BashOutput for killed shell should return "Shell was terminated" not trigger reminders

Workarounds (None Effective)

Attempted Result
KillShell Process dies, reminders continue
fuser -k <port> Process dies, reminders continue
Delete ~/.claude/shell-snapshots/* No effect
Delete ~/.claude/session-env/* No effect
Any settings change No relevant setting exists

Only fix: Start a completely new conversation (loses all context).

Suggested Fix

  1. Track killed shells in session state (not just conversation history)
  2. Before sending background shell reminders, check if shell was killed
  3. Or: Add a way to clear/acknowledge background shell notifications
  4. Or: Add setting to disable background shell reminders entirely

Environment

  • Claude Code version: 2.0.60
  • OS: Linux (WSL2)
  • Shell: bash

Severity

High - This makes background shells essentially unusable for any session longer than a few turns. The workaround in docs says "don't use background shells" but that defeats the purpose of having the feature.

diegocconsolini avatar Dec 07 '25 00:12 diegocconsolini

This appears to be a duplicate of #11716, #12813, #13091, #7479, and others. This bug has been reported multiple times since at least September 2025 and remains unfixed. Adding my detailed root cause analysis to help with the fix.

diegocconsolini avatar Dec 07 '25 00:12 diegocconsolini

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/12813
  2. https://github.com/anthropics/claude-code/issues/12659
  3. https://github.com/anthropics/claude-code/issues/11716

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

github-actions[bot] avatar Dec 07 '25 00:12 github-actions[bot]

Ran into this exact issue today. Killed multiple background shells and the reminders kept flooding context. The result: 35% of weekly Opus quota burned in a few hours just from the context pollution.

We're planning to implement a PostToolUse hook as a workaround - it will detect repeated 'killed/terminated' patterns and excessive output size, then block before more Opus tokens get wasted.

The irony: the actual productive work (Sonnet indexing 595 files multiple times) only used ~8% of Sonnet quota. The context pollution from killed shells hitting the Opus conversation is what destroyed the budget.

Platform: Windows with WSL2

deafsquad avatar Dec 07 '25 07:12 deafsquad