Parallel Isolation with Worktrees: Let Multiple Codex Agents Work Separately Without Interference
📚 Series Navigation: The previous article [24 Rules and Lifecycle Hooks (Hooks)] added gates and triggers to Codex to automate repetitive tasks. This article changes dimensions—instead of asking one Codex to do more tasks, we allow multiple tasks to start concurrently without interference. Worktrees (Worktree) are the core isolation method used by Codex to achieve this: how to create them, how to use them, why the same branch cannot be checked out in two places simultaneously, and how Handoff moves tasks between the foreground and background. The next article [26 Git and GitHub Integration] covers how to commit, push, and open PRs after modifying code.
Let's talk about a foolish mistake I made in March this year.
To save trouble, I opened two Local (local) threads in the Codex Desktop App pointing to the same repository, asking one to refactor the data layer and another to edit routing. I felt smart, thinking this dual-thread setup doubled my efficiency. It turned out both threads modified the same config.ts, and when the second thread wrote its changes, it overwrote half of what the first thread had just written. I stared at the red and green diff block for several minutes before realizing: it wasn't Codex glitching; I was asking two people to write on the same paper with the same pen.
After that, I started using the tool I should have used from the start—Worktree. When parallel tasks on the same project are needed, always use a Worktree. Each thread receives an isolated copy of the codebase, preventing overwriting issues completely.
I briefly mentioned Worktrees in Article 07 on the Desktop App—as one of the three modes for new threads (Local / Worktree / Cloud), paired with Handoff to move tasks between the foreground and background (Cloud mode is covered separately in Article 10 Codex Cloud). In this article, we dig deeper: how it isolates files, why the "branch checked out in one place only" rule exists, how Handoff works in both directions, and how to clean up accumulated copies. Master these settings to avoid tripping over them later.
By reading this article, you will get:
- An explanation of what Worktree resolves, and its difference from "running two Local threads on the same path"
- The steps to create a Worktree thread in the Desktop App, plus the counter-intuitive fact that it defaults to a detached HEAD (detached HEAD) state
- The rule most likely to trip you up—the same branch cannot be checked out in two places simultaneously, what error it throws, and how to bypass it
- The two directions of Handoff (Handoff) for moving threads between Local and Worktree, and when to use each
- Using the Local environment (local environment) setup script to install dependencies automatically when a new Worktree is created
- How to manage disk space when Worktrees accumulate: how many are kept by default, what is preserved, and whether snapshots can be recovered before deletion
⚠️ Worktree, Handoff, and Local environments are features of the Codex Desktop App (desktop app), with no corresponding
--worktreeswitches in the CLI—do not look for them in your terminal. Specific buttons, defaults, and configuration options mentioned below are subject to the official Codex documentation (Worktrees / Local environments); features may adjust with versions, subject to the active GUI.
01 Understand First: What Problem Does a Worktree Solve?
The bottom line: A Worktree solves the need to work on multiple unrelated tasks concurrently in the same repository without overwriting changes. It works under a single condition: never let these tasks write to the exact same file.
Recall our previous articles—we worked almost exclusively in a "single thread": starting a task, giving instructions, and waiting for it to finish. This works for 90% of tasks. But two scenarios make it feel restrictive.
First: tasks are independent and do not rely on each other. For example, "modifying frontend styles," "fixing a backend bug," and "adding test cases" have nothing to do with each other, but you are forced to wait—fixing the backend only after the frontend is done. They could run concurrently.
Second: you want to test a new idea but don't want to mess up your active work. Your active workspace contains uncommitted changes, and you want to verify another approach. Editing files directly risks breaking the unfinished work.
You might think: can't I just open multiple threads? This is the pitfall. Running multiple Local threads on the same project directory leads to the issue I faced: multiple Codex agents modifying the same files at the same time, overwriting each other.
Analogy: A patient's medical record. There is only one copy of a medical record. If three doctors write their notes on that single copy simultaneously, their writing overlaps and overrides. The correct procedure is—giving each doctor a copy of the record to write on, and consolidating them back to the master file later. A Worktree does this: it extracts isolated working directories from the same repository history, each containing its own set of files while sharing a single .git directory (commit history, branches, and metadata are shared). Changes made in one isolated copy do not touch another copy.
The official docs state this benefit clearly:
Each worktree has its own independent copy of every file in your repository, but they share the same metadata about commits, branches, etc. (the
.gitfolder). This allows you to check out and work on multiple branches in parallel.
Practical use cases for Worktrees:
- "Fixing a bug in module A and adding a feature in module B concurrently"—run them in separate Worktree threads, keeping them completely isolated.
- "Testing an alternative approach while holding uncommitted changes"—run the test in a Worktree, keeping your main workspace intact and discarding the Worktree if it fails.
- "Letting Codex run a large refactoring task in the background while you work in the foreground"—push the refactoring task to a Worktree background run (detailed in the next section).
💡 Summary in one sentence: A Worktree allows running unrelated tasks concurrently in the same repository without overwriting changes (giving each doctor a copy of the file); the only rule is do not write to the same files at once, preventing parallel tasks from clashing.

Diagram: A single Git repository spawns three independent Worktrees, allowing three Codex tasks to run in isolation without overwriting each other.
02 Creating a Worktree Thread in the Desktop App
Having covered why to use them, let's look at how to set them up. Everything is handled in the Desktop App with a few clicks; no commands are needed.
Worktrees only function inside a Git repository—as the feature uses Git's built-in Worktree capability. Ensure your selected project is a Git repository; otherwise, the option will not display.
The Four-Step Setup
Step 1: Choose Worktree mode for a new thread. Below the input box of a new thread, toggle the mode from Local to Worktree. (You can also select a local environment to run a setup script, covered in Section 05.)
Step 2: Choose the starting branch. Below the input box, select which branch the Worktree should branch from—such as main / master, a feature branch, or your active branch including uncommitted changes. This is convenient: you can carry your active changes over to continue in the Worktree.
Step 3: Submit your prompt. Send the task, and Codex creates a Git Worktree based on the selected branch and starts working.
Step 4: Decide what to do next. When the task finishes, you have two choices—continue working in this Worktree (committing, pushing, and opening a PR) or Handoff the thread back to Local (Section 04).
A Counter-Intuitive but Critical Detail: Worktrees Default to a Detached HEAD State
This is where beginners often get confused.
Worktrees created by Codex do not reside on any branch by default, but rather in a detached HEAD (detached HEAD) state—meaning they point to a specific commit rather than a branch name. The official docs state:
By default, Codex operates in a "detached HEAD" state.
Why this design? The docs explain: it allows Codex to create multiple Worktrees without cluttering your branch list. Your git branch list won't grow by five temporary branch names just because you opened five Worktrees.
What if you want to turn the changes into a regular branch? Click the Create branch here button at the top of the thread. This converts the Worktree into a branch, allowing you to commit, push, and open PRs.
💡 Summary in one sentence: Setting up a Worktree thread involves four steps—select Worktree mode → choose starting branch → send prompt → decide what to do next; remember it defaults to a detached HEAD, and you must click Create branch here to turn it into a branch for committing and pushing.
03 The Critical Rule: One Branch Cannot Be Checked Out in Two Places Simultaneously
This section is short but critical—a pitfall many developers, including myself, trip over.
Git enforces a rule: a branch can only be checked out in one Worktree at any given time. If you check out feature/a in a Worktree, your Local workspace cannot check out feature/a at the same time, and vice versa.
Analogy: A library book. A physical book can only be borrowed by one person at a time—not because the library is restrictive, but because the book's status ("who holds it") can only have one answer at a time. Git branches are the same: a branch name (refs/heads/<name>) represents the state of a Worktree, and allowing two Worktrees to write commits to it simultaneously would lead to lost commits and index conflicts. Thus, Git restricts it: one branch, one Worktree at a time.
What happens if you violate this? Suppose Codex finishes work in a Worktree, and you click Create branch here to create a feature/a branch. If you then try to check out feature/a in your Local workspace, Git throws an error:
fatal: 'feature/a' is already used by worktree at '<WORKTREE_PATH>'This tells you the branch is occupied by the Worktree and cannot be checked out locally.
What should you do? The solution is to use Handoff instead of forcing Git. The official paths:
- To inspect changes briefly: check out a different branch in the Worktree, releasing
feature/a. - To continue the task locally: Handoff the thread to Local (detailed next) instead of checking out the branch in multiple places.
💡 Summary in one sentence: A branch can only be checked out in one Worktree at a time (like a library book borrowed by one person), throwing an
already used by worktreeerror if attempted in multiple places; use Handoff to move the task to Local instead.
04 Handoff: Moving Threads Between Local and Worktree
We mentioned Handoff several times; let's explain it. It is the official solution for managing the "one branch checked out in one place" restriction, and is a workflow tool you will use daily.
Understand the mental model: Local is the foreground, and Worktree is the background. Local (your main repository path) is where you work directly, run IDEs, and launch dev servers—the desk in front of you. Worktrees are isolated copies running in the background. Handoff moves a thread between this foreground and background.
Analogy: A kitchen's open counter and prep room. The open counter (Local) is where food is prepared and served in front of guests. The prep room (Worktree) is in the back, handling chopping and simmering. Where a dish is prepared depends on the stage: to plate and inspect it, bring it to the open counter; to let it simmer while freeing up the counter for other dishes, move it to the prep room. Handoff is this "moving in and out" action—and Codex handles the underlying Git operations safely, saving you from running git worktree commands.
The official docs highlight the reason for Handoff, connecting to the previous section:
This is important because Git only allows a branch to be checked out in one place at a time.
It works in two directions:
Direction 1: Worktree → Local (bringing background threads to the foreground). Click Hand off at the top of the thread and select Local. When to use it? When you want to inspect changes in your daily environment—reading diffs in your preferred IDE, running dev servers, or when your app can only run one instance and cannot launch a second copy in the Worktree. I use this flow: let Codex build a feature in the Worktree background, and Handoff to Local when done to review the code in my editor.
Direction 2: Local → Worktree (pushing foreground threads to the background). The reverse path. If you are working in Local and want to free up the foreground for other tasks, click Hand off to push the thread to a Worktree—letting Codex run in the background while you focus on other local tasks.
A convenient detail: each thread remains bound to the same Worktree. If you Handoff a thread to Local and later push it back to the background, Codex sends it back to its original Worktree to continue from where you left off, rather than starting fresh.
A critical limitation:
Because Handoff uses Git operations under the hood, any files matching your
.gitignoreare not moved with the thread.
Simply put—untracked files like .env or local caches do not carry over with Handoff. This aligns with the "clean copy" nature of Worktrees. The next section covers how to manage this.
| Worktree → Local | Local → Worktree | |
|---|---|---|
| Direction | Background to foreground | Foreground to background |
| Typical Scenario | Reviewing code in your IDE, running single-instance dev servers | Freeing up your workspace to let Codex run in the background |
| Git Operations | Handled automatically by Codex | Handled automatically by Codex |
.gitignore Files | Do not carry over | Do not carry over |
💡 Summary in one sentence: Handoff moves threads between Local (foreground) and Worktree (background) (like moving dishes between the counter and prep room), with Git operations handled automatically; threads stay bound to their Worktrees, but files in
.gitignoredo not carry over.
05 Preparing New Worktrees: Local Environment Setup Scripts
Connecting to the .gitignore limitation: a Worktree is a fresh checkout residing in a different directory from your Local path, so untracked dependencies, configurations, and local files do not exist inside it at start. Typically, a new Worktree lacks node_modules or .env files, stalling tasks.
I ran into this in April: I created a Worktree asking Codex to modify a backend, but it couldn't connect to the database—only to realize the .env file was missing from the Worktree (since .gitignore files do not carry over). Adding a setup script resolved it.
Analogy: A checklist for opening a new branch store. The main store (your Local path) is fully equipped; a new branch store (the Worktree) starts empty. A chain store uses a standard setup checklist: stocking inventory, installing registers, and decorating. Running this setup gets the branch ready. The Local environment setup script is that checklist—run automatically by Codex whenever a new Worktree is created to install dependencies and build assets.
Where and how to configure it:
- Configure local environments via the settings panel in the Codex App, which saves the configuration inside the
.codexdirectory of your project root. - This configuration file can be committed to Git to share with the team—once configured, all team Worktrees set up automatically.
An example for a TypeScript project, where the setup script is just two lines:
npm install
npm run buildWhen a new Worktree is created, these two lines execute automatically, installing dependencies and compiling assets. Codex starts working immediately with everything in place.
Platform differences: if your setup steps vary by platform (macOS / Windows / Linux), define separate setup scripts for each platform to override defaults. Windows Desktop App support follows official Windows documentation.
A related feature: besides setup scripts, local environments support Actions (Actions)—making common tasks like "starting dev servers" or "running test suites" accessible as shortcut buttons in the App's top bar, running them inside the built-in terminal on click. This was touched upon in Article 07.
💡 Summary in one sentence: Worktrees are clean copies lacking dependencies and
.envfiles; use a local environment setup script (saved under the.codexfolder in the project root, committable to Git) to install dependencies automatically upon creation, like following a checklist to set up a new branch store.
06 Managing Disk Space: Cleanup, Limits, and Snapshot Recovery
As you run parallel tasks, you will hit a practical issue: Worktrees consume disk space. Each contains its own copy of project files, dependencies, and build caches—and opening a dozen can shrink your disk space. Codex helps by managing the number of Worktrees automatically.
Two facts to help you locate Worktrees:
- Codex creates and manages Worktrees under
$CODEX_HOME/worktrees(whereCODEX_HOMEdefaults to~/.codex, as covered in Article 18). - By default, Codex retains your 15 most recent Codex-managed Worktrees; you can modify this limit in settings or disable automatic deletion to manage disk space yourself.
How does Codex choose which Worktrees to delete? It avoids deleting active ones:
Codex-managed Worktrees are NOT deleted automatically if:
- The thread bound to it is pinned (pinned);
- The thread is still active;
- It is configured as a permanent Worktree (permanent worktree, see below).
They are deleted if:
- You archive (archive) the thread;
- Codex needs to prune older Worktrees to stay under your configured limit.
A reassuring safety net—snapshots are saved before deletion:
Before deleting a Codex-managed worktree, Codex saves a snapshot of the work. If you reopen the thread after the worktree is deleted, you will see an option to restore it.
Even if a Worktree is cleaned up automatically, the thread remains in your history, and reopening it allows you to restore its files.
Distinguish these two concepts: Codex-managed Worktree vs. Permanent Worktree:
| Codex-managed Worktree (Default) | Permanent Worktree (permanent) | |
|---|---|---|
| Origin | Created automatically by Codex when starting a Worktree thread | Created manually via the project's three-dot menu in the sidebar |
| Thread Association | Typically dedicated to a single thread | Can spawn multiple threads from the same path |
| Automatic Deletion? | Yes (when limit exceeded or thread archived) | No, never deleted automatically |
| Suitable For | Lightweight, disposable temporary tasks | Long-term, stable development environments |
Simply put: use defaults for temporary tasks, letting the system clean them up when done; create a permanent Worktree via the project menu for long-term workspaces, which acts as a project and is never deleted automatically.
💡 Summary in one sentence: Worktrees are saved under
$CODEX_HOME/worktrees, with the system retaining the 15 most recent by default, pruning older ones or archived threads (with snapshots saved for recovery), and keeping pinned, active, or permanent Worktrees intact; use defaults for temporary tasks and permanent Worktrees for long-term setups.
07 Hands-on: Running a Worktree Workflow in the Desktop App
Practice makes perfect. Below, we run a Worktree workflow in the Codex Desktop App using a Git project. We provide expected outcomes for each step to build muscle memory.
Prerequisite: Use a Git repository (run
git initin a directory if needed). This workflow is exclusive to the Desktop App, as the CLI lacks corresponding switches. The steps do not require external network configurations.
Step 1: Create a thread in Worktree mode
Click to create a new thread in the App, toggle the mode from Local to Worktree below the input box, and select a starting branch (like main).
Expected: The mode displays as Worktree, and the "starting branch" selector appears. This prepares an isolated copy, leaving your main workspace untouched.
Step 2: Submit a read-only task
Send a simple, safe instruction that does not modify code, for example: "list the titles of all Markdown files in this project."
Expected: Codex creates a Worktree based on the selected branch and starts working. This thread's directory is located under $CODEX_HOME/worktrees (defaulting to ~/.codex/worktrees), separate from your Local path.
Step 3: Verify the isolated Worktree in the built-in terminal
Open the thread's built-in terminal (Cmd + J on macOS, Windows keys follow system defaults) and run:
git worktree listExpected: The list displays your main checkout along with an extra line pointing to the .../.codex/worktrees/... path. This confirms the isolated copy exists and you are working inside it.
Step 4: Handoff the thread to Local
Click Hand off at the top of the thread and select Local.
Expected: The thread moves to your Local workspace, allowing you to inspect its changes in your daily IDE and terminal. Codex handles the underlying Git operations automatically.
Step 5: Cleanup
To clean up the temporary Worktree, archive (archive) the thread—which triggers automatic pruning of the Codex-managed Worktree (saving a snapshot if you want to restore it later). Check settings to manage limits and auto-deletion switches.
Expected: The thread disappears from the active list, the Worktree is pruned, and disk space is reclaimed. This completes the workflow.
Running these steps walks you through the flow: creating an isolated copy → verifying isolation → Handoff to Local → cleanup. Parallel tasks follow this exact process.
💡 Summary in one sentence: The hands-on workflow has five steps—create a thread in Worktree mode → run a task to create the worktree → run
git worktree listto verify isolation → Hand off to Local to inspect → archive the thread to trigger cleanup; running it builds muscle memory.
08 Summary
We have explored running multiple Codex tasks concurrently in a repository without conflicts—covering isolation concepts, thread creation, branch restrictions, Handoff, environment setup, and cleanup.
Let's review the key points:
| Objective | Method / Concept | Key Takeaway |
|---|---|---|
| Understand isolation | Two prerequisites | Work on parallel tasks in a repository without writing to the same files (giving doctors copies of records) |
| Create isolated threads | Select Worktree mode | Choose starting branch; defaults to detached HEAD, click Create branch here to commit |
| Manage branch locks | Git restriction | A branch can only be checked out in one worktree at a time, throwing already used by worktree errors if violated |
| Move tasks | Handoff | Dual path between Local (foreground) and Worktree (background), handled automatically; .gitignore files do not carry over |
| Prepare environments | Local environment setup script | Saved under .codex in the project root, installs dependencies automatically on creation |
| Manage disk space | Pruning rules | Retains 15 most recent Worktrees by default, saving snapshots before deletion; use permanent Worktrees for long-term setups |
You should now be able to: explain what problems Worktrees resolve; create a Worktree thread in the App, knowing it defaults to a detached HEAD state and requires clicking Create branch here to commit; understand the branch checkout restriction and use Handoff to resolve conflicts; move threads using Handoff and write setup scripts to prepare environments; and manage disk space and recover deleted Worktrees from snapshots. You can now run background tasks without overwriting active changes.
Remember: do not run concurrent Local threads on the same repository path; use Worktree isolation instead.
The next article [26 Git and GitHub Integration]—you encountered Git actions in this article: converting Worktrees to branches, Handoff operations, and committing changes. The next article covers Codex's Git and GitHub capabilities: committing, pushing, and opening PRs directly in the App, managing staging and reverts in the diff panel, and integrating with GitHub. Once Worktrees isolate your tasks, you must merge them back into the main branch—which is the focus of the next article.