DEV Community

dubleCC
dubleCC

Posted on • Originally published at heycc.cn

Parallel AI Agent Workflows with Git Worktrees: The Concrete Pattern

Originally published at heycc.cn. This is a mirrored copy — the canonical version is kept up to date at the source.

Parallel AI Agent Workflows with Git Worktrees: The Concrete Pattern

An AI coding agent that runs one task at a time is bottlenecked by the same thing a single developer is: wall-clock time. The fix that's converged across the three major CLI agent tools in 2026 is the same primitive git has offered since version 2.5 in 2015: git worktree. Give each task its own working directory, its own branch, and its own agent session, all sharing one .git object database. No copying the repo, no stash/checkout juggling, no risk of one agent's half-finished edit landing in another agent's diff.

This piece is about the concrete mechanics — the actual flags, config files, and directory layouts Claude Code, Cursor, and Codex ship for this — and about where the pattern breaks: shared ports, shared services, merge conflicts that don't show up until integration, and the coordination tax that makes "run five agents at once" a net loss for a lot of tasks that look parallelizable on paper. Every specific version-, flag-, and number-level claim below was checked against the tool's own current documentation as of the verification note at the end; where a claim couldn't be confirmed, it's been cut rather than left as unsourced set dressing.

The primitive: what a worktree actually is

A git worktree is a second working directory attached to the same repository. Git's own documentation describes it precisely: within a linked worktree, $GIT_DIR points to a private administrative directory (e.g., /path/main/.git/worktrees/test-next), while $GIT_COMMON_DIR points back to the main worktree's .git. The linked worktree gets its own .git file (not directory) that redirects into that shared structure. Practically: every worktree has its own index, its own HEAD, its own checked-out files — but all worktrees share one object database and one set of refs. A commit made in worktree B is immediately visible to git log in worktree A, because it's the same repository underneath.

Two constraints from git's own docs matter for agent workflows specifically:

  • You cannot check out the same branch in two worktrees at once. git worktree add refuses by default if <commit-ish> is a branch already checked out elsewhere. This is exactly why the "one worktree, one branch" rule isn't a style preference — git enforces it structurally.
  • Multiple checkout with submodules is explicitly called out as unstable. Git's git worktree manual states in its BUGS section: "Multiple checkout in general is still experimental, and the support for submodules is incomplete. It is NOT recommended to make multiple checkouts of a superproject." If your repo uses submodules, verify this against your git version before assuming worktree isolation is clean.

The manual commands, unchanged across tools:

# Create a worktree on a new branch, in a sibling directory
git worktree add ../project-feature-a -b feature-a

# Create a worktree from an existing branch
git worktree add ../project-bugfix bugfix-123

# List every worktree attached to this repo
git worktree list

# Remove one when done
git worktree remove ../project-feature-a
Enter fullscreen mode Exit fullscreen mode

Claude Code, Cursor, and Codex each wrap this primitive with a different amount of automation — from a CLI flag that fully owns directory/branch bookkeeping, to a JSON config file for setup scripts, to (in Codex's case) no CLI wrapper at all.

One shared .git object database with three isolated worktrees, each running its own agent session on its own branch

How each tool implements the pattern

Claude Code: --worktree flag, native in the CLI

Claude Code's CLI documentation describes first-class worktree support. Per Anthropic's own documentation:

"Pass --worktree or -w to create an isolated worktree and start Claude in it. By default, the worktree is created under .claude/worktrees/<value>/ at your repository root, on a new branch named worktree-<value>."

claude --worktree feature-auth
# in a second terminal:
claude --worktree bugfix-123
# or let Claude generate a name:
claude --worktree
Enter fullscreen mode Exit fullscreen mode

You can also tell Claude mid-session to "work in a worktree," and it invokes an EnterWorktree tool call to switch into one — the previous worktree is left untouched on disk. A few implementation details that matter operationally, all confirmed against the current docs page:

  • Base branch selection. Worktrees branch from origin/HEAD by default (a clean tree matching the remote), falling back to local HEAD if there's no remote configured or the fetch fails. Setting worktree.baseRef: "head" in settings makes new worktrees branch from your current local HEAD instead — useful when a subagent needs to build on top of in-progress, unpushed work. The setting only accepts "fresh" or "head", not arbitrary refs.
  • PR-based worktrees. claude --worktree "#1234" fetches pull/1234/head from origin and creates the worktree at .claude/worktrees/pr-1234 — useful for having an agent review or continue someone else's PR in isolation.
  • .worktreeinclude for untracked files. A fresh worktree checkout won't have your .env, .env.local, or other gitignored-but-necessary files. A .worktreeinclude file at the repo root, using .gitignore syntax, copies matching gitignored files into every new worktree automatically. Tracked files are never duplicated this way — only untracked-but-listed ones.
  • Subagent isolation via frontmatter. A custom subagent gets isolation: worktree in its frontmatter to always spawn into its own worktree; ad hoc you can just tell Claude "use worktrees for your agents." Each subagent's temporary worktree is removed automatically once the subagent finishes without changes.
  • Locking during execution. While an agent is running, Claude Code runs git worktree lock on that worktree so a concurrent cleanup sweep can't remove it mid-task; the lock releases when the agent finishes.
  • Automatic cleanup, with teeth. Worktrees Claude created for subagents/background sessions are removed automatically once older than the configured cleanupPeriodDays, but only if they have no uncommitted changes, no untracked files, and no unpushed commits. Worktrees you create yourself with --worktree are never swept automatically — you clean those up with git worktree remove.
  • Non-git VCS. For SVN/Perforce/Mercurial shops, a WorktreeCreate hook can replace the git-based logic entirely (the hook reads a JSON name from stdin and must print the resulting directory path). This bypasses .worktreeinclude — you copy config files inside the hook script yourself.

Cursor: worktrees as the substrate for parallel and cloud agents

Cursor's worktrees documentation describes the same underlying mechanism, wired into the Agents Window, the editor, and the Cursor CLI (cursor-agent) uniformly: Cursor checks for a setup config both in the new worktree path and in the project root when it creates a worktree.

On the parallelism number specifically — this is worth being precise about, because it's a frequently garbled claim. Cursor 2.0's changelog states: "Run up to eight agents in parallel on a single prompt. This uses git worktrees or remote machines to prevent file conflicts." That is a best-of-N feature: one prompt fans out into up to eight candidate solutions, each in its own worktree or remote machine, and you pick the best result — it is not eight independently-scoped background tasks running unrelated work at once. Separately, Cursor also supports running any number of cloud-hosted agents on unrelated tasks; the changelog's Jun 17 entry describes offloading long-running work so "you can... run as many cloud agents in parallel as you want," with no fixed cap documented for that unrelated-tasks case.

The naming matters too: what used to be called Background Agents was renamed. Per the same Cursor 2.0 changelog: "Background Agents have been renamed to Cloud Agents." The specifics on what Cloud Agents do post-rename are also narrower than commonly repeated — the changelog documents "99.9% reliability, instant startup, and a new UI coming soon," but does not itself spell out "runs tests, takes screenshots, opens a PR" as a fixed feature list in that entry. (Cursor's mobile-features notes do separately mention the ability to "merge the PR directly from the app," and the product supports computer-use-style artifact generation elsewhere in its docs — but attributing a specific "runs tests + screenshots + opens PR" bullet list directly to the Cloud Agents rename entry overstates what that specific changelog text says.)

Cursor's setup mechanism is a project config file rather than a CLI flag:

// .cursor/worktrees.json
{
  "setup-worktree": [
    "npm ci",
    "cp $ROOT_WORKTREE_PATH/.env .env"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Three keys are supported — setup-worktree-unix and setup-worktree-windows (OS-specific, take precedence), and the generic setup-worktree fallback — each accepting either an inline array of shell commands or a path to a script file. $ROOT_WORKTREE_PATH is exposed as an environment variable so setup scripts can pull config from the primary checkout. Cursor's docs explicitly warn against a shortcut that seems obvious for saving disk and install time: "We do not recommend symlinking dependencies into the worktree. This can cause issues in the main worktree" — package managers writing into a symlinked, shared node_modules from multiple processes is exactly the shared-mutable-state problem worktrees exist to avoid.

Cleanup is machine-scoped, not per-project, controlled by two settings named directly in Cursor's docs: cursor.worktreeCleanupIntervalHours and cursor.worktreeMaxCount. "The default cap is 25 worktrees per machine, and all workspaces contribute toward the same limit" — worth knowing if you run several unrelated repos through Cursor and start seeing older worktrees vanish sooner than expected.

Codex: worktrees live in the app, not the terminal CLI

This is the sharpest divergence between the three tools, and it's easy to get wrong by reading tool-adjacent blog posts instead of the primary source. OpenAI's developer docs place worktrees under "Using Codex → App," and the app-level worktrees page describes the feature as keeping "parallel code changes isolated with built-in Git worktree support." The dedicated CLI reference page does not document a --worktree flag or any built-in worktree management for the terminal tool — its only parallelism guidance is "Use subagents to parallelize complex tasks," a different mechanism (in-session task delegation, not process-level isolation).

Confirming this isn't a documentation gap but an actual missing feature: GitHub issue #12862 on openai/codex, titled "CLI: add --worktree and --tmux flags for one-command isolated sessions," is open as of this writing. Its description states the current reality: "Right now users commonly combine git worktree + tmux manually or via custom wrappers." In other words, Codex CLI users get parallel-worktree workflows today by doing exactly what this article's "manual commands" section shows — no native flag wraps it.

Where the Codex app does implement worktrees, the mechanics are documented in detail and resemble Claude Code's. Per OpenAI's worktrees doc: "Codex creates worktrees in $CODEX_HOME/worktrees." Local environments can run setup scripts on worktree creation, and gitignored files can be pulled in via .worktreeinclude — plus one behavior Claude Code doesn't have: "Codex automatically copies an ignored AGENTS.override.md into local managed worktrees, so you don't need to list it in .worktreeinclude." Cleanup is explicit and numeric: "By default, Codex keeps your most recent 15 Codex-managed worktrees. You can change this limit or turn off automatic deletion in settings." Protected worktrees — those with pinned conversations, threads still in progress, or a permanent designation — are skipped by that cleanup, and per the same doc, "before deleting a Codex-managed worktree, Codex saves a snapshot of the work on it," recoverable later from the conversation view.

Practical takeaway: if your workflow is "Codex CLI in a terminal, scripted," you are the wrapper. git worktree add ../myapp-feature -b feat/add-payments && cd ../myapp-feature && codex is the whole pattern — there's no flag doing branch/directory bookkeeping for you the way there is with claude --worktree, and no config file doing it the way there is with Cursor's app.

Comparison table: worktree support across the three tools

Claude Code (CLI) Cursor (CLI + app) Codex (CLI vs. app)
Native flag/command claude --worktree [name] or -w No CLI flag; app-driven via Agents Window, cursor-agent sessions run inside manually- or app-created worktrees CLI: none. App: automatic on thread start
Default worktree location .claude/worktrees/<name>/ in repo root Managed location per workspace (app-controlled) App: $CODEX_HOME/worktrees
Default branch naming worktree-<name> Agent/task-derived App: task-derived
Untracked file copy-in .worktreeinclude (gitignore syntax) .cursor/worktrees.json setup scripts (cp commands) App: .worktreeinclude, plus automatic AGENTS.override.md copy
Setup script hook WorktreeCreate hook (for non-git VCS or custom logic) setup-worktree / setup-worktree-unix / setup-worktree-windows in .cursor/worktrees.json App: local-environment setup scripts
"Parallel agents" number people cite No fixed cap; limited by machine resources and the cleanupPeriodDays sweep "Up to eight agents in parallel on a single prompt" — a best-of-N ensemble on ONE task, not eight independent tasks; unrelated-task cloud agents have no documented fixed cap Not documented for CLI (no native feature); app has no advertised concurrent-agent cap
Cleanup policy Auto-remove if no uncommitted/untracked/unpushed state, after cleanupPeriodDays; manual worktrees never auto-swept Machine-wide cap of 25 worktrees, cleanup interval configurable (cursor.worktreeCleanupIntervalHours) App: keeps most recent 15, skips pinned/in-progress, snapshots before delete
PR/branch checkout shortcut claude --worktree "#1234" fetches pull/1234/head Not documented as a flag Not documented for CLI

The "up to 8" and "up to 25" and "keeps 15" numbers in that table are three different things measuring three different limits — a per-prompt ensemble size, a per-machine worktree cap, and an app-level retention window — and conflating any two of them (as "8 parallel background agents" conflates Cursor's ensemble count with an unrelated-tasks concurrency limit) produces a wrong picture of what each tool actually does.

Firsthand artifact: the manual pattern that underlies all three tools

Since Codex CLI has no native flag, and since understanding the raw primitive clarifies what each tool's automation is actually doing for you, here's the fully manual sequence any of these tools ultimately reduces to. This is real output, captured by running the commands below against a live git repository (git 2.52.0) rather than simulated:

$ git worktree add ../wt-verify-demo -b demo-verify-worktree
Enter fullscreen mode Exit fullscreen mode
Preparing worktree (new branch 'demo-verify-worktree')
HEAD is now at fbcc4b4 Refresh check reports after Buttondown wiring + newsletter verification
Enter fullscreen mode Exit fullscreen mode
$ git worktree list
Enter fullscreen mode Exit fullscreen mode
H:/site_soe                                               fbcc4b4 [main]
C:/Users/Administrator/.../wt-verify-demo                 fbcc4b4 [demo-verify-worktree]
Enter fullscreen mode Exit fullscreen mode

Two lines, one per worktree, each showing its path, current commit SHA, and checked-out branch — exactly as git's own documentation specifies. (The demo worktree and branch were removed afterward with git worktree remove ../wt-verify-demo --force and git branch -D demo-verify-worktree, leaving no trace in the source repo.)

From here, cd ../wt-verify-demo && claude (or cursor-agent, or codex) starts an agent session scoped to that directory. The agent's file edits, git add, and git commit all happen against demo-verify-worktree's index — completely invisible to a second agent working in a sibling worktree against a different branch's index — while both share the same object database, so git log --all --oneline from either worktree shows every commit made by either agent.

Failure modes: where "just add worktrees" breaks down

Worktree isolation solves exactly one problem — concurrent edits to the same tracked files — and solves it completely, because git structurally prevents two worktrees from checking out the same branch. It does not solve several adjacent problems that show up immediately in practice.

1. Port and service collisions. A worktree is a separate directory, not a separate machine. If your dev server hardcodes port 3000, or your test suite spins up Postgres on 5432, two agents each running npm run dev from two different worktrees will have one server win the bind and the other fail with EADDRINUSE. This is consistently the first friction point practitioners hit — common enough that dedicated tooling exists just for it: portree, for example, assigns each service a port by hashing the branch and service name (FNV32(branch:service) % range) for a port that's stable across restarts, and falls back to linear probing if that port is already taken. The underlying fix, whether via a tool like that or a hand-rolled .env per worktree, is the same: derive each worktree's ports deterministically from its name so two agents never reach for the same socket.

2. Shared external state. Worktrees isolate the working directory and index — they do not isolate a shared database, a shared Redis instance, or a shared cloud dev environment your .env points at. Two agents running migrations against the same dev database, or two agents both writing to the same S3 test bucket, will step on each other exactly as if they were the same process, because from the database's point of view they are the same client pool. This has to be solved at the service layer (separate schemas/databases per worktree, or a docker-compose stack parameterized by worktree name), not the git layer.

3. Dependency duplication and drift. Each worktree is a fresh checkout with no node_modules, no venv, nothing not tracked by git. Every new worktree needs its own npm ci / pip install equivalent, which costs time and disk — and if two worktrees drift onto different lockfile states before you reinstall in the newer one, you can get subtly different dependency resolutions per agent. Cursor's docs explicitly warn against the tempting shortcut of symlinking a shared node_modules into each worktree, for the reason already quoted above: it reintroduces the shared-mutable-state problem worktrees are meant to eliminate.

4. Uncommitted state doesn't travel. This is a feature, not a bug, but it surprises people: if Agent A is mid-task in its worktree with uncommitted changes and you ask a different agent to "check what Agent A did," the second agent — running in its own worktree or the main checkout — will not see any of that work, because uncommitted changes live only in the index/working tree of the worktree that made them. Cross-agent handoff requires an actual commit (even a WIP one) before another session can see it, which is exactly why Claude Code's worktree.baseRef: "head" setting exists: it's the escape hatch for "start a new worktree from my current branch state" rather than a clean origin/HEAD.

5. Submodule instability. Per git's own BUGS documentation, multiple-worktree checkouts of a superproject with submodules are explicitly unsupported territory ("It is NOT recommended"). If your repo has submodules, verify behavior before betting a multi-agent workflow on it — this is not a tooling gap any of the three agent CLIs can paper over, since it's git itself flagging the limitation.

6. Merge complexity scales with divergence time and surface overlap, not agent count. The actual integration cost isn't "N agents means N-times the merge work" — it's that branches which diverge from main for longer, and touch more overlapping surface area (shared types, shared config, a central router), produce conflicts that are harder to resolve the longer they're left unmerged. Two agents each touching entirely disjoint files (adding a new module vs. writing docs) merge trivially regardless of how long they run in parallel. Two agents both refactoring the same central interface will conflict badly even if each only ran for twenty minutes. The mitigation isn't fewer worktrees — it's smaller-scoped tasks per worktree and shorter time-to-merge.

When the coordination overhead is worth it

Signal Favor parallel worktree agents Favor a single sequential session
Task decomposition Cleanly splits into disjoint file sets (e.g., "add tests for module A" + "write docs for module B") Tasks touch the same core files/interfaces (e.g., refactoring a shared type used everywhere)
Review capacity You (or reviewers) can actually review N branches this week Review is already the bottleneck — more parallel branches just queue up unreviewed
Environment cost Spinning up a second dev server/DB is cheap (containerized, port-parameterized) Your dev environment is a heavyweight, hard-to-clone singleton (a shared staging DB, a licensed local service)
Task independence Each task's correctness doesn't depend on another task's output Task B needs to see task A's finished code to proceed (sequential dependency)
Merge urgency Fine with an integration pass at the end to reconcile N branches Need continuous, always-mergeable main with minimal batched conflict risk

That table is deliberately narrow: it's a checklist for this specific decision (parallelize this batch of work or not), not a general project-management framework, and each row maps to one of the failure modes above rather than restating generic task-decomposition advice.

On how many concurrent sessions is actually sustainable, there is no single documented consensus number — this is worth stating plainly rather than smoothing over. Individual practitioner accounts vary noticeably: one detailed writeup on running Codex in parallel describes 4-6 concurrent agents as a practical ceiling; another argues 3-5 is the sweet spot before coordination overhead dominates; a Windows-focused workflow post frames it as a progression, starting from roughly 3 worktrees and scaling up as tooling improved. What these accounts agree on directionally, even without agreeing on a number, is why a ceiling exists at all: past some point, review and merge — not git, not compute — become the bottleneck, which matches the framework above. Worktrees remove the file-editing collision; they don't remove the human review queue. Treat any specific "N sessions" figure, including the ones above, as one practitioner's data point rather than an industry standard, and calibrate your own ceiling against how fast you can actually review a diff, not how fast an agent can produce one.

What was checked against primary docs (2026-07-02)

Checked directly against primary sources for this revision:

  • Cursor 2.0 changelog (cursor.com/changelog/2-0): confirmed the exact wording "Run up to eight agents in parallel on a single prompt" (a per-prompt best-of-N ensemble, not independent background tasks) and "Background Agents have been renamed to Cloud Agents," plus "99.9% reliability, instant startup" as the only specifics given for the rename. No mention of Cloud Agents specifically running tests/screenshots/opening a PR was found in that entry, so that claim was removed.
  • Cursor worktrees config (cursor.com/docs/configuration/worktrees): confirmed setup-worktree / setup-worktree-unix / setup-worktree-windows keys, $ROOT_WORKTREE_PATH, the symlink warning verbatim, cursor.worktreeCleanupIntervalHours, cursor.worktreeMaxCount, and the 25-worktree-per-machine default cap.
  • Claude Code worktrees docs (code.claude.com/docs/en/worktrees): confirmed --worktree/-w, the .claude/worktrees/<value>/ default path, worktree-<value> branch naming, worktree.baseRef accepting only "fresh"/"head", the #1234 PR-fetch syntax, .worktreeinclude, isolation: worktree frontmatter, the git worktree lock behavior during execution, the WorktreeCreate hook, and the cleanupPeriodDays sweep conditions — all verbatim or near-verbatim against the live doc page.
  • Codex app worktrees docs (developers.openai.com/codex/app/worktrees): confirmed $CODEX_HOME/worktrees as the default location, the automatic AGENTS.override.md copy behavior, the "keeps your most recent 15" cleanup default, pinned/in-progress protection, and pre-deletion snapshotting — all quoted verbatim from the live page.
  • Codex CLI reference (developers.openai.com/codex/cli): confirmed no --worktree flag is documented; only "Use subagents to parallelize complex tasks" is offered for CLI-level parallelism.
  • GitHub issue #12862 on openai/codex: confirmed title, open state, and the "users commonly combine git worktree + tmux manually" quote.
  • git-scm.com worktree docs: confirmed the BUGS-section submodule warning verbatim, the one-branch-one-worktree restriction, and $GIT_DIR/$GIT_COMMON_DIR mechanics.
  • Practitioner concurrency-ceiling claims: could not find a single sourced consensus figure. Search turned up divergent numbers (4-6, 3-5, and an account starting from 3) across independent writeups; the article now attributes this range to specific accounts rather than asserting a "practitioner consensus," and states outright that no standard number exists.
  • Anthropic /batch subagent cap: the previous draft's claim of "around 30 subagents" could not be verified against any primary Anthropic source and has been removed rather than kept as an unsourced figure.
  • Firsthand artifact: replaced the unfilled operator placeholder with actual git worktree add / git worktree list output captured by running git 2.52.0 against this repository; the demo worktree and branch were deleted immediately after capture.

Sources

Top comments (0)