Background processes started by Bash tool are not cleaned up on session exit

Resolved 💬 8 comments Opened Apr 5, 2026 by kaenyitocole-fr Closed Jun 7, 2026

Problem

When Claude Code starts background processes via the Bash tool (e.g., run_in_background, dev servers, builds, tests), those processes are not cleaned up when the session ends. The spawned Node processes get reparented to PID 1 (launchd on macOS) and continue running indefinitely.

Over time, this leads to significant memory consumption — orphaned next dev servers can grow to 8+ GB, and smaller orphaned processes (builds, codegen, PostCSS workers, test runners) accumulate and add up.

Current behavior

  1. Claude session starts a background process (e.g., PORT=3000 npm run dev)
  2. Session ends (user exits, context exhausted, etc.)
  3. The shell wrapper exits, but child Node processes are reparented to PID 1
  4. Processes run indefinitely until manually killed

Why hooks don't solve this

  • A Stop hook could kill processes on known ports, but that also kills user-started processes (false positives).
  • A PID-file approach works for specific process types (dev servers) but doesn't scale to every npm run build, npx jest, codegen, etc.
  • Hooks can't inject env vars into Bash tool calls, so there's no way to tag Claude-spawned processes for selective cleanup.

Desired behavior

Claude Code should track all child processes spawned by the Bash tool during a session and clean them up (SIGTERM → SIGKILL) when the session exits. This should include the full process tree, not just the top-level PID.

Environment

  • macOS (Darwin)
  • Processes are primarily Node.js (Next.js dev servers, PostCSS workers, Jest, codegen)
  • Multiple concurrent Claude sessions (tmux teammates, background agents) make port-based cleanup unreliable

View original on GitHub ↗

This issue has 8 comments on GitHub. Read the full discussion on GitHub ↗