Git worktrees
This guide covers running commands in git worktrees — separate checkouts of your repository on different branches. Each worktree has its own working directory, so multiple runs work on separate branches simultaneously.
Prerequisites
- Moat installed
- A git repository (
moat wtalso requires anagent.yamlat the repository root)
Quick start
Start a run on a new branch:
moat wt dark-mode
This creates the dark-mode branch from HEAD (if it doesn’t exist), creates a worktree at ~/.moat/worktrees/<repo-id>/dark-mode, and starts the command defined in agent.yaml.
How it works
moat wt <branch> does three things:
- Creates the branch from HEAD if it doesn’t already exist
- Creates a git worktree — a separate checkout of the branch at
~/.moat/worktrees/<repo-id>/<branch> - Starts a run using the command from
agent.yamlwith the worktree as its workspace
The repository is identified by its remote URL (or local path if no remote is configured). Each branch gets its own directory under that repo ID.
If the branch and worktree already exist, they are reused.
Two ways to use worktrees
The moat wt command
moat wt reads agent.yaml from the repository root and starts a run in the worktree:
# Start the command defined in agent.yaml on the dark-mode branch
moat wt dark-mode
# Run in background
moat wt dark-mode -d
# Run a specific command instead of the agent.yaml default
moat wt dark-mode -- make test
This requires an agent.yaml in the repository root.
The --worktree flag
The --worktree flag works on moat claude, moat codex, and moat gemini:
# Start Claude Code on the dark-mode branch
moat claude --worktree dark-mode
# Start Codex on a feature branch with a prompt
moat codex --worktree feature/auth -p "implement OAuth login" -d
# Start Gemini on a refactor branch
moat gemini --worktree cleanup
The --worktree flag creates the branch and worktree the same way as moat wt, but starts the specified agent instead of reading agent.yaml. --wt is accepted as a shorthand alias.
Run naming
Run names are generated automatically:
- If
agent.yamlhas anamefield (or--nameis passed), the run name is{name}-{branch} - Otherwise, the run name is
{branch}
Override with --name:
moat wt dark-mode --name my-custom-name
Parallel branches
Start runs on multiple branches simultaneously:
moat wt feature/auth -d
moat wt feature/dark-mode -d
moat wt fix/login-bug -d
Each run gets its own worktree, its own container, and its own branch. Branch names with slashes (like feature/auth) are supported.
Check on all worktree runs:
$ moat wt list
BRANCH RUN NAME STATUS WORKTREE
feature/auth my-agent-feature/auth running ~/.moat/worktrees/github.com/my-org/my-project/feature/auth
feature/dark-mode my-agent-feature/... running ~/.moat/worktrees/github.com/my-org/my-project/feature/dark-mode
fix/login-bug my-agent-fix/login-bug stopped ~/.moat/worktrees/github.com/my-org/my-project/fix/login-bug
Active run detection
If a run is already active in a worktree, moat wt returns an error:
Error: a run is already active in worktree for branch "dark-mode": my-agent-dark-mode (run_a1b2c3d4e5f6)
Attach with 'moat attach run_a1b2c3d4e5f6' or stop with 'moat stop run_a1b2c3d4e5f6'
The --worktree flag on agent commands behaves the same way.
Cleaning up
Remove worktree directories for stopped runs:
# Clean all stopped worktrees for the current repo
moat wt clean
# Clean a specific branch's worktree
moat wt clean dark-mode
moat wt clean removes the worktree directory and runs git worktree prune. It never deletes branches — your work remains in git.
Active worktrees (with running containers) are skipped.
moat clean also removes worktree directories as part of its broader cleanup (stopped runs, unused images, orphaned networks).
Worktree storage
Worktrees are stored at:
~/.moat/worktrees/<repo-id>/<branch>
The <repo-id> is derived from the repository’s remote URL in host/owner/repo format. For example, github.com:my-org/my-project.git becomes github.com/my-org/my-project. Repositories without a remote use _local/<directory-name>.
Override the base path with MOAT_WORKTREE_BASE:
export MOAT_WORKTREE_BASE=/mnt/fast-disk/worktrees
moat wt dark-mode
Configuration
moat wt reads agent.yaml from the repository root. If the worktree directory also contains an agent.yaml, the worktree’s copy takes precedence.
Branch-specific configuration works as follows:
- Start with
agent.yamlin your main branch - The worktree inherits it when the branch is created
- Modify the worktree’s
agent.yamlfor branch-specific settings (extra grants, different dependencies)
Example: parallel feature development
-
Configure
agent.yaml:name: my-agent grants: - anthropic - github dependencies: - node@20 - git - claude-code -
Start runs on multiple branches:
moat wt feature/auth -d moat wt feature/dark-mode -d -
Monitor progress:
moat wt list moat logs run_a1b2c3d4e5f6 moat attach run_a1b2c3d4e5f6 -
When finished, clean up worktree directories:
moat wt clean -
Branches remain in git. Merge as usual:
git merge feature/auth git merge feature/dark-mode
Troubleshooting
”agent.yaml not found”
moat wt requires an agent.yaml in the repository root. Create one, or use moat claude --worktree / moat codex --worktree / moat gemini --worktree which work without agent.yaml.
”not inside a git repository”
Run moat wt from within a git repository. Worktrees are a git feature and require a git repo.
”a run is already active in worktree”
Another run is already active on that branch. Either attach to it or stop it first:
moat attach <run-id>
moat stop <run-id>
Worktree persists after stop
moat stop stops the container but does not remove the worktree. Use moat wt clean to remove stopped worktree directories, or moat clean to remove all stopped resources including worktrees.
Related guides
- Running Claude Code — Use
--worktreewith Claude Code - Running Codex — Use
--worktreewith Codex - Running Gemini — Use
--worktreewith Gemini