This article has been machine-translated from Chinese. The translation may contain inaccuracies or awkward phrasing. If in doubt, please refer to the original Chinese version.
Preface
I’ve been using Claude Code more and more frequently lately, sometimes running three or four tasks simultaneously: one fixing a bug, one adding a new feature, one under review, and another running tests to validate new ideas. The problem is: they all need independent working directories, otherwise the code will interfere with each other.
Git’s worktree feature was designed exactly for this scenario, but the native commands are quite verbose. The traditional way to create a new worktree looks like this:
git worktree add -b feature-auth ../myproject-feature-auth
cd ../myproject-feature-auth
And removing it requires going back to the main directory:
cd ../myproject
git worktree remove ../myproject-feature-auth
git branch -d feature-auth
You have to type the branch name three times and manually cd each time. After doing this repeatedly, it starts to feel like a waste of life, which is also why I didn’t like worktree before.
Until I discovered Worktrunk, and realized that worktree management could actually be this elegant (of course there are many other tools too).
After using it for a while, it felt really great, so I’m writing a blog post to share the love.
What is Worktrunk
Simply put, Worktrunk is a CLI wrapper tool for Git Worktree, specifically optimized for scenarios where you’re running multiple AI Agents in parallel. Its core philosophy is:
Each worktree corresponds to a branch, use the branch name to manage worktrees, and paths are auto-generated.
Compare the command differences to feel the impact:
| Task | Worktrunk | Native Git |
|---|---|---|
| Switch to a worktree | wt switch feat | cd ../repo.feat |
| Create worktree + start Claude | wt switch -c -x claude feat | git worktree add -b feat ../repo.feat && cd ../repo.feat && claude |
| Clean up current worktree | wt remove | cd ../repo && git worktree remove ../repo.feat && git branch -d feat |
| List all worktree statuses | wt list | git worktree list (only shows paths) |
Essentially, it reduces the complexity of git worktree operations from “remember three parameters” to “just say a branch name”.
Why Do You Need Worktrunk?
If you only use worktree occasionally, native commands are perfectly fine. But when you need frequent parallel development (like running multiple AI Agents simultaneously) or need automated workflows (auto-installing dependencies and running tests after creating a worktree), Worktrunk can save you a lot of time and mental overhead. It essentially codifies “the proper way to use worktree” into a tool.
Installation and Configuration
Installation
macOS/Linux (Homebrew recommended):
brew install max-sixty/worktrunk/wt
Or using Cargo:
cargo install worktrunk
Shell Integration
After installation, you must run this step, otherwise wt switch cannot change directories:
wt config shell install
This adds a function to your .zshrc or .bashrc that allows the wt command to change the current shell’s working directory.
After installation, restart your terminal and run wt --version to confirm successful installation.
Core Commands Explained
wt switch - Switch/Create Worktree
This is the most commonly used command, with minimal usage:
# Switch to an existing worktree (branch name feat)
wt switch feat
# Create new worktree + branch feat based on main branch
wt switch -c feat
# Create worktree + auto-start Claude Code
wt switch -c feat -x claude
# Create new worktree + branch feat-new based on dev branch (not main) + auto-start claude
wt switch -c feat-new -b dev -x claude
Path rules: Worktrunk automatically creates worktrees in the sibling directory of the main repository, with the naming format <repo>.<branch>. For example, if the main repo is at ~/code/myproject, the worktree for branch feat will be at ~/code/myproject.feat.
Parameter explanation:
-c/--create: Create new worktree + branch-x <cmd>: Auto-execute command after switching (e.g.,claude,code,npm install)-b <base>: Specify base branch (default ismain)
| Shortcut | Meaning |
|---|---|
^ | Default branch (main/master) |
@ | Current branch/worktree |
- | Previous working directory (like cd -) |
wt switch - # Back to previous
wt switch ^ # Default branch worktree
wt switch --create fix --base=@ # Branch from current HEAD
Practical Scenarios
Suppose you’re running three parallel tasks:
# Terminal 1: Fix auth bug
wt switch -c -x claude fix-auth
# Terminal 2: Refactor API
wt switch -c -x claude refactor-api
# Terminal 3: Add new feature
wt switch -c -x claude feat-dashboard
Each Claude instance runs in an independent directory without interfering with each other.
wt list - View All Worktrees
wt list
Output looks something like this:
wt list
Branch Status HEAD± main↕ Remote⇅ Commit Age Message
@ feature-api + ↕⇡ +54 -5 ↑4 ↓1 ⇡3 ec97decc 30m Add API tests
^ main ^⇅ ⇡1 ⇣1 6088adb3 4d Merge fix-auth: hardened to…
+ fix-auth ↕| ↑2 ↓1 | 127407de 5h Add secure token storage
○ Showing 3 worktrees, 1 with changes, 2 ahead, 1 column hidden

Much more powerful than native git worktree list, you can see a lot of information:
- Git status: How many uncommitted/untracked files
- CI status: If GitHub Actions is configured, it shows the latest build status
For managing multiple worktrees, this view is very practical.
wt remove - Clean Up Worktree
# Remove current worktree + branch
wt remove
# Remove specified worktree
wt remove feature-branch
wt remove old-feature another-branch
# Remove worktree but keep the branch
wt remove --no-delete-branch feature-branch
# Force delete unmerged branch
wt remove -D experimental
wt merge - Merge Workflow
This command wraps the complete “merge -> clean up” workflow:
# Merge current worktree into default branch like main
wt merge
# Merge current worktree into dev branch
wt merge dev
# Keep worktree after merge
wt merge --no-remove
# Preserve commit history (don't squash)
wt merge --no-squash
# Skip commit/merge (rebase still runs unless --no-rebase is used)
wt merge --no-commit
If a pre-merge hook is configured, tests or lint will run automatically before merging.
wt select - Interactive Selector
If you can’t remember the worktree name, use the select command:
wt select
It pops up an fzf-style interface where you use arrow keys to select the worktree to switch to.

Hooks
Worktrunk supports executing commands at different stages of the worktree lifecycle, with both global user hook configuration (~/.config/worktrunk/config.toml) and project hook configuration (.config/wt.toml).
Hook Types Overview
| Hook | Trigger Time | Blocking | Fail-fast |
|---|---|---|---|
post-create | After worktree creation | Yes | No |
post-start | After worktree creation | No (background) | No |
post-switch | After each switch | No (background) | No |
pre-commit | Before commit during merge | Yes | Yes |
pre-merge | Before merging to target branch | Yes | Yes |
post-merge | After successful merge | Yes | No |
pre-remove | Before worktree deletion | Yes | Yes |
Blocking mode: The main flow waits until the command finishes Fail-fast: The first failed command aborts the entire operation
Core Hooks Explained
post-create - Executes immediately after worktree creation, blocks until complete:
[post-create]
install = "npm ci" # Install dependencies
migrate = "npm run db:migrate" # Database migration
env = "cp .env.example .env" # Copy environment config
post-start - Executes in background after worktree creation, doesn’t block switching:
[post-start]
build = "npm run build" # Build project
server = "npm run dev" # Start dev server
Logs output to .git/wt-logs/{branch}-{source}-post-start-{name}.log
post-switch - Executes in background after every wt switch (whether creating, switching, or staying on current):
post-switch = "echo 'Switched to {{ branch }}'"
pre-commit - Executes before commit during merge, fail-fast:
[pre-commit]
format = "cargo fmt -- --check" # Code format check
lint = "cargo clippy -- -D warnings" # Lint check
pre-merge - Executes before merging to target branch, fail-fast:
[pre-merge]
test = "cargo test" # Run tests
build = "cargo build --release" # Production build
post-merge - Executes on the target branch’s worktree after successful merge (if it exists), otherwise on the main worktree:
post-merge = "cargo install --path ."
pre-remove - Executes before worktree deletion, fail-fast:
[pre-remove]
cleanup = "rm -rf /tmp/cache/{{ branch }}"
Template Variables
Hook commands support template variables that are automatically expanded at runtime:
| Variable | Example | Description |
|---|---|---|
{{ repo }} | my-project | Repository name |
{{ branch }} | feature-foo | Branch name |
{{ worktree }} | /path/to/worktree | Worktree absolute path |
{{ worktree_name }} | my-project.feature-foo | Worktree directory name |
{{ repo_root }} | /path/to/main | Main repository root path |
{{ default_branch }} | main | Default branch name |
{{ commit }} | a1b2c3d4e5f6… | HEAD full SHA |
{{ short_commit }} | a1b2c3d | HEAD short SHA |
{{ remote }} | origin | Primary remote name |
{{ remote_url }} | git@github.com/repo.git | Remote URL |
{{ upstream }} | origin/feature | Upstream tracking branch |
{{ target }} | main | Target branch (merge hooks only) |
Security Mechanism
Project hooks (.config/wt.toml) require user approval on first run:
▲ repo needs approval to execute 3 commands:
○ post-create install:
echo 'Installing dependencies...'
❯ Allow and remember? [y/N]
- Approval records are saved in user config
- Command changes require re-approval
--yesskips prompts (suitable for CI)--no-verifycompletely skips hooks
Managing approval records:
wt hook approvals add # Pre-approve all commands for current project
wt hook approvals clear # Clear approvals for current project
wt hook approvals clear --global # Clear global approvals
User-Level Hooks
Hooks configured in ~/.config/worktrunk/config.toml apply to all repositories and don’t require approval:
| Dimension | Project Hook | User Hook |
|---|---|---|
| Config Location | .config/wt.toml | ~/.config/worktrunk/config.toml |
| Scope | Single repository | All repositories |
| Requires Approval | Yes | No |
| Execution Order | Runs later | Runs first |
Looking at it, I think this hook is very important — it can reuse the main worktree’s cache:
[post-create]
# Symlink node_modules to avoid duplicate installs
cache = "ln -sf {{ repo_root }}/node_modules node_modules"
env = "cp {{ repo_root }}/.env.local .env"
Running Hooks Independently
Besides automatic triggers, you can also manually run hooks for testing or retrying:
wt hook pre-merge # Run pre-merge hooks
wt hook pre-merge --yes # Skip approval prompt (suitable for CI)
wt hook show # View all configured hooks
Use cases: Hook development testing, CI pipelines, retrying after failure, etc.
Claude Code Plugin Status Monitoring
claude plugin marketplace add max-sixty/worktrunk
claude plugin install worktrunk@worktrunk
Manually Setting Status Markers
Besides auto-tracking Claude status, you can also manually set any marker on a worktree for other workflows:
# Set marker on current branch
wt config state marker set "🚧"
# Set marker on specified branch
wt config state marker set "✅" --branch feature
# Directly manipulate Git Config (advanced usage)
git config worktrunk.state.feature.marker '{"marker":"💬","set_at":0}'
Statusline
wt list statusline --claude-code outputs a compact status line for Claude Code’s statusline display:
~/w/myproject.feature-auth !🤖 @+42 -8 ↑3 ⇡1 ● | Opus
LLM Commit Messages - Auto-generating Commit Messages
LLM Commit Messages | Worktrunk
Worktrunk can call LLMs to automatically generate commit messages, integrated into wt merge, wt step commit, wt step squash, and other commands.
It works without configuration — by default, it generates simple messages based on file names, but configuring an LLM can produce more meaningful commit messages.
Installation and Configuration
1. Install the llm tool
Uses llm:
uv tool install -U llm
# Or directly via brew
brew install llm
2. Configure API Key
Choose your preferred LLM provider:
# Use Claude (recommended)
llm install llm-anthropic
llm keys set anthropic
# Enter your Anthropic API Key
# Or use OpenAI
llm keys set openai
# Enter your OpenAI API Key
3. Configure Worktrunk
Create the config file (if not already present):
wt config create
Edit ~/.config/worktrunk/config.toml, add:
[commit-generation]
command = "llm"
args = ["-m", "claude-3-5-haiku-latest"] # Or gpt-4o-mini
Usage Scenarios
After configuration, the following commands will auto-generate commit messages:
Scenario 1: Generate squash commit when merging branches
$ wt merge
◎ Squashing 3 commits into a single commit (5 files, +48)...
◎ Generating squash commit message...
feat(auth): Implement JWT authentication system
- Add JWT token generation and validation
- Implement refresh token mechanism
- Add middleware for protected routes
Scenario 2: Commit current changes
$ wt step commit
◎ Generating commit message...
fix(api): Handle null response in user endpoint
Scenario 3: Squash multiple commits into one
$ wt step squash
◎ Squashing 5 commits...
◎ Generating squash commit message...
refactor(ui): Modernize component architecture
Using Other AI Tools
Besides llm, any tool that can read prompts from stdin and output text works:
# Using aichat
[commit-generation]
command = "aichat"
args = ["-m", "claude:claude-3-5-haiku-latest"]
# Using custom script
[commit-generation]
command = "./scripts/generate-commit.sh"
Fallback Behavior
Without LLM configured, Worktrunk generates simple file-name-based messages:
Changes to auth.rs & config.rs
CI Status Integration
If you use GitHub Actions, Worktrunk can show build status in wt list:
# Configure GitHub Token
wt config github.token "ghp_xxxxxxxxxxxx"
# After that, wt list will show CI status
wt list
Practical Workflows
Running Multiple Claude Code Instances in Parallel
Suppose you’re using Zellij or Tmux to manage multiple terminal windows:
# Pane 1: Fix bug
wt switch -c -x claude fix-login-bug
# Pane 2: Refactor
wt switch -c -x claude refactor-utils
# Pane 3: New feature
wt switch -c -x claude feat-export
Each Claude works in an independent directory. You can switch back to the main directory at any time to see the global status:
wt switch main
wt list
Quickly Verifying Ideas
Sometimes you want to quickly verify an idea without polluting the current branch:
# Create temporary worktree
wt switch -c -x code experiment
# Done verifying, just delete it
wt remove
Since worktrees are independent directories, deleting them won’t affect other branches.
Running Code During PR Review
When a PR comes in and you want to run the code locally:
# Create worktree based on PR branch
wt switch -c review-pr-123 -b origin/pr-123
# Install deps, run tests
npm install
npm run test
# Done reviewing, clean up
wt remove
References
- Worktrunk Official Website
- Anthropic - Claude Code Best Practices (Officially recommended worktree workflow)
- incident.io - Shipping faster with Claude Code and Git Worktrees
- Git Worktree Official Docs
喜欢的话,留下你的评论吧~