Headless (desktop-app agent-mode) runs complete their work but the claude process never exits — accumulates until OOM/swap exhaustion
Environment:
- Claude Code bundled with the macOS desktop app — observed on bundled builds 2.1.229 (first diagnosis, 2026-08-15) and still present on 2.1.247 (current)
- Standalone CLI also installed: 2.1.220 (not the leaking path)
- macOS Darwin 25.5.0, Apple Silicon, 36 GB RAM
- Runs are launched by the desktop app's local-agent-mode service (scheduled tasks / background sessions), i.e.
claude --output-format stream-json --input-format stream-json --permission-prompt-tool stdio …under…/Application Support/Claude/claude-code/<version>/claude.app/Contents/MacOS/claude
Behavior: Each headless run completes its work correctly — tool calls finish, status files are written, the final message is delivered. The process then persists indefinitely: an rss≈0 disclaimer wrapper plus the real claude process holding ~160–210 MB. Nothing reaps them until the desktop app itself restarts.
Impact (measured):
- 2026-08-15: 78 live process entries (≈39 leaked runs over ~3 days ≈ 13/day) totalling 7.72 GB RSS against 36 GB RAM; swap 24.4/25.6 GB (95%); ~65 MB free pages; interactive session died with
Claude Code process exited with code 137(SIGKILL by the OS). Restarting the desktop app dropped the count 78 → 2. - Reconfirmed live 2026-08-30: runs fired at 00:05/00:20/00:35/00:50 (each verified complete via their own status-file writes) were all still resident at 16:30 — e.g. a 02:50 run still holding 205 MB thirteen hours after finishing.
- Rate: roughly one leaked pair per headless fire; a fleet of ~20 scheduled tasks reaches OOM territory in ~3 days.
Repro:
- Schedule any recurring task in the desktop app (agent mode) that does modest work and exits normally.
- Let it fire once; confirm the run's work completed (its output/status file is written, transcript closed).
ps aux | grep "claude.app/Contents/MacOS/claude"— the run's process pair is still alive, and remains alive hours later.- Repeat across fires: the count grows monotonically until the app restarts.
What it is not:
- Not subagents (they run in-process; no child
claudespawned). - Not a hang mid-work — the runs demonstrably finish (artifacts + status files land on time).
- Not specific to one task/skill — reproduced across ~20 unrelated scheduled tasks.
SIGTERM behavior: not yet fully characterized — a controlled SIGTERM test on a leaked process is in progress; will follow up in a comment. The user-side reaper escalates SIGTERM → 20s → SIGKILL and that sequence clears them either way.
Workarounds in place (user-side): a completion-gated per-task reaper script appended to every scheduled-task prompt, plus a weekly scheduled app restart. Both are mitigations; the process should exit on its own when its run completes.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗