[Docs] worktrees: exit-time cleanup of an ADOPTED worktree (opened by name, not created by Claude Code) removes the directory but not the branch; WorktreeRemove hook contract is undocumented

Status Open
Reported on v2.1.261
Maintainer reply None cached
Activity 0 comments · opened Sep 6, 2026

Docs gap

Page: https://code.claude.com/docs/en/worktrees § "Clean up worktrees", and https://code.claude.com/docs/en/hooks (WorktreeRemove).

The cleanup section says:

The worktree is clean: for an unnamed session, Claude removes the worktree and its branch automatically. A named session prompts you first so you can keep the worktree for later

This describes a worktree Claude Code created itself (.claude/worktrees/<name> on worktree-<name>). The page also says, under "Reuse a worktree name":

Passing --worktree a name whose directory already exists opens that existing worktree instead of creating a new one.

The docs do not say what exit-time cleanup does to a worktree that was adopted this way — one created with git worktree add (or by another tool) on its own branch, then opened with --worktree <name> from the main checkout.

What we measured (Claude Code 2.1.261, macOS)

Ten sessions on 2026-09-05, each claude --worktree <name> --permission-mode auto from the main checkout with no --name, where .claude/worktrees/<name> already existed as a linked worktree on a feat/<name> branch created by git worktree add:

  • At /exit with a clean tree, the worktree directory was removed with no prompt (the transcript ends with a relocated record to the launch directory, then worktree-state: null; the binary carries Worktree removed (no changes) for this path).
  • The branch survived every time (git branch --list feat/<name> still showed it).

So "removes the worktree and its branch" is half true for an adopted worktree: the directory goes, the branch stays. Nothing on the page tells a reader that an adopted worktree is subject to the same silent removal as a Claude-created one, nor that its branch is treated differently.

What we could only learn from the binary

The hooks reference has no WorktreeRemove entry describing the hook's contract. From strings on the 2.1.261 binary:

  • Input to command is JSON with worktree_path (absolute path to worktree).
  • Exit code 0 - worktree removed successfully
  • WorktreeRemove hook did not remove worktree, kept at: <path>
  • No WorktreeRemove hook configured; falling back to git worktree remove for: <path>

i.e. a registered WorktreeRemove hook replaces the removal (like WorktreeCreate replaces creation), and a hook that leaves the path in place keeps the worktree. That is the lever we ended up using to keep adopted worktrees, and it is not documented.

Suggested doc changes

  1. In "Clean up worktrees", add a sentence for the adopted case: a worktree opened by name (not created by Claude Code) is removed by the same unnamed-session rule when clean, but its branch is left in place.
  2. In the hooks reference, give WorktreeRemove the same treatment as WorktreeCreate: the input fields (worktree_path, session_id, cwd, …), that it replaces the default git worktree remove when configured, that leaving the path in place keeps the worktree ("kept at" is reported to the user), and that exit codes are logged in debug mode only.
  3. Optionally, note in "Clean up worktrees" that registering a WorktreeRemove hook is the way to opt a repo's worktrees out of exit-time removal without naming every session.

View original on GitHub ↗