From one agent to many: patterns for parallel agent orchestration
When to fan out AI agents, how to tune concurrency and depth, batch CSV processing with spawn_agents_on_csv, and the architectural patterns that make multi-agent systems predictable instead of chaotic.
A single capable agent solves most problems. Until it doesn’t. The moment you need to review 40 files, audit a monorepo for a pattern, or process a batch of incidents, the one-agent model breaks down — not because the agent isn’t smart enough, but because doing them serially takes too long and fills the context window with intermediate results.
Codex’s subagent system turns these problems into parallel workflows. Instead of one agent doing 40 things, 6 agents each do 7 things simultaneously. The orchestration — spawning, routing, waiting, collecting — is handled for you. Your job is knowing when to fan out and how to configure the boundaries.
The two knobs: concurrency and depth
Every multi-agent setup in Codex is governed by two settings:
[agents]
max_threads = 6
max_depth = 1 max_threads caps how many agent threads can be open concurrently. It defaults to 6 when unset. This is your fan-out budget: 6 agents can work in parallel, each in its own context window, each returning results independently.
max_depth caps how deeply agents can nest. A depth of 1 means a direct child agent can spawn but that child cannot spawn its own children. This is the default and should stay the default unless you have a specific, tested reason to allow recursive delegation.
Pattern 1: Parallel independent tasks
The simplest and most reliable pattern. Each agent works from the same input, doesn’t need other agents’ output, and returns results independently.
Main thread: "Review this branch for security, quality, bugs, and test coverage."
├── agent_1: security review → returns findings
├── agent_2: code quality → returns findings
├── agent_3: bug detection → returns findings
└── agent_4: test coverage → returns findings
All four agents run simultaneously. Each gets the same diff. Each applies different criteria. The main thread waits for all four and synthesizes.
This works because security review doesn’t depend on code quality findings, and bug detection doesn’t need test coverage analysis. The tasks are genuinely independent — same input, different lenses.
Pattern 2: Explore-then-act
Two-phase pattern where exploration runs first, then implementation follows with full context:
Phase 1 (parallel exploration):
├── code_mapper: traces relevant code paths
└── browser_debugger: reproduces the issue, captures evidence
Phase 2 (sequential implementation):
└── ui_fixer: applies the fix with full context from both explorers
Phase 1 runs in parallel because the code mapper and browser debugger work from the same bug report independently. Phase 2 runs sequentially because the fixer needs both exploration results before it can act.
This is the pattern for debugging workflows. Don’t chain exploration agents sequentially — they’re independent. But don’t start fixing until exploration is complete.
Pattern 3: Batch CSV processing
When you have tens or hundreds of similar tasks, spawn_agents_on_csv turns a CSV into a parallel work queue:
Input CSV:
path,owner
src/auth/login.ts,alice
src/auth/signup.ts,bob
src/payments/checkout.ts,carol
... (40 rows)
Output: one worker agent per row, all running in parallel (capped by max_threads)
Each row spawns a worker that receives the column values as template variables, performs the task, and reports a structured result:
Create /tmp/components.csv with columns path,owner and one row per frontend component.
Then call spawn_agents_on_csv with:
- csv_path: /tmp/components.csv
- id_column: path
- instruction: "Review {path} owned by {owner}. Return JSON with keys path, risk,
summary, and follow_up via report_agent_job_result."
- output_csv_path: /tmp/components-review.csv
- output_schema: an object with required string fields path, risk, summary, and follow_up Each worker must call report_agent_job_result exactly once. If a worker exits without reporting, Codex marks that row with an error in the exported CSV. The output includes original row data plus metadata: job_id, item_id, status, last_error, and result_json.
Pattern 4: Nicknamed agents for readable UIs
When you run multiple instances of the same custom agent, the UI can become unreadable — six threads all labeled “reviewer” tells you nothing. nickname_candidates fixes this:
name = "reviewer"
description = "PR reviewer focused on correctness, security, and missing tests."
developer_instructions = """
Review code like an owner.
Prioritize correctness, security, behavior regressions, and missing test coverage.
"""
nickname_candidates = ["Atlas", "Delta", "Echo", "Fox", "Gale", "Hawk"] When Codex spawns six reviewer agents, each gets a distinct nickname from the pool. The underlying agent type is still reviewer, but the UI shows “Atlas,” “Delta,” and “Echo” instead of six identical labels.
Nicknames are presentation-only. Codex identifies and spawns agents by name. The nickname pool just makes parallel runs readable.
Understanding the thread lifecycle
Each subagent goes through a defined lifecycle:
- Spawn — Main thread creates a new agent with a fresh context window and a task prompt.
- Execute — The agent reads files, runs commands, searches code. All intermediate work stays in the subagent’s context.
- Report — The agent returns a structured result to the main thread.
- Discard — The subagent’s context window is destroyed. Intermediate exploration is gone.
The main thread never sees the subagent’s intermediate work — only the final report. This is the core tradeoff: you save context space in the main thread at the cost of visibility into how the subagent reached its conclusions.
When not to fan out
Parallel orchestration fails predictably in two situations:
Sequential dependencies. If agent B needs agent A’s output to do its job, don’t run them in parallel. Agent B will either wait (wasting a thread slot) or run with incomplete context (producing bad output). Sequential dependencies belong in the main thread or in a phased pipeline where phase 1 completes before phase 2 starts.
Debugging workflows. When you’re diagnosing a bug, you need full visibility into what the agent discovers. A subagent that returns “found 3 issues” without showing the stack traces, error messages, or unexpected states forces you to redo the investigation yourself. Debugging stays in the main thread.
Tuning for production
Start conservative and widen based on observed behavior:
- Begin with
max_threads = 4— enough for parallelism, not so many that you overwhelm local resources. - Keep
max_depth = 1— there is almost never a good reason to allow recursive delegation. - Set per-call
max_runtime_secondson CSV batch jobs based on the expected work per row. A 30-second review per file with 40 files at 6 threads takes about 4 minutes. Adjust the timeout to match. - Monitor token usage — each subagent run shows up in your usage. If parallel agents aren’t producing enough value to justify the token cost, reduce fan-out width or switch to sequential processing.
Fan out when tasks share input but not dependencies
The test for parallelism: can each agent work without seeing the others' intermediate results? If yes, fan out. If no, keep it sequential.
max_threads caps concurrency, max_depth prevents runaway recursion
Default to 6 threads and depth 1. Raise depth only with a specific, tested reason — it's the dangerous knob.
CSV batches turn serial audits into parallel work queues
spawn_agents_on_csv maps one worker per row, enforces structured output via output_schema, and exports combined results with error tracking.
Nicknames make parallel runs readable
Use nickname_candidates when running multiple instances of the same agent. The UI shows distinct labels instead of repeating the agent name.
Debugging and test runs stay in the main thread
Subagents summarize away the details you need for diagnosis. When you need full visibility into intermediate discoveries, don't delegate.