Summary
The SessionStart warmup pattern codedb . status & leaks a ~20 GB resident process that never exits. Each invocation spawns another one, so on a machine where it runs repeatedly (e.g. a Claude Code SessionStart hook) the orphans accumulate until RAM is exhausted and macOS freezes the UI and force-restarts.
Environment
- codedb 0.2.5824
- macOS 26.0.1, Apple Silicon, 64 GB unified memory
- Invoked from a Claude Code hook:
codedb . status >/dev/null 2>&1 & on SessionStart
What happens
codedb . status appears to load the full index into memory (~20 GB RSS; ~2.8 GB private/dirty + ~18 GB mmap'd index) and then does not exit — the process stays resident for hours.
- When backgrounded (
&) from a short-lived parent, it is reparented to launchd (ppid=1) and lives forever.
- Repeated invocations stack: I observed 3 simultaneous orphaned
codedb . status processes at ~20 GB RSS each, all ppid=1, plus the live codedb mcp.
Observed via ps:
pid=7591 ppid=1 up=07:04 rss=20.2GB codedb . status
pid=9377 ppid=1 up=03:50 rss=20.7GB codedb . status
pid=7585 ppid=7574 rss=20.1GB codedb mcp (live, expected)
Impact
On a 64 GB machine this exhausts RAM. With swap effectively at 0, macOS responds with jetsam kills and WindowServer userspace_watchdog_timeout hangs — i.e. the screen freezes and the only recovery is a hard restart. Confirmed from /Library/Logs/DiagnosticReports/:
JetsamEvent-2026-06-07-170555.ips (largestProcess = python3.12)
WindowServer_..._userspace_watchdog_timeout.spin (x2)
Reproduce
for i in 1 2 3; do codedb . status >/dev/null 2>&1 & done
sleep 5
ps -axo pid,ppid,rss,command | grep 'codedb . status' # 3 procs, ~20 GB RSS each, none exit
Expected
codedb . status should be a cheap, fast-exiting status query — it should not need to load and hold the entire ~20 GB index resident, and it should return promptly and exit.
- If warming the index is the intent, that should be an explicit subcommand (e.g.
codedb warm) that either (a) hands off to / reuses the already-running daemon rather than spawning a second full copy, or (b) is bounded and reaps itself.
Likely root cause
status seems to mmap/load the whole index (like a query path) and then block instead of exiting — so any &-detached call becomes a permanent ~20 GB orphan, and nothing dedupes against an already-running instance.
Suggested fixes
status should not load the full index — report state from metadata and exit immediately.
- If a warm/daemon is desired, make warmup idempotent (no-op when an instance is already running) and self-terminating.
- Document that
codedb . status must not be backgrounded as a warmup, since it currently never exits.
Workaround (for anyone hitting freezes)
Harden the Claude SessionStart hook so it can't pile up or linger:
command -v codedb >/dev/null 2>&1 || exit 0
pgrep -f 'codedb . status' >/dev/null 2>&1 && exit 0 # no pile-up
{ codedb . status >/dev/null 2>&1 & cp=$!
( sleep 30; kill -9 "$cp" 2>/dev/null ) & wp=$!
wait "$cp" 2>/dev/null; kill "$wp" 2>/dev/null; } >/dev/null 2>&1 &
And reap existing orphans:
ps -axo pid,ppid,command | awk '$2==1 && /codedb . status/{print $1}' | xargs kill -9
Summary
The
SessionStartwarmup patterncodedb . status &leaks a ~20 GB resident process that never exits. Each invocation spawns another one, so on a machine where it runs repeatedly (e.g. a Claude CodeSessionStarthook) the orphans accumulate until RAM is exhausted and macOS freezes the UI and force-restarts.Environment
codedb . status >/dev/null 2>&1 &onSessionStartWhat happens
codedb . statusappears to load the full index into memory (~20 GB RSS; ~2.8 GB private/dirty + ~18 GB mmap'd index) and then does not exit — the process stays resident for hours.&) from a short-lived parent, it is reparented tolaunchd(ppid=1) and lives forever.codedb . statusprocesses at ~20 GB RSS each, allppid=1, plus the livecodedb mcp.Observed via
ps:Impact
On a 64 GB machine this exhausts RAM. With swap effectively at 0, macOS responds with jetsam kills and WindowServer
userspace_watchdog_timeouthangs — i.e. the screen freezes and the only recovery is a hard restart. Confirmed from/Library/Logs/DiagnosticReports/:Reproduce
Expected
codedb . statusshould be a cheap, fast-exiting status query — it should not need to load and hold the entire ~20 GB index resident, and it should return promptly and exit.codedb warm) that either (a) hands off to / reuses the already-running daemon rather than spawning a second full copy, or (b) is bounded and reaps itself.Likely root cause
statusseems to mmap/load the whole index (like a query path) and then block instead of exiting — so any&-detached call becomes a permanent ~20 GB orphan, and nothing dedupes against an already-running instance.Suggested fixes
statusshould not load the full index — report state from metadata and exit immediately.codedb . statusmust not be backgrounded as a warmup, since it currently never exits.Workaround (for anyone hitting freezes)
Harden the Claude
SessionStarthook so it can't pile up or linger:And reap existing orphans: