Skip to main content

Claude Code: Parallel Development with /worktree

· 5 min read
Craig P. Motlin
Software Engineer

Building on my workflow with /todo and /commit, I've created the /worktree command to enable parallel development on multiple tasks using Git worktrees.

This post is part of my Claude Code setup series.

Evolution of My Workflow

I started with a simple pattern: maintain a todo list and repeatedly run three commands:

  • /todo - Implement one task
  • /commit - Create a commit
  • /compact - Manage the context window

This workflow steadily churned through my todo list, but LLMs can be slow. While waiting for one task to complete, I'd switch to working on a second task. Initially, I tried running Claude on two tasks in the same directory simultaneously, but they would trample each other's changes.

I started using Git worktrees. It worked well. Each instance of Claude works in its own directory, eliminating conflicts, while still working on a single git repository. Later, Anthropic officially recommended using worktrees in their documentation, which validated the approach.

Building the /worktree Command

While Anthropic recommends using worktrees, they don't provide any automation or commands for managing them yet. I found myself spending too much time creating worktrees, copying todo lists, and managing branches myself. That's where my /worktree command comes in.

Using the command

This command can be used within claude, with a number of worktrees to create.

/worktree 3

⏺ 1 worktree has been created so far.
⏺ 2 worktrees have been created so far.
⏺ 3 worktrees have been created.

Even though the worktrees used for parallel work, they are created in serial. Each time a worktree is created, Claude also opens a new iTerm tab, and kicks off the command:

claude --dangerously-skip-permissions /todo

How It Works

The /worktree command automates several key steps:

1. Find and mark the next available todo

- [ ] Implement user authentication with JWT

becomes:

- [>] Implement user authentication with JWT <!-- worktree: implement-user-auth-jwt -->

2. Create the worktree

git worktree add ../my-app-implement-user-auth-jwt -b task/implement-user-auth-jwt HEAD

3. Set up the worktree environment

# Copy environment files if they exist
cp .envrc ../my-app-implement-user-auth-jwt/
direnv allow ../my-app-implement-user-auth-jwt

# Trust the directory for mise
mise trust ../my-app-implement-user-auth-jwt

4. Create a focused todo file

mkdir ../my-app-implement-user-auth-jwt/.llm
echo "- [ ] Implement user authentication with JWT" > .llm/todo.md

5. Launch Claude in a new terminal tab

Launch a new iTerm tab and run:

cd ../my-app-implement-user-auth-jwt
claude --dangerously-skip-permissions /todo

And if we wrote /worktree 3, the command will repeat these steps until 3 worktrees are created.

Integration with /todo Workflow

The /worktree command creates a new worktree with its own .llm/todo.md file containing just the single task. This means you can use the same /todo workflow we've already established, but now with better isolation and the ability to work on multiple tasks in parallel. Each worktree starts fresh from main, giving you a clean context for every task.

Managing Context Size

If we have a large number of tasks we want to run in parallel, we need to be careful about the context size. There are two ways I manage this.

A command like /worktree 10 can run out of context in a single Claude session, trigger auto-compaction, and get lost. To avoid this, I move the looping outside of Claude.

for i in $(seq 1 10); do claude --dangerously-skip-permissions --print /worktree; done

The second problem is that if we run too many tasks in parallel, we can quickly hit API usage limits. To avoid this, I sometimes downgrade the model. At the time of writing, that means switching from Opus 4 to Sonnet 4.

If I'm going step away for a while, I can also use the sleep command to space out the requests. This allows me to run tasks overnight without hitting API limits.

for i in $(seq 1 11); do claude --dangerously-skip-permissions --print /worktree; sleep 1200; done

Finishing Up

After all parallel tasks complete, I cherry-pick the completed work into a single branch. This gives me a chance to review all the changes together and ensure they work well as a cohesive whole.

If there are any merge conflicts, and they look at all tricky to resolve, I just throw away the work and mark the todo as [ ] again.

Finally, I clean up all worktrees except the current one.

git worktree remove ../myproject-add-user-auth-jwt
git branch -d task/add-user-auth-jwt

Or I ask Claude to do it for me. If you ask Claude to clean up worktrees, make sure to tell it not to use --force.

Full /worktree Command

Here's the complete /worktree command that automates the entire process:

.claude-prompts/commands/worktree.md
# 🌳 Create Git Worktree for Next Available Todo

You are to create $ARGUMENTS new git worktree(s) in peer directories for the first available todo items (not completed and not already in progress).

## Todo Status Icons:
- `[ ]` - Not started
- `[x]` - Completed
- `[>]` - In progress in a peer directory/worktree

## Steps to follow:

1. **Find the next available todo**:
- Spawn a sub-agent or sub-task to find the next task in the todo list.
- Read the file `./.llm/todo.md`. The file will only exist in this directory. Don't look in other locations. Don't look in the home directory.
- Look for the first todo that is marked with `[ ]` (not `[x]` or `[>]`)
- This will be the todo to work on
- End the sub-agent or sub-task here and share back the entire task information verbatim.
- If no available todos exist, inform the user that all todos are either completed or in progress

2. **Update the todo status**:
- Spawn a sub-agent or sub-task to update the task to show that it's in progress
- Change the selected todo from `[ ]` to `[>]` in the original todo list
- Add a comment indicating which worktree it's being worked on in, e.g.:
```markdown
- [>] Implement user authentication with JWT <!-- worktree: implement-user-auth-jwt -->
```

3. **Create the git worktree**:
- In parallel with marking the task in progress, spawn a second sub-agent or sub-task to create the git worktree
- Determine the current repository's root directory
- Create a worktree name based on the todo item (use kebab-case)
- Create the worktree in a peer directory: `git worktree add ../<worktree-name> -b <branch-name> ${UPSTREAM_REMOTE:-origin}/${UPSTREAM_BRANCH:-main}`
- `<worktree-name>` and `<branch-name>` are placeholders for you to replace with names of your choice
- `UPSTREAM_REMOTE` and `UPSTREAM_BRANCH` are real environment variables
- The `<branch-name>` should be prefixed with `task/`
- The `<worktree-name>` should start with the original repository's directory name
- If there is a `.envrc` file in this directory, copy it into the new directory and run `direnv allow ../<worktree-name>`
- Run `mise trust ../<worktree-name>`

- Set up the todo file in the new worktree:
- Create the directory `.llm` if it doesn't exist
- Create `.llm/todo.md` with ONLY this single todo item:

```markdown
# Todo

- [ ] [Single todo item text here]
- [Other context that was under the original todo]

When this task is complete:
- Edit the original task list at `<this directory>/.llm/todo.md`, on line <line>
- Update the todo status from `[>]` to `[x]`
```

## Conclusion

Run a command to create a new terminal tab in tme newly created worktree, and run `claude --dangerously-skip-permissions /todo` in that tab.

If we are running in iTerm:

```console
osascript -e '
tell application "iTerm"
tell current window
create tab with default profile command "claude code --dangerously-skip-permissions /todo" working directory "../<worktree-name>"
end tell
end tell
'
```

If we are running in xfce4-terminal:

```console
xfce4-terminal --tab --working-directory="../<worktree-name>" -x bash -c "claude code --dangerously-skip-permissions /todo; exec bash"
```

## Loop

Say how many worktrees you have created.

Repeat the instructions to create another worktree until you have created $ARGUMENTS worktrees.

View on GitHub