fix(sessions): verify session id in liveness check to prune ghost sessions#10
Merged
Clast merged 1 commit intoJun 4, 2026
Merged
Conversation
…ump to 1.2.2 Navi's liveness check was PID-only (kill(pid, 0) == 0), which only asks whether some process holds the PID — not whether it's still the Claude session that created it. After PID reuse, or a resumed session whose original PID exited, a dead session could pass the check and linger as a ghost, inflating the session count. discoverSessions() now returns the set of session IDs whose own ~/.claude/sessions/<pid>.json points at a live PID, and pruning keeps a session only when its own id is in that set. Tracked sessions also refresh their stored PID when a resume moves the id to a new process, so the PID-based display guard and terminal focus stay correct. Pruning is skipped on a transient sessions-dir read error so live sessions are never wiped. No new filesystem work — this reuses the per-poll directory scan discoverSessions() already performs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clast
approved these changes
Jun 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Navi was showing more sessions than were actually running (e.g. 8 shown for 5 live Claudes). The liveness check was PID-only:
kill(pid, 0) == 0only asks whether some process holds that PID — not whether it's still the Claude session that created it. Two things defeated it:--resume, or/clear/compaction minting a new id on the same process), the stored PID drifts from reality.kill(oldPid, 0)returns 0 and the dead session lingers as a ghost.Confirmed concretely: a session id with hook activity but no live session file was still being counted because its recorded PID resolved to an unrelated live process.
Fix
discoverSessions()now returns the set of session IDs whose own~/.claude/sessions/<pid>.jsonpoints at a live PID — the authoritative identity-verified live set.SessionInfo.isAlive(among:)), so a reused/drifted PID can no longer keep a dead session alive.Performance
Zero new filesystem work — this reuses the per-poll directory scan
discoverSessions()already performs (1 readdir + a handful of small file reads). The only added cost is building a smallSet<String>and one dictionary filter by set membership — microseconds. No process spawns; poll cadence unchanged.Testing
swift buildcleanswift test— all 95 tests pass, including 3 newisAlive(among:)cases (id in live set, ghost id with a live-but-wrong PID, empty set)Version bumped
1.2.1 → 1.2.2in.claude-plugin/plugin.jsonandSources/NaviCore/Version.swift.🤖 Generated with Claude Code