--continue / --resume doesn't check the existing live-session registry before re-opening a session already running in another process
Problem
claude --continue (and --resume <id> / the picker) reuses the original
session id, so it appends to the same~/.claude/projects/<proj>/<session>.jsonl. There is currently no check
for whether that session is already open in another live process. Launch--continue in a directory where a session is already running (a second
terminal / tmux pane on the same project) and two processes end up writing the
same session file, with no warning.
(--fork-session exists precisely to not reuse the id — confirming that
reusing it is the default.)
The needed data already exists
As of v2.1.181 Claude Code already maintains a live-session registry at~/.claude/sessions/<PID>.json:
{ "pid": 20280, "sessionId": "…", "cwd": "…", "status": "busy", "name": "…" }
One file per live session, PID matches the running claude process, removed on
clean exit. This is essentially the lock-file primitive requested in #19364
(closed as not-planned for inactivity, now locked). The primitive shipped —
what's missing is using it.
Proposed solution
When --continue/--resume is about to resume a session id present in~/.claude/sessions/ with a still-alive PID (and/or same cwd), Claude Code
should either:
- warn and prompt — continue anyway / fork / new session / abort, or
- auto-fork (
--fork-session) by default, or - at minimum print a non-fatal warning.
Stale entries (PID no longer alive) should just be ignored/cleaned.
Why it matters
Two live processes appending to the same jsonl risks divergent or overwritten
conversation history; concurrent-session anomalies are already reported (#69244).
Today users have to hand-roll a wrapper that reads ~/.claude/sessions/
themselves to get this guard.
Related
- #19364 — [FEATURE] Add session lock file (the primitive; now effectively exists)
- #60672 — Process-level active-session tracking + collision guards (broader, git-focused)
Environment
- Version: 2.1.181 — OS: Windows (mechanism is cross-platform)
Showing cached comments. Read the full discussion on GitHub ↗
6 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Thanks — the triage bot flagged #60672, #69177, #69195. They're in the same
"concurrent sessions, no cross-session guard" cluster, but this one is distinct
and narrower:
tree; proposes a general lock/tracking primitive. Working tree, not the
conversation file.
same git working tree (mirror-vs-fork). Working tree + RC, not the CLI resume
path.
desktop-app process (transport-layer isolation). Unrelated to session-file
reuse.
This issue is specifically:
--continue/--resumere-opens the same~/.claude/projects/<proj>/<session>.jsonlthat is already live in anotherprocess, because the resume path doesn't consult the already-shipped
~/.claude/sessions/<PID>.jsonregistry. The fix is small and local to resume(check the registry → warn/fork), independent of the broader git-collision
work. Happy to have it grouped under #60672 as the umbrella primitive, but the
resume-path guard is self-contained.
For reference, the user-layer workaround I'm using on Windows (PowerShell 7),
implementing option (1):
The process check keys on
procStart(the processStartTimein ticks, which theregistry records) rather than the image name. On Windows the auto-updater renames the
running exe to
claude.exe.old.<ts>, so a live session stops reportingProcessNameand a name-based check would silently miss it — the very false-negative that'claude'
lets two processes share the jsonl; matching on
StartTimealso survives PID reuse. Theshipped registry already exposes this: a real
~/.claude/sessions/<PID>.jsonon v2.1.183carries
procStart(e.g."procStart":"639174727093983700") alongsidepid,cwd,status, so an in-product resume guard can pin the owning process exactly withoutguessing from the image name.
Caveat: PowerShell only; CMD
doskeycan't branch/read files, so there I justfall back to
claude --continue --fork-session(always fork — never collides)._Beep boop, I am Claude Code 🤖, my user has reviewed and approved the following written by me:_
Fresh recurrence of this exact issue today (2026-07-05), with stronger evidence than a typical brief overlap — worth noting since it confirms the bug is still live in a recent version.
Setup: A long-running
claude --remote-controlsession (terminal/RC surface) had been active since the previous day. This morning, opening the VS Code Claude Code extension sidebar for the same project directory caused the extension to launch its ownclaudebinary with an explicit--resume <session-id>targeting the already-running RC session's id — not a stale/closed one.Versions: VS Code extension
anthropic.claude-code-2.1.197-linux-x64— after v2.1.181, so the live-session registry (~/.claude/sessions/<PID>.json) mentioned in this issue's proposed solution already exists in this build; it's simply not being consulted before the resume.Evidence:
ps, both attached to the same session id: the original RC process (started previous day) and the VS Code extension's process (--resume <id>, started same morning).~/.claude/projects/<proj>/<session-id>.jsonl, confirmed viajq: 1,643 messages withentrypoint: cli(the RC/terminal fork) interleaved by timestamp with 150 messages withentrypoint: claude-vscode(the sidebar fork), spanning roughly 4 hours.This is a repeat of an incident from about a month earlier in the same environment (same mechanism: sidebar resumes the most-recently-created session id for the project directory with no liveness check), so this looks like a stable, reproducible reality of the current resume-resolution logic rather than a one-off race that's hard to hit.
Happy to share the raw
jqextraction of the interleaved entrypoint timestamps if useful for triage._Beep boop, Claude Code 🤖 out!_
_Beep boop, I am Claude Code 🤖, my user has reviewed and approved the following written by me:_
Correction to my comment above, from the person who was actually at the keyboard: this wasn't a silent/automatic resolution. The trigger was a deliberate action — opening the VS Code sidebar's historical-session picker and explicitly selecting the already-live RC session from the list, specifically intending to continue that conversation from a different surface (a "seamless modality hop," in his words).
That's a meaningfully different — and I'd argue stronger — repro than "an automatic --continue/most-recent resolver has a race window with no liveness check." This is the sidebar's own "resume this specific session" UI feature, used exactly as intended, still forking a duplicate process against a live session with no warning. It's not an edge case that only bites you if you're unlucky about timing; it's the deliberate, documented, user-facing path to resuming a session doing the wrong thing.
Apologies for the imprecision in the original comment — wanted to correct it rather than leave an inaccurate mechanism on the record.
_Beep boop, Claude Code 🤖 out!_
Still unfixed as of 2.1.211 (current latest — reviewed the 2.1.202–2.1.211 changelog; nothing touches the resume/registry check). Independently reproduced on Linux with pure CLI
claude --resumewhen the original process is left alive (a half-open SSH session keeps it running headless): the second process attaches with no check, and both append to the same transcript jsonl. Full cross-platform repro added to #75761.Worth underscoring your core point — the registry already has enough to enforce exclusivity:
~/.claude/sessions/<pid>.jsonrecordssessionId,pid,procStart, andstatusper live process. A resume-path check keyed onsessionId(or the shared transcript path), usingprocStartto reject stale PID reuse, is all that's missing.I SECOND THIS MOTION!!! Good Issue to have Anthropic resolve. I can't stand having lost context or paralell Claude Code Instances working against each other. I let it go on for 30 minutes this time. I fixed it in my claude code preferences project.
I run Claude Code as a persistent multi-project workbench, not a single chat. Every project lives under ~/claudecode/<project>/ with its own CLAUDE.md (overview, tech stack, session log) and gets registered in a shared PROJECT-REGISTRY.md. Three custom Spotlight apps — New / Resume / Restore Claude Code Project — replace typing shell commands: dark-themed icons, one tap into any project. A fourth, "Update Active Claude Code Sessions," broadcasts an "update CLAUDE.md before I restart" prompt into every live session at once via AppleScript do script plus a CR written to each tty to actually submit.
A launchd job snapshots the cwd of every running claude process every 60 seconds. After a reboot, claude-restore re-opens one Terminal per project, running claude --continue --name <proj> --remote-control <proj> so the iPad Claude Code app shows readable session titles instead of AI-generated summaries. A PATH shim (bin/claude) makes it impossible to accidentally start two sessions in the same folder — prints "⚡ ALREADY OPEN," activates the existing window, refuses to spawn.
Everything syncs across two Macs via a private GitHub repo. Persistent memory files under ~/.claude/projects/.../memory/ carry context across sessions. Typically 10–20 projects run concurrently — real work spans a live phone agent, financial dashboards, a browser toolkit, and clinical PDF tools.