[BUG] Desktop: EnterWorktree never updates the session record, so the branch chip shows the wrong branch (path:) or disappears (name:)
Preflight
Refiling #65808, which was auto-closed not planned for inactivity on 2026-07-12 with "Please open a new issue if this is still relevant." It is still relevant on current builds (CLI 2.1.165 → 2.1.246, Desktop 1.11187.1 → 1.37937.1).
Searched issues created since 2026-07-01 for the branch-chip / worktree-indicator symptom (worktree branch indicator, worktree chip stale, EnterWorktree harnessCwd). Nearest neighbours are #85778 (chip shows — on WSL), #85301 (chip stuck on "Create PR" after squash merge) and #84237 (chip resolves remote repo path locally) — all different causes. No open duplicate.
This report adds what #65808 lacked: the persisted session record as the root cause, measured across 235 records, plus a second, differently-broken code path.
Paths, branch and repository names below are placeholders; the shapes are faithful to the real ones.
What's wrong
EnterWorktree moves the session's runtime working directory correctly, but nothing writes the new directory back to the Desktop session record. The record's cwd keeps pointing at the launch directory, and the worktree-specific fields (harnessCwd, worktreePath, worktreeName) are never populated at all. The branch chip above the composer renders from that stale record.
The two ways into a worktree fail differently:
| Entry | Chip while inside the worktree |
|---|---|
| EnterWorktree({path}) — existing worktree | Keeps showing the launch checkout's branch. Actively wrong. |
| EnterWorktree({name}) — new worktree under .claude/worktrees/ | Disappears entirely. |
The CLI is unaffected — it derives its status line from the live cwd rather than from a persisted record.
Steps to reproduce
Launch checkout ~/code/myproject, on branch feature/alpha.
Case A — existing worktree by path
- In a Desktop session, call
EnterWorktree({path: "~/code/myproject-worktrees/beta"}).
Returns: "Entered worktree at … on branch feature/beta. The session is now working in the worktree."
- Confirm the runtime really moved — all three agree it did:
pwd→ the worktree pathgit rev-parse --abbrev-ref HEAD→feature/beta- project-scoped skills reload from the worktree, and the transcript moves to a new
~/.claude/projects/slug for the worktree path
- Look at the chip → still
myproject feature/alpha. ❌
Case B — new worktree by name
- From the same launch directory, call
EnterWorktree({name: "chip-scope-test"})→ creates.claude/worktrees/chip-scope-teston branchworktree-chip-scope-test. - Look at the chip → the chip is gone. ❌
Evidence: the session record never moves
Read while the session was live inside the name:-created worktree (so this is not a post-exit reset artifact) — both via the session-metadata API and from the record on disk at~/Library/Application Support/Claude/claude-code-sessions/<…>/local_<session-id>.json:
cwd = '~/code/myproject' ← launch dir, not the worktree
originCwd = '~/code/myproject'
harnessCwd = None
worktreePath = None
worktreeName = None
branch = None
Identical values were captured while inside the path:-entered worktree in the same session.
This is not specific to one session. Scanning every persisted session record on a machine that uses EnterWorktree many times a day:
records: 235 with harnessCwd: 0 with worktreePath: 0 cwd != originCwd: 0
Zero out of 235. These fields appear to be dead on the local-session path.
Evidence: the tracking hook never fires
app.asar (1.37937.1) contains detectWorktreeMoveEvent, which maps EnterWorktree / ExitWorktree tool-use ids to enter / exit, requires the tool result to carry worktreePath and message, and otherwise logs:
detectWorktreeMoveEvent: EnterWorktree result carried no worktreePath; harness cwd tracking skipped
Two things follow:
- The CLI is holding up its end. The transcript entry for the
EnterWorktreeresult carries exactly the expected payload:
``json``
{"worktreePath": "~/code/myproject-worktrees/beta",
"worktreeBranch": "feature/beta",
"message": "Entered worktree at …"}
- The hook never runs. Neither that warning nor any other
detectWorktreeMoveEventorharnessCwdline appears anywhere in~/Library/Logs/Claude/*.log, across every log file, while warn-level logging is demonstrably live there (1070[warn]lines). The onlyLocalSessions.updateSessioncalls logged are title changes.
So this is not the "result carried no worktreePath" branch failing — the update path is not reached at all for a live local session.
Expected
The chip shows the branch of the directory the session is actually working in, and refreshes on both EnterWorktree and ExitWorktree.
Actual
path: — the chip shows the launch checkout's branch for the entire time the session is inside the worktree.name: — the chip disappears for the entire time the session is inside the worktree.
Impact
Wrong-branch hazard. In the path: case the chip names a real branch that the session is not on, which is worse than showing nothing: a user glancing at it before asking for a commit has positive, confident, incorrect information. The runtime is right, so the mistake only surfaces later, in the branch the commit actually landed on.
Suggested fix
Populate the session record on worktree transitions — set harnessCwd / worktreePath (and clear them on ExitWorktree) from the EnterWorktree result, which already carries worktreePath and worktreeBranch. Then render the chip from worktreePath ?? harnessCwd ?? cwd rather than from cwd / originCwd alone. Worth checking why the name: path blanks the chip rather than leaving it stale — it reacts to something the path: flow does not.
Environment
- Claude Code CLI 2.1.246
- Claude Desktop 1.37937.1
- macOS 26.5.1 (25F80), Apple Silicon
- Worktrees both under a sibling
<repo>-worktrees/directory (path:flow) and under<repo>/.claude/worktrees/(name:flow); many concurrent worktrees on different branches
Related
- #65808 — this report's predecessor (closed not planned, stale). Same symptom,
path:flow only, no root cause. - #50921, #57251 — earlier reports of the same symptom, both dead.
- #60097 — request for a worktree/cwd indicator where none exists. Different: here the indicator exists and misreports.
- #65554 —
/desktoptransfer drops the runtime cwd. The inverse of this one. - #64191 — transcript fragmented across two
~/.claude/projects/slugs after a worktree round-trip. Consistent with what is measured here: the transcript follows the live cwd to a new slug while the session record keeps pointing at the launch directory.