[BUG] --worktree runs WorktreeCreate for --version/--help and on failed --tmux attach, never calls WorktreeRemove (leaks worktrees + tmux sessions)

Status Open
Reported on v2.1.293
Maintainer reply None cached
Activity 0 comments · opened Oct 11, 2026

Summary

With --worktree, Claude Code runs the WorktreeCreate hook before it decides what the invocation will do. Early-exit flags (--version, --help) and a failed --tmux attach then exit without ever calling WorktreeRemove, so every such invocation leaks a worktree. Combined with --tmux it also leaks a tmux session with an idle interactive claude inside.

Environment

  • Claude Code 2.1.293, macOS (Darwin 27.0.0), Ghostty, zsh
  • Worktrees provided by hooks (jj workspaces, no .git in the worktree):
"hooks": {
  "WorktreeCreate": [{ "hooks": [{ "type": "command", "command": "claude-worktree-create" }] }],
  "WorktreeRemove": [{ "hooks": [{ "type": "command", "command": "claude-worktree-remove" }] }]
}
# claude-worktree-create
dest="$(jj workspace root)/.claude/worktrees/$(jq -r .name)"
mkdir -p "$dest"
jj workspace add "$dest" >&2
echo "$dest"

# claude-worktree-remove
jj workspace remove "$(jq -r '.worktree_path | split("/") | last')" >&2

Steps to reproduce

  1. In a repo with the hooks above, from a shell without a tty (e.g. a subprocess, CI, or a Claude Code Bash tool call):

``
claude --worktree --tmux --version
``

Output:

``
Using worktree via hook: /Users/arian/Projects/nixos-stuff/.claude/worktrees/bright-fox-xpaa
open terminal failed: not a terminal
``

The worktree directory stays behind. The remove hook never runs.

  1. Same with --help: the worktree is created, help is printed, nothing is cleaned up.
  1. From a real tty, claude --worktree --tmux --version creates the worktree, creates a tmux session named <repo>_worktree-<name>, and starts a full interactive session inside it. --version is effectively ignored, and the tmux session plus worktree stay alive after the calling shell moves on.

Evidence

jj op log after six such invocations contains only add workspace operations and not a single removal:

17:14:15  add workspace 'bright-ray-2zot'
17:12:56  add workspace 'calm-ray-tjke'
17:12:45  add workspace 'calm-ray-cgeh'
17:12:35  add workspace 'bright-oak-knl6'
17:09:45  add workspace 'bright-elm-0fcc'
17:09:43  add workspace 'bright-fox-xpaa'

tmux ls afterwards:

nixos-stuff_worktree-calm-ray-cgeh: 1 windows (attached)
nixos-stuff_worktree-calm-ray-tjke: 1 windows (attached)

All leaked worktrees are empty (unchanged from the base commit), so the documented "unchanged worktrees are removed automatically on exit" behaviour should have applied if the exit path had reached it.

Expected

  • --version and --help short-circuit before any worktree or tmux setup, as they do for every other side-effecting flag.
  • If the tmux attach fails, the just-created (unchanged) worktree is rolled back via WorktreeRemove.
  • More generally, any exit after WorktreeCreate has run should go through the same cleanup as a normal session exit.

Why it matters

The natural way to make worktree+tmux the default is alias claude='claude --worktree --tmux' (there is no settings key for it). With that alias, every incidental claude --version, claude -p ..., claude mcp ... or claude update leaks a worktree, and a Claude Code session whose Bash tool inherits the alias will leak one per probe without anyone noticing.

Related

  • #93676 and #99270 cover other paths where WorktreeRemove never fires.
  • #94212 / #92342 ask for cleanup events in general.
  • A settings.json option to default --worktree / --tmux for interactive sessions would remove the need for the alias entirely.

View original on GitHub ↗