Multi-agent V2 full-history forks duplicate historical compaction snapshots and inline images, causing >100 GiB session storage growth
What issue are you seeing?
A long-running Codex Desktop conversation using Ultra reasoning and multi-agent V2 produced approximately 110 GiB of local session data under $CODEX_HOME/sessions.
The growth appears multiplicative rather than being caused by subagents producing unusually large outputs:
- Context compaction persists
Compactedrollout records containing a completereplacement_history. - These replacement histories can contain inline base64-encoded screenshots.
- Older compaction records remain in the append-only parent rollout.
- A full-history subagent fork loads the parent’s persisted rollout items.
- Those inherited items—including all historical compaction snapshots—are serialized into the child rollout.
- Ultra reasoning proactively creates many subagents, multiplying the retained history across many files.
Observed impact from one session tree:
| Measurement | Result |
|---|---:|
| Total rollout files | 300 |
| Total reported size | approximately 110.09 GiB |
| Subagent rollout files | 294 |
| Size attributed to subagent rollouts | approximately 106.56 GiB |
| Files sharing the same root session ID | 295 |
| Files at least 1 GB | 51 |
| Files at least 500 MB | 86 |
| Files at least 100 MB | 155 |
Of those files, 159 were recorded by 0.145.0-alpha.18 with multi_agent_version: "v2" and accounted for approximately 88.18 GiB.
Many individual subagent rollouts were between 1.3 GB and 1.9 GB.
A representative completed child rollout was 1,706,557,797 bytes and contained 23,564 JSONL records. Its composition was:
- 141
compactedrecords - Approximately 1.55 GiB in
compactedrecords - 97.6% of the entire file attributable to
compactedrecords - 125 individual JSONL records larger than 10 MB
- Largest JSONL record approximately 12.93 MiB
One inspected replacement_history contained:
- 118 history items
- 19
input_imageentries - 13,316,621 characters of inline
data:image/png;base64,...data - Approximately 197,716 characters of input text
The child files are not small records that merely reference their parent. A representative child begins with its own session_meta, followed by a copy of the parent’s original session_meta and inherited parent events. Sampled parent payloads were identical, while outer timestamps were rewritten to the child creation time and some response items received new IDs.
The files have separate inodes and link counts of 1, and their allocated sizes are close to their logical sizes. This appears to be independently serialized history rather than sparse files or parent references.
This can consume enough storage to exhaust a local disk during a single long-running Ultra session.
What steps can reproduce the bug?
The severity depends on having a sufficiently large parent history, multiple compactions, inline images, and multiple full-history forks.
- Start a persisted local Codex thread using Codex Desktop or another local surface backed by the shared Codex runtime.
- Use the same thread for an extended period.
- Add several screenshots or other image inputs to the conversation.
- Continue the conversation long enough to trigger multiple context compactions.
- Select Ultra reasoning with multi-agent V2 enabled.
- Give Codex work that causes it to proactively spawn multiple subagents.
- Allow the generated
spawn_agentcalls to omitfork_turns. In multi-agent V2, the omitted value defaults to"all". - Inspect the newly created child rollouts under
$CODEX_HOME/sessions. - Compare their sizes and initial JSONL records with the parent rollout.
- Repeat with additional subagents and observe that each full-history child can approach the persisted historical size of the parent before doing significant child-specific work.
Example read-only inspection commands:
du -sh "$CODEX_HOME/sessions"
find "$CODEX_HOME/sessions" -type f -name '*.jsonl' -print0 \
| xargs -0 stat -f '%z %N' \
| sort -nr \
| head -50
For a suspected child file:
head -n 1 "$CHILD_ROLLOUT" \
| jq '.payload | {
id,
session_id,
thread_source,
forked_from_id,
parent_thread_id,
multi_agent_version,
source
}'
The child metadata should identify it as a subagent and point to the parent through parent_thread_id and/or forked_from_id.
Inspecting the first several records should show the child’s new session_meta followed by inherited parent rollout records.
The problem becomes increasingly visible as these factors increase:
- Number of retained compaction records
- Number and size of inline images
- Length of the parent thread
- Number of spawned subagents
- Use of full-history/default
fork_turns="all"behavior
What is the expected behavior?
Spawning subagents should not cause local persisted session storage to grow in proportion to the parent’s complete append-only rollout history for every child, particularly when the history contains multiple historical compaction snapshots representing earlier versions of substantially the same model context.
A newly spawned child should not routinely approach 1–2 GB before performing meaningful child-specific work.
Disk growth should remain bounded enough that proactive multi-agent behavior cannot unexpectedly create more than 100 GiB of local session data from one conversation tree.
This expectation applies regardless of whether the triggering surface is Codex Desktop, the CLI, or codex exec, since the relevant multi-agent and rollout-persistence behavior appears to be shared.
Additional information
Environment and metadata from the affected session:
- Platform: macOS
- Surface: Codex Desktop
- Reasoning mode: Ultra
- Root metadata:
originator: "Codex Desktop"source: "vscode"history_mode: "legacy"- Child metadata:
thread_source: "subagent"multi_agent_version: "v2"- Codex versions present:
0.144.20.144.50.145.0-alpha.18
Relevant source locations:
codex-rs/core/src/session/multi_agents.rseffective_multi_agent_modemaps Ultra reasoning to proactive multi-agent behavior.- The behavior applies to
SessionSource::Cli,SessionSource::VSCode,SessionSource::Exec, and other sources.
codex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rsSpawnAgentArgs::fork_modedefaults omitted or emptyfork_turnsto"all"."all"becomesSpawnAgentForkMode::FullHistory.
codex-rs/core/src/agent/control/spawn.rsAgentControl::spawn_forked_threadflushes the parent and reads the stored thread withinclude_history: true.- It uses
parent_history.itemsas the forked rollout items. - The fork filter retains
RolloutItem::Compacted. - The inspected
Compactedrecords contain almost all of the affected bytes.
codex-rs/core/src/session/mod.rs- The
InitialHistory::Forkedbranch inrecord_initial_historypersists the inherited rollout items. - The code comment says:
If persisting, persist all rollout items as-is (the store filters).
codex-rs/core/src/compact.rs- Compaction creates a
CompactedItemwithreplacement_history: Some(new_history.clone()).
codex-rs/core/src/session/mod.rsreplace_compacted_historyalso persists aCompactedItemcontaining a cloned replacement history.
codex-rs/rollout/src/recorder.rsJsonlWriter::write_rollout_itemassigns a new timestamp, serializes the item withserde_json::to_string, and writes it to the child JSONL.
codex-rs/app-server/README.mdthread/forkis documented as creating a new thread by copying stored history.
Questions that may help confirm whether the observed persistence is intentional:
- Is a subagent fork expected to persist every historical
Compactedrecord from the source rollout? - Is each earlier
replacement_historyexpected to remain independently serialized after later compactions supersede it? - Is inline base64 image data expected to be repeated across every compaction snapshot and every full-history child fork?
- Is there an intended upper bound for inherited persisted bytes when spawning a subagent?
- Should proactive Ultra subagents have the same persistence behavior as an explicit user-created full thread fork?
I can provide additional sanitized structural evidence if needed, including record-size distributions, parent/child metadata relationships, payload hash comparisons, compaction counts, and encoded image lengths.
I cannot attach the complete affected rollouts because they are individually up to approximately 1.9 GB and contain private conversation and image data.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗