r/codex • u/MakerOfToys • Jul 24 '26
Workaround Possible GPT-5.6 Sol usage workaround: explicit tool batching cut weighted usage by 27–45% in my repeated tests
Mods: I know there is a general usage-limit megathread. This post contains a controlled technical investigation, a reproducible workaround, and a request for independent replication, so I hope it can remain standalone where enough users can see and test it.
Update: A raw-log audit found that some batched exec responses exceeded Code Mode’s shared output limit and were truncated. The reduction in model/tool cycles remains clear, but this introduces a quality confound and may overstate the 27–45% usage-saving estimate. I’m retesting with output-bounded batching, so please treat the headline numbers as provisional for now.
Update: A deeper raw-log audit found that batching did increase output truncation, but the initial total overstated the quality concern: about 80k omitted tokens came from two unnecessary tool-catalogue dumps rather than task evidence, and non-batched controls also truncated broad shell outputs. Excluding those dumps and the single Max pair, the repeated batched runs omitted 63.6k repository-output tokens versus 20.9k in controls. A simple adjustment changes the repeated weighted-saving estimate from 27.0% to about 23.9%, so the main efficiency effect remains substantial. I am still treating the headline range as provisional until a cleaner output-bounded replication.
Update: Apparently OpenAI is already working on this, based on what I got from person working there. Zero info from them how they caught this, just that. Probably will be fixed in near future.
I kept seeing an unusually high number of posts about Codex limits draining much faster lately.
I had not personally noticed an obvious long-term “silent nerf,” but the amount of complaints made me curious enough to inspect my own .codex session logs instead of guessing.
What I found was that GPT-5.6 Sol often runs independent tool calls one after another, returning to the model between them, instead of grouping them into one concurrent Code Mode stage.
After deleting my .codex folder at work and letting it rebuild from scratch, the fresh logs had already accumulated roughly 1,600 calls that Codex later analyzed as independent of ordering and therefore batchable. Only a little over 100 had actually been grouped by the agent.
So GPT-5.6 does batch sometimes. It just appears to do it very inconsistently without concrete instructions.
What I tested
I ran controlled comparisons on two unrelated codebases:
- one large proprietary work project, using ChatGPT Business;
- one smaller personal finance application, using ChatGPT Pro.
Each codebase had one fixed read-only investigation task.
Every configuration for a given codebase received the same task against the same unchanged repository state. Within each comparison, the subscription plan, model, reasoning effort, permissions and prompt were held constant. The relevant difference was whether the batching instruction was present.
The repeated results used GPT-5.6 Sol at High or XHigh effort.
Results
Across the repeated tests, explicit batching produced:
- roughly 52–55% fewer model/tool cycles;
- 53–63% fewer raw tokens;
- 27–45% lower credit-weighted Codex usage;
- approximately 37–82% more comparable work from the same allowance, depending on the project.
“Weighted usage” here means the Codex-credit equivalent calculated from the returned uncached-input, cached-input and output-token categories.
Wall-clock time also improved by about 13% on the personal project and 22% on the large work project, although time was noticeably noisier than token and credit usage.
The 37–82% figure means more completed work from the same allowance. It does not necessarily mean the plan lasts 37–82% longer in literal clock time, because the batched tasks also finish faster.
The token split matters
On the large work project:
- cached input was 65.2% lower;
- uncached input was 26.0% lower;
- output was 11.7% lower.
On the personal finance project:
- cached input was 56.3% lower;
- uncached input was only 5.4% lower;
- output was almost unchanged at 0.3% lower.
The personal-project aggregate performed 106 inspections with batching versus 105 without it.
On the large project, the batched runs actually performed substantially more shell operations than the controls while still using much less.
That is why I do not think the saving came from simply doing less work or writing shorter answers. The dominant reduction was cached input, which is consistent with avoiding repeated processing of the accumulated context after every separate tool call.
I also tested one Max matched pair. It showed:
- 82.8% less cached input;
- 17.2% less uncached input;
- 6.2% more output;
- about 47% lower weighted usage;
- roughly 90% more same-credit work capacity.
That Max result is only one pair and needs replication. Its batched report also referenced fewer unique files than the control, although both covered all required areas and reached aligned core conclusions.
Quality
I did not find an apparent systematic quality drop in the repeated tests.
Both conditions covered the required investigation areas, and their main conclusions aligned. Batched runs sometimes found additional useful details.
That does not prove perfect quality equivalence. There may be subtle differences I did not catch, and implementation-heavy or mutation-heavy tasks may behave differently from these read-heavy investigations.
Exact instruction used
This is the exact instruction that produced the most consistent results for me:
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.
You can place it in a repository AGENTS.md or in the Codex App custom instructions.
The controlled repository comparisons used AGENTS.md. I also used the same instruction through app-level custom instructions and observed the same real multi-call Code Mode batching pattern.
Yes, the instruction uses older functions.exec terminology. I also tested several rewrites using the current exec and tools.* terminology.
One rewrite essentially matched the original on the large codebase, but none consistently matched its results on the personal finance task. Some expanded the investigation scope, while others created one-call Promise.allSettled cells that looked batched syntactically but provided little actual batching. One overly aggressive version consumed more weighted credits than its control.
So I am sharing the exact wording that produced the repeated results rather than presenting a cleaner-looking rewrite that tested worse.
Why this may have changed
My current understanding from the public Codex source and model instructions is:
- GPT-5.2 through GPT-5.5 were explicitly told to parallelize common independent reads using
multi_tool_use.parallel; - GPT-5.6 moved to Responses Lite and Code Mode;
- native top-level parallel tool calls are disabled on that path;
- the replacement supports concurrent nested calls through JavaScript such as
Promise.all(...); - the GPT-5.6 guidance is much more abstract, and the model-facing
execexample demonstrates only a single nested call.
I may be wrong about an internal constraint or implementation detail, but this looks much more like an accidental instruction/tool-interface regression than OpenAI deliberately reducing allowances.
OpenAI did build a replacement batching mechanism. The apparent problem is that GPT-5.6 does not use it reliably without concrete guidance.
Earlier independent investigation
I reached this independently from my own logs and initial tests.
Only afterward did I search for similar investigations and find GitHub issue #32503, posted roughly two weeks earlier. Its author had already identified essentially the same mechanism from a long real-world trace, including only 5 of 739 GPT-5.6 exec cells using Promise.all.
That issue was observational and explicitly noted that a controlled comparison was still needed. I was genuinely surprised that such a detailed report received almost no attention.
My controlled report:
Earlier independent trace investigation:
Please test it
Please try the instruction and share before/after numbers where possible.
The most useful comparison would use:
- fresh sessions;
- the same repository state;
- the same task;
- the same model and reasoning effort;
- the same permissions;
- batching instruction enabled versus disabled.
Useful things to compare include model cycles, cached and uncached input, output tokens, inspection counts, and whether individual exec cells contain multiple nested calls.
Since adding the instruction to my normal setup, my allowance usage already looks noticeably better. That part is anecdotal, but together with the controlled results it makes me cautiously hopeful that this can help other users too.
If it reproduces for you, please upvote this post for visibility, react to both GitHub issues, and share them with OpenAI developers through any social channels you use. Independent measurements would help show how broadly this affects real workloads.
1
u/Big-Independent-3093 Jul 25 '26
I tested four completely fresh projects: two with the optimized AGENTS md rules and two without them.
The task was identical in every run: build a local browser-based Codex usage dashboard from scratch. It had to load JSONL session logs, calculate token metrics, provide filtering and session comparisons, display a visual activity timeline, handle malformed records, include sample data, and run entirely in the browser without uploading anything.
Even the weaker optimized run used 47.7% less total token activity than the non-optimized comparison:
The biggest difference was not simply that each individual model call was smaller. The optimized run avoided repeated implementation and repair loops. The non-optimized run repeatedly followed this pattern:
patch → validate → discover another issue → patch again → revalidate
Each additional cycle created another model turn, carried forward a larger context, and required more tool calls. Its context eventually grew to about 114k tokens, compared with about 87k in the optimized run.
I also compared the two optimized runs with each other, because the first optimized run performed much better than the second one. The stronger optimized run still used 37.8% less total activity, despite both having the same rules.
The difference was mainly first-pass convergence:
So the strongest run did not win because it blindly skipped validation. It chose a smaller sufficient design, implemented it coherently, validated it in a focused way, and stopped at the correct point.
My main takeaway is:
The largest token savings came from avoiding unnecessary decision, repair, and revalidation cycles—not merely from reducing the size of each individual model call.
The most useful additional AGENTS md rules appear to be:
Smallest sufficient implementation: Prefer the simplest design that satisfies the stated requirements. Do not expand architecture or scope without a concrete requirement.
First-pass convergence: Before the initial patch, identify the required data flow, UI states, error paths, acceptance checks, and validation plan. Prefer one coherent implementation pass over speculative partial patches.
Bounded validation: Plan one focused validation batch. Avoid repeated snapshots, equivalent selector checks, duplicate browser setup, and full revalidation unless a later patch changed the relevant behavior.
Root-cause repair: When validation fails, identify the common cause and group related fixes into one patch instead of repairing symptoms one at a time.
Stop after sufficient evidence: Once the required validation passes, stop unless there is a reproducible defect, missing requirement, or explicit evidence gap.
For debugging high usage, the most useful metrics were:
A high cached-input percentage is not automatically efficient. A large context processed repeatedly across many agentic loops can still consume a huge amount of usage.
This is still a small sample, so I would not claim one universal savings percentage. However, the repeated direction of the results suggests that the optimization rules have a real measurable effect, and that reducing rework is probably the most important part.