# 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 wt` also requires a `moat.yaml` at the repository root)

## Quick start

Start a run on a new branch:

```bash
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 `moat.yaml`.

## How it works

`moat wt <branch>` does three things:

1. **Creates the branch** from HEAD if it doesn't already exist
2. **Creates a git worktree** — a separate checkout of the branch at `~/.moat/worktrees/<repo-id>/<branch>`
3. **Starts a run** using the command from `moat.yaml` with 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 `moat.yaml` from the repository root and starts a run in the worktree:

```bash
# Start the command defined in moat.yaml on the dark-mode branch
moat wt dark-mode

# Run a specific command instead of the moat.yaml default
moat wt dark-mode -- make test
```

This requires a `moat.yaml` in the repository root.

### The `--worktree` flag

The `--worktree` flag works on `moat claude`, `moat codex`, and `moat gemini`:

```bash
# 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"

# 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 `moat.yaml`. `--wt` is accepted as a shorthand alias.

## Run naming

Run names are generated automatically:

- If `moat.yaml` has a `name` field (or `--name` is passed), the run name is `{name}-{branch}`
- Otherwise, the run name is `{branch}`

Override with `--name`:

```bash
moat wt dark-mode --name my-custom-name
```

## Parallel branches

Start runs on multiple branches simultaneously, each in its own terminal:

```bash
# Terminal 1
moat wt feature/auth

# Terminal 2
moat wt feature/dark-mode

# Terminal 3
moat wt fix/login-bug
```

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:

```bash
$ 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:

```text
Error: a run is already active in worktree for branch "dark-mode": my-agent-dark-mode (run_a1b2c3d4e5f6)
Follow with 'moat logs -f 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:

```bash
# 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:

```text
~/.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`:

```bash
export MOAT_WORKTREE_BASE=/mnt/fast-disk/worktrees
moat wt dark-mode
```

## Configuration

`moat wt` reads `moat.yaml` from the repository root. If the worktree directory also contains a `moat.yaml`, the worktree's copy takes precedence.

Branch-specific configuration works as follows:

1. Start with `moat.yaml` in your main branch
2. The worktree inherits it when the branch is created
3. Modify the worktree's `moat.yaml` for branch-specific settings (extra grants, different dependencies)

## Example: parallel feature development

1. Configure `moat.yaml`:
   ```yaml
   name: my-agent

   grants:
     - anthropic
     - github

   dependencies:
     - node@22
     - git
     - claude-code
   ```

2. Start runs on multiple branches:
   ```bash
   moat wt feature/auth
   moat wt feature/dark-mode
   ```

3. Monitor progress:
   ```bash
   moat wt list
   moat logs run_a1b2c3d4e5f6
   moat logs -f run_a1b2c3d4e5f6
   ```

4. When finished, clean up worktree directories:
   ```bash
   moat wt clean
   ```

5. Branches remain in git. Merge as usual:
   ```bash
   git merge feature/auth
   git merge feature/dark-mode
   ```

## Troubleshooting

### "moat.yaml not found"

`moat wt` requires a `moat.yaml` in the repository root. Create one, or use `moat claude --worktree` / `moat codex --worktree` / `moat gemini --worktree` which work without `moat.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. Follow its logs or stop it first:

```bash
moat logs -f <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.

## Multi-repo workspaces

### Submodules and subtrees

If your repository uses git submodules or subtrees, worktrees do not automatically initialize them. Add initialization to your `moat.yaml` command or `pre_run` hook:

```yaml
hooks:
  pre_run: git submodule update --init --recursive
```

Submodule HEAD pointers in a worktree are frozen at the commit recorded in the parent repo at branch creation time. Run `git submodule update --remote` inside the worktree to pick up newer commits.

### Multiple independent repos

To give an agent access to multiple independent repos at once, pass their parent directory as the workspace:

```bash
moat run ~/dev
```

This mounts `~/dev` at `/workspace`, giving the agent access to all repos underneath. However, `moat wt` does not work here because the parent directory is not a git repository — there is no branch to create a worktree from.

For worktree-style isolation across independent repos, one approach is a wrapper git repository above the child repos (with the repos in `.gitignore`) and a `pre_run` hook that clones or checks out matching branches. This requires project-specific scripting and is beyond the scope of this guide.

## Related guides

- [Running Claude Code](/moat/guides/claude-code) — Use `--worktree` with Claude Code
- [Running Codex](/moat/guides/codex) — Use `--worktree` with Codex
- [Running Gemini](/moat/guides/gemini) — Use `--worktree` with Gemini

---
[← Moat documentation index](https://majorcontext.com/moat/llms.txt)
