Codex multi-agent workflows: parallel lanes, subagents and cloud fan-out
A Codex multi-agent workflow splits one body of work into lanes that share no files, runs one Codex agent per lane in its own Git worktree or cloud container, and merges the lanes in dependency order after each passes its own gate. Parallel lanes pay off only when shared contracts land first and every lane is verified independently.
Your epic has five subtasks: a migration, an API, a service change, a settings page and end-to-end tests. You can run five Codex sessions at once, but the last time you tried, two of them rewrote the same barrel file, a third invented its own response shape, and you spent the afternoon untangling merges. This page is for the developer who runs the agents and the tech lead who decides how many run at once and what “done” means for each.
What you get from a Codex multi-agent setup
Section titled “What you get from a Codex multi-agent setup”- A rule for what runs in parallel, what runs first and what must stay serial.
- Four copy-paste prompts: decomposition, foundation, lane worker and cross-lane conflict resolution.
- A fan-out script that starts one
codex execagent per Git worktree, and a lane gate that rejects work outside its lane before you read it. config.tomlsettings that cap subagent concurrency and cost.- A merge order and an integration check that prove the combined result works.
Commands and config keys on this page were checked against codex 0.157.1 (--help and the rust-v0.157.1 source) on 2026-09-26.
Which Codex surface runs which kind of parallel work?
Section titled “Which Codex surface runs which kind of parallel work?”Codex gives you four ways to run agents side by side. They differ in what they isolate, and isolation decides what can safely run in parallel.
| Surface | Start it with | Isolation | Use it for |
|---|---|---|---|
| Subagents in one session | Ask for them in the prompt; switch with /subagents | One session; you control concurrency with [agents] in config.toml | Read-heavy fan-out: exploring a codebase, reviewing a diff from several angles |
| Managed worktree sessions | codex --worktree, or /worktree inside a session | A new managed Git worktree per session | Interactive lanes you want to watch and steer |
Scripted codex exec | git worktree add, then codex exec -C <dir> | A worktree and branch you name yourself | Repeatable fan-out from a script, with logs you keep |
| Cloud tasks | codex cloud exec --env ENV_ID | A cloud container per task; up to four attempts each | Long lanes, heavy builds, and best-of-N on a hard lane |
The Codex desktop app (codex app, macOS and Windows) runs the same worktree pattern with one thread per lane. Neowin reported (secondary, 2026-07-09) that it now ships as a Codex mode of the ChatGPT desktop app. For worktree setup and cleanup on every surface, see isolated Codex tasks with Git worktrees.
When should you run Codex agents in parallel, and when serially?
Section titled “When should you run Codex agents in parallel, and when serially?”Parallelize a piece of work only when all three conditions hold:
- It owns its files. No other lane creates or edits the same paths.
- It depends on nothing another lane is still writing. Its inputs are already on the base branch.
- It can prove itself alone. It has its own tests, and type check and lint pass on its branch without the other lanes.
Serialize everything else: database migrations, shared types and interfaces, route or schema registration in barrel files, and any step where you need to make a judgment call before the next one starts.
Most feature sets have the same shape. A thin foundation (migration, shared interfaces, registration lines) blocks everything, then three to five lanes run in parallel, then an integration phase runs once after every merge. Conflicts almost always come from skipping the foundation: two agents each add “one line” to src/routes/index.ts, or each invent their own EventPayload.
Run a feature set as parallel Codex lanes
Section titled “Run a feature set as parallel Codex lanes”The walk-through uses a notification-preferences feature: users choose email, SMS or push per notification type. The same steps work for a quarter’s worth of independent features; only the lane list gets longer.
-
Decompose the work and write the plan to a file. Run the planning prompt below in a normal Codex session on your base branch. Review the plan, not the code: the file-ownership table and the contracts are where parallel work succeeds or fails. Commit
docs/plan/notification-prefs.md, because every lane prompt points to it. -
Land the foundation serially. Run the foundation prompt in one session on a feature branch, for example
feature/notification-prefs. When its tests pass, commit it. Every lane now starts from a branch that already has the table, the shared types and the registration lines, so no lane needs to touch a shared file. -
Launch one agent per lane. For two or three lanes you want to watch, open a terminal per lane and run
codex --worktreefrom the feature branch, then paste the lane prompt. For more lanes, or a run you want to repeat, use the fan-out script in the next section. -
Monitor and steer without joining every conversation.
codex agents(or/agentsin a session) opens the agent command center, where you can search, open, rename and stop sessions. Rename each session after its lane there. To redirect a lane without switching to it, queue a message by session name:codex queue --thread prefs-api --message "Use the NotificationPreference type from src/types/notifications.ts; do not define a new one."When one lane needs to know what another decided,@-mention that task in the prompt instead of pasting its output. Check/usagebefore you launch another batch. -
Gate each lane on its own. Run the lane gate below on every branch as it finishes. A managed
codex --worktreesession leaves its changes uncommitted in a worktree that Codex names, so commit the lane’s work there first and pass that worktree’s path (fromgit worktree list) as the gate’s fourth argument. A lane that fails its gate goes back to its agent with the gate output; you do not read its diff yet. -
Merge in dependency order, then run integration. Merge the lane with the fewest shared touch points first, and the end-to-end tests lane last. After the last merge, run the full suite once on the feature branch. Only then open the pull request and request
@codex reviewon it, alongside your team’s reviewers.
Fan out lanes from a script with codex exec
Section titled “Fan out lanes from a script with codex exec”The script creates one worktree and branch per lane from the current branch, installs dependencies outside the sandbox, runs one non-interactive agent per lane in parallel, and commits each lane’s result so the gate has a clean branch to check. Run it from the repository root on the branch that holds the foundation commit, with one prompt file per lane in prompts/. The script stops if a lane’s branch or worktree already exists, so before a rerun remove the previous ones (the “Old worktrees pile up” row in When parallel Codex agents break); that discards any lane work you have not merged.
#!/usr/bin/env bash# fan-out.sh: one codex exec agent per lane, each in its own worktreeset -euo pipefailBASE=$(git rev-parse --abbrev-ref HEAD)RUNS="$PWD/.codex-runs"mkdir -p "$RUNS"pids=(); lanes=()
for lane in api service ui; do wt="../wt-prefs-$lane" git worktree add -b "feat/prefs-$lane" "$wt" "$BASE" (cd "$wt" && npm ci --silent) # installs need the network the sandbox withholds codex exec -C "$wt" \ -c default_permissions=":workspace" \ --json -o "$RUNS/$lane.md" \ "$(cat "prompts/prefs-$lane.md")" < /dev/null > "$RUNS/$lane.jsonl" & pids+=("$!"); lanes+=("$lane")done
failed=0for i in "${!pids[@]}"; do wait "${pids[$i]}" || { echo "FAIL ${lanes[$i]}: codex exec exited non-zero"; failed=1; }done[ "$failed" -eq 0 ] || exit 1
for lane in api service ui; do git -C "../wt-prefs-$lane" add -A git -C "../wt-prefs-$lane" commit -m "prefs: $lane lane (codex exec)" || echo "$lane: nothing to commit"doneThree choices in the script are deliberate. -c default_permissions=":workspace" selects the built-in workspace permission profile, which OpenAI prefers over the legacy --sandbox flag; profiles are beta (Codex CLI 0.138.0 and later), so pin your CLI version in scripts. npm ci installs from the lockfile, so five lanes cannot resolve five different dependency trees. The script, not the agent, commits, so the result does not depend on whether the agent’s sandbox can write to the repository’s shared .git directory. .codex-runs/ holds each lane’s final message and JSONL event log; add it to .gitignore. Two guards keep a bad lane from reaching a commit: the script waits on each lane’s process ID and stops if any codex exec exited non-zero (a bare wait returns 0 regardless), and < /dev/null matters because codex exec appends piped stdin to the prompt, so a script run from CI or bash < file would otherwise feed stray input to every agent.
Write the service and UI lane prompts the same way: the lane’s name, its editable files, the contract it imports, and a definition of done with commands. A lane prompt that omits “edit only” invites the agent to fix whatever it notices on the way, and that is where cross-lane conflicts come from.
How do you prove each lane without reading every diff?
Section titled “How do you prove each lane without reading every diff?”Put machine checks in front of your attention, in this order. Each layer is cheaper than the one after it, so a lane reaches a human only after the cheap checks pass.
| Layer | What it catches | How |
|---|---|---|
| Lane boundary | The agent edited files outside its lane | git diff --name-only against the lane’s allowed paths |
| Lane tests and static checks | Broken behaviour inside the lane | The lane’s own tests, type check and lint on its branch |
| Reviewer agent | Contract drift, missing tests, logic errors | A codex exec run under the :read-only permission profile, with the plan as the rubric |
| Contract tests at the seams | Lanes that each pass but disagree | Tests that import the shared types from both sides, written in the foundation |
| Integration run | Interactions: shared test state, ports, ordering | The full suite once, after the last merge |
| Human sign-off | Wrong plan, wrong contract, risky files | You approve the plan and contracts before launch, and read diffs only in files your plan marks as risky (auth, payments, migrations) |
The lane gate automates the first three layers. Run it from the repository root once per finished lane:
#!/usr/bin/env bash# lane-gate.sh LANE ALLOWED_PATHS_REGEX [BASE] [WORKTREE]# example: ./lane-gate.sh api '^(src/routes/notifications/|src/services/notifications/api|tests/.*notification)'set -euo pipefaillane="$1"; allowed="$2"; base="${3:-feature/notification-prefs}"; wt="${4:-../wt-prefs-$lane}"runs="$PWD/.codex-runs"cd "$wt"
test -z "$(git status --porcelain)" || { echo "FAIL $lane: uncommitted changes"; exit 1; }
stray=$(git diff --name-only "$base"...HEAD | grep -v -E "$allowed" || true)if [ -n "$stray" ]; then echo "FAIL $lane: files outside the lane:"; echo "$stray"; exit 1; fi
npm run typechecknpm run lintnpm test
codex exec -c default_permissions=":read-only" -o "$runs/$lane-review.md" \ "Review git diff $base...HEAD against docs/plan/notification-prefs.md. Report only correctness bugs, contract drift from src/types/notifications.ts, and behaviour without a test. Give file and line for each finding. If there are none, reply with exactly NO FINDINGS on its own line." < /dev/null[ "$(tr -d '[:space:]' < "$runs/$lane-review.md")" = 'NOFINDINGS' ] || { echo "FAIL $lane: review findings in $runs/$lane-review.md"; exit 1; }echo "PASS $lane"The review step is a plain codex exec run rather than codex exec review, because codex exec review --base rejects a custom prompt: --base and a custom prompt are mutually exclusive (checked in codex 0.157.1), so it cannot take the plan as its rubric. If you prefer codex exec review --base "$base", run it without a prompt and put the rubric in the review guidelines of AGENTS.md. The gate fails unless the review file holds nothing but NO FINDINGS (whitespace aside), so a review that lists findings and also writes that line still fails; when it fails, read the findings and send them back to the lane’s agent, or overrule a false positive yourself. Each check sits on its own line because under set -e a failure in any command before the last && of a chain does not stop the script, so a failing type check would still print PASS.
A lane that fails the boundary check goes back to its agent, or you move the stray file into the foundation and re-plan. Do not merge the lane and fix the overlap by hand: that is how the next lane’s conflict starts. For the review side of this at team scale, see Codex review strategies and running the review queue when agents open the pull requests.
Fan out inside one session with Codex subagents
Section titled “Fan out inside one session with Codex subagents”Subagents are on by default (multi_agent is stable in 0.157.1). The session’s agent spawns them when your prompt asks for parallel work, and /subagents switches between them. They suit questions more than edits: several readers covering one codebase, or several reviewers covering one diff. Keep lanes that write files in separate worktrees, where Git isolates them.
Cap them in ~/.codex/config.toml. Every key below is in the 0.157.1 config schema:
[agents]max_threads = 4 # alias of max_concurrent_threads_per_sessiondefault_subagent_reasoning_effort = "medium" # used when the spawn call sets none# default_subagent_model = "gpt-6-sol" # only after your own evals favour it
[agents.reviewer]description = "Read-only reviewer. Reports findings with file and line; never edits files."config_file = "./agents/reviewer.toml" # a config layer, relative to this file
[goals]max_goal_token_budget = 2000000 # nested subagent tokens count toward itLeave default_subagent_model unset until you have a reason. Codex runs GPT-6 Astra by default, and the site’s rule is to tune effort before switching model; the models hub lists the current Codex models and prices. Since 0.151.0, tokens spent by nested subagents count toward a /goal budget, so a goal budget also caps a fan-out.
Send long or risky lanes to Codex cloud
Section titled “Send long or risky lanes to Codex cloud”A lane that needs a heavy build, runs for a long time, or has several plausible designs fits a cloud task better than a laptop worktree. Push the foundation branch first: codex cloud exec runs on your current branch unless you pass --branch (checked in codex cloud exec --help, 0.157.1), and the container clones from your remote.
# run in your terminal, inside the repositorygit push -u origin feature/notification-prefscodex cloud exec --env ENV_ID --branch feature/notification-prefs --attempts 2 - < prompts/prefs-service.mdcodex cloud list --env ENV_ID # watch progresscodex cloud diff TASK_ID --attempt 2 # compare attempts# apply the chosen attempt inside the lane's own worktree, commit it, then gate itgit worktree add -b feat/prefs-service ../wt-prefs-service feature/notification-prefs(cd ../wt-prefs-service && codex cloud apply TASK_ID --attempt 2 \ && git add -A && git commit -m "prefs: service lane (cloud)")./lane-gate.sh service "$SERVICE_PATHS" # the service lane's allowed-paths regexENV_ID is your cloud environment’s ID or label, and TASK_ID is the ID or URL that codex cloud exec prints. codex cloud apply writes the diff into the checkout you run it in, so run it inside the lane’s worktree and commit before the gate, which refuses uncommitted changes. That way a cloud lane goes through the same lane gate as a local one. Drop a lane you send to the cloud from the for lane in list in fan-out.sh, or the two would claim the same worktree. Environment setup, internet access and when best-of-N is worth paying for are covered in Codex cloud environments.
How many Codex agents should you run at once?
Section titled “How many Codex agents should you run at once?”Set the number by review capacity, not by what your machine or plan allows. Faros AI’s “AI Engineering Report 2026” (April 2026, telemetry from 22,000 developers) reported task throughput per developer up 33.7%, while median time in review rose 441.5% and incidents per pull request rose 242.7%. More generation without more verification moves the queue to review and the cost to production.
Practical limits that follow from that:
- Start with three lanes. Add a fourth only when the lane gates of the first three pass without rework. Treat five lanes per developer as a ceiling you have to justify, not a target.
- One owner per merge. Whoever wrote the plan merges the lanes, because merge order depends on the plan.
- Budget before launch. Check
/usagein a session before starting a batch, setmax_threadsfor subagents, and set a/goalbudget on long lanes. Plan allowances and their five-hour and weekly windows are covered in Codex cost management.
When parallel Codex agents break
Section titled “When parallel Codex agents break”| Symptom | Cause | Recovery |
|---|---|---|
Conflicts in src/routes/index.ts or another barrel file | Several lanes registered themselves | Move registration into the foundation with stubs, as in the foundation prompt. For a merge already in conflict, use the prompt below |
| Lanes pass alone and fail together | Shared test state, fixed ports, or two lanes seeding the same table | Add the missing contract test to the foundation, isolate test data per suite, then rerun integration |
| Two lanes disagree on a response shape | The contract was left to the agents | Put the shape in src/types/notifications.ts in the foundation; queue a message to both lanes pointing at it |
| The lane gate reports files outside the lane | The prompt lacked “edit only”, or the plan missed a shared file | Send the gate output back to the agent, or move the file into the foundation and re-plan |
| A cloud lane is missing the foundation | The branch was not pushed, or --branch pointed elsewhere | Push the foundation branch and resubmit with --branch |
npm ci or builds exhaust the laptop | Five worktrees installing and testing at once | Stagger launches, or move the heaviest lanes to cloud tasks |
| A lane stalls or loops | Unclear definition of done, or a full context window | Stop it from codex agents, tighten the definition of done in the lane prompt, and start a fresh session in the same worktree |
| Old worktrees pile up | Every lane leaves a worktree and a branch | After merging, git worktree remove ../wt-prefs-api, git branch -d feat/prefs-api, then git worktree prune |
Where to go next with multi-agent Codex work
Section titled “Where to go next with multi-agent Codex work”- Before this page: isolated Codex tasks with Git worktrees and writing
AGENTS.mdfor Codex. Every lane readsAGENTS.mdfor its build and test commands. - Scripted runs in depth: non-interactive Codex with
codex exec. - The same fan-out over dozens of files or repositories: Codex batch operations.
- Keeping each lane’s context small: Codex context patterns.
- Tool-neutral patterns (planner, workers, judge): multi-agent orchestration patterns.
- The Claude Code equivalent: custom subagents in Claude Code.