GPT-5.6 often serializes independent Code Mode calls; explicit batching reduced weighted usage by 27–45%
What version of the Codex App are you using (From “About Codex” dialog)?
26.721.30844
What subscription do you have?
ChatGPT Pro for the personal-project tests; ChatGPT Business for the work-project tests.
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What issue are you seeing?
Related to #32503, but this report adds controlled same-model benchmarks, credit-weighted usage measurements, quality comparisons, and a tested workaround across two unrelated codebases.
I began investigating this independently after noticing an unusually high number of recent complaints about Codex usage depletion. I had not personally noticed an obvious long-term reduction in my limits, so I inspected my own .codex session logs rather than assume that allowances had been silently changed.
Only after reaching the batching hypothesis and completing my initial tests did I search for similar reports and find #32503. Its author had already identified essentially the same Code Mode parallelism problem from a long observational trace, including only 5 of 739 GPT-5.6 exec cells using Promise.all. The tests below appear to provide the controlled validation that report said was still missing.
I tested two unrelated repositories:
- one large proprietary work codebase;
- one smaller personal finance application.
Each repository had one fixed read-only investigation task. Within each comparison, the subscription plan, repository state, task prompt, model, reasoning effort and permissions were unchanged. Only the presence of the batching instruction differed. No code was modified during the investigations.
Main results
| Dataset | Sample | Model cycles | Raw tokens | Weighted usage | Same-credit capacity |
|---|---:|---:|---:|---:|---:|
| Large work codebase | 4 batched runs vs 3 controls, High | 52.1% fewer | 63.1% lower | 45.0% lower | 81.8% more |
| Personal finance app | 4 matched pairs, High/XHigh | 54.7% fewer | 52.6% lower | 27.0% lower | 37.0% more |
| Personal finance app, Max | 1 matched pair, adjusted | 80.4% fewer | 79.5% lower | 47.4% lower | 90.2% more |
The Max result is a single pair and needs replication. It still covered all required areas and aligned on the core conclusions, but the batched report referenced fewer unique files than its control, so I treat both its efficiency and quality result cautiously. The repeated High/XHigh results are the stronger basis for the current conclusion.
The exact improvement varied substantially by workload. I am not claiming that every Codex task will gain 37–82% more capacity.
“Weighted usage” is the Codex-credit equivalent calculated from the returned uncached-input, cached-input and output-token categories. Reasoning tokens are included in output tokens.
Most of the raw-token reduction came from repeated context processing:
- cached input fell by 56–65% in the repeated datasets;
- uncached input fell by 5–26%;
- output changed by only about 0–12%.
This is consistent with batching reducing outer model round trips rather than simply reducing the amount of investigation performed.
Normal-usage observation
At work I deleted my .codex directory and allowed it to rebuild from scratch.
By July 23, the fresh logs had accumulated roughly 1,600 calls that a post-hoc Codex analysis classified as independent and batchable. Only a little over 100 had actually been grouped by the agent.
This was not part of the controlled benchmark, but it suggests that GPT-5.6 sometimes discovers batching on its own while doing so very inconsistently without concrete instructions.
Quality
I did not find an apparent systematic quality reduction.
Across the Finance comparisons:
- both conditions covered every required investigation area;
- the main conclusions aligned;
- the aggregate performed 106 batched inspections versus 105 control inspections.
On the large codebase, the batched runs performed substantially more shell operations than the controls while still using much less.
Batched runs sometimes found additional useful details. Subtle quality differences may still exist, and implementation-heavy or mutation-heavy tasks may behave differently from these read-only investigations.
---
What steps can reproduce the bug?
- Choose a read-heavy repository task involving several independent searches, file reads or metadata inspections.
- Freeze the repository state.
- Start fresh GPT-5.6 Sol sessions using the same:
- task prompt;
- reasoning effort;
- permissions;
- repository state.
- Run one condition without custom batching guidance.
- Run the other with this exact instruction in either repository
AGENTS.mdor the Codex App custom instructions:
In Code Mode, within each bounded stage, run independent, functions.exec-available tool calls concurrently in one functions.exec call. Use await Promise.allSettled([...]) when partial results are useful, and inspect every result; use await Promise.all([...]) only when any failure should abort the batch. Keep dependencies, waits/resumes, approvals, conflicting or interdependent mutations, and adaptive investigations where each result may change the next step sequential. Do not split otherwise batchable inspections across outer tool calls.
- Compare the session logs:
- outer model/tool cycles;
- direct tool calls and
execcells; - nested calls per
execcell; - use of
Promise.allorPromise.allSettled; - cached, uncached and output tokens;
- task coverage and final conclusions.
The controlled repository comparisons used AGENTS.md. I also used the same instruction through app-level custom instructions and observed the same multi-call Code Mode batching pattern.
Despite using older functions.exec terminology, it reliably caused GPT-5.6 Sol to group multiple nested operations into concurrent Code Mode stages.
---
What is the expected behavior?
GPT-5.6 Code Mode should receive concrete guidance to:
- group independent, non-conflicting calls into one bounded
execstage; - use
Promise.allorPromise.allSettledfor nested concurrency; - keep dependent, adaptive, approval-sensitive and conflicting operations sequential;
- avoid repeated one-call
execcells when multiple independent calls are already known; - avoid expanding investigation scope only because more calls can be launched concurrently.
The model-facing exec description should include an example containing multiple nested tools.* calls inside Promise.all(...) or Promise.allSettled(...).
It would also help if telemetry distinguished outer model cycles from nested tool calls and showed quota-weighted usage more directly.
---
Additional information
GPT-5.2 through GPT-5.5 were explicitly instructed to parallelize common independent reads using multi_tool_use.parallel.
GPT-5.6 moved to the Responses Lite and Code Mode path. Native top-level parallel calls are disabled there, while JavaScript inside exec is the practical replacement. The runtime supports nested concurrency, but the shipped GPT-5.6 guidance is generic and the exec example demonstrates only a single nested call.
I may be missing an internal constraint or implementation detail, but the public source, local traces, controlled behavior and the independent findings in #32503 are consistent with an instruction/tool-interface regression during that transition.
I do not see evidence that this was an intentional allowance reduction. OpenAI added a replacement batching mechanism; the model appears not to use it reliably without concrete guidance.
I also tested several rewritten instructions using the current exec and tools.* terminology. One essentially matched the original instruction on the large codebase, but none consistently matched its Finance results. Some expanded investigation scope, while others produced one-call Promise.allSettled cells that provided little real batching. One overly aggressive variant consumed 26.8% more weighted credits than its control.
Limitations
These tests covered read-heavy repository investigations.
The large-codebase result used grouped averages rather than matched simultaneous pairs. The Max result and each revised instruction variant currently have only one pair. Model sampling, service load and differences in peripheral investigation scope remain sources of variance.
“Same-credit capacity” means more comparable completed work from the same allowance. It does not mean the allowance necessarily lasts the same additional percentage in literal wall-clock time, because the batched tasks also tend to finish faster.
Additional sanitized per-run measurements are available on request.
25 Comments
Update: output-truncation caveat
A raw-log audit found that some batched exec responses exceeded Code Mode’s shared output limit and were truncated. This may have overstated the measured usage savings and introduces a quality risk, although the reduction in model/tool cycles remains clear and the repeated comparisons still showed aligned required coverage and core conclusions.
I am retesting with a minimally revised instruction that bounds combined output and narrowly retrieves any missing evidence. Until then, please treat the 27–45% savings range as provisional.
Independent replication on a different setup (Codex CLI 0.145.0, WSL2,
ChatGPT Pro auth,
gpt-5.6-sol), plus two findings I haven't seen in thisthread or #32503: the effect is effort-gated, and
ultraeffort is aseparate order of magnitude.
Setup
Controlled A/B, only variable = a batching instruction (the
Promise.allSettled paragraph from this issue) vs a length-matched placebo
instruction, injected via
AGENTS.md(synthetic repos) or-c developer_instructions=...(real repos, read-only sandbox). Freshsession per trial, alternating arm order, MCP/plugins/memories disabled,
fixed model + effort per run. Metrics parsed from the
~/.codex/sessionsrollout JSONL (token_countevents = model cycles;custom_tool_call name="exec"cells inspected fortools.*(counts andPromise.all/allSettled). Harness: https://github.com/ForrestGrump/codex-batch-bench.Results — synthetic 48-module repo, effort sweep (no-instruction ÷ instructed)
| effort | model cycles | raw tokens | weighted credits* |
|---|---|---|---|
| low | 1.00× | 1.11× | 0.98× |
| medium | 1.14× | 1.01× | 0.90× |
| high | 1.06× | 0.96× | 0.89× |
| xhigh | 1.50× | 1.56× | 1.16× |
| max | 1.33× | 1.36× | 0.99× |
| ultra | 4.83× | 4.44× | 3.65× |
\* at the published 125/12.5/750 per-1M rate card.
At low–high, the uninstructed model batches on its own (often via shell
loops in plain
exec_commandcalls — zero Code Mode cells). At xhigh/max itdegenerates to one tool call per model cycle. A fix that only tests at
high effort will not see this bug.
Results — three real repos, xhigh, 2 trials/arm each
Raw-token multipliers (uninstructed ÷ instructed): 1.41× / 3.15× / 2.66×
(mean ≈ 2.4×, consistent with the 2.1–2.7× in the OP). Worst trial: 25
cycles / 1.71M raw tokens uninstructed vs 7 cycles / 400k instructed for the
identical task. Deliverable quality was equivalent in all trials, both arms
(graded on the synthetic repos: 48/48 modules + 40/40 config keys at every
effort level including ultra).
Ultra is its own problem
At
ultra, the uninstructed runs spawned 23–25 sub-sessions despitefeatures.multi_agent=false, usedPromise.all*zero times across ~50exec cells, and consumed 7.5–17.6M raw tokens (267–605 credits) per
read-only investigation task — the worst single trial moved a Pro weekly
meter a full 1%. Filed separately: #35177.
Also verified: sub-agents inherit the parent's resolved config (including
-c developer_instructionsoverrides); they do not re-read~/.codex/config.toml.Repro
Happy to provide raw rollout logs / metrics CSVs for any trial.
Further truncation-audit context
A more detailed comparison shows that roughly 80k of the batched-side omitted tokens came from two ALL_TOOLS catalogue dumps rather than repository evidence. Non-batched controls also truncated broad compound shell outputs.
Excluding those catalogue dumps and the single Max pair, the four repeated High/XHigh comparisons omitted 63.6k repository-output tokens with batching versus 20.9k in controls. Restoring all explicitly omitted repository output once changes the repeated weighted-saving estimate from 27.0% to approximately 23.9%; the large reduction in model cycles and cached-input usage remains.
Truncation is therefore still a real output-reliability issue, but the detailed logs do not suggest that it explains most of the measured efficiency gain or caused an apparent systematic collapse in answer quality. A cleaner output-bounded replication is still needed.
@MakerOfToys I ran your truncation audit against my 52-trial replication (methodology upthread; harness: https://github.com/ForrestGrump/codex-batch-bench, audit script now in the repo as
audit_ingestion.py). Metric: characters of all tool output entering each trial's transcript (function_call_output+custom_tool_call_outputpayloads in the rollout JSONL), split unique vs exact-duplicate.| run | no-instruction | batching | ingestion ratio | raw-token ratio |
|---|---|---|---|---|
| synthetic 48-module @ xhigh | 55.8k | 55.9k | 1.00× | 1.56× |
| real repo A @ xhigh | 92.2k | 70.4k | 1.31× | 1.41× |
| real repo B @ xhigh | 245.9k | 169.7k | 1.45× | 3.15× |
| real repo C @ xhigh | 109.8k | 70.7k | 1.55× | 2.66× |
| synthetic @ ultra | 849k | 420k | 2.02× | 4.44× |
Three observations relevant to "a cleaner output-bounded replication is still needed":
Caveat matching yours: exact-duplicate share was only 0–2% by hash, but overlapping re-reads via different commands/line ranges hash as unique, so byte-level dedup understates redundancy. Net: truncation is a real output-reliability concern on open-ended tasks, but on this dataset it cannot account for the majority of the measured gap, and on the bounded task it accounts for none of it.
@ForrestGrump Thank you for doing all this work and for continuing to test the different explanations. The ingestion audit is especially useful - it’s reassuring to see a clean case where both arms received essentially the same amount of tool output while the batching run still used substantially fewer tokens. Really appreciate you publishing the harness and results too.
Edited after a source and benchmark audit (July 26, 2026).
I still think a description-only PR is the right first experiment, but I would narrow the causal claim and make the output-limit guidance more precise.
Why this scope still fits the current source
gpt-5.6-soluses Responses Lite andcode_mode_only.parallel_tool_calls, so JavaScript concurrency inside Code Modeexecis the practical batching path.execdescription shows a single awaited nested call and does not explainPromise.all(...)orPromise.allSettled(...).Proposed PR scope
Change only the model-facing Code Mode
execdescription and focused tests. Do not change request serialization,parallel_tool_calls, model metadata, runtime scheduling, telemetry, or approval behavior in this first patch.Suggested guidance:
A compact example could be:
The exact example can be adjusted to match the repository's preferred tool and platform-neutral style.
Tests I would add
execdescription for:Promise.allSettledguidance;Promise.allSettled, confirming that the successful result remains available and the failure is explicit.execbudget.Validation before calling it fixed
Compare stock and patched binaries with the public harness using:
I would look for a material reduction in XHigh outer model cycles and singleton
execstages, no more than a 5% regression at Low–High, no increase in runtime failures or unrecovered truncation, and exact task grading rather than only checking module-name and unused-key presence.This remains a bounded, testable first fix rather than a claim that description text is the sole root cause. I am happy to prepare the focused patch and validation if a Codex-team member agrees with the approach and explicitly invites a PR under the repository's contribution policy.
@avoethan Strong +1 on this scope from the replication side — the data says a description-only fix is aimed at the right layer:
Promise.allSettledinsideexecin every xhigh/max/ultra trial with zero runtime failures — the capability is fine; only the contract is silent about it. A prompt-contract fix matches the failure mode.highand below the model already groups reads on its own (often via shell compounds), and my always-batch instruction was mildly negative there (0.89× weighted credits vs placebo). Unconditional "batch everything" wording risks regressing the healthy tiers; conditional wording ("already-known, independent, non-mutating, one bounded stage") produced the wins without measurable quality cost (graded 48/48 + 40/40 in both arms at every tier).max_output_tokens" is the right mitigation for exactly the truncation concern discussed above.To help review such a PR: the harness now supports
--codex-bin, so a patched build can be benchmarked against stock with identical prompts — compare the placebo arms across the two runs (no explicit instruction anywhere; any delta isolates the built-in description change), with the batching arm as a positive-control ceiling. Recipe in the README: https://github.com/ForrestGrump/codex-batch-bench#validating-a-tool-description-pr-binary-vs-binaryOne review-criterion suggestion: validate at
xhigh/max(and ideallyultra, where the orchestrator + sub-agents inherit the same description — see #35177), and checkhigh-and-below for non-regression. A description change validated only at default efforts will not exercise the failure mode this issue is about.Happy to run the pre/post sweep on a candidate branch and post numbers.
Relevant to the truncation caveat this thread has been weighing against the batching results: I traced the large truncations to source and filed #35421.
They are not a batching artifact. In my sample, across 4,841 legacy
shell_command/function_call_outputrecords, 9 hit the 1 MiB capture cap — andexectruncations were almost entirely trivial (96–100 characters). Roughly 96% of all dropped content came from the non-batched shell path.The mechanism is that the shell capture retains the first 1 MiB and discards the remainder without counting it, then a separate formatter elides the survivor to the model budget and inserts
…252144 tokens truncated…mid-payload. That figure is a constant — (1,048,576 − 40,000) / 4 — so it is the same regardless of how much was actually lost.Practical implication for the measurements here: truncation of this kind affects both arms of the A/B and is not introduced by batching, so it should not be netted against the batched arm'''''s savings. @ForrestGrump this may also bear on the ingestion-ratio comparison — some of the difference could be capped output rather than reduced duplication.
@tylorsaling-source Good catch — I re-audited all 52 trials with a full-text marker scan (my earlier scan only sampled output heads), and your hypothesis is partially confirmed on my dataset, in an instructive way:
No 1 MiB cap events fired here. Zero markers with the ≈252k constant figure; largest single output was 156 KB. All outputs were clamped by model-chosen
max_output_tokens(2k–20k) well before your capture cap — so #35421's silent-discard path doesn't contaminate this dataset, though it clearly could at larger scales.**But budget-level elision was asymmetric — and concentrated in the batched arm. 33 exec-path markers (median 1,235, max 48,634 claimed tokens): multi-call
Promise.allSettledresults overflowing the per-call budget. Placebo's shell-path markers were trivial (n=26, median 5** tokens claimed). Crediting the claimed-elided volume back as "attempted ingestion":| real repo @ xhigh | seen ratio (no-instr ÷ batched) | attempted ratio |
|---|---|---|
| A | 1.31× | ≈1.09× |
| B | 1.45× | ≈0.90× |
| C | 1.55× | ≈1.36× |
So yes — much of the seen-ingestion difference I reported was capped output, not reduced duplication. Thanks for pushing on this.
Net effect on the thread's question, though, is to strengthen the no-confound conclusion: the batched arm fetched roughly as much repository data as the non-batched arm; the formatter trimmed the presentation; deliverables stayed equivalent (and on the graded synthetic task, perfect in both arms at every effort tier); and the 1.41–3.15× consumption gaps remain — attributable to round trips, not evidence volume. The synthetic-xhigh pair keeps its status as the clean bounded replication: 1.00× seen ingestion, equal grades, 1.56× consumption.
(Caveat inherited from #35421: I treat the claimed figures as approximate. Also practical support for the proposed exec-description scope above — batched multi-file results routinely exceeded model-chosen budgets, which is exactly why the "narrow fields/ranges, deliberate max_output_tokens" guidance belongs in the description.)
Updated audit in the repo: https://github.com/ForrestGrump/codex-batch-bench
can you please fix this issue? I only have like 32% left usage on my weekly. I just gave it a task and it completed the task and just one over and a half. It made the plan and it executed that so I was using GPT 5.6 Terra Medium for the implementation. And it did not complete the whole task for that plan as well. Still, my usage was really exhausted.
Independent Codex Desktop replication at medium effort
I ran a small controlled A/B and saw the same direction of effect at
mediumeffort.Setup
gpt-5.6-sol,mediumfunctions.exec/Promise.allSettledbatching guidance present vs absentResults
| Metric | Batched | No batching guidance | Difference |
|---|---:|---:|---:|
| Outer tool calls | 1 | 2 | 50% fewer |
|
token_countevents | 2 | 3 | 33.3% fewer || Cached input | 32,835 | 78,726 | 58.3% lower |
| Uncached input | 45,142 | 48,102 | 6.2% lower |
| Output | 3,419 | 5,779 | 40.8% lower |
| Raw total tokens | 81,396 | 132,607 | 38.6% lower |
| Uncached input + output | 48,561 | 53,881 | 9.9% lower |
| End-to-end duration | 41.848 s | 71.805 s | 41.7% faster |
The batched arm used one
functions.execcell containing 13 concurrentexec_commandcalls throughPromise.allSettled. The uninstructed arm used one large sequential compoundexec_command, then a second adaptiveexec_commandto narrow and correct the result.Raw shell time was not the source of the wall-clock win: the batched outer execution reported about 380 ms, versus about 290 ms across the control's shell batches. The overall improvement came from avoiding the additional model/tool round trip and its repeated context processing, consistent with the large cached-input reduction.
Quality/output caveat
Both arms covered all 12 requested areas and reported no command failures. However, both encountered an overly broad documented-command search. The batched arm acknowledged truncation but did not recover the missing evidence; the control used its second cycle to narrow that search and also refined the interpretation of “source files” to exclude test trees.
I therefore treat the 38.6% raw-token and 41.7% duration reductions as a useful single-pair replication, not a general savings estimate or proof of equal output quality. It also supports the output-safety wording proposed above: bound combined output and narrowly recover truncated evidence rather than stopping after the initial concurrent stage.
For anyone arriving here because your usage is vanishing: batching is one drain, and this thread has it well characterized — but it isn't the only one, and for a lot of "a single task ate my week" reports the larger, separate cause is the context auto-compaction loop, not tool-call serialization.
Quick way to tell which you're hitting:
execcalls that could have run together. The instruction in this issue helps.Context automatically compactedmessages, the model rereading the same files, restating it "found the defect," and never finishing — while usage drains. The batching instruction won't help that.If it's the second, these track it directly: #35226, #32809 ("eats up my limit … compaction loops"), #31351 (~30% of usage consumed), #34095, #32888. It's a long-standing cluster.
(And for the truncation caveat this thread weighed against the batching results: I traced those large truncations to source and filed #35421 — they come almost entirely from the non-batched legacy shell path, not batching.)
🤖
I made a local proof-of-concept patch against Codex main commit
61a44880a85d.The part relevant to this issue adds concrete model-facing guidance and an example for using
Promise.all/Promise.allSettledwhen nested tool calls are already known, independent, and read-only. It explicitly keeps dependent, mutating, approval-sensitive, and adaptive work sequential.The patch also enables buffered execution by default and lengthens several interruptible wait defaults. Those changes are broader and may deserve separate consideration; maintainers may only find the description change useful.
A few important caveats:
Promise.allSettledexec cell could contain two nested shell calls.codex-coresuite was not green in my Windows environment because of missing test helpers, symlink permissions, and related environmental failures, so I am not claiming full-suite validation.Please treat this as an exploratory patch rather than something ready to merge as-is. Feel free to take, rewrite, split, or discard any portion that is useful. I do not need attribution and will not open a PR unless invited.
Patch: https://gist.github.com/PRMS-magnet/5e856fb33f1d293a7d03d37fa3cc2816
Follow-up: stronger
AGENTS.mdwording substantially changed normal-session batchingI ran a longitudinal follow-up in a separate, read-heavy scientific repository. The only model-facing intervention was the repository’s
AGENTS.mdwording. The optional hook was audit-only: it did not block, rewrite, warn, or feed results back to the model.This complements the controlled benchmarks in this issue, but it is not another controlled A/B. Some sessions were resumed or forked while the wording was refined, so I treat the results as normal-usage evidence rather than a causal effect estimate.
Historical behavior
Before adding the stronger batching guidance, historical rollout logs were dominated by one-tool
execcells:| Surface | Root sessions |
execcells | Single-tool cells | Promise cells | Median single-tool rate || --- | ---: | ---: | ---: | ---: | ---: |
| CLI | 6 | 299 | 210 (70.2%) | 83 (27.8%) | 86.1% |
| Desktop | 16 | 33,218 | 31,718 (95.5%) | 1,296 (3.9%) | 96.1% |
The Desktop history is the clearest signal: 95.5% of
execcells contained one tool, while only 3.9% contained an explicit Promise.First instruction
The first version established the mechanism and safety exceptions:
This improved batching, especially during initial discovery, but singleton follow-up calls still reappeared during later reads, diffs, hashes, status checks, and verification.
Hardened instruction
The next revision made batching an explicit decision gate that must be re-applied throughout the turn:
<details>
<summary>Current hardened wording</summary>
</details>
The important additions were:
| Addition | Intended effect |
| --- | --- |
| “Hard pre-call gate” | Force an explicit inventory before each call rather than relying on a general preference. |
| Re-apply after every result | Prevent regression to singleton calls during follow-up and closeout. |
| No direct or one-child call when a sibling is known | Make the failure mode concrete and locally testable. |
| Explicit sequential exceptions | Preserve dependencies, waits, approvals, adaptive investigation, and conflicting mutations. |
| Per-child output bounds | Avoid serializing independent reads merely because their combined output might be large. |
Observed behavior with the hardened wording
| Rollout observation | Shell calls | Calls grouped into multi-call stages | Pure / mixed / non-Promise cells | Direct shell calls |
| --- | ---: | ---: | ---: | ---: |
| First fresh observed stream | 205 | 95.1% | 30 / 12 / 6 | 0 |
| Longer monitored stream | 351 | 92.9% | 60 / 7 / 17 | 6 |
| Companion resumed/fork stream | 74 | 95.9% | 11 / 0 / 1 | 2 |
| Two newest fresh streams combined | 72 | 100.0% | 18 / 0 / 0 | 0 |
The longer streams were not perfect, but the newest fresh sessions issued all 72 shell calls through 18 multi-call Promise stages, with no direct shell calls.
The exact wording and optional audit tooling are available here:
https://github.com/tho-stack/codex-pretool-batching
My main takeaway is that “parallelize when possible” is too abstract. The model responded much more consistently when the instruction defined:
functions.execstage usingPromise.allSettled;This supports the issue’s core conclusion: the runtime can batch effectively, but the default model/tool guidance would benefit from a concrete multi-call example and an explicit pre-call decision rule.
@tho-stack Your framework is a clear improvement in specification quality, so I gave it the controlled test you noted was missing: 3 fresh trials/arm, arm A = the short mechanism-plus-exceptions wording from my earlier comments, arm B = your hardened "hard pre-call gate" wording verbatim, same frozen 48-module repo, gpt-5.6-sol @ xhigh, fresh sessions, alternating order (harness:
setup --agents-a/--agents-b, texts ininstructions/— https://github.com/ForrestGrump/codex-batch-bench).| metric (mean, 3 trials) | short wording | hardened gate | Δ |
|---|---|---|---|
| model cycles | 5.3 | 5.7 | +8% |
| raw tokens | 167k | 194k | +16% |
| output tokens | 6.3k | 8.7k | +37% |
| weighted credits | 11.7 | 14.0 | +20% |
| exec cells with ≥2 calls | 1.3 | 2.7 | better grouping |
| Promise cells / exec cells | 11/13 | 14/14 | slightly better |
| answer grade | 48/48 + 40/40 | 48/48 + 40/40 | equal |
On a short bounded task, the hardened wording does group more consistently — but the gains never convert to savings: the gate discipline shows up as more output tokens (60× the weight of cached input on the rate card) plus an extra cycle, and the 3× longer instruction rides every request. Best hardened trial ≈ worst short-wording trial on credits.
Two caveats that keep your result and mine compatible: (1) my benchmark tasks are short and single-stage — your failure mode (singleton regression during follow-up and closeout of long sessions) is real-usage territory my harness barely probes, and your longitudinal data speaks to exactly that; (2) n=3/arm, ranges overlap.
Synthesis for the description-PR discussion: your items 1–4 (when / what failure looks like / how / when not) look like the right contract structure, but maximum-strength enforcement wording ("hard gate", "habit is not an exception") measurably costs tokens on tasks that were already batching fine. That's the same shape as the effort-curve result upthread — the wording should teach the decision boundary concretely, and stop there. A middle variant (short wording + one sentence extending it to follow-up/closeout, without the gate framing) is the obvious next A/B; happy to run it if useful.
Today an OpenAI employee posted (see below) on X that the 5h limit is returning and that Sol should be 18% more efficient for typical use.
What exactly counts as "typical use"? Is it asking a simple question or renaming a file?
I went back to my original tests I described above and reran them without the batching instructions, in their original state, just like I did last week.
I ran every task without batching instructions twice. So that's 4 tasks × 2 = 8 runs. The average results were:
It's honestly confusing and so far from what OpenAI is claiming.
On X it's "Yay, more efficient!", the Codex pricing page shows more messages for 5.6, and the release post highlights improved token efficiency. Yet my results show the exact opposite.
It seems that four small, scoped analysis tasks in small repositories are not considered "typical use."
<img width="889" height="1323" alt="Image" src="https://github.com/user-attachments/assets/f10c4d30-d5fd-4949-9f5d-1457c3ca080b" />
I'm monitoring your work and today got curious. Are you using CLI or Codex desktop? And, have you applied the latest update (from yesterday 29th) before making the updated tests (those with the claim for 18% improvement). Thanks for your work!
@ID-Yo To be honest, I didn’t run the same tests in the CLI because I use the Codex app about 99% of the time. I obviously can’t claim anything without testing it, but I suspect the CLI may have the same issue, since the root of the problem seems to be the model’s instructions and how it is guided to use batching.
As for the July 29 changes, I saw the model-instruction updates yesterday, so I automatically assumed they were related to the claimed efficiency improvement. I’ll probably run some more tests and make sure to include a CLI run this time.
Thanks for the idea!
@MakerOfToys That would be interesting to see. I myself rarely use the CLI and use mainly the Codex app, although sometimes see some benefits in CLI. I asked you about the because yesterday there was an update of Codex app, but I saw it just today, just before your update. Yesterday, after the reset, I saw no immediate positive effect on the usage, but I haven't made any tests, it is all based on how I feel it. Again, based on how it feels, I see that some accounts seem to perform better that the others, which corresponds with possible A/B testing that is in progress. This gave me an idea for you. It seems like you taking the scientific approach of rigorous testing, comparing apples with apples. If you are interested in this, I would suggest to make some form of software/proxy, something like OpenCodex (fork maybe) or similar, that makes neccessary changes for test A, executes the prompt, makes the measurement and then does test B.... Now as I think about it, part of this (settings, prompts) can be done in the easiest form of automation that is currently present: skills and/or plugins within Codex. The easier it is for others to replicate, the bigger group will be those that apply and test it (I myself included). The bigger group comes to the same conclusion, the bigger chances for update by OpenAI.
@ID-Yo yeah, really great ideas, it's definitely something that should be considered. Actually, I just noticed one thing. Right now it appears that there is a big gap between latest Codex CLI and Codex (now ChatGPT) app.
Version comparison:
CLI (standalone): v0.146.0
CLI (integrated in app): 0.146.0-alpha.3.1
Looking and diff between the two reveals quite some gap of new changes that seem to affect the performance/usage.
Still needs reviewing but this seems promising. So at least in my case newest desktop (Windows) build does not have the newest CLI ver.
@MakerOfToys Here is one more thing to read on the topic, a great article from yesterday. Not sure where they had applied the things mentioned (hey guys from @codex / OpenAI, great article but next time just say where it was applied and when will be available), but they all look promising: https://openai.com/index/gpt-5-6-frontier-intelligence-efficiency/
If GPT-5.6 burns a lot of quota on Code Mode, check whether independent reads are going out one turn at a time. Explicit batching is the user-side control that has been measured.
Method:
AGENTS.md(or the first prompt): when several tool calls are independent, read-only, and known up front, issue them in one turn.AGENTS.mdso later sessions inherit it.Evidence: the reporter measured 27-45% lower weighted usage with explicit batching, and a later comment reproduced the same direction. This is a prompting/method change, not a config flag.
Independent community workaround; not an official OpenAI fix.
@rka-oai Sorry for the direct ping. This seems closely related to #26487, where Responses Lite intentionally disables top-level parallel tool calls.
The discussion here has since narrowed the remaining gap fairly well: Code Mode already supports concurrent nested calls, but the current model-facing
execdescription still only demonstrates a singleawait tools.exec_command(...)call and does not describe thePromise.all/Promise.allSettledreplacement path or its decision boundary. Multiple controlled reproductions in this thread found that explicit, bounded batching materially reduces outer model cycles and repeated cached-context processing atxhigh/max, whilehighand below need a non-regression-sensitive/conditional rule rather than unconditional fan-out.Could you clarify whether this serialization behavior is an intentional Responses Lite tradeoff, already tracked internally, or an unaddressed regression from the transition? A maintainer steer on the intended contract would be very helpful before the community keeps iterating on increasingly strong
AGENTS.mdworkarounds.<head></head><h2 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Independent production trace: 121 Sol calls and ~333.6 credits for one four-turn planning/review cycle</span></h2><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>I have independently investigated this issue from the economics of a real, large-context Codex workflow.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>I think the problem is broader than individual tool-call batching. Codex currently appears to use the selected premium reasoning model for too many phases of the request pipeline, including repeated evidence acquisition and context processing where deterministic processing, batching or a cheaper model could do the same work.</span></p><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Environment</span></h3><ul style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><li><p><span>ChatGPT Pro</span></p></li><li><p><span>Codex Desktop 26.814.41407</span></p></li><li><p><span>macOS / Apple silicon</span></p></li><li><p><span>GPT-5.6 Sol</span></p></li><li><p><span>reasoning effort: High</span></p></li><li><p><span>service tier: Standard/default</span></p></li><li><p><span>analysed session:<span class="Apple-converted-space"> </span></span><code><span>01a018f5-5d19-7bf2-a553-034dca485ed5</span></code></p></li><li><p><span>date: 19 August 2026, Australia/Sydney</span></p></li></ul><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Importantly, this particular trace was<span class="Apple-converted-space"> </span></span><strong><span>not Fast mode</span></strong><span>, so no Fast-mode multiplier is included below.</span></p><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Observed session</span></h3><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>The session contained:</span></p><ul style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><li><p><strong><span>121 Sol model invocations</span></strong></p></li><li><p><strong><span>116 tool calls</span></strong></p></li><li><p><strong><span>15.64M input tokens</span></strong></p><ul><li><p><span>approximately<span class="Apple-converted-space"> </span></span><strong><span>15.00M cached</span></strong></p></li><li><p><span>approximately<span class="Apple-converted-space"> </span></span><strong><span>643k uncached</span></strong></p></li></ul></li><li><p><strong><span>87.6k output tokens</span></strong></p></li><li><p><strong><span>18.3k reasoning tokens</span></strong></p></li><li><p><strong><span>1 context compaction</span></strong></p></li><li><p><strong><span>18 tool outputs larger than 30 KB</span></strong></p></li><li><p><span>approximately<span class="Apple-converted-space"> </span></span><strong><span>1.23 MB of tool output</span></strong></p></li><li><p><span>final model request: approximately<span class="Apple-converted-space"> </span></span><strong><span>200,328 input tokens</span></strong><span>, of which<span class="Apple-converted-space"> </span></span><strong><span>199,424 were cached</span></strong></p></li></ul><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Using the published Sol rate of 125 credits/M uncached input, 12.5/M cached input and 750/M output gives:</span></p><pre style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><code><span>uncached input: 0.643M × 125 = 80.38 credits
cached input: 15.000M × 12.5 = 187.50 credits
output: 0.0876M × 750 = 65.70 credits
------
estimated total 333.58 credits</span></code></pre><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>This is a rate-card reconstruction from local telemetry, not a claim about OpenAI's private billing ledger.</span></p><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Where it occurred</span></h3><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>The four user turns divide unusually clearly:</span></p>
Work | Sol calls | Input tokens | Estimated credits
-- | -- | -- | --
Prepare implementation plan | 54 | 7.08M | ~137.8
Review bootstrap | 13 | 1.14M | ~27.5
Review Claude feedback | 2 | 96k | ~5.0
Update specification from feedback | 52 | 7.32M | ~163.3
Total | 121 | 15.636M | ~333.6
<p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>I am<span class="Apple-converted-space"> </span></span><strong><span>not</span></strong><span><span class="Apple-converted-space"> </span>proposing that the complete task should simply be moved to Luna.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>The point is that the current architecture appears to make model selection at too coarse a granularity.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>A more economical pipeline is:</span></p><pre style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><code><span>deterministic/batched retrieval
↓
bounded evidence packet
↓
Luna: mechanical synthesis / preparation where needed
↓
Terra: routine implementation/reasoning
↓
Sol: bounded load-bearing decision/review
↓
deterministic validation</span></code></pre><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Retaining Sol for the decisions for which Sol was selected, while moving only mechanically reducible work away from it, makes a<span class="Apple-converted-space"> </span></span><strong><span>60–80% reduction in total weighted usage a conservative target</span></strong><span>. The 60% lower bound is available from Terra pricing alone before counting any reduction in repeated context processing.</span></p><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Experimental follow-up</span></h3><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>I subsequently tested the pipeline architecture in an overnight Varro governed trace-validation experiment.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>The experiment deliberately used no OpenAI credits. Deterministic Rust/local processing handled repository facts, graph checks, validation, tests and benchmarking; routine construction used Sonnet 5; expensive Opus 5 review received only bounded evidence packets and was prohibited from browsing the repository.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>The experiment completed within the overnight window.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Its significance here is architectural rather than a Claude-vs-OpenAI price comparison: frontier reasoning did not need to own repository retrieval, repeated tool loops, mechanical validation or every intermediate transformation in order to remain the final high-quality review authority.</span></p><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Compaction exposes the same architectural problem</span></h3><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>There is also a closely related example in context compaction.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Current Codex compaction is model-mediated and inherits the active turn/session model configuration. A user selecting Sol because a task requires frontier reasoning can therefore also spend Sol-class credits summarising the conversation history.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>That is tracked separately in #22486.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Compaction may require semantic summarisation, but it does not follow that it should automatically inherit the most expensive active reasoning route. Deterministic extraction + cheaper synthesis + validation + fallback would provide a safer economic architecture.</span></p><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>What I think should change</span></h3><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>I suggest treating model invocation itself as a scarce resource and planning the request pipeline before execution.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>In particular:</span></p><ol start="1" style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><li><p><span>Batch independent repository and tool reads before returning to the model.</span></p></li><li><p><span>Do not invoke a frontier model merely to decide to perform the next mechanical operation.</span></p></li><li><p><span>Produce bounded evidence packets at model boundaries rather than repeatedly feeding accumulated repository history back into Sol.</span></p></li><li><p><span>Support phase-specific model selection for retrieval/synthesis, implementation, review and compaction.</span></p></li><li><p><span>Make compaction model and reasoning effort independently configurable.</span></p></li><li><p><span>Prefer deterministic code for mechanically derivable validation and state extraction.</span></p></li><li><p><span>Expose per-phase credit telemetry:</span></p><ul><li><p><span>model/reasoning;</span></p></li><li><p><span>evidence acquisition;</span></p></li><li><p><span>cached-context processing;</span></p></li><li><p><span>tool coordination;</span></p></li><li><p><span>waiting/polling;</span></p></li><li><p><span>compaction;</span></p></li><li><p><span>retries;</span></p></li><li><p><span>subagents.</span></p></li></ul></li><li><p><span>Add weighted-credit regression tests for representative long-context workflows, rather than optimising only model-output quality.</span></p></li></ol><h3 style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Why this matters now</span></h3><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>Under per-token charging this is no longer merely an implementation efficiency issue.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>The orchestration strategy is directly visible to the customer as cost.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>A model/tool pipeline which is 2–5× less efficient than necessary can turn a technically successful Codex workflow into an economically unusable one without improving the final answer.</span></p><p style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-line: none; text-decoration-thickness: auto; text-decoration-style: solid;"><span>I am happy to provide the sanitised rollout telemetry and analysis methodology for session<span class="Apple-converted-space"> </span></span><code><span>01a018f5-5d19-7bf2-a553-034dca485ed5</span></code><span>.</span></p>
Cross-client validation: client-level batching (OpenCode) ≈ 3.3× lower credits per tool call, same account, no prompt changes
---
The controlled results in this thread show explicit batching instructions reduce weighted usage 27–45%. I can add a complementary data point from the opposite direction: instead of instructing the model to batch, I compared Codex against OpenCode, a third-party agent client that enforces batching at the client level, on the same ChatGPT Pro account and the same GPT-5.6 Sol model. The gap is consistent with this thread's findings and isolates the mechanism further.
All numbers are aggregate metadata from local logs (Codex session rollouts vs OpenCode's local DB): event types, timestamps, token counts. No prompt content, no account identifiers. Credit weighting uses the published rate card (125 / 12.5 / 750 credits per M uncached-input / cached-input / output; reasoning counted inside output).
---
Setup
| | Codex App/CLI | OpenCode |
|---|---|---|
| Auth / plan | ChatGPT Pro (same account) | ChatGPT Pro (same account) |
| Model | gpt-5.6-sol | gpt-5.6-sol (its "-fast" catalog alias; server bills standard) |
| Reasoning effort | mostly low/high | max (biases against OpenCode) |
| Window | 7 days of real mixed work (7,792 own API requests) | 3 days of read-heavy agent work (5,732 requests) |
| Data hygiene | multi-agent mirror
token_countevents excluded (~68% were sibling duplicates) | subagent sessions included |Workloads are real usage, not controlled pairs — treat ratios as indicative, not exact. The reasoning-effort asymmetry (low vs max) makes the comparison conservative: OpenCode should be more expensive per request, and isn't.
---
Headline
| Metric | Codex | OpenCode | Ratio |
|---|--:|--:|--:|
| Tool calls per request (mean) | 0.81 | 2.72 | 3.4× |
| Max tool calls observed in one request | 1 (n=7,792) | 13 | — |
| Requests per tool call | 1.23 | 0.37 | 3.3× |
| Credits per tool call | ~2.4 | ~0.7 | ~3.3× |
| Credits per round trip | 1.96 | ~1.9–2.0 | ≈1× |
| Requests per user message (median) | 8 | 8–9 | ≈1× |
The last two rows are the point: a round trip costs ~2 credits in both clients, and both make a similar number of round trips per user interaction. The only difference is how much work each round trip carries. Codex never carried more than one tool call per request in 7,792 requests; 85.9% of its requests were auto-continuations fired immediately after a single tool output. OpenCode reasons once, emits up to 13 independent calls, executes them concurrently (97% measured wall-clock overlap), waits for all results, then makes one round trip.
---
Where the credits actually go (decomposition)
Codex, 201 Sol threads (~12.3k credits):
| Bucket | Share |
|---|--:|
| Cached-prefix re-reads on later requests | 65.4% |
| Later uncached input (appends + cache breaks + compaction) | 20.0% |
| Output (incl. reasoning) | 12.1% |
| First-request overhead (system prompt + tools + AGENTS.md) | 0.5% (fresh) + 1.9% (subagent spawns) |
OpenCode, 427 sessions (~11k credits): cache re-reads 44.1%, uncached appends 35.9%, output 15.9%, first-step overhead 4.1%.
This rules out the popular alternative explanations:
maxadded only ~5% of its total spend in reasoning tokens. I can afford Sol-max there while being pushed to Sol-low in Codex — the difference is round-trip count, not thinking.What remains is arithmetic: with a ~90k-token median context (p90 178k), every extra round trip costs ~1.2 credits in cache re-reads plus fresh output before any new work happens. One-call-per-request multiplies exactly that. Serialization also compounds: it inflates transcript length, which inflates context for all subsequent trips (heaviest observed thread: 1,010 requests for 22 user messages, 140.6M cached tokens re-read, ~2.2k credits).
---
Two secondary findings from the same data
---
Alignment with this thread
AGENTS.md— the model doesn't "forget" to batch (cf. the ~1,600 batchable vs ~100 batched observation above).gpt-5.6-sol/terra/luna) is flaggeduse_responses_liteinmodels-manager/models.json, andcore/src/client.rsforcesparallel_tool_calls: prompt.parallel_tool_calls && !model_info.use_responses_lite— i.e. always false for these models, over both HTTPS and theresponses_websockets=2026-02-06transport. Notably, OpenCode talks to the same model and backend endpoint over plain HTTPS Responses (its own WS transport is env-gated off by default in the tested build) without the lite profile, and there the model emits up to 13 tool calls in one response — the batching capability exists server-side; the lite client policy suppresses it. The coupling is as old as the profile itself — #26487 introduceduse_responses_lite, the parallel-tools override, and forced persistent reasoning (reasoning.context: all_turns) in the same change, and #27946 notes tool namespacing was waiting on "coordination & fixes in Responses API (around collisions & return items)" — suggesting single-call-per-turn is a lite-contract limitation, not a model limitation. Theexectool description showing only single-call examples (this issue) compounds it.execdescription with aPromise.all/allSettledexample and decision boundary, and treat the "wait for all results, then one round trip" barrier as the default loop discipline rather than an opt-in prompt hack.---
Caveats
service_tier: "priority"but is serviced standard (originator-gated, and sent over HTTPS where priority routing reportedly doesn't engage anyway), so both sides were billed at standard Sol rates — verified via alternating throughput benchmarks (~54 tok/s both).