[BUG] WorktreeCreate hook does not keep the session transcript at the launch directory (docs say it does)
Summary
The worktrees docs state:
As of v2.1.198, entering or exiting a worktree also relocates the session transcript to that directory's project storage, the same way/cddoes, so/desktopand--resumefind the session there afterward. Worktrees created by aWorktreeCreatehook are excluded and keep the transcript at the launch directory.
That exclusion does not happen. A worktree created by a WorktreeCreate hook has its transcript relocated to the worktree's project storage exactly like a default one, leaving the launch directory with zero transcripts — even though the app itself records the worktree as "hookBased": true.
This matters because the transcript's project slug is what scopes a session list. When a session's transcript is re-filed under the worktree's slug, the session disappears from the session list of the directory it was started in. The documented WorktreeCreate exclusion is the only advertised way to opt out of that, so it is load-bearing for anyone running multiple sessions per repo.
Environment
- Claude Code 2.1.207, native install
- Windows 11, git 2.x,
pwsh7
Repro
mkdir repo && cd repo
git init -b main . && echo x > a.txt && git add a.txt && git commit -m init
Add a project-scoped WorktreeCreate hook in repo/.claude/settings.json that creates the worktree itself and prints its path:
{
"hooks": {
"WorktreeCreate": [
{ "hooks": [ { "type": "command", "command": "bash /abs/path/to/wtcreate.sh" } ] }
]
}
}
# wtcreate.sh — reads {..., "name": "..."} on stdin, prints the created worktree path on stdout
payload=$(cat)
name=$(printf '%s' "$payload" | jq -r .name)
repo=$(printf '%s' "$payload" | jq -r .cwd)
wt="$repo/.claude/worktrees/$name"
git -C "$repo" worktree add -q -b "hookwt-$name" "$wt" >&2
echo "$wt"
Then:
claude -p --worktree wt-hooked "Reply with exactly: OK"
Expected
The transcript stays at the launch directory's project storage — i.e. under the slug for .../repo.
Actual
The transcript is filed under the worktree's slug. The launch directory's slug is created but holds no transcript:
projects/…-repo 0 transcript(s)
projects/…-repo--claude-worktrees-wt-hooked 1 transcript(s) <-- the whole conversation
~/.claude.json shows the app knew it was hook-created:
"activeWorktreeSession": {
"originalCwd": ".../repo",
"worktreePath": ".../repo/.claude/worktrees/wt-hooked",
"sessionId": "…",
"hookBased": true
}
Variants tested — all three relocate
- Plain
--worktree(no hook) → transcript under the worktree slug. (Expected; this is the documented behaviour.) WorktreeCreatehook returning a path inside.claude/worktrees/→ transcript under the worktree slug.WorktreeCreatehook returning a sibling path outside.claude/worktrees/(e.g.../repo-wt) → transcript under the worktree slug.
In all three, the launch directory ended up with zero transcripts.
Notes
ExitWorktree with action: "keep" does move the transcript back to the launch directory — so the relocation is symmetric and reversible. The loss only becomes permanent when a session ends while still inside the worktree. That is a useful escape hatch, but it isn't the documented one.
Either the exclusion is not implemented, or the docs describe an intent that didn't ship. Happy to test a fix.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗