Reference orphan claude reaper
Console (11 GB VM) gets crushed by orphaned claude processes. Cause: when the
Claude Code Remote Control desktop UI archives a session, it kills the tmux
server but the claude binary doesn't always exit. Each orphan = 250-450 MB.
A day's accumulation (10+ orphans) pushes Console into swap.
Files¶
forge/scripts/forge_reap_orphan_claudes.py— the reaper/etc/systemd/system/forge-reap-orphan-claudes.{service,timer}— system unitsforge/data/orphan_claude_state.json— first-seen tracking, keyed bypid:start_timeforge/logs/orphan-claude-reaper.log— silent runtime log
Detection (v2, 2026-05-04)¶
Source of truth: ~/.claude/sessions/<pid>.json — written by the claude
binary on startup, consumed by the Remote Control desktop UI. Each registry
has fields pid, sessionId, procStart, entrypoint, bridgeSessionId,
optional name.
Mapping rule: a session shows as "Active" in the desktop UI iff
bridgeSessionId is a non-null string AND process is alive AND
entrypoint != "claude-vscode".
Reap rule: a registry whose process is alive AND has null/missing
bridgeSessionId AND entrypoint != "claude-vscode" is "archived from
user's view." Track first-seen by pid:procStart (procStart defeats PID
reuse). After 2h grace -> SIGTERM (30s) -> SIGKILL.
Protected: any session whose name starts with a prefix in
PROTECTED_NAME_PREFIXES (currently ("home-base",)) is skipped — these
are intentional persistent anchors whose bridge tokens often go stale.
Also sweeps stale tmux sockets in /tmp/tmux-1000/ and dead registry
files in ~/.claude/sessions/.
v1 (deprecated) — why it was wrong¶
v1 walked tmux sockets in /tmp/tmux-1000/ and labeled any claude whose
ppid shell wasn't a registered pane an "orphan." False positives because
tmux servers can run on sockets outside that dir, so genuinely live
sessions got mis-labeled. Replaced with the registry-based approach above.
Cadence¶
OnUnitActiveSec=15min, OnBootSec=5min. Silent (no notify).
Tuning knobs (in script)¶
GRACE_SECONDS = 2 * 60 * 60— orphan must persist 2h before killSIGTERM_WAIT = 30— seconds before SIGKILL
Verify¶
sudo systemctl status forge-reap-orphan-claudes.timer
tail -f /home/justinwieb/forge/logs/orphan-claude-reaper.log
sudo systemctl start forge-reap-orphan-claudes.service # force a tick
Caveats¶
- First detection sets the grace clock at NOW, not at process start. So on initial deploy, existing orphans get a 2h reprieve before they're killed.
claude --dangerously-skip-permissions(no other args) raw invocations from ssh ttys are eligible for reap if their tty's tmux pane disappears.