Desktop: new sessions reuse an existing session worktree instead of creating a new one
What's Wrong?
Starting a new session in the desktop app reuses an existing session worktree instead of creating a new one. The new session checks out a fresh claude/<generated-name> branch inside a directory another session already occupies, so the session→worktree mapping becomes many-to-one and permanent.
Two consequences:
- Session isolation is weakened. Two sessions record the same
cwd. Their branches are checked out one after another in the same working tree, so they are not isolated from each other in the way separate worktrees imply. - A worktree's branch no longer corresponds to any session that claims it. The directory name is fixed at creation from the first session, and never updates. After a few reuses the folder name, the sessions pointing at it, and the branch actually checked out there are three different things.
This also makes the sidebar's archive action ambiguous. The docs say:
To remove a worktree when you're done, hover over the session in the sidebar and click the archive icon.
With reuse, "done" is not well defined — archiving the session that owns the directory would remove it out from under whatever else has since adopted it, including branches with unpushed commits and gitignored files.
Subagent worktrees are not affected — they behave correctly, which is what isolates this to session creation. Branch switches per worktree in one repo:
| Worktree | Kind | Branch switches |
| --- | --- | ---: |
| agent-<id> | subagent | 1 |
| agent-<id> | subagent | 1 |
| wf_<id> | workflow | 1 |
| <session-slug> (new today) | session | 0 |
| <session-slug> | session | 2 |
| <session-slug> | session | 5 |
| <session-slug> | session | 10 |
| <session-slug> | session | 11 |
Each subagent/workflow worktree is created, checked out once from its own worktree-agent-<id> branch to its work branch, and never reused. Session worktrees accumulate.
The behaviour is inconsistent, not uniformly broken: one session worktree created today shows 0 switches, so new directories do get created in some cases.
What Should Happen?
Each new session gets its own worktree, per the docs:
For Git repositories, each session gets its own isolated copy of your project using Git worktrees, so changes in one session don't affect other sessions until you commit them.
A given worktree directory should be associated with exactly one session for its lifetime.
Error Messages/Logs
No error — it is silent. The evidence is the correlation between session creation times and checkout entries in the worktree's reflog.
Session metadata (redacted), two sessions reporting the same cwd:
session A: { cwd: <repo>/.claude/worktrees/<slug>, branch: claude/<name-a>,
createdAt: 2026-08-02T02:59:23.849Z, originCwd: <repo>, sourceBranch: main }
session B: { cwd: <repo>/.claude/worktrees/<slug>, branch: claude/<name-b>,
createdAt: 2026-08-08T19:31:56.881Z, originCwd: <repo>, sourceBranch: main,
worktreePath: <repo>/.claude/worktrees/<slug>, worktreeName: <slug> }
git -C <repo>/.claude/worktrees/<slug> reflog show HEAD --date=iso, matching those creation times to the second (timestamps below are local, -0700; the ISO values above are UTC):
HEAD@{2026-08-08 12:31:56 -0700}: checkout: moving from <sha> to claude/<name-b>
HEAD@{2026-08-01 19:59:23 -0700}: checkout: moving from <sha> to claude/<name-a>
The full history of that one directory — created 30 July, nine branches in ten days:
2026-07-30 01:58 (created, on claude/<slug>)
2026-07-30 02:35 checkout: moving from claude/<slug> to docs/<topic-1>
2026-07-31 12:37 checkout: moving from <sha> to claude/<name-c> <- session
2026-07-31 13:27 checkout: moving from claude/<name-c> to fix/<topic-2>
2026-08-01 19:59 checkout: moving from <sha> to claude/<name-a> <- session A
2026-08-02 00:25 checkout: moving from claude/<name-a> to fix/<topic-3>
2026-08-08 12:31 checkout: moving from <sha> to claude/<name-b> <- session B
2026-08-08 14:44 checkout: moving from claude/<name-b> to docs/<topic-4>
The repeating two-step shape is: a new session opens in the directory and gets claude/<generated-name>, then the work moves to a purposefully named branch. The directory keeps the name of the very first session indefinitely.
A second worktree in the same repo shows the same pattern with 11 switches across three unrelated tasks over nine days.
Steps to Reproduce
- Open a git repository in the Code tab and start a session, letting it create a worktree. Note the directory name under
.claude/worktrees/. - Let that session do some work; the branch typically moves off
claude/<generated-name>to a named branch. - Start a new session from the same project root (
+ New session), same base branch. - Ask each session for its working directory, or compare
cwdacross sessions. - Inspect the first worktree:
````
git -C <repo>/.claude/worktrees/<slug> reflog show HEAD --date=iso | grep checkout
Observed: the new session's claude/<generated-name> branch is checked out in the existing worktree, with a reflog timestamp matching the new session's creation time to the second. Both sessions now report the same cwd.
Expected: a new worktree directory for the new session.
I have not isolated which factor triggers reuse versus creation. Both sessions above record originCwd = project root and sourceBranch = main, which is what a fresh-worktree session looks like. Candidates I could not test from outside the app: whether a worktree was explicitly selected in the UI, whether the session was resumed or forked from an existing one, or whether sessions are matched and reused on (project, sourceBranch).
Claude Model
claude-opus-5 (also observed with claude-fable-5 — the two sessions above used different models)
Is this a regression?
Not sure — I do not know when it started. The oldest affected worktree in this repo dates from 2026-07-30 and was already being reused by 2026-07-31.
Claude Code Version
CLI 2.1.226 · Desktop app 1.26832.0
Platform
macOS 26.6.1 (Apple silicon), git 2.50.1 (Apple Git-155)
Additional context
Worth considering alongside the archive behaviour. Because a reused directory can hold a branch belonging to no live session, plus commits that exist on no remote and gitignored files (.env, local secrets) that git worktree remove deletes without warning, automatic removal on archive would be unsafe in exactly this state. In my case the directory that two sessions pointed at was on a third branch, with a local-only commit and a gitignored credentials file — neither session's record hinted at any of it.
3 Comments
Follow-up with a concrete data point on the archive interaction I mentioned in "Additional context".
Archiving a session does remove its worktree, and it does pre-check first — a confirmation dialog appears:
That guard is good and worth keeping. The gap is its scope: it checks uncommitted changes only. In the directory I was about to archive,
git statusshowed the one modified file the dialog listed (53 insertions / 14 deletions), and three further things the dialog said nothing about:| Present in the worktree | In the dialog? | Recoverable after removal? |
| --- | --- | --- |
| 1 modified tracked file | yes | — |
| A local branch with 1 commit on no remote | no | No |
| A gitignored credentials file (
*.secret.json) | no | Regenerable, but silently deleted || 2 commits pushed to a branch never merged to main | no | Yes (on the remote) |
So the dialog catches the most visible risk and misses the one that is actually unrecoverable.
git worktree removedeletes gitignored files without warning, which is exactly why a credentials or.envfile is the dangerous case — it is invisible togit statusand therefore invisible to a check built on it.Suggested widening of the pre-archive check, in rough order of value:
git rev-list --count <branch> --not --remotes. This is the only unrecoverable class.git status --porcelain --ignored, filtered to excludenode_modules/,dist/and similar build output, so the signal is.env/ secrets rather than noise.For reference, a repo-side script I use applies checks 1–3 plus a nested-git-repo check before allowing a worktree removal, and it classified this same directory as unsafe while the app's dialog surfaced only the modified file.
Measured result, replacing the speculation in my previous comment: archiving a session does not remove its worktree — not even in the clean, finished case with no confirmation dialog.
Earlier I guessed the worktree survived because the session was still running. That was wrong, and this rules it out.
Reproduction
Observed
The session record flips as expected:
The worktree is untouched:
Both branches associated with that directory also remain.
So
isArchived: trueis set, and nothing else happens. Nothing is left half-done either — no orphaned metadata, no stale entry to prune. The removal step simply does not run.Why this looks like a bug rather than an unimplemented feature
The docs describe archiving as the removal mechanism:
And the app already implements a pre-archive guard for it — archiving a session whose worktree has uncommitted changes raises:
That dialog only makes sense if removal is intended. The guard runs; the removal it guards does not. That points at a removal step failing silently or gated on an unmet condition, rather than a feature that was never built.
Practical impact
With no working cleanup path, worktrees accumulate indefinitely. The repository I am working in is at 51, the large majority on branches whose pull requests merged long ago, and the count only goes up — archiving finished sessions does not reduce it. The only way to reclaim them is
git worktree removeby hand, one at a time, which also means the safety checks the dialog performs are bypassed entirely.Combined with the worktree-reuse behaviour in the original report, the two compound: directories are reused by later sessions rather than created fresh, and never removed when those sessions finish.
This happened to me today with Claude Desktop for Mac 1.37937.1 (edbd3c) 2026-08-25T22:55:59.000Z (the latest version at the time of writing this). I started a new Code session, with the worktree checkbox selected. It reused a worktree directory originally created by another session that is still active and should be isolated.