sysnote
News

Codex Desktop forks pay full price for their history: 13 extra tools break the prompt cache, a bug report shows

Forking a long Codex thread is supposed to be cheap: the fork shares the parent's history, so its first request should hit the prompt cache and only pay full rate for the new message. A detailed bug report filed on November 6 says that in the Codex desktop app it doesn't work that way. The fork is sent 13 tool definitions the parent never had, and because tool definitions sit at the very start of the prompt, the entire inherited history misses the cache.

The report, openai/codex #59977 by GitHub user Gor4 (Codex App 26.1103.31037, ChatGPT Pro), is unusually well measured. OpenAI hasn't responded to it yet, so treat what follows as a reproduced user finding, not a confirmed bug.

What the fork gets that the parent doesn't

Gor4 captured parent and fork requests with a local logging proxy. Normally started threads carried 285 tools; every fork carried 298. Everything else in the fork's first request (system instructions, reasoning items, web-search results, messages) matched the parent up to the fork point. The extra 13 are all situational app tools:

  • from codex_app: complete_conversational_onboarding_task, complete_sidebar_onboarding_checklist_task, request_onboarding_input, request_option_picker, setup_codex_step, fire_confetti, transfer_voice_call, consume_usage_reset, request_environment_input, finalize_environment;
  • from the Pages connector: create_presentation, execute_artifact_code, inspect_artifact.

In other words, onboarding, confetti, voice-call handoff, cloud environment setup and a usage-reset tool, none of which a forked coding thread needs. A normal thread start apparently filters them out; the fork path apparently doesn't.

The numbers from the report:

Test Parent tools Fork tools Fork's first request: input / cached / written
A. Agent thread with web search and a sub-agent, fork on same model 285 298 187,887 / 0 / 180,558
C. Control: fork of a thread that already had 298 tools 298 298 212,135 / 206,668 (97%) / 1,231
D. Real use: fork of a ~770K-token user thread not logged 298 773,289 / 190,522 / 573,580

The control is what makes the case: when parent and fork have the same tool list, forking keeps 97% of the prompt cached. The partial cache hit in test D came from an earlier fork with the same 298 tools, never from the parent's own history.

One caveat matters. Gor4's model provider is a custom Responses-compatible endpoint serving Claude models, so the cache figures come from that provider, not from OpenAI's backend. The tool list, though, is assembled by the Codex app before any provider sees it, and prefix caching on any backend breaks the same way when the first bytes of the prompt change.

Where the code points

A second contributor, r266-tech, tried to find the mechanism in the open-source Codex code. With codex-cli 0.167.0 and two synthetic MCP servers, they showed that a tool filter passed through thread/start.config (mcp_servers.<name>.disabled_tools) is not carried into an ordinary thread/fork: the parent saw 2 fixture tools, the fork 15. Passing the same filter to the fork, or putting it in config.toml, made the lists match.

We checked the fork handler they cite. In thread_processor.rs at commit 086ccc8, unless the experimental prediction mode is on, the fork builds its config with load_for_cwd(request_overrides, typesafe_overrides, history_cwd), the overrides of the fork request itself, under a comment that says it derives the config "using the same logic as new conversation". Copying the parent's full effective options happens only on the experimental_prediction_mode path a few hundred lines earlier.

That is a plausible mechanism, not a proven one: r266-tech is explicit that they haven't shown the desktop app passes its tool filters that way, and the desktop app itself isn't open source. Gor4 also confirmed that the 13 tools are MCP tools (mcp__codex_app__*), not the dynamicTools the CLI restores from history.

What it costs

OpenAI doesn't publish how included subscription usage converts into tokens, so there is no exact answer for a Plus or Pro allowance. The Codex rate card does give the ratio that matters: on GPT-6.1 Sol, cached input costs 2.5 credits per million tokens against 50 for uncached input, a 20× gap, and the same page lists caching among the things that affect usage.

So, as our own illustration: test D's request, priced at GPT-6.1 Sol credit rates, comes to roughly 29.6 credits with 190,522 tokens cached. With 97% of the prompt cached, as in the control, it would be about 3 credits. That is about ten times more for a one-line follow-up in a fork, before the model writes a single output token. The comparison is approximate (Codex credit billing has no separate cache-write charge, and the measurements came from a different provider), but the order of magnitude follows directly from the rate card.

Not the whole weekend story

The report has been passed around on X this weekend as an explanation for Codex five-hour and weekly limits "draining so fast". It doesn't show that. It affects forks, and the worst cases need long threads. People who never fork won't hit it.

It also isn't the first cache problem with Codex forks. openai/codex #24704, open since May 27, describes forked subagents getting their own prompt_cache_key and so losing the parent's cache lineage on OpenAI's backend. Gor4 notes that the tool-list problem would break caching even with a matching key, so on OpenAI's backend the two compound.

This gets more expensive in December, when ChatGPT and Codex move to one shared, token-based allowance. Until there's a fix, the reporter's workaround is the obvious one: don't fork long threads; start a new thread with a summary instead.

Comments

No comments yet. Be the first.

Write a comment

Comments are published after review.