We run three Claude Code sessions most of the day: one fixing, in its own worktree; one testing the app on the Mac; one planning and reviewing. Worktrees solved the first problem that setup has, two sessions editing the same file. They do nothing for the second, knowing which of the three has stopped and what you were doing there when you left. This is how we run them, from the Claude Code worktrees documentation on 22 September 2026 and from a week of doing it.
Start a session in a worktree
claude --worktree fix-hover
--worktree (or -w) with a name creates a git worktree, a separate working directory with its own branch that shares the repository’s history, and starts Claude in it. The worktree goes under .claude/worktrees/<name>/ at the repository root, on a new branch named worktree-<name>. Run the same command with another name in another tab and you have two sessions that cannot touch each other’s files. Leave the name out and Claude Code invents one like bright-running-fox.
Two things to do once:
- Add
.claude/worktrees/to.gitignore, or every worktree shows up as untracked files in the main checkout. - Run
claudeonce in the repository first and accept the trust dialog.--worktreerefuses to start in a directory you have not trusted (non-interactive-pruns skip the check).
You can also ask a running session to “work in a worktree”; it creates one with its EnterWorktree tool and moves there. Entering a path outside .claude/worktrees/ asks for your approval, because the session’s working directory, write access and CLAUDE.md all move with it.
What is not in a worktree
A worktree is a fresh checkout. Tracked files are there; everything gitignored is not. The first session we started this way spent its first ten minutes discovering there was no .env.
Secrets and local config. Put their names in a .worktreeinclude file at the project root, gitignore syntax. Claude Code copies matching gitignored files into every worktree it creates, whether from --worktree, a subagent, or the desktop app:
.env
.env.local
config/secrets.json
Dependencies and build output. node_modules, .build, target are not copied and should not be. Install per worktree, or ask the session to. The trap is the other direction: each worktree gets its own build folder, and a Swift .build is 2 to 4 GB. Six worktrees filled a disk here on 17 September; our done script now deletes .build before it removes the worktree.
Hooks. ${CLAUDE_PROJECT_DIR} in a hook command still points at the main checkout after Claude enters a worktree. The hook’s stdin JSON carries cwd, which does follow the worktree. Read that when a hook needs the worktree path, which matters below.
Which branch it starts from
By default a new worktree branches from the remote’s default branch, usually main, fetched if the repository has not been fetched in the last 24 hours. That is what you want for a fix: a clean tree that matches what will be merged. To branch from your current local HEAD instead, unpushed commits included, set it in settings.json:
{
"worktree": {
"baseRef": "head"
}
}
baseRef takes only "fresh" or "head", not a branch name. To start from a specific existing branch, create the worktree with git and start Claude inside it:
git worktree add ../project-bugfix fix-issue-456
cd ../project-bugfix
claude
To review a pull request in isolation, pass its number with # (quoted, or the shell eats it) or its URL. Claude Code fetches the PR head from origin into .claude/worktrees/pr-<number>:
claude --worktree "#1234"
Reusing a name opens the existing worktree. With the default "fresh" base, a reopened worktree that is clean, still on its own branch and already merged resets to main instead of continuing at its old tip.
What the session is not allowed to do
While a session is in a worktree, Claude Code blocks four kinds of tool call: an Edit or Write that targets a path in the main checkout; a Bash command whose working directory resolves to the main checkout; a git command redirected into it through git -C, --git-dir, GIT_DIR or a cd; and a command whose text it cannot verify stays inside the worktree, such as a command name computed at runtime. Claude sees each refusal as a tool error that names the worktree and says how to rewrite the command. The same rules cover every subagent the session spawns.
Subagents can get their own worktrees too. Ask for “use worktrees for your agents”, or make it permanent for a custom subagent with isolation: worktree in its frontmatter. A subagent worktree that ends with no changes is removed at once; one with changes stays until a periodic sweep can remove it without losing work.
Cleanup
When you exit an interactive worktree session, Claude Code looks at the worktree before removing anything: changed or untracked files, uncommitted work in submodules, new commits.
| the worktree is | what happens |
|---|---|
| clean, session unnamed | removed with its branch, no question |
clean, session named with /rename | asks, so you can keep it for later |
| has work in it | asks: keep (directory and branch stay) or remove (everything in it goes) |
| cannot be inspected | asks, and names what it could not check |
-p runs have no exit prompt and never clean up. For those, and for anything the sweep left behind:
git worktree list
git worktree remove .claude/worktrees/fix-hover # --force if it has uncommitted changes
git worktree unlock .claude/worktrees/fix-hover # first, if a killed session left a lock
Claude Code holds a git worktree lock on a worktree while its agent runs, so a concurrent cleanup cannot remove it. A killed background session’s lock is released by the next sweep; a lock you set yourself never is.
What worktrees share with the main checkout is worth knowing: the .git directory (commits from inside a worktree work with the sandbox on), project-scope plugins, and permission approvals. Choosing “don’t ask again” for a Bash command in a worktree session saves the rule to the main checkout’s .claude/settings.local.json, so it applies in every worktree and survives the worktree’s removal.
Name the tabs
Three terminal tabs that all say claude are three identical doors. /rename <what this session is for> gives the session a name; resume finds it by that name later, and a named session gets the cleanup prompt instead of silent removal. We name each tab after the row on our task board it is working, so a glance at the tab bar says what is in flight.
Claude Code also writes its state into the terminal window title, a spinner while it works. Ghostty, iTerm2 and Terminal all show it. That is the only built-in signal that a session in the background has stopped, and it is one character wide.
The problem worktrees do not solve
Files no longer collide. Attention still does. You give the fixing session a task, switch to the testing session, get pulled into a Slack thread, and twenty minutes later the fixing session has been sitting on a permission prompt for nineteen of them.
The first fix is a Notification hook that puts the worktree folder in the banner title, so three sessions send three different notifications. The full setup, with the macOS gotcha that makes half of these fail silently, is in Claude Code notification when done. The short version reads cwd from stdin:
#!/bin/sh
input=$(cat)
dir=$(printf '%s' "$input" | jq -r '.cwd // "" | split("/") | last')
osascript -e "display notification \"needs you\" with title \"Claude Code · $dir\""
A hook fires per session, for Claude Code only. It does not know that Codex in the fourth tab is also waiting, that the session you left an hour ago has been idle since, or which Slack thread you were reading when you switched away. It lands you in a terminal, not on the thought.
One list over the tabs
Three sessions mean three threads of work, and the tasks behind them live in Linear, GitHub, Slack and your head. Sharpy is a to-do list for Mac that writes itself from those: a review request, an assigned issue, “can you look at this?” in a thread. A merged pull request crosses its task off.
Claude Code, Codex and Cursor read the same list over MCP. Start a session with “take the top task from my list”, and the agent marks it done in Sharpy when the work lands. With three worktrees, that is three sessions pulling from one list, and the list shows what is still open when the banners stop.
Sharpy is free in early access on Macs with Apple silicon: join the waitlist. The MCP setup per agent is on the MCP page, and what Claude Code remembers between sessions is in Claude Code memory: what it keeps, and what it can’t see.






