2026-07-17

Codex Agent Teams: A 24-Case Parallel PR Review Drill

Bind one exact diff, partition four read-only reviewers, require evidence-shaped findings, and reject stale or incomplete Codex review packets.

Codex Agent Teams: A 24-Case Parallel PR Review Drill cover illustration

Four reviewers do not make a pull request safer if they inspect different commits, overlap without saying so, or return conclusions with no file evidence. That is the real design problem behind Codex agent teams: parallelism is easy to request; a review you can admit, combine, and reject deterministically is harder.

I built a local 24-case control-shell drill around one narrow use case: a root Codex session delegates read-only PR review to four specialist workers, then accepts their packets only if the original diff is still current. The drill matched all 24 expected decisions. It did not run Codex, inspect a repository, or measure review accuracy. Its value is more modest and more useful: it exposes the contract that should exist before model output enters the path.

The team is not the control plane

OpenAI's current Codex guidance recommends subagents first for independent, read-heavy work such as exploration, tests, triage, and summarization. It also warns that parallel write-heavy work creates conflicts and coordination overhead. A PR review is a good fit because the workers can remain observers while the root session keeps the requirements, decision, and final response.

That division is important. A security worker can flag a timing leak; a test worker can notice missing unequal-length coverage. Neither worker needs permission to edit, commit, push, or merge. The root reviewer owns the decision about whether two observations are the same finding, whether evidence is strong enough, and whether the head commit has changed.

Accountability stays singular by design.

One review manager connected to four isolated specialist work areas
Parallel review works best when the root retains the decision and each specialist gets a bounded read-only lane.

Prerequisites: bind the review before spawning anyone

The admission record in the drill has four fields: base commit, head commit, SHA-256 of the diff manifest, and the exact changed-file list. A useful implementation can add repository identity, pull-request number, and generated-file policy, but it should not remove those four bindings.

{
  "base": "1a2b3c4d",
  "head": "5e6f7a8b",
  "diffSha256": "e1606c60...d45cf0d9d",
  "changedFiles": [
    "src/auth.ts",
    "tests/auth.test.ts"
  ]
}

Six manifest cases tested the boundary. The valid manifest was admitted. A changed head returned STALE_HEAD; a mismatched diff hash returned STALE_DIFF. A symbolic base name, an empty file list, and duplicate paths were denied as malformed manifests. Those are not model judgments. They are preconditions.

This also fixes a quiet failure in long reviews: a worker can produce a perfectly reasonable comment about a line that no longer exists. If the aggregator cannot prove that every packet belongs to the admitted head, the correct result is not “best effort.” It is “run the review again.”

The head is a lease, not a label.

Freshness beats plausible stale prose.

Partition by question and path, not by vague job title

The fixture uses four roles because they cover distinct questions without pretending that a larger headcount creates more certainty:

WorkerQuestionExample scope
CorrectnessCan this behavior produce the wrong result?Changed runtime paths
SecurityDoes the change expand trust or leak data?Auth and boundary code
TestsWhich failure or branch has no assertion?Related test files
MaintainabilityWhat new coupling will make the next change risky?Interfaces and shared types

Six assignment cases made the split explicit. The complete four-role partition passed. Duplicate roles, unknown roles, overlapping file ownership, and any write-enabled worker were denied. A three-worker packet was marked incomplete rather than silently lowering the review standard.

Real code does not always divide into disjoint files. When two reviewers must inspect the same path, treat that as deliberate corroboration instead of accidental ownership. Give them different questions and preserve both role labels. The drill rejects unannounced path overlap because ambiguous duplication is expensive: it burns extra tokens and makes the aggregator guess why two workers were assigned the same material.

Parallelism needs a reason.

Make every finding evidence-shaped

A worker summary is too weak if the root must reconstruct where the claim came from. The tested finding shape requires six fields: role, file, line, severity, evidence, and proposed action.

{
  "role": "security",
  "file": "src/auth.ts",
  "line": 42,
  "severity": "high",
  "evidence": "The token comparison returns on the first unequal byte.",
  "action": "Use a constant-time comparison."
}

Five finding cases checked the schema. A complete record passed. Missing file identity, line zero, empty evidence, and an unsupported severity were rejected. The rule is deliberately mechanical. It does not prove the finding is correct; it ensures that the root has something concrete to verify.

Evidence makes a claim inspectable.

Three specialist reviewers presenting separate evidence packets to one human decision maker
The handoff is an evidence packet, not a vote. The root checks and integrates it.

Do not ask workers to flatten uncertainty into a confident sentence. If evidence is incomplete, the packet should say so. If two roles disagree about severity, keep both assessments until the root inspects the code. Consensus generated by averaging labels is not review.

Testing: 24 cases for admission and aggregation

The complete aggregation case contained four worker packets and three raw findings. Correctness and security returned the same file, line, evidence, and action. Exact-key deduplication reduced the set to two distinct findings and recorded that one was corroborated by two roles. A missing worker returned INCOMPLETE_REVIEW; a new head returned STALE_REVIEW.

GateCasesMatched
Manifest admission66
Worker assignment66
Depth, thread, and tool policy44
Finding schema55
Completion and aggregation33
Total2424

The test result is useful because the failure names are actionable. “The team failed” tells an operator nothing. STALE_HEAD, DENY_ASSIGNMENT, and INCOMPLETE_REVIEW identify different recovery paths.

Completion is binary at this gate.

Failure modes: inherited permissions and recursive fan-out

Codex subagents inherit the parent session's sandbox and permission mode. In a non-interactive flow, a new action that requires approval fails when the approval cannot be surfaced. That is why the parent turn should enter the review with the narrowest useful permissions, and why the worker contract should repeat “read-only” instead of assuming the role name provides isolation.

A role name is not a sandbox.

The drill accepts four open worker threads, nesting depth one, and read tools only. It denies a seven-thread fan-out and depth two. A request to git_push returns APPROVAL_REQUIRED. The numbers are local choices, not Codex defaults: current documentation says agents.max_threads defaults to six and agents.max_depth defaults to one. Keeping depth one is the valuable part; it prevents a reviewer from quietly creating another layer of reviewers.

More workers are not free. Each subagent performs its own model and tool work, so parallel review consumes more tokens than a comparable single-agent pass. Four focused lanes are easier to audit than an unconstrained fan-out, and a small diff may be better reviewed by one root session.

Move the stable contract into repository guidance

Once the split works, put the durable parts in AGENTS.md or a referenced review file: supported checks, read-only worker rule, required finding schema, what counts as complete, and who owns the final response. OpenAI describes AGENTS.md as repository guidance for build commands, conventions, constraints, PR expectations, and verification.

For PR review:
- The root binds base, head, diff hash, and changed files.
- Workers are read-only and may not spawn children.
- Use correctness, security, tests, and maintainability lanes.
- Return file, line, severity, evidence, and action for each finding.
- Wait for all requested packets; fail on a stale head.
- The root verifies, deduplicates, and writes the final review.

Keep volatile identifiers out of that file. The actual base, head, and diff hash belong in the run manifest. The repository file defines the contract; the manifest binds one execution.

Where the 24-case drill stops

The harness is a deterministic control-shell simulation. It did not spawn a Codex subagent, call a model, clone a repository, inspect a real diff, run tests, trigger an approval interface, or measure tokens. It says nothing about review recall, false positives, latency, price, provider reliability, or production safety.

This is a control test, not a benchmark.

That limitation is the trade-off. A read-only, depth-one team cannot simultaneously implement fixes, and the root must wait for all four packets before declaring the review complete. In return, the workflow avoids merge conflicts, makes stale evidence visible, and leaves one accountable integration point.

Use Codex agent teams here when the diff is large enough to justify independent questions and the admission record can stay stable. For a tiny change, keep one reviewer. For implementation, split ownership by isolated files or worktrees and treat that as a separate workflow. Review and writing have different failure modes; combining them because both can run in parallel is how the control plane disappears.

Primary sources