Insane Codex Disk Usage from Subagents

Open 💬 22 comments Opened Jul 18, 2026 by jezell
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

0.144.6

What subscription do you have?

Pro

Which model were you using?

gpt-5.6

What platform is your computer?

macos

What terminal emulator and version are you using (if applicable)?

_No response_

Codex doctor report

What issue are you seeing?

Subagents are eating my hard drive alive with session logs

What steps can reproduce the bug?

Codex CLI subagent session logs consumed ~755 GiB and nearly exhausted a 1.8 TiB disk

Summary

Codex CLI persisted approximately 755 GiB of JSONL session data under $HOME/.codex/sessions. Approximately 731.5 GiB of the logical file size is attributable to 2,393 subagent session files spawned from a single resumed parent thread.

The problem is not primarily one malformed or unusually large JSON record. Representative sessions show either extremely high event volume or repeated retention of large compaction/tool-output records:

  • One child session ran for 3 minutes 19 seconds and wrote 483,714,063 bytes across 353,255 valid JSONL records—approximately 2.31 MiB/sec and 1,770 records/sec.
  • Another session grew to 925,599,939 bytes; in that file, 175 compacted records accounted for 571,600,883 bytes and 27,848 custom_tool_call_output records accounted for 211,681,025 bytes.
  • July contained approximately 2,931 session files, including 797 files larger than 400 MiB.

This nearly exhausted the system's APFS Data volume. During diagnosis, df reported only 10–32 GiB available and 99–100% capacity used.

Severity and impact

Suggested severity: Critical / P1 for affected users

  • The Codex session store grew to approximately 760 GiB total, with session JSONL files accounting for approximately 755 GiB.
  • The user's entire home directory occupied approximately 1.46 TiB; Codex session data alone accounted for roughly half of it.
  • The 1.8 TiB Data volume reached 99–100% reported capacity.
  • Continued logging risks failed builds, corrupted application state, OS instability, and data loss due to complete disk exhaustion.
  • The affected processes were still actively holding session JSONL files open during diagnosis.
  • Removing these files would likely make historical sessions unavailable to codex resume, so cleanup has a product-data-loss cost even though the files are not project source files.

Environment

Captured on 2026-07-18 in the America/Los_Angeles timezone.

| Component | Value |
|---|---|
| Current Codex CLI | codex-cli 0.144.6 |
| Versions recorded in affected July session metadata | 0.142.4 through 0.144.6 |
| Primary affected versions by file count | 0.144.1 (1,138), 0.144.4 (819), 0.144.5 (461) |
| Originator | Mostly codex-tui (2,870 files); codex_exec (62 files) |
| OS | macOS 15.5 (24F74) |
| Architecture | arm64 |
| Node.js | v26.0.0 |
| Filesystem | APFS Data volume, 1.8 TiB |
| Working directory in representative session metadata | $HOME/office |
| History mode in representative session metadata | legacy |
| Explicit history/session persistence config | None found in $HOME/.codex/config.toml |

Observed behavior

Disk usage

760G  $HOME/.codex
755G  $HOME/.codex/sessions
734G  $HOME/.codex/sessions/2026/07

July's growth accelerated sharply:

| Date (2026) | Session files | Files >400 MiB | Allocated size (approx.) |
|---|---:|---:|---:|
| Jul 10 | 50 | 0 | 2.8 GiB |
| Jul 11 | 473 | 0 | 109.1 GiB |
| Jul 12 | 506 | 0 | 149.2 GiB |
| Jul 13 | 291 | 1 | 50.6 GiB |
| Jul 14 | 313 | 4 | 88.4 GiB |
| Jul 15 | 340 | 265 | 108.6 GiB |
| Jul 16 | 355 | 263 | 109.0 GiB |
| Jul 17 | 300 | 189 | 81.7 GiB |
| Jul 18, partial day | 137+ | 75+ | 33.5+ GiB |

Counts for the partial day continued increasing during diagnosis.

Single-parent concentration

Parsing only the first session_meta record from each July file showed:

source: subagent
parent_thread_id: 019ee8d1-94c0-7090-a65a-faeeab8c626d
child session files: 2,393
combined logical size: 785,467,490,368 bytes (~731.5 GiB)

The parent was actively running as a resumed Codex TUI session:

codex resume 019ee8d1-94c0-7090-a65a-faeeab8c626d

At capture time, that resumed process had been running for approximately 23 hours. Another codex resume process had been running for approximately 22 hours and held open a separate 6.9 GiB session file.

Representative high-event-volume child session

Representative child session metadata:

session id: 019f76a8-32b1-77e3-854c-4fb405a58155
parent thread id: 019ee8d1-94c0-7090-a65a-faeeab8c626d
source: subagent/thread_spawn
depth: 1
originator: codex-tui
CLI version: 0.144.5
history mode: legacy
started: 2026-07-18T19:16:06.710Z
last record: 2026-07-18T19:19:26.008Z
duration represented: ~199.3 seconds
file size: 483,714,063 bytes
records: 353,255
JSON parse errors: 0

Largest record categories by aggregate bytes:

| JSONL record category | Record count | Aggregate bytes | Largest record |
|---|---:|---:|---:|
| event_msg/token_count | 185,461 | 139,268,416 | 815 |
| compacted | 1,618 | 121,571,279 | 105,608 |
| event_msg/patch_apply_end | 36,295 | 110,668,600 | 521,129 |
| event_msg/agent_message | 104,653 | 41,623,387 | 2,780 |
| response_item/message | 9,947 | 34,412,319 | 34,584 |
| world_state | 607 | 18,638,285 | 34,723 |
| turn_context | 5,322 | 11,032,351 | 2,915 |
| event_msg/task_complete | 3,682 | 4,879,881 | 2,870 |
| event_msg/task_started | 3,718 | 866,294 | 233 |

This implies severe event amplification. The file does not depend on a single giant line; many categories are being emitted thousands to hundreds of thousands of times during a short-lived subagent task.

Representative large-payload session

A second file, 925,599,939 bytes, showed a different but related persistence pattern:

| JSONL record category | Record count | Aggregate bytes | Largest record |
|---|---:|---:|---:|
| compacted | 175 | 571,600,883 | 5,986,172 |
| response_item/custom_tool_call_output | 27,848 | 211,681,025 | 5,586,220 |
| response_item/reasoning | 27,400 | 50,952,588 | 5,164 |
| response_item/custom_tool_call | 27,841 | 31,213,363 | 35,226 |
| event_msg/token_count | 31,379 | 22,580,057 | 755 |
| event_msg/patch_apply_end | 5,137 | 14,546,399 | 33,282 |

This suggests that both event frequency and repeated retention of large compacted/tool-output payloads contribute to growth.

Expected behavior

  • Session persistence should remain bounded relative to actual user-visible conversation and tool activity.
  • A subagent lasting about three minutes should not persist hundreds of megabytes or hundreds of thousands of events under normal use.
  • Repeated subagent spawning should not replicate parent state, compaction payloads, tool outputs, or event streams into every child log without bounds.
  • Codex should protect the host from disk exhaustion through quotas, rotation, deduplication, compression, backpressure, or a clear warning before storage becomes critical.
  • codex resume should not allow a long-running thread to generate hundreds of gigabytes of local history silently.

Actual behavior

  • A single resumed parent thread produced 2,393 child JSONL logs totaling approximately 731.5 GiB.
  • Hundreds of child session files were created per day.
  • Many individual child sessions grew to approximately 400–500 MiB within minutes.
  • At least one historical session file reached 6.9 GiB and remained open for writing by a resumed Codex process.
  • No storage warning, retention limit, or automatic pruning was observed before the Data volume reached 99–100% capacity.

Reproduction / observed workflow

This is an observed reproduction rather than a minimal deterministic reproducer:

  1. Start Codex TUI in a local project.
  2. Work in a thread that uses collaboration/subagent spawning.
  3. Resume the long-running parent thread with codex resume <thread-id>.
  4. Allow the resumed process to run for many hours and continue spawning depth-1 subagents.
  5. Monitor $HOME/.codex/sessions/YYYY/MM/DD.
  6. Observe hundreds of new child JSONL files per day, many hundreds of MiB each.
  7. Aggregate session_meta.source.subagent.thread_spawn.parent_thread_id; most affected files resolve to the same parent.

The exact prompt/task content has intentionally not been included. The issue is visible from metadata, event counts, byte counts, and process/file-handle information alone.

Suspected failure modes

These are hypotheses based on the persisted metadata and should be verified by the Codex team:

  1. Child event fan-out: parent or sibling events may be replicated into each subagent's JSONL stream.
  2. Unbounded task/event loop: task_started, task_complete, agent_message, patch_apply_end, and token_count events are emitted at implausibly high rates.
  3. Compaction persistence amplification: compacted state may be repeatedly stored in full instead of referenced, deduplicated, or replaced.
  4. Tool-output replay: custom tool outputs may be retained repeatedly across compactions or child sessions.
  5. Legacy history interaction: representative sessions report history_mode: legacy; no explicit user history configuration was found.
  6. Resume lifecycle leak: long-running resumed sessions may keep spawning or persisting child state after user-visible work has completed.

Requested investigation

Please investigate:

  • Why one parent thread spawned 2,393 persisted child sessions totaling ~731.5 GiB.
  • Whether parent/child/sibling events are being copied into multiple JSONL files.
  • Whether compacted records retain repeated full snapshots or previously persisted tool output.
  • Why a three-minute child task emits ~353,000 records, including ~185,000 token-count events and ~36,000 patch-apply completion events.
  • Whether completed subagent sessions continue receiving or retaining events.
  • Whether history_mode: legacy is expected for these versions and whether it changes persistence behavior.
  • Whether the resume path leaks task/event subscriptions across subagent generations.

Recommended safeguards

Independent of the root-cause fix, consider:

  • A configurable per-session and global session-store quota.
  • Automatic rotation/compression and an age/size-based retention policy.
  • Deduplication or content-addressing for compaction snapshots and tool outputs.
  • Rate limiting or coalescing high-frequency telemetry-like events such as token counts.
  • A warning and pause when Codex storage exceeds a threshold or the disk approaches exhaustion.
  • A built-in command to report and safely prune session storage while explaining the impact on resumability.
  • Detection of anomalous event rates or session growth, with a diagnostic bundle users can attach to reports.

Privacy-safe diagnostic commands

These commands report sizes and metadata without printing prompts, messages, tool arguments, or tool outputs.

# Overall usage
du -sh "$HOME/.codex" "$HOME/.codex/sessions"
df -h /System/Volumes/Data

# Counts and large files
find "$HOME/.codex/sessions" -type f | wc -l
find "$HOME/.codex/sessions" -type f -size +400M | wc -l

# Size by day
du -k -d 3 "$HOME/.codex/sessions" 2>/dev/null | sort -n | tail -30

# Open session files and their writer processes
lsof +D "$HOME/.codex/sessions/2026/07/18" 2>/dev/null

# Read only selected, non-content session metadata from the first record
head -1 path/to/session.jsonl | jq '{
  timestamp,
  type,
  payload: {
    id: .payload.id,
    cli_version: .payload.cli_version,
    originator: .payload.originator,
    source: .payload.source,
    history_mode: .payload.history_mode
  }
}'

Suggested attachments

Safe to attach after review:

  • Output of the size/count commands above.
  • The redacted session_meta line for the parent and one representative child.
  • Record-type count/byte aggregations that do not include payload content.
  • lsof output showing active writers, with username/path redacted.
  • Codex version and macOS version output.

Do not attach the full JSONL files without reviewing them. They contain conversation history, instructions, tool inputs/outputs, filesystem paths, and other potentially sensitive content.

Cleanup caveat

The session JSONL files appear to support session history and codex resume. Before deleting them:

  1. Stop the processes actively writing the affected sessions.
  2. Preserve a small, redacted diagnostic sample if the Codex team requests it.
  3. Assume deleted sessions may no longer be resumable or visible in local history.
  4. Verify that disk space is actually released after the writers exit.

What is the expected behavior?

_No response_

Additional information

_No response_

View original on GitHub ↗

22 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #33644

Powered by Codex Action

jezell · 1 month ago

Seems to be what you get when you combine long running sessions like this:

<img width="317" height="126" alt="Image" src="https://github.com/user-attachments/assets/4a379615-3550-42fd-88c9-f1cfc46edab0" />

with subagents.

jezell · 1 month ago

Asked whether subagents are forking the context.

• Yes—in your affected run, Codex copied a large filtered snapshot of the parent context into almost every forked child.

It is conditional, not universal:

  • MultiAgent V1: fork_context=true creates a full-history fork; default is false.
  • MultiAgent V2: omitting fork_turns defaults to "all", which creates a full-history fork.
  • fork_turns:"none" starts without parent conversation history.
  • fork_turns:"N" copies only the last N turns.

The Rust path is:

  1. spawn_agent maps "all" or fork_context=true to SpawnAgentForkMode::FullHistory. V2 spawn handler (https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rs), V1 spawn

handler (https://github.com/openai/codex/blob/main/codex-rs/core/src/tools/handlers/multi_agents/spawn.rs)

  1. It flushes the parent rollout to disk.
  2. It loads the parent’s model context. With your history_mode: legacy, this uses include_history: true.
  3. Unless LastNTurns was requested, it does not truncate the history.
  4. It constructs the child with InitialHistory::Forked(forked_rollout_items). Fork implementation (https://github.com/openai/codex/blob/main/codex-rs/core/src/agent/control/spawn.rs)

“Full history” is filtered, but still very broad. It retains:

  • System, developer, and user messages
  • Final assistant messages
  • Compaction records
  • All EventMsg records in legacy mode
  • Session metadata
  • Turn context and world state

It removes most raw tool-call/output and reasoning records, although those may remain embedded in compaction snapshots. Paginated history has an additional filter for token-count and several other event types;
legacy history does not.

On your machine, the affected parent rollout contains 2,322 detectable spawn_agent calls:

Setting Calls
━━━━━━━━━━━━━━━━━━━━ ━━━━━━━
fork_context=true 1,932
──────────────────── ───────
Setting omitted 234
──────────────────── ───────
fork_context=false 156

That matches the 2,393 child logs totaling approximately 731.5 GiB. A representative child JSONL contains both the child and parent session_meta, confirming inherited history was serialized into the child file.

This also corrects part of the earlier bug report: the 353,255 records in a three-minute child were probably copied during initialization, not all newly generated during those three minutes. The core bug is
primarily repeated full-history materialization, compounded by legacy mode retaining event records.

There is already an upstream issue describing this exact large-parent snapshot risk: openai/codex#14981 (https://github.com/openai/codex/issues/14981).

The immediate workaround is to use fork_context:false on V1 or fork_turns:"none"—or a small bounded number—on V2.

jezell · 1 month ago

Subagent session cleanup script (python) if anyone runs into this and needs to free up the space:

https://gist.github.com/jezell/6ad849791fc64d61d1ef1e66ad788eb5

georgfranz · 1 month ago

I can independently reproduce this on Codex CLI 0.144.5 on Linux x86_64 with gpt-5.6-sol, ultra effort, MultiAgent V2, and legacy history.

One child rollout contained:

  • 53,897 valid JSONL records
  • 118,285,692 bytes
  • child session_meta at line 1
  • embedded parent session_meta at line 2
  • first inter_agent_communication_metadata record with trigger_turn: true at line 53,749

The persisted prefix before the child’s first actual turn therefore contained 53,748 records and 117,949,758 bytes: 99.72% of both the records and bytes in the child file.

## Reproduction

  1. Build up or resume a sizeable parent thread using history_mode: legacy.
  2. Spawn a V2 subagent with fork_turns: "all" or omit it, since all is the default.
  3. Inspect the child rollout JSONL.
  4. Observe that almost the complete parent history is serialized before the child’s first turn.

## Expected behavior

Inherited context should be referenced, content-addressed, paginated, or otherwise bounded. The child rollout should primarily contain child-owned records.

## Actual behavior

Legacy full-history forks physically materialize the parent rollout into every child file. Repeated spawning therefore causes multiplicative disk growth.

Downstream consumers also require special replay detection to avoid interpreting the copied prefix as new events.

## Suggested improvement

The current source contains special handling for paginated subagents, but existing local sessions remain in legacy mode.

Could paginated or reference-based storage become the default, with a size guard or warning for legacy full-history forks?

ayanamislover · 1 month ago

Independent Windows / Codex Desktop reproduction, captured 2026-07-21 and cleaned up on 2026-07-22.

Environment

  • Windows x64
  • Codex Desktop package: 26.715.7063.0
  • Affected rollout metadata spans embedded CLI versions 0.136.0-alpha.2 through 0.145.0-alpha.18
  • Model: gpt-5.6-sol
  • Originator: Codex Desktop
  • Representative parent and child rollouts use history_mode: legacy

No conversation content, thread IDs, project names, or filesystem paths are included below.

Storage concentration

Before cleanup, the local session store contained:

  • 1,379 rollout JSONL files
  • 87.142 GiB total (sessions + archived_sessions)
  • 33 files larger than 1 GiB
  • 79 files larger than 100 MiB

The files were neither sparse nor hardlinked, so this was real allocated storage.

Two parent families accounted for 76.747 GiB, about 88% of the entire store:

| Family | Root | Children | Family total |
|---|---:|---:|---:|
| A | 2.708 GiB | 43 files / 37.128 GiB | 39.836 GiB |
| B | 1.495 GiB | 69 files / 35.416 GiB | 36.911 GiB |

This strongly matches multiplicative full-history materialization rather than ordinary child-owned output growth.

Representative child

One depth-1 child rollout was 2.429 GiB. It contained roughly 38.7k JSONL records, 56 session_meta blocks, and about 20.8k cumulative token_count events. The actual child takeover / inter-agent boundary appeared near line 38,690, so almost the entire persisted file preceded the child's own work.

This also explains why downstream usage readers can badly overcount child usage unless they identify and strip the inherited prefix.

Cleanup evidence

The Desktop state DB contained 1,307 spawn edges:

  • 989 closed
  • 318 open

A dependency-aware cleanup removed 982 closed child rollouts while protecting seven closed nodes that still had open descendants. That reclaimed 20.595 GiB without deleting any parent rollout or in-use file. This required a custom manifest, state DB backup, open-descendant traversal, file-handle checks, and transactional thread/edge deletion.

This is functionality the product should provide directly. Users should not need to reverse-engineer the local thread graph to recover disk space safely.

There was also a separate 3.153 GB logs_2.sqlite file. SQLite reported 713,127 free pages out of 769,925 total pages (92.6% free), but the file had not been compacted. Automatic checkpoint/rotation/compaction would recover roughly another 2.7 GiB in this case.

Requested safeguards

  1. Persist inherited parent context by reference or content address instead of serializing it into every child rollout.
  2. Make bounded/empty fork history the default, or warn before a full-history fork materializes a very large parent.
  3. Add per-thread and global session-store quotas with visible disk-usage warnings.
  4. Add a built-in dependency-aware command/UI action to prune closed subagents while preserving roots and open descendants.
  5. Rotate and compact logs_2.sqlite automatically after retention deletes rows.

I can provide the privacy-safe metadata audit and dependency-aware cleanup scripts if maintainers would find them useful.

shrishmanglik · 1 month ago

We hit this at scale and ran a byte-level attribution that may help prioritize — sharing the evidence.

Environment: Codex app 26.715.8383.0 / codex-cli 0.145.0-alpha.27, Windows 11.

Measured (single day, 2026-07-21): 52 rollout .jsonl files, 15,367,765,044 bytes. Attribution:

  • Inline data:image/...;base64 strings: 89.98% of all bytes (13.83GB)
  • compacted.replacement_history records: 83.3% of bytes; images inside compaction snapshots = 90.4% of all image bytes
  • In the largest file (1.02GB, 18,658 lines): 1,219 inline-image occurrences but only 241 unique payloads (45MB) — a 20.95× duplication factor from subagent history-forks re-materializing parent history plus compaction retaining images
  • 25 child sessions forked from one image-heavy parent = 77.3% of the day's bytes
  • Tool output was negligible (~8KB in the largest file) — this is not a tool-log problem

Config-schema check (0.145.0-alpha.27): no supported key for image persistence, rollout retention, rollout max-bytes, or append-only references. [history].max_bytes caps a different file; tool_output_token_limit doesn't touch this cohort.

Mitigation that worked for us: developer_instructions mandating fork_turns="none" (children get a bounded task packet instead of forked image history) + an external retention prune. Happy to share the full audit methodology if useful.

Suggested fixes from the data: store images as content-addressed references (241 unique payloads would collapse 13.8GB → 45MB), and/or exclude image payloads from fork materialization and compaction snapshots.

Coldain · 1 month ago

Independent macOS Codex Desktop corroboration, captured 2026-07-25. I inspected sizes, selected session metadata, JSON record types, and string lengths only; no prompts, task names, tool arguments, payload values, thread IDs, or project paths are included.

Environment

  • macOS 27.0 (26A5388g), Apple Silicon
  • APFS
  • ChatGPT/Codex Desktop app: 26.721.41059
  • Current bundled runtime: codex-cli 0.146.0-alpha.3.1
  • Representative affected child metadata: Codex Desktop, 0.145.0-alpha.18, depth-1 thread_spawn subagent, history_mode: legacy

Store-level measurements

  • $HOME/.codex/sessions: 122.2 GiB
  • rollout files: 1,007
  • files over 100 MB: 397
  • files over 400 MB: 57
  • files over 512 MB: 15
  • files over 1 GB: 5
  • 2026-07-18 alone: 41.2 GiB across 250 files
  • largest observed rollout: 4,102,031,496 bytes

Representative depth-1 child rollout

  • size: 597,936,910 bytes
  • valid JSONL records: 14,933
  • records over 1 MiB: 130
  • largest record: 18,742,520 bytes

Aggregate bytes by record category:

| Category | Count | Aggregate |
|---|---:|---:|
| event_msg/image_generation_end | 102 | 406.3 MiB |
| response_item/custom_tool_call_output | 362 | 114.4 MiB |
| compacted | 54 | 18.1 MiB |
| event_msg/mcp_tool_call_end | 352 | 14.2 MiB |
| event_msg/token_count | 9,271 | 7.2 MiB |

The largest strings were multi-megabyte payload.result and payload.output.*.image_url values. This case therefore combines full-history subagent materialization with inline visual/tool artifacts; compaction is present but is not the dominant category in this representative child.

The current runtime is newer than the representative affected runtime, but there is still no visible quota, retention warning, or safe built-in cleanup flow. Deleting these files would affect resumability, so I have not attached or removed them.

LiuChang-ao · 1 month ago

Additional anonymized Windows/Desktop data point (no session content, images, full paths, user IDs, thread IDs, or hashes included):

I performed a read-only stream scan of a local Codex state directory.

  • Total .codex storage: ~13.56 GiB; sessions: 12.01 GiB across 726 rollout JSONL files.
  • Across readable rollout files (a few currently active files were locked and therefore excluded), 198 files contained inline data:image/...;base64,... values.
  • There were 37,621 inline image occurrences but only 1,282 distinct payload hashes: 36,339 copies beyond the first occurrence.
  • The inline image Base64 character data alone totaled ~8.11 GiB. The most frequently repeated payload appeared 3,369 times.
  • The largest inspected non-subagent rollout was 236.72 MiB and contained 532 inline image occurrences (~115.84 MiB of Base64 data).
  • Among the 40 largest rollouts, 39 were marked thread_source=subagent; together they totaled 4,969.75 MiB.
  • The largest inspected non-subagent rollout also contained 160 compacted records and 80 replacement_history references.

This is a lower-bound measurement, but it independently corroborates the same combination of inline image persistence and subagent-driven storage amplification described here. The scan used only structural markers, byte counts, and payload hashes; no conversation or tool-output content was inspected or retained.

guanxuewen-eng · 1 month ago

Additional reproduction from a newer Codex Desktop build (privacy-safe; paths, project names, thread IDs, and conversation contents omitted).

Environment

  • Codex Desktop: 26.721.41059 (build 5848)
  • Bundled CLI: codex-cli 0.146.0-alpha.3.1
  • Model: GPT-5.6
  • Platform: macOS / arm64

Observed

  • ~/.codex/sessions reached approximately 209 GiB.
  • One depth-1 subagent session grew to 3,846,420,707 bytes (~3.58 GiB) in about 7 minutes.
  • The session metadata identified it as a subagent spawned from a long-lived parent Desktop thread.
  • In the first 5,000 valid JSONL records, the largest categories were:
  • event_msg/token_count: 2,075
  • event_msg/agent_message: 1,743
  • event_msg/patch_apply_end: 298
  • response_item/message: 250
  • turn_context: 136
  • task_started: 114
  • task_complete: 112
  • compacted: 22
  • Individual repeated JSONL records reached about 4.46 MiB.
  • The Codex app-server reached roughly 5 GiB RSS and 55-70% CPU while holding multiple multi-GiB session files open.
  • During the incident, system write counters increased by about 58 GiB in 83 minutes; ~/.codex grew by about 10 GiB, while APFS free space fell by about 15 GiB.

Important distinction
The diagnostic SQLite database was not the active growth source: logs_2.sqlite remained around 627 MiB and its WAL stayed around 4-32 KiB. The rapid growth was in sessions/**/*.jsonl.

This appears to reproduce the same subagent event amplification / compaction persistence problem on 0.146.0-alpha.3.1, so the issue is either still unfixed in this newer build or has regressed.

The practical workaround was to restart Codex Desktop, avoid resuming the affected long-lived parent thread, and temporarily avoid subagent spawning in long sessions. Please consider a per-session size cap/rotation and an automatic pause or warning when a session grows at GiB-per-minute rates.

tylorsaling-source · 1 month ago

Sharing measured evidence on where these bytes come from, because it reframes the mechanism and rules one candidate out.

Post-cap tool output is not the source

The legacy shell path discards output beyond its 1 MiB cap without persisting it (details in #35421). I verified this on a real event — a 4,095,789-byte single-line match:

  • raw output ≥ 4.1 MB → 1 MiB capture cap → 40,073-byte persisted JSONL record
  • the persisted tail fingerprints the 1 MiB boundary, not command EOF; the ~3.05 M chars after it appear nowhere in the rollout (source-EOF fingerprint: 0 matches)
  • the 13 custom_tool_call_output records in that rollout maxed out at 609 chars

So oversized single tool outputs are not what fills the disk — the dropped bytes are gone, not stored.

The bytes are in amplification, not raw capture

This issue's own numbers point the same way:

  • custom_tool_call_output: 211,681,025 B ÷ 27,848 records ≈ 7.6 KB/record
  • compacted: 571,600,883 B ÷ 175 records ≈ 3.3 MB/record

The mass is in compaction snapshots (~430× larger per record) and in sheer record volume multiplied across subagents. So the mechanism worth measuring is how often already-persisted records (the ~40 KB tool results and the multi-MB compacted snapshots) are replayed or copied across compactions, resumes, and child sessions — i.e. duplication, not first-write size.

Closely related on that mechanism: #35226 (compaction loop), #33735 (session JSONL → 24 GB from repeated inline image data during compaction), #24191 (remote compact creates huge compacted records), #33493 (compaction retains unbounded payloads), #24048 (~27 GB memory handling large output).

Separate branch worth noting

The SQLite state stores (logs_2.sqlite, state_5.sqlite) are independently affected by a lifecycle gap — e.g. logs_2 was ~1.5 GiB with ~75% free-list pages (no VACUUM/auto_vacuum) and heavy WAL churn from a 4-index log table. That's high-rate tracing/telemetry, not truncation-driven, so it's a distinct issue from the JSONL growth here — possibly relevant to #23168 (configurable storage backend).

tylorsaling-source · 1 month ago

Following up with the measured version of the amplification I described above — including which lifecycle boundaries do the copying. All read-only, bounded scans of the local session store.

Duplication is large and crosses file boundaries

Bounded scan of a high-mass cohort (one parent + its 8 largest children; 9 files; 758 MB of canonical payload; 534,723 records; 0 parse errors):

  • 46.96% of canonical payload bytes are exact SHA-256 duplicates (356 MB of 758 MB); ≥286 MB crosses file boundaries. Still 49% after normalizing volatile id/timestamp fields, so it isn't an artifact of those.
  • Hash-proven examples: one 37,905-byte session_meta payload repeated 1,354× across 9 files; a 1,086,769-byte mcp_tool_call_end payload in 7 files; token_count 81% duplicate; compacted 64.77% duplicate.

(The cohort was deliberately picked for high mass — this is not a whole-store rate.)

Which boundary copies (separate test, strict causal criteria)

Child attribution required explicit parent linkage and pre-spawn timing and ordered replay and anchors unique in the parent prefix — equality alone was never treated as causal.

  • Child spawn — confirmed. 12 of 14 parent-linked children begin by re-emitting an ordered prefix of parent payloads that existed before the child's spawn timestamp (2,937 records, ~4.3 MB, 2,385 unique-parent anchors). Zero exact raw-line matches → it's payload re-emission into new records, not file copying.
  • Compaction — confirmed, localized. Prior persisted items are rewritten inside compacted.payload.replacement_history (171 matching earlier top-level payloads; 155 repeated across compaction histories). No large post-boundary burst (~2 KB in ±64-record windows) — the compaction record itself carries the cost.
  • Desktop reopen — confirmed. Identical session_meta rewritten on reinitialization (175,891 duplicate bytes across 7 rows).
  • CLI codex resume — NOT isolated. The reopens here are Desktop reinitializations; attributing them to codex resume would be a false positive. That needs a controlled before/after test in a disposable store.

Fix targets these suggest

  • Child spawn: reference immutable inherited history (a content-addressed shared segment) instead of re-emitting parent payloads into each child rollout.
  • Compaction: dedupe stable history items across successive replacement_history snapshots by content hash.
  • Session reopen: don't rewrite identical session_meta — one record plus small versioned deltas.

Notes

The dominant mechanism in this cohort is duplication after first persistence, not the size of any single first write. (Confirming the separate point from my earlier comment: the legacy-shell truncation path discards post-cap bytes rather than persisting them — verified on a 4.1 MB line that contracted to a 40 KB record, source-EOF fingerprint absent everywhere — so truncation is not the disk driver; duplication is.) Related manifestations: #33735 (session JSONL → 24 GB from repeated inline images during compaction), #24191 (huge compacted records). Method: read-only file opens, zero DB connections/writes/locks, no payload dumps, a pre-open byte fence to handle the live parent.

Loong0x00 · 1 month ago

Independent Linux reproduction: this is still present in codex-cli 0.145.0.

Environment:

  • Arch Linux x86_64
  • Codex CLI 0.145.0
  • Btrfs home filesystem
  • Measurements below used metadata, record types, byte counts, and bounded structural comparisons only. No prompt, tool payload, repository content, username, absolute path, or thread UUID is included.

Current store snapshot:

| Item | Measurement |
|---|---:|
| Total Codex home | 9.145 GB |
| Session JSONL | 7.212 GB |
| Session files | 979 |
| Files >= 10 MiB | 121 |
| Files >= 100 MiB | 14 |
| Files >= 300 MiB | 3 |
| Files carrying forked_from_id | 528 |
| Bytes in fork-marked files | 6.521 GB |
| Subagent-source files | 747 files / 3.425 GB |
| CLI-source files | 69 files / 3.686 GB |

The 528 fork-marked files holding 6.521 GB does not mean all 6.521 GB is duplicate data, so I separately tested a large explicit fork chain.

Three consecutive rollouts in that chain were approximately 386.1 MB, 440.1 MB, and 443.6 MB. After excluding the leading inherited session_meta records and normalizing only the volatile top-level timestamp, ordered comparison confirmed:

  • first child re-emitted a 302.5 MB / 87,930-record parent prefix;
  • second child re-emitted a 386.0 MB / 103,977-record parent prefix.

That is at least 688.5 MB of confirmed inherited history re-persisted by only two forks. This is payload re-emission with fresh timestamps, not byte-for-byte file copying.

A structural scan of the 443.6 MB rollout found:

| Record category | Rows | Aggregate bytes |
|---|---:|---:|
| response_item/custom_tool_call_output | 17,363 | 189.6 MB |
| compacted | 376 | 112.0 MB |
| response_item/reasoning | 23,492 | 49.9 MB |
| response_item/function_call_output | 4,110 | 29.2 MB |
| event_msg/token_count | 23,285 | 19.0 MB |

Within the custom-tool outputs, string aggregation attributed about 142.2 MB to text fields and 32.2 MB to inline image_url fields.

A read-only zstd level-3 measurement across all 979 session files reduced 7.212 GB to 1.541 GB, a 78.6% reduction. The installed binary contains transparent .jsonl.zst reader/materialization support, but codex features list reports:

local_thread_store_compression  under development  false

There were zero compressed rollout files in this store. This suggests that enabling bounded cold-rollout compression by default would be a useful safeguard even before the fork/compaction amplification is fully fixed.

This Linux data independently confirms both mechanisms already discussed here: full-history child/fork materialization and repeated retention of compaction/tool-output state. The issue persists in 0.145.0.

dheeraj5612 · 1 month ago

Adding another data point for this, from a macOS install.

Environment

  • codex-cli 0.144.0
  • macOS (Darwin 25.5.0), Apple Silicon
  • 460 GB internal volume

Scale

~/.codex had grown to 79 GB, of which sessions/ was 72 GB across 6,856 files. This was the single largest consumer on the machine apart from the system Messages store, and it took the volume to 96% full.

Monthly totals under sessions/2026/:

| Month | Size |
|---|---|
| 01 | 1.7 MB |
| 02 | 151 MB |
| 03 | 19 MB |
| 04 | 38 MB |
| 05 | 1.3 GB |
| 06 | 2.6 GB |
| 07 | 67 GB |

Growth is not linear with usage — July alone was 25x June. Daily breakdown for July shows it concentrated in a handful of days rather than spread evenly:

| Day | Size |
|---|---|
| 13 | 6.5 GB |
| 15 | 5.2 GB |
| 16 | 15 GB |
| 17 | 5.4 GB |
| 18 | 2.5 GB |
| 19 | 3.8 GB |
| 20 | 25 GB |
| 23 | 1.3 GB |

25 GB in a single day, and 15 GB in another. Individual rollout files:

  • largest single file: 1.3 GB
  • several in the 500-552 MB range

Per #22004 the 1.3 GB file would already be unopenable in the desktop app, so the session is effectively lost while still occupying the disk.

Separately, ~/.codex/logs_2.sqlite was 6.2 GB on its own — worth noting as a second sink distinct from sessions/.

Config context that may be relevant

  • chronicle = true
  • a notify hook wired to Codex Computer Use (heavy screenshot usage on the high-volume days, which per #24676 would mean large inline image_url records)
  • several plugins enabled

The spike days correlate with heavy Computer Use and subagent activity, which lines up with the amplification described in this issue.

On mitigation

There is currently no way to bound this from config. Per the configuration reference, [history] persistence and history.max_bytes govern history.jsonl only, not the rollout files under sessions/. codex archive moves rollouts into archived_sessions/ on the same volume, so it reclaims nothing. The only available remedy is deleting files out from under Codex manually, which is what I ended up doing — 72 GB down to ~275 MB by deleting everything older than a few days.

Echoing #6015 and #20230: an age or size based retention policy, even opt-in, would make this self-limiting. A per-session size cap would additionally prevent the #22004 unopenable-session failure mode.

NasCorp · 1 month ago

I traced a remaining amplification path in current main. The paginated-history changes filter legacy presentation events, but multi-agent full-history forks still appear to persist inherited context through the copied path.

spawn_forked_thread constructs InitialHistory::Forked and calls fork_thread_with_source. That path uses ForkPersistence::Copied, and paginated subagents are initialized through LiveThread::create_with_inherited_model_context.

This means a retained Compacted.replacement_history, including a large ImageGenerationCall.result or another inline payload, can still be serialized into every full-history child rollout. Paginated mode reduces event noise but does not eliminate N children x large compacted context storage amplification.

The repository already has a reference-backed paginated fork path using ForkPersistence::Referenced and history_base. Would maintainers be open to using an equivalent mechanism for multi-agent full-history forks, with child-specific developer instructions represented as an overlay rather than by mutating and copying inherited history?

I can prepare an invited PR with a deterministic regression test:

  1. create a paginated parent containing a large sentinel payload inside Compacted.replacement_history;
  2. spawn multiple full-history children;
  3. verify the inherited context remains model-visible;
  4. verify the sentinel is not reserialized into each child rollout;
  5. verify the child records a reference-backed history boundary.

If reference-backed multi-agent forks are not currently compatible with the instruction-sanitization design, I can instead prepare a bounded-size guard that rejects or warns on oversized inherited prefixes.

IkenHuub · 26 days ago

Can confirm this is still happening in Codex Desktop 26.727.51351 on macOS 15.7.5 (arm64). ~/.codex had grown to 105 GB, including 103 GB under sessions, leaving only 2.4 GiB free. I found approximately 849 completed subagent JSONL files totaling about 95 GiB; individual files were commonly 0.5–1.5 GB.

After deleting only completed subagent rollouts that were no longer open, ~/.codex dropped to 9.8 GB and free space increased to 98 GiB. The main threads and two active subagents were preserved. I have not shared raw logs because they contain private project data.

haoyu-haoyu · 25 days ago

I had the same problem here the bundle of subagent take way almost 60-70GB from me and after research out just find they never close it after it complete, sometime in a heavy task run can also cause crash. I just made this componet to doing storage usage monitor of codex session and subagent session. And It can also help you he clean completed/dead subagent session to free more disk space
https://github.com/haoyu-haoyu/codex-janitor

shleder · 14 days ago

The 755 GiB store and 2,393 child rollouts from one resumed parent are an exceptional real stress case. The three-minute child writing 353k valid records is particularly useful because the pathology is event amplification, not just one giant line.

I’m trying to validate whether Codex Rescue remains bounded and useful on this layout. It will not delete, compress, or archive sessions, and it does not modify SQLite or rollouts. It also cannot fix subagent fan-out; uncertain state remains fail-closed.

If a retained snapshot is still available, could you run:

pipx install codex-rescue==0.1.0a3
codex-rescue sessions
codex-rescue doctor --latest

Sanitized counts/status are enough—please don’t share raw JSONL, databases, tool output, prompts, project data, paths, or secrets.

https://github.com/shleder/codex-rescue

mik-0 · 9 days ago

Another confirmed reproduction, this time on Codex Desktop 26.810.52044 with bundled codex-cli 0.148.0-alpha.9 on macOS 26.2 arm64.

~/.codex/sessions grew to 42.52 GiB. A metadata-only classification showed 97 inactive subagent rollouts using 37.71 GiB. Individual child files were approximately 0.4–2.21 GiB, and three subagents spawned from one huge parent generated 6.53 GiB in a single batch. Free disk fell from 50+ GiB to 3.1 GiB.

The rollout metadata confirmed the files were subagent forks tied to the same parent thread. This is severe storage amplification from normal multi-agent use, with no quota, warning, deduplication, or automatic cleanup. We had to delete the inactive subagent files manually after excluding open sessions and sessions belonging to another workspace.

Please prioritize deduplicated fork history, bounded inheritance persistence, completed-subagent garbage collection, storage quotas/warnings, and a supported cleanup UI/command. A coding agent should not be able to silently consume the host disk as a side effect of delegation.

hes7 · 7 days ago

Additional Windows case with the same failure pattern (privacy-safe metrics only):

  • Platform: Windows x64
  • Session store: %USERPROFILE%\.codex\sessions
  • Total session store before cleanup: 390.77 GB across 924 rollout files
  • Parsing only the first session_meta record classified:
  • 454 ROOT files totaling 30.41 GB
  • 470 FORK files totaling 360.32 GB
  • The largest fork family contained 107 child/fork files totaling 179.61 GB from one parent; another contained 158 forks totaling 137.21 GB.
  • Many child rollouts were ~8.0–8.1 GB each and shared the same parent session_id / forked_from_id relationship.
  • C: drive free space had fallen to 9.15 GB before intervention.
  • After backing up and verifying all 470 fork files byte-for-byte on an external NTFS drive, removing only those verified fork files recovered 360.32 GB, leaving the ROOT session store at 30.45 GB and increasing C: free space to 369.22 GB.

This strongly suggests that full-history fork persistence is responsible for the overwhelming majority of local storage in this Windows case as well (about 92% of the session store). No raw JSONL files are attached because they may contain private conversation/tool data.

A product safeguard would be very valuable here: global/per-session storage caps, warnings before the system drive becomes critically full, and/or a supported command/UI to identify and safely prune duplicated fork/session data without risking root conversation history.

shleder · 1 day ago

Additional Windows datapoint matching the pattern: total store far exceeding visible conversations. Before mass cleanup, vetto rescue --json scan breaks down actual bytes per rollout read-only - worth running so cleanup targets real duplicates rather than index guesses.

robert-claypool · 1 day ago

Still reproducible in codex-cli 0.149.1.

Environment

  • macOS 26.5.1, Apple Silicon
  • GPT-5.6 Sol, xhigh
  • MultiAgent V2 depth-one subagents
  • Representative rollouts report history_mode: legacy

Impact

Captured today:

  • ~/.codex: approx 897 GiB
  • ~/.codex/sessions: approx 890 GiB
  • Rollout files: 1,443
  • Files larger than 1 GiB: 65
  • One day's directory: 354 GiB across 81 files
  • One resumed parent accounted for 39 depth-one child files totaling 336.3 GiB
  • The 1.8 TiB APFS Data volume reached 100% capacity with approximately 182 MiB free
  • Codex emitted no storage warning, quota refusal, or backpressure before exhaustion

Byte-level representative child

One bounded subagent provides a clear attribution:

  • Spawn record explicitly used fork_turns: "all"
  • Parent rollout prefix at spawn: 19,728,188,607 bytes
  • Completed child rollout: 18,404,435,437 bytes
  • First inter_agent_communication_metadata boundary in the child: byte 18,399,038,336
  • Therefore 99+% of the child file preceded its own inter-agent activity boundary
  • Only 5,397,101 bytes followed that boundary
  • Elapsed time from child session_meta to task_complete: approx 7 minutes 29 seconds

The runtime re-materialized ~18.4 GB of inherited parent history for one child. Repeating that across 39 children used ~336 GiB in one day.