Quick answer
To run multiple AI coding agents in parallel safely, keep one session as the commander that plans, verifies, and merges. Give each worker its own git worktree and branch, exclusive ownership of a set of files, and a written task spec with a verification command. Dispatch the CLIs non-interactively (codex exec, claude -p, gemini -p) as background processes with one log and one PID file per worker. Merge the lowest-risk branch first and run the test suite after every merge. Treat a worker as finished only when the process exited cleanly and its log ends with a real report.
Why parallelize at all
Three practical reasons, none of them about sounding impressive:
- Quota. Usage limits are per tool and per account. If your Claude plan throttles mid-week, your codex and Gemini allowances are usually untouched. Running several CLIs concurrently spends several independent quota pools instead of draining one while the others idle.
- Latency. A coding agent spends much of its runtime reading files, waiting on model responses, and running builds. That is dead wall-clock time for you. Independent tasks, such as a rate-limit fix and a docs rewrite, have no reason to wait for each other.
- Context. One conversation juggling five tasks accumulates stale decisions, half-finished threads, and conflicting constraints. One worker per task gives each a fresh context window and a single, narrow objective, which is the main quality win, not just a speed win.
Parallelism also has a cost: coordination. If two tasks must touch the same files, run them serially. Parallel agents pay off when tasks are genuinely independent, and the rest of this guide is about enforcing that independence mechanically instead of hoping for it.
Split into a commander and workers
Do not launch five peers and hope they coordinate. They cannot see each other. The pattern that works is one commander session plus any number of workers:
- The commander decomposes the work, writes task specs, dispatches workers, then verifies results by running the tests itself, reading exit codes, reviewing diffs, and committing. It avoids writing feature code so its context stays reserved for judgment.
- Each worker receives one task, in one worktree, and reports back through its log file.
Every task spec has four fields: a goal, an explicit file scope, a verification command, and a definition of done. Write it to a file so dispatch is a one-liner:
Task: add exponential backoff to the rate-limit client
Scope: src/ratelimit/**, tests/ratelimit/**
Forbidden: src/auth/**, package.json, CI workflows
Verification: npm test -- tests/ratelimit/
Done means: verification passes and `git status --short`
shows no changes outside Scope.
Add one sentence to every dispatch prompt: do not ask for approval; implement immediately, choose reasonable defaults when something is ambiguous, and report your assumptions in the final message. The most common parallel-agent failure is a worker that exits with a plan and a question instead of an implementation, which looks identical to success if you only check whether the process ended.
Isolate every worker in a git worktree
Two agents editing one checkout will corrupt each other's state mid-run. git worktree gives each worker its own working directory and branch while sharing the repository's object database:
mkdir -p .agents/specs .agents/logs .agents/work
printf '.agents/\n' >> .git/info/exclude
git worktree add -b agent/ratelimit .agents/work/ratelimit
git worktree add -b agent/docs .agents/work/docs
git worktree add -b agent/changelog .agents/work/changelog
git worktree list
Keeping worktrees under an excluded path stops the main checkout from seeing them as untracked noise. Each worker later commits to its own branch, so nothing conflicts until you merge deliberately.
Two caveats worth knowing before you script this. First, build artifacts and dependencies (node_modules, .venv, target) are not shared between worktrees, so each worker that must build or test needs its own install step, which costs disk and a few minutes. Second, uncommitted files stay inside their worktree, which is exactly the isolation you want. After a branch is merged, clean up:
git worktree remove .agents/work/docs
git branch -d agent/docs
For a longer treatment of branch layout and cleanup, see parallel agents without merge hell .
Draw a file-ownership map
Worktrees prevent physical collisions; the ownership map prevents logical ones. The rule is one writer per file. If two tasks need the same file, they are not parallel tasks, and one of them must wait or produce a patch for review instead.
| Worker | Owns | Off limits | Merge risk |
|---|---|---|---|
| changelog | CHANGELOG.md | src/**, tests/** | Low |
| docs | docs/**, README.md | src/**, tests/** | Low |
| ratelimit | src/ratelimit/**, tests/ratelimit/** | src/auth/**, package.json | Medium |
| commander | package.json, CI workflows, migrations | merged serially, last | High |
Shared surfaces like dependency manifests, CI configuration, and database migrations belong to the commander or one designated worker. They are where parallel agents step on each other hardest, so serialize them and merge them last.
Dispatch codex, claude -p, and gemini in the background
All three CLIs have a non-interactive mode suitable for scripting: codex exec, claude -p (print mode), and gemini -p. Launch each worker with nohup, its worktree as the working directory, and a dedicated log and PID file:
# codex: non-interactive exec, cwd pointed at the worktree
nohup codex exec -C .agents/work/ratelimit \
--sandbox workspace-write \
"$(cat .agents/specs/ratelimit.md)" \
> .agents/logs/ratelimit.log 2>&1 &
echo $! > .agents/logs/ratelimit.pid
# Claude Code: headless print mode inside a subshell
(
cd .agents/work/docs || exit 1
nohup claude -p --permission-mode acceptEdits \
"$(cat ../../specs/docs.md)" \
> ../../logs/docs.log 2>&1 &
echo $! > ../../logs/docs.pid
)
# Gemini CLI: same pattern
(
cd .agents/work/changelog || exit 1
nohup gemini -p "$(cat ../../specs/changelog.md)" \
> ../../logs/changelog.log 2>&1 &
echo $! > ../../logs/changelog.pid
)
That is the entire dispatch contract: one process, one log, one PID per worker. The permission flags matter as much as the prompts. --sandbox workspace-write confines codex to writing inside its working directory, and --permission-mode acceptEdits lets Claude Code edit files without blanket bypass. Flags in these tools change between versions, so confirm names with --help before scripting a new setup.
Dispatching across different CLIs is also quota strategy. When one worker burns its weekly allowance, reassign that task to another CLI instead of waiting for a reset. For codex specifically, this worker-loop walkthrough covers log rotation and exit-code capture in more depth.
Merge by risk, not by convenience
Merge one branch at a time, lowest risk first, and run the test suite after every merge rather than once at the end. Before merging, check that the diff respects the ownership map, because agents sometimes reformat unrelated files they merely read:
git diff --name-only main...agent/docs
git diff --stat main...agent/ratelimit
git switch main
git merge --no-ff agent/docs
npm test
git merge --no-ff agent/ratelimit
npm test
If the changed-file list crosses the map, stop and inspect before merging. Order matters: docs and generated output first, isolated feature modules next, and shared-file changes such as dependency bumps, CI edits, or migrations last, after everything they might affect is already in. When a merge does conflict, the commander resolves it. Never hand a conflicted worktree to another worker to "fix up", because it lacks the intent behind both sides.
One more pattern earns its cost on risky core logic: assign the same spec to two workers in separate worktrees, compare the two diffs, and adopt the better one, or combine them. It spends double quota on the task, so reserve it for changes where being wrong is expensive.
Detect stalls before they cost hours
Two failure modes ruin parallel runs: a worker that exits without doing the work (an error, a permission prompt, a truncated prompt), and a worker that hangs silently for a long time. Silence is not progress, and exit is not success. Check state explicitly instead of assuming:
for w in ratelimit docs changelog; do
pid=$(cat ".agents/logs/$w.pid" 2>/dev/null)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo "$w: running"
else
echo "$w: exited — last log lines:"
tail -n 5 ".agents/logs/$w.log"
fi
done
Judge completion by the exit status and the end of the log. Each CLI signals differently: recent codex versions print a token-usage summary at the end of a normal exec run, while claude -p ends with its final answer text. The portable rule is: exited zero, plus a substantive final report in the log, equals done. Anything else, a bare exit, an error, or a trailing question, means the task is unfinished.
For a live process whose log has not grown in several minutes, look at what it is doing before killing it; long test suites look identical to hangs from the outside. A full watcher script with per-worker markers is in DONE, FAILED, or stalled?
Common questions
How many agents should I run at once?
Start with two or three on genuinely independent tasks. Coordination, merge, and verification overhead grow with every worker, and a large fan-out of related tasks usually collapses into merge conflicts no matter how good your ownership map is.
Do the agents share one context or conversation?
No. Each CLI process is independent, with its own context window and its own view of the repo through its worktree. That separation is the point: the commander holds the plan, and each worker holds exactly one task.
Can I run this on one laptop?
Yes. The CLIs are network-bound for most of their runtime. The resource pressure comes from concurrent builds and test suites in separate worktrees, so watch memory and stagger heavy test runs if the machine is small.
What if two workers edited the same file anyway?
The ownership map is a convention, not a lock. Detect it at merge time with git diff --name-only against each branch, resolve the overlap yourself in merge order, and tighten the spec that allowed it.