Desktop: new sessions reuse an existing session worktree instead of creating a new one

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 3 comments · opened Aug 9, 2026

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:

  1. 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.
  2. 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

  1. Open a git repository in the Code tab and start a session, letting it create a worktree. Note the directory name under .claude/worktrees/.
  2. Let that session do some work; the branch typically moves off claude/<generated-name> to a named branch.
  3. Start a new session from the same project root (+ New session), same base branch.
  4. Ask each session for its working directory, or compare cwd across sessions.
  5. 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.

View original on GitHub ↗

3 Comments

simpson-paul · 21 days ago

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:

Archive session with uncommitted changes? This session's worktree has 1 uncommitted change that will be permanently discarded. `` M docs/<file>.md ` Cancel / Archive anyway`

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 status showed 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 remove deletes gitignored files without warning, which is exactly why a credentials or .env file is the dangerous case — it is invisible to git status and therefore invisible to a check built on it.

Suggested widening of the pre-archive check, in rough order of value:

  1. Commits reachable from a local branch but from no remotegit rev-list --count <branch> --not --remotes. This is the only unrecoverable class.
  2. Gitignored filesgit status --porcelain --ignored, filtered to exclude node_modules/, dist/ and similar build output, so the signal is .env / secrets rather than noise.
  3. Whether the checked-out branch matches the session being archived. Given the reuse behaviour this issue reports, the branch in the directory frequently belongs to a different session, or to none — worth surfacing before removal, since "this session is finished" does not imply "this directory is finished".

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.

simpson-paul · 21 days ago

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

  1. Take a session whose work is finished — PR merged, working tree clean, nothing uncommitted.
  2. Archive it from the sidebar. With a clean tree no confirmation dialog appears; the archive completes immediately.
  3. Check the session record and the worktree.

Observed

The session record flips as expected:

{ sessionId: <id>, cwd: <repo>/.claude/worktrees/<slug>,
  isArchived: true, isRunning: false, prNumber: <n>, prState: "MERGED" }

The worktree is untouched:

directory    : PRESENT
git metadata : PRESENT      (still listed by `git worktree list`)
prunable     : 0            (`git worktree prune --dry-run -v` finds nothing)
worktree count: unchanged

Both branches associated with that directory also remain.

So isArchived: true is 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:

To remove a worktree when you're done, hover over the session in the sidebar and click the archive icon.

And the app already implements a pre-archive guard for it — archiving a session whose worktree has uncommitted changes raises:

Archive session with uncommitted changes? This session's worktree has 1 uncommitted change that will be permanently discarded.

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 remove by 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.

TimMooreGradeo · 5 days ago

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.