[FEATURE] ExitWorktree: condition the ask-only rule on who created the worktree

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

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Searched ExitWorktree, worktree cleanup, ExitWorktree proactively, and tool description only when the user asks. The nearest neighbours are all about the removal mechanism failing (#69802 orphaned removal, #78355 / #84856 the refusal predicate false-positiving on squash-merges, #84027 auto-cleanup disqualified by a dirtied worktree) or about exit-time cleanup being unsafe. This request is about neither the mechanism nor the predicate — it is about the authorization rule stated in the tool description. See the note on #80132 under Additional Context, which is the closest relative and, I think, complementary rather than duplicative.

Problem Statement

EnterWorktree and ExitWorktree state asymmetric authorization rules, and the asymmetry severs the lifecycle.

EnterWorktree accepts two authorizing sources:

Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by project instructions (CLAUDE.md / memory).

ExitWorktree accepts one:

- The user explicitly asks to "exit the worktree", "leave the worktree", "go back", or otherwise end the worktree session - Do NOT call this proactively — only when the user asks

So a project instruction may authorize creation but cannot authorize removal. A workflow defined in CLAUDE.md that legitimately enters a worktree for an isolated task has no sanctioned way to clean up after itself when that task finishes — the agent is explicitly forbidden from taking the closing step of a lifecycle it was explicitly permitted to open.

The consequences compound:

  1. Worktrees accumulate. The documented backstop is "On session exit, if still in the worktree, the user will be prompted to keep or remove it" — an interactive prompt. In headless / claude -p / background-agent runs there is nobody to prompt, so the worktree simply persists.
  2. The cost lands on the user, who must remember which of N worktrees an agent opened days ago and whether it is safe to remove — the agent that created it, and is the only party that knows whether its work is finished, is the one forbidden to say so.
  3. Compliance and correctness pull in opposite directions. An agent that follows the rule leaves litter; one that cleans up is violating a stated tool constraint. Neither is a good outcome, and the ambiguity is resolved differently on different runs.

The rule reads as though it were written to protect user-created worktrees — which is reasonable, and should stay. But it is currently stated unconditionally, so it also governs the case where the agent created the worktree itself, moments earlier, as an implementation detail of a task it was told to isolate.

Proposed Solution

Invert the default, conditioned on provenance — and the tool already tracks that provenance.

ExitWorktree's description already scopes itself by ownership:

This tool ONLY operates on worktrees created by EnterWorktree in this session. It will NOT touch: worktrees you created manually with git worktree add; worktrees from a previous session (even if created by EnterWorktree then); the directory you're in if EnterWorktree was never called.

That is exactly the "you created it, you clean it" predicate. It is currently used to bound what the tool may touch, but not to set what the agent should do by default. Reusing it costs no new state:

| Worktree provenance | Proposed default | Rationale |
|---|---|---|
| Created by EnterWorktree in this session | Teardown by default once the work that motivated it is complete | The agent opened it, knows the work is done, and can already only touch this class |
| Created by the user, or by a previous session, or entered via path | Unchanged — ask only | These are the cases the current rule exists to protect; the tool already refuses to remove path-entered worktrees |

Concretely, the "When to Use" section could read something like:

- When the work that motivated the worktree is complete, and this session created it via EnterWorktree, clean it up (action: "remove") rather than leaving it behind. - Keep it (action: "keep") instead when the user asked you to, when there is a specific reason to preserve it (unfinished work, artifacts the user may want, an explicit hold), or when you are unsure. - Do not call this for a worktree this session did not create.

The destructive case is already fenced, which is what makes flipping the default safe rather than reckless. Per the current description, discard_changes defaults to false and the tool "will REFUSE to remove" a worktree that has uncommitted files or commits not on the original branch, listing them instead. So a default-teardown cannot silently destroy work: the refusal is the safety mechanism, and it stays. What changes is only the disposition of a worktree that is already clean and already merged — the case where removal is unambiguously correct and the current rule still forbids it.

Alternative Solutions

  • Leave the rule and have workflows instruct removal explicitly. Does not work: the rule names the user as the sole authorizing party, so a CLAUDE.md instruction cannot satisfy it — which is precisely the asymmetry with EnterWorktree, whose rule does accept project instructions. Making the two symmetric would be a smaller fix than this request and would also resolve it.
  • Rely on the session-exit prompt. Interactive-only, and absent in headless/background runs — exactly where unattended worktrees accumulate fastest.
  • Ask the user every time. What I currently do, and it is the wrong trade: the question carries no information the user has and I lack (I know whether the task finished; they are being asked to re-derive it), so it reads as conservative while actually transferring a decision without transferring any basis for it. It also does not scale to batch/autonomous runs that open many worktrees.
  • Shell out to git worktree remove instead. Bypasses the tool, so the session's working directory and CWD-dependent caches are not restored — the documented reason to use the tool at all. Worth noting that widespread bypass of these tools is already reported in #80132.
  • A setting (e.g. worktree.autoCleanup). Would work, but seems heavier than needed when the tool already tracks the provenance required to decide, and it puts configuration burden on every user to get the common case right.

Priority

Medium - Would be very helpful

Feature Category

Other

Use Case Example

Concrete, from a run today:

  1. A user-defined workflow command in my config repo is invoked with an isolation modifier. Per its own documented protocol it calls EnterWorktree and records itself as the worktree's owner — authorized by project instructions, exactly as EnterWorktree permits.
  2. The agent does the work across many phases: implementation, five review rounds, a validation pass, a commit, a PR, an external review gate.
  3. The PR merges. Post-merge cleanup runs. The branch is merged, the remote ref is pruned, the working tree is clean. The workflow's final documented phase is: remove the worktree.
  4. The agent cannot take that step. ExitWorktree says do not call this proactively. So it stops, leaves the worktree on disk, and asks the user — who has been away, has no context on whether the run finished, and can only reasonably answer "yes, you just told me it's merged and clean."

Step 4 is pure friction: the agent knows the answer, the tool can already verify the safety condition itself (clean tree, merged branch), and the only thing standing between them is a rule aimed at a different situation — protecting worktrees the agent did not create.

The same shape appears whenever an autonomous or batch run opens a worktree per work item. Every completed item leaves a worktree that only a human can dismiss, and in a headless run there is no prompt at session exit either.

Additional Context

Relationship to #80132 (EnterWorktree/ExitWorktree bypassed almost entirely — 27:1 ratio favouring raw git worktree add, and the one structured call's promised cleanup never fired). That report measures the symptom account-wide, including that ExitWorktree had been called twice, ever. I think this request names one contributing cause for the ExitWorktree half of that ratio: an agent reading the tool description correctly concludes it is not permitted to call the tool on its own initiative, so the call is never made and the promised cleanup path is never exercised. The two are complementary — #80132 is the evidence, this is one mechanism behind it. Fixing this alone would not fix #80132's larger bypass finding.

This is a tool-description / behavioural-contract change, not a code change, unless the maintainers also want the "work that motivated the worktree is complete" condition to be checkable programmatically. The existing discard_changes refusal already covers the safety half.

| Detail | Value |
|--------|-------|
| Claude Code | 2.1.226 |
| Platform | macOS (darwin), arm64 |

Quotes above are from the EnterWorktree and ExitWorktree tool descriptions as presented to the model in 2.1.226; if those strings have changed in a newer build, the asymmetry is the thing to check rather than the exact wording.

View original on GitHub ↗