# Isolated Codex tasks with Git worktrees

URL: https://developertoolkit.ai/en/codex/automate/worktrees/
Description: Run each Codex task in its own Git worktree with --worktree, /worktree or git worktree add, bootstrap it, prove it with gates, and clean up without losing work.

A Codex worktree task runs one session in its own Git worktree, so its edits, installs and tests never touch your main checkout. Codex CLI 0.157.1 creates a managed worktree with `--worktree` or `/worktree`; `git worktree add` lets you name the path and branch. It is finished only when its gates pass and its commits sit on a branch.

You asked Codex to fix a flaky auth test while you kept working on a migration in the same directory. Twenty minutes later your working tree holds both sets of changes, `npm install` has rewritten the lockfile under you, and you cannot tell which edits are yours. This page is for the developer who runs Codex locally and wants every task in its own checkout, with a clean way to verify it, keep it and throw it away.

## What you get from running Codex tasks in worktrees

- A decision table for managed worktrees (`codex --worktree`), explicit ones (`git worktree add`) and the desktop app.
- The facts about what a managed worktree does and does not carry over, measured on Codex CLI 0.157.1.
- A bootstrap script that makes a fresh worktree runnable without copying production secrets.
- Two copy-paste prompts: one that starts a task safely inside a worktree, one that hands it back ready to merge.
- A gate you run before you read any diff, and a cleanup order that never deletes an unmerged commit.

Coordinating many worktrees at once (lanes, fan-out scripts, merge order) is the job of [Codex multi-agent workflows](/en/codex/automate/multi-agent-workflows/). This page covers one task's worktree from creation to removal.

## Which kind of Codex worktree should you use?

Worktree support is on by default since Codex CLI 0.156.0 (the `worktrees` feature is `stable` and `true` in `codex features list`, 0.157.1). A session still runs in your current directory unless you opt in. Codex 0.162.0 (2026-10-08) added managed Git worktree tools that create and list worktrees from trusted projects (OpenAI's release notes). The carry-over measurements in the next section were taken on 0.157.1, and the release notes do not say whether the carry-over changed, so repeat that check after you upgrade.

| You want | Use | Where the checkout lives | Branch |
| --- | --- | --- | --- |
| A quick isolated interactive task | `codex --worktree` | `$CODEX_HOME/worktrees/<id>/<repo>` (by default under `~/.codex/`) | None: detached `HEAD` at your current commit |
| To move a running conversation into isolation | `/worktree` inside the session ("start or continue a conversation in a new worktree") | Same managed location | None until you create one |
| A scripted, non-interactive task | `codex exec --worktree`, or `git worktree add` plus `codex exec -C DIR` | Managed location, or a path you choose | None with `codex exec --worktree` (detached `HEAD`); named with `git worktree add -b` |
| A path, branch and base you control (ports, CI scripts, review tooling) | `git worktree add -b BRANCH PATH BASE`, then `codex` in that path | Where you put it | Named from the start |
| Threads in the desktop app | The app's worktree option per thread (`codex app`, macOS and Windows) | Managed by the app | See [Codex desktop app mastery](/en/codex/build/app-mastery/) |

`codex fork --worktree` and `codex resume --worktree` exist too (checked in `--help`, 0.157.1): they continue an earlier session in a new managed worktree, which is the clean way to try a second approach without disturbing the first.

The rule of thumb: use `--worktree` for throwaway or exploratory tasks, and `git worktree add` when the result must become a named branch and pull request, or when a script, a port allocator or a teammate needs to find the checkout by path.

## What does a managed Codex worktree carry over?

We ran `codex exec --worktree` on Codex CLI 0.157.1 (2026-09-26) in a repository with a modified tracked file, an untracked file and a gitignored `.env`. The managed worktree contained:

| State in your main checkout | In the managed worktree? |
| --- | --- |
| Committed files at `HEAD` | Yes, checked out at the same commit |
| The current branch | No. The worktree is on a detached `HEAD` |
| Uncommitted edits to tracked files | No. The file has its committed content |
| Untracked files | No |
| Gitignored files (`.env`, `node_modules/`, build caches) | No |

Three consequences follow. Commit (or stash and re-apply) anything the task depends on before you start it. Expect every managed worktree to need a dependency install and local configuration. Create a branch before the agent commits, because commits on a detached `HEAD` belong to no branch and are easy to lose when the worktree is removed.

The managed worktree also outlives the session: in the same run it was still listed by `git worktree list` after `codex exec` exited. `codex --help` in 0.157.1 lists no subcommand that removes a worktree, so removal is Git's job, from any checkout of the repository.

## Run one Codex task in an isolated worktree

1. **Check what the task will start from.**

   ```bash
   git status --short        # anything listed here will NOT reach a new worktree
   git branch --show-current
   git worktree list         # existing worktrees, including Codex-managed ones
   ```

   Commit the work the task needs. If you do not want to commit half-finished code, create the worktree from the last good commit and describe the missing piece in the prompt instead.

2. **Create the worktree.** Pick one of the two forms.

   Managed, for a quick task:

   ```bash
   codex --worktree
   ```

   The session opens in `$CODEX_HOME/worktrees/<id>/<repo>`; in a second terminal, find it with `git worktree list` and run the bootstrap there before you send the first prompt.

   Explicit, when you want the branch and path fixed up front:

   ```bash
   git fetch origin
   git worktree add -b codex/fix-auth-flake ../myapp-fix-auth-flake origin/main
   cd ../myapp-fix-auth-flake
   codex
   ```

   Replace `origin/main` with your repository's real default branch (`git symbolic-ref refs/remotes/origin/HEAD` prints it). Git refuses a branch that is already checked out in another worktree, which is a feature: two agents cannot share one branch by accident.

3. **Bootstrap the checkout.** Run this from inside the new worktree, in your own terminal rather than through the agent, so installs get the network access the sandbox withholds:

   ```bash
   #!/usr/bin/env bash
   # bootstrap-worktree.sh: make a fresh worktree runnable
   set -euo pipefail
   MAIN=$(git worktree list --porcelain | awk 'NR==1 {print $2}')   # the main checkout is always listed first
   for f in .env.development .env.test; do                          # development files only, never production
     if [ -f "$MAIN/$f" ]; then cp "$MAIN/$f" .; fi
   done
   npm ci                                                           # install from the lockfile, do not re-resolve
   grep -qs '^PORT=' .env.development || echo "PORT=$((4000 + RANDOM % 1000))" >> .env.development   # a port no other worktree is likely using; added once
   ```

   Re-running the script is safe: it copies the same files again, reinstalls from the lockfile and keeps the port it already assigned. Keep an allowlist of files to copy, as above. Copying every gitignored file is how a production key ends up in a directory an agent can read. If your repository already has a setup script, call it here instead. When the task also needs its own database or service stubs, give it a full per-task stack as in [ephemeral environments for agent tasks](/en/workflows/harness/ephemeral-environments/).

4. **Start the task with a scoped prompt.** Paste the first prompt below. It tells Codex where it is, what it may touch and what "done" means.

5. **Prove the result before you read it.** Run the gate in [How do you verify a worktree task without reading every line?](#how-do-you-verify-a-worktree-task-without-reading-every-line) below. Read the diff only when the gate passes, and then only the files it flags.

6. **Integrate through the normal path.** Push the branch and open a pull request, so CI and your review rules apply exactly as they do to human work. Do not copy files between worktrees by hand, and do not `git apply` several agent patches onto one branch without rerunning the gates after each.

7. **Remove the worktree only after the work is safe.** See [clean up Codex worktrees without losing commits](#clean-up-codex-worktrees-without-losing-commits).

**Copy-paste prompt: start a task inside a worktree**

```text
You are working in a dedicated Git worktree. Work only inside this directory.

First:
1. Run `git rev-parse --show-toplevel`, `git status --short` and `git branch --show-current`, and tell me what you found.
2. If HEAD is detached, create a branch with `git switch -c codex/fix-auth-flake` before changing anything.
3. Read AGENTS.md for the build, lint and test commands.

Task: make tests/auth/session-refresh.test.ts pass reliably. It fails about one run in five on CI. Find the cause (timer, shared state or ordering) before changing code; do not add retries or increase timeouts to hide it.

Rules:
- Do not touch files outside src/auth/ and tests/auth/ unless you stop and ask first.
- Do not install new dependencies, change the lockfile, or read or write any .env file.
- Do not push, merge, deploy, or remove this worktree.

Done means: the test passes 20 times in a row with `for i in $(seq 20); do npx vitest run tests/auth/session-refresh.test.ts || exit 1; done`, and type check, lint and the full test suite pass. End with each command you ran, its exit code, the root cause in two sentences, and the list of files you changed.
```

Adjust the test file, paths and repeat command to your project; the structure (locate, branch, rules, a done condition with exit codes) is what makes the prompt work in any worktree.

## How do you verify a worktree task without reading every line?

A worktree gives you something the shared checkout never does: a diff that belongs to exactly one task. Use it. Run these checks from the task's worktree, in order, and stop at the first failure.

```bash
#!/usr/bin/env bash
# worktree-gate.sh BASE ALLOWED_PATHS_REGEX
# example: ./worktree-gate.sh origin/main '^(src/auth/|tests/auth/)'
set -euo pipefail
base="$1"; allowed="$2"

test -z "$(git status --porcelain)" || { echo "FAIL: uncommitted changes"; exit 1; }
git symbolic-ref -q HEAD >/dev/null   || { echo "FAIL: detached HEAD, create a branch"; exit 1; }

stray=$(git diff --name-only "$base"...HEAD | grep -v -E "$allowed" || true)
[ -z "$stray" ] || { echo "FAIL: files outside the task:"; echo "$stray"; exit 1; }

npm run typecheck                    # separate lines: set -e stops on the first failing check
npm run lint
npm test

codex review --base "$base" || echo "WARN: codex review did not complete"   # advisory: findings never fail the script
echo PASS
```

`codex review --base` runs the built-in review prompt. In Codex CLI 0.157.1 it cannot take custom instructions as well: `codex review --base main "..."` fails with `the argument '--base <BRANCH>' cannot be used with '[PROMPT]'` (checked 2026-09-26), and `--uncommitted` has the same restriction. Put standing review rules, such as "flag behaviour without a test", in `AGENTS.md` instead of on the command line. `codex review` is advisory in this script: it prints findings, and `codex review --help` in 0.157.1 documents no exit code that fails on them, so a `PASS` line means the mechanical checks passed. If the review cannot run at all (not signed in, no network), the `|| echo` prints a warning instead of letting `set -e` stop the script. Read its output, and treat the files it flags as the ones you read by hand.

| Check | What it catches |
| --- | --- |
| Clean status and a named branch | Work that exists only in the worktree and would vanish on removal |
| Allowed-paths diff | An agent that "fixed" something outside its task |
| Type check, lint, tests | Broken behaviour, run in isolation from other tasks' edits |
| `codex review --base` | Logic errors and missing tests, from a second pass that did not write the code |
| CI on the pull request | Everything above again, on a clean machine, plus integration with the latest base |

You sign off on two things: the done condition in the prompt before the task starts, and the files the gate flags afterwards. Auth, payments and migrations always get a human read, whatever the gate says. The done condition works best as an executable acceptance criterion ([how to turn acceptance criteria into failing tests](/en/workflows/plan/acceptance-criteria/)), and the pull request should carry the [evidence bundle an agent's pull request must prove](/en/workflows/ship/evidence-bundle/). For how review scales across a team, see [Codex review strategies](/en/codex/ship/review-strategies/).

**Copy-paste prompt: hand the worktree back ready to merge**

```text
Prepare this worktree for review. Do not push, merge or delete anything.

1. Run `git status --short`. Commit every change that belongs to the task with a message that says what changed and why; list anything you did not commit and why.
2. Confirm HEAD is on a named branch, not detached.
3. Run `git diff --name-only origin/main...HEAD` and flag every file outside src/auth/ and tests/auth/.
4. Run type check, lint and the full test suite, and report each command with its exit code.
5. Write a pull request description: the problem, the root cause, the fix, how it was tested, and the risks a reviewer should check by hand.
```

## Clean up Codex worktrees without losing commits

Every task leaves a checkout, and a managed one sits under `$CODEX_HOME/worktrees/` where you will not notice it filling the disk. Clean up in this order:

```bash
git worktree list                                  # find the path, including managed ones
git -C PATH status --short                         # must be empty
git -C PATH log --oneline BASE..HEAD               # commits not yet on the base
git branch -r --contains "$(git -C PATH rev-parse HEAD)"   # empty output = not pushed anywhere
git worktree remove PATH
git worktree prune                                 # drop records of worktrees deleted by other means
```

`PATH` is the worktree's directory from `git worktree list`, and `BASE` is the branch the task started from, such as `origin/main`. `git worktree remove` refuses a worktree with modified or untracked files. Add `--force` only after the status and log checks show there is nothing you want, because it deletes those files for good. Delete the branch last, with `git branch -d` (which refuses unmerged branches), not `-D`.

## When Codex worktree tasks go wrong

| Symptom | Cause | Recovery |
| --- | --- | --- |
| The agent reports missing modules or config on its first command | Managed and new worktrees get no gitignored files | Run the bootstrap script, then restart the task |
| The task ignores a fix you made minutes ago | The worktree starts from the last commit, not your working tree | Commit the fix, then `codex fork --worktree` or start again |
| Commits disappeared after cleanup | The agent committed on a detached `HEAD`; `git worktree remove` does not refuse that, and it deletes the worktree's own reflog | Before Git garbage-collects them, list orphaned commits with `git fsck --lost-found`, find yours with `git show SHA`, then `git branch rescue/TASK SHA`. Prevent it with the branch step in the first prompt and the gate's named-branch check |
| Git reports the branch is already used by (or checked out in) another worktree | The branch is checked out in another worktree | Use a new branch name, or remove the other worktree first |
| The agent cannot commit, or asks for approval on every `git` write | A worktree's Git metadata lives in the main repository's `.git/`, which can sit outside the sandbox's writable area | Commit from your own terminal, or make that directory writable deliberately with `--add-dir` (see [permissions and sandboxing](/en/workflows/harness/permissions-and-sandboxing/)) |
| Codex says "The new worktree is not trusted; run Codex there." | The new checkout path has not been marked as trusted, and untrusted projects do not supply `AGENTS.md` (since Codex CLI 0.150.0) | Run `codex` in the worktree, accept the trust prompt only for a repository you trust, then restart the task so it reads `AGENTS.md` |
| Two dev servers fight over one port | Every worktree inherited the same `PORT` | Give each worktree its own port in the bootstrap step and pass it to the dev server and end-to-end tests |
| Two tasks' changes conflict at merge | Both touched a shared file (router, barrel export, schema) | Merge one, rebase the other on it, rerun the full gate. Next time, split tasks by file ownership as in [multi-agent workflows](/en/codex/automate/multi-agent-workflows/) |
| The disk fills up | Every worktree holds its own dependencies and build output, and managed worktrees stay after the session ends | Remove finished worktrees weekly with the cleanup sequence above |

**Isolation stops at the filesystem**

A worktree separates files, not the outside world. Tasks in different worktrees still share your production database, cloud accounts, third-party APIs and any secrets in your shell environment. Keep those out of the bootstrap step, and tell the agent in the prompt which remote systems it must not touch. A per-task database and service stubs close most of that gap; the ephemeral-environments page linked in step 3 shows how.

## Where to go next with Codex worktrees

- Before this page: [configure Codex](/en/codex/quick-start/configuration/) and [write `AGENTS.md` for Codex](/en/codex/quick-start/agents-md/), so every worktree knows its build and test commands.
- Next: [Codex multi-agent workflows](/en/codex/automate/multi-agent-workflows/) to run several worktree tasks as parallel lanes, and [non-interactive Codex with `codex exec`](/en/codex/automate/non-interactive/) to script them.
- For tasks too heavy for a laptop: [Codex cloud environments](/en/codex/automate/cloud-environments/).
- The same isolation in Claude Code and Cursor: [running parallel agents in isolated worktrees](/en/developer-scorecard-guide/git-worktrees/), and tools that manage many at once in [parallel agent tools](/en/ecosystem/agent-tools/parallel-agents/).
