Skip to content

Rollouts persist each command's stdout 3x per item_completed record (stdout/aggregated_output/formatted_output) — 60% of session bytes; thread_history stores a 4th copy #41269

Description

@shaswatshah

What version of Codex CLI is running?

codex-cli 0.150.1 (also Codex Desktop app-server 151.0.7922.170 on the same ~/.codex)

What subscription do you have?

Pro

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Darwin 25.5.0 arm64 arm

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

Orca (terminal multiplexer/agent launcher) driving codex TUI sessions; Codex Desktop app-server also running against the same CODEX_HOME.

Codex doctor report

See "Additional information" (full JSON attached at the bottom; nothing redacted was needed).

What issue are you seeing?

~/.codex reached 14 GB on a machine where Codex is the secondary agent (Claude Code is primary). After removing rollouts older than 30 days, the last 30 days alone are 6.7 GB across 5,271 rollout files. Sizing what is inside them shows the dominant cost is not model traffic but the same command stdout being persisted four times — three copies inside a single rollout record, plus one more in thread_history_1.sqlite.

1. event_msg/item_completed for CommandExecution stores the full stdout three times in one record.

Each completed command is appended to the rollout as an event_msg whose item has stdout, stderr, aggregated_output, and formatted_output. Measured on the largest rollout (114 MB, 1,359 CommandExecution items):

field bytes note
stdout 27.9 MB
aggregated_output 27.9 MB byte-identical to stdout in 1,359 / 1,359 items
formatted_output 16.8 MB byte-identical to aggregated_output in 1,186 / 1,359 items
stderr ~0

That one record type is 75 MB of the 114 MB file (68%). The response_item/function_call_output / custom_tool_call_output records — the (truncated) output the model actually saw — total only 22 MB in the same file. So the rollout carries ~3.4× more untruncated stdout than model-visible output.

Across the 200 largest rollouts in ~/.codex/sessions (2.0 GB total):

record type bytes share
event_msg/item_completed (CommandExecution) 1,199 MB 59.9%
response_item/custom_tool_call_output 311 MB 15.5%
response_item/function_call_output 128 MB 6.4%
response_item/reasoning 110 MB 5.5%
everything else ~250 MB ~12%

Inside those CommandExecution items: stdout 461 MB + aggregated_output 461 MB + formatted_output 236 MB.

2. thread_history_1.sqlite stores a fourth copy.

The projection DB is 1.68 GB; thread_items rows with item_type = 'commandExecution' account for 1,486 MB of it, and json_extract(item_json, '$.aggregatedOutput') alone sums to 1,416 MB (individual items cap at ~1 MB). Every thread in it still has its rollout on disk, so this is a straight duplicate of data already in sessions/.

3. There is no age-based retention for any of this, so it only grows. (Tracked separately in #6015 / #28187 / #20230 — noted here only because it turns the duplication into a permanent cost.) logs_2.sqlite separately sat at 2.63 GB with 1.76 GB of freelist pages; that is #35823 and VACUUM fixed it.

Why this is distinct from existing reports. #36557 / #39469 / #31198 / #29531 are about parent history or compacted.replacement_history being replayed into child/resumed rollouts; #24948 and #34061 attribute growth to raw function_call_output volume and event counts. In my data the response_item outputs are the small part. The cost is the three redundant fields on item_completed events plus the projection copy — it applies to every command in every session, subagent or not, and stacks multiplicatively on top of the issues above. Workload context: 77% of my rollouts (4,631 of 5,271; 5.1 GB) are subagent threads from a multi-agent plugin whose workers run many read-heavy shell commands (cat, grep, git show), so each byte of stdout costs ~4 bytes on disk, forever.

What steps can reproduce the bug?

  1. Run any session that executes a shell command with non-trivial stdout, e.g. codex exec "run: cat some-200KB-file" (or any TUI session doing normal work).
  2. Open the rollout under ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl and find the event_msg record with payload.type == "item_completed" and payload.item.type == "CommandExecution".
  3. Observe item.stdout == item.aggregated_output == item.formatted_output (the last differs only when the formatted view truncates).
  4. Observe the same output again, truncated, in the preceding response_item (custom_tool_call_output / function_call_output).
  5. Observe it a fourth time: sqlite3 ~/.codex/thread_history_1.sqlite "select length(json_extract(item_json,'$.aggregatedOutput')) from thread_items where item_type='commandExecution' order by 1 desc limit 5".

Measurement script used for the numbers above (Python 3, stdlib only):

import json, sys, collections
by = collections.Counter(); fld = collections.Counter(); tot = 0
for path in sys.argv[1:]:
    for line in open(path):
        tot += len(line)
        r = json.loads(line); p = r.get("payload", {})
        t = r.get("type", "?") + "/" + str(p.get("type", ""))
        if t == "event_msg/item_completed":
            t += "/" + str(p.get("item", {}).get("type"))
        by[t] += len(line)
        if t == "event_msg/item_completed/CommandExecution":
            it = p["item"]
            for k in ("stdout", "stderr", "aggregated_output", "formatted_output"):
                fld[k] += len(it.get(k) or "")
print(f"total {tot/2**20:.0f} MB")
for t, b in by.most_common(8): print(f"{b/2**20:7.0f} MB {100*b/tot:5.1f}%  {t}")
for k, v in fld.items(): print(f"{v/2**20:7.0f} MB  {k}")

Example thread id with the 114 MB rollout: 01a020c7-c50c-7850-b187-da14ba3adc88.

What is the expected behavior?

  • A command's output is persisted once per rollout. item_completed should either omit the output fields (the response_item already carries what the model saw, and the raw output could be referenced by offset) or carry a single field; stdout / aggregated_output / formatted_output should not be three literal copies.
  • thread_history_1.sqlite should reference rollout offsets (it already stores rollout_byte_offset per turn) rather than re-embedding aggregatedOutput.
  • Some size cap or retention on persisted raw output, so a cat of a large file does not become a permanent multi-megabyte on-disk cost.

Additional information

Disk state when this was measured (macOS, single user, Codex used a few hours a day):

codex doctor --json
{
  "schemaVersion": 1,
  "generatedAt": "1787893861s since unix epoch",
  "overallStatus": "warning",
  "codexVersion": "0.150.1",
  "checks": {
    "app_server.status": {
      "id": "app_server.status",
      "category": "app-server",
      "status": "ok",
      "summary": "background server is not running",
      "details": {
        "control socket": "/Users/shaswat/.codex/app-server-control/app-server-control.sock",
        "daemon state dir": "/Users/shaswat/.codex/app-server-daemon",
        "mode": "ephemeral",
        "pid file": "/Users/shaswat/.codex/app-server-daemon/app-server.pid (missing)",
        "settings": "/Users/shaswat/.codex/app-server-daemon/settings.json (missing)",
        "status": "not running",
        "update-loop pid file": "/Users/shaswat/.codex/app-server-daemon/app-server-updater.pid (missing)"
      },
      "remediation": null,
      "durationMs": 0
    },
    "auth.credentials": {
      "id": "auth.credentials",
      "category": "auth",
      "status": "ok",
      "summary": "auth is configured",
      "details": {
        "auth env vars present": "OPENAI_API_KEY",
        "auth file": "/Users/shaswat/.codex/auth.json",
        "auth storage mode": "File",
        "stored API key": "false",
        "stored ChatGPT tokens": "true",
        "stored agent identity": "false",
        "stored auth mode": "chatgpt"
      },
      "remediation": null,
      "durationMs": 0
    },
    "config.load": {
      "id": "config.load",
      "category": "config",
      "status": "ok",
      "summary": "config loaded",
      "details": {
        "CODEX_HOME": "/Users/shaswat/.codex",
        "config.toml": "/Users/shaswat/.codex/config.toml",
        "config.toml parse": "ok",
        "cwd": "/Users/shaswat/.codex",
        "enabled feature flags": "shell_tool, view_image, unified_exec, unified_exec_zsh_fork, shell_snapshot, code_mode_host, terminal_resize_reflow, sqlite, hooks, enable_request_compression, unbounded_connection_retries, multi_agent, multi_agent_v2, tool_search_always_defer_mcp_tools, tool_suggest, plugins, in_app_browser, in_app_chat, in_app_dictation, in_app_local_automation, in_app_updates, browser_use, browser_use_full_cdp_access, browser_use_external, computer_use, remote_plugin, plugin_sharing, image_generation, resize_all_images, item_ids, skill_mcp_dependency_install, skill_search, mentions_v2, steer, guardian_approval, goals, collaboration_modes, tool_call_mcp_elicitation, auth_elicitation, personality, fast_mode, tui_app_server, remote_compaction_v2, compaction_image_budget, workspace_dependencies",
        "feature flag overrides": "multi_agent_v2=true, apps=false",
        "feature flags enabled": "45",
        "log dir": "/Users/shaswat/.codex/log",
        "mcp servers": "3",
        "model": "gpt-5.6-sol",
        "model provider": "openai",
        "sqlite home": "/Users/shaswat/.codex"
      },
      "remediation": null,
      "durationMs": 0
    },
    "desktop.app.version": {
      "id": "desktop.app.version",
      "category": "desktop",
      "status": "ok",
      "summary": "the desktop application is installed",
      "details": {
        "log directory": "$HOME/Library/Logs/com.openai.codex",
        "running": "true",
        "version": "26.818.61809"
      },
      "remediation": null,
      "durationMs": 0
    },
    "desktop.app_server.handshake": {
      "id": "desktop.app_server.handshake",
      "category": "desktop",
      "status": "ok",
      "summary": "no desktop app-server handshake was recorded",
      "details": {},
      "remediation": null,
      "durationMs": 0
    },
    "desktop.security.enforcement": {
      "id": "desktop.security.enforcement",
      "category": "desktop",
      "status": "ok",
      "summary": "the desktop application passed available macos security assessments",
      "details": {
        "gatekeeper": "accepted"
      },
      "remediation": null,
      "durationMs": 0
    },
    "git.environment": {
      "id": "git.environment",
      "category": "git",
      "status": "ok",
      "summary": "git version 2.50.1 (Apple Git-155)",
      "details": {
        "PATH git #1": "/usr/bin/git",
        "PATH git entries": "1",
        "git build options": "git version 2.50.1 (Apple Git-155); cpu: arm64; no commit associated with this build; sizeof-long: 8; sizeof-size_t: 8; shell-path: /bin/sh; feature: fsmonitor--daemon; libcurl: 8.7.1; zlib: 1.2.12; SHA-1: SHA1_DC; SHA-256: SHA256_BLK",
        "git exec path": "/Library/Developer/CommandLineTools/usr/libexec/git-core",
        "git version": "git version 2.50.1 (Apple Git-155)",
        "repo detected": "false",
        "selected git": "/usr/bin/git"
      },
      "remediation": null,
      "durationMs": 146
    },
    "installation": {
      "id": "installation",
      "category": "install",
      "status": "ok",
      "summary": "installation looks consistent",
      "details": {
        "PATH codex #1": "/opt/homebrew/bin/codex",
        "current executable": "/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin/codex",
        "install context": "npm (package /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin, bin /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin, resources /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/codex-resources, path /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/codex-path)",
        "managed by bun": "false",
        "managed by npm": "true",
        "managed by pnpm": "false",
        "managed package root": "/opt/homebrew/lib/node_modules/@openai/codex",
        "npm update target": "/opt/homebrew/lib/node_modules/@openai/codex"
      },
      "remediation": null,
      "durationMs": 191
    },
    "mcp.config": {
      "id": "mcp.config",
      "category": "mcp",
      "status": "ok",
      "summary": "MCP configuration is locally consistent",
      "details": {
        "configured servers": "3",
        "disabled servers": "1",
        "stdio servers": "2",
        "streamable_http servers": "1"
      },
      "remediation": null,
      "durationMs": 250
    },
    "network.env": {
      "id": "network.env",
      "category": "network",
      "status": "ok",
      "summary": "network-related environment looks readable",
      "details": {
        "managed proxy": "not configured",
        "proxy env vars": "none",
        "respect system proxy": "disabled",
        "system proxy": "direct"
      },
      "remediation": null,
      "durationMs": 1
    },
    "network.provider_reachability": {
      "id": "network.provider_reachability",
      "category": "reachability",
      "status": "ok",
      "summary": "active provider endpoints are reachable over HTTP",
      "details": {
        "ChatGPT inference URL": "https://chatgpt.com/backend-api/<redacted> reachable (HTTP 405)",
        "desktop assets CDN": "https://chatgpt.com/backend-api/<redacted> reachable (HTTP 200)",
        "reachability mode": "ChatGPT auth"
      },
      "remediation": null,
      "durationMs": 274
    },
    "network.websocket_reachability": {
      "id": "network.websocket_reachability",
      "category": "websocket",
      "status": "ok",
      "summary": "Responses WebSocket handshake succeeded",
      "details": {
        "DNS": "2 IPv4, 2 IPv6, first IPv6",
        "auth mode": "chatgpt",
        "connect timeout": "15000 ms",
        "endpoint": "wss://chatgpt.com/backend-api/<redacted>",
        "handshake result": "HTTP 101 Switching Protocols",
        "model provider": "openai",
        "provider name": "OpenAI",
        "proxy env vars": "none",
        "reasoning header": "false",
        "server model present": "false",
        "supports websockets": "true",
        "wire API": "responses"
      },
      "remediation": null,
      "durationMs": 1130
    },
    "runtime.provenance": {
      "id": "runtime.provenance",
      "category": "runtime",
      "status": "ok",
      "summary": "running npm on macos-aarch64",
      "details": {
        "commit": "unknown",
        "current executable": "/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin/codex",
        "install method": "npm (package /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin, bin /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin, resources /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/codex-resources, path /opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/codex-path)",
        "platform": "macos-aarch64",
        "version": "0.150.1"
      },
      "remediation": null,
      "durationMs": 0
    },
    "runtime.search": {
      "id": "runtime.search",
      "category": "search",
      "status": "ok",
      "summary": "search is OK (bundled)",
      "details": {
        "search command": "/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/codex-path/rg",
        "search command readiness": "file exists",
        "search provider": "bundled"
      },
      "remediation": null,
      "durationMs": 0
    },
    "sandbox.helpers": {
      "id": "sandbox.helpers",
      "category": "sandbox",
      "status": "ok",
      "summary": "sandbox configuration is readable",
      "details": {
        "approval policy": "OnRequest",
        "codex-linux-sandbox helper": "none",
        "execve wrapper helper": "/Users/shaswat/.codex/tmp/arg0/codex-arg06QuFb4/codex-execve-wrapper",
        "filesystem sandbox": "restricted",
        "network sandbox": "enabled"
      },
      "remediation": null,
      "durationMs": 0
    },
    "security.endpoint": {
      "id": "security.endpoint",
      "category": "security",
      "status": "ok",
      "summary": "no supported endpoint protection detected",
      "details": {
        "endpoint products": "none detected"
      },
      "remediation": null,
      "durationMs": 92
    },
    "state.paths": {
      "id": "state.paths",
      "category": "state",
      "status": "ok",
      "summary": "state paths and databases are inspectable",
      "details": {
        "CODEX_HOME": "/Users/shaswat/.codex (dir)",
        "active rollout files": "5271 files, 7021023063 total bytes, 1332009 average bytes",
        "archived rollout files": "0 files, 0 total bytes, 0 average bytes",
        "goals DB": "/Users/shaswat/.codex/goals_1.sqlite (file)",
        "goals DB integrity": "ok",
        "log DB": "/Users/shaswat/.codex/logs_2.sqlite (file)",
        "log DB integrity": "ok",
        "log dir": "/Users/shaswat/.codex/log (dir)",
        "memories DB": "/Users/shaswat/.codex/memories_1.sqlite (file)",
        "memories DB integrity": "ok",
        "queue DB": "/Users/shaswat/.codex/queue_1.sqlite (file)",
        "queue DB integrity": "ok",
        "sqlite home": "/Users/shaswat/.codex (dir)",
        "state DB": "/Users/shaswat/.codex/state_5.sqlite (file)",
        "state DB integrity": "ok",
        "thread history DB": "/Users/shaswat/.codex/thread_history_1.sqlite (file)",
        "thread history DB integrity": "ok"
      },
      "remediation": null,
      "durationMs": 7875
    },
    "state.rollout_db_parity": {
      "id": "state.rollout_db_parity",
      "category": "threads",
      "status": "warning",
      "summary": "rollout files and state DB thread inventory differ",
      "details": {
        "default model provider": "openai",
        "rollout DB active files": "5271",
        "rollout DB active rows": "8220",
        "rollout DB archive mismatches": "0",
        "rollout DB archived files": "0",
        "rollout DB archived rows": "0",
        "rollout DB duplicate DB paths": "0",
        "rollout DB duplicate rollout thread ids": "0",
        "rollout DB malformed file names": "0",
        "rollout DB missing active rows": "0",
        "rollout DB missing archived rows": "0",
        "rollout DB model providers": "openai=8220",
        "rollout DB rows": "8220",
        "rollout DB scan cap reached": "false",
        "rollout DB scan errors": "0",
        "rollout DB sources": "subagent:thread_spawn=6838, cli=1300, exec=58, subagent:review=17, vscode=7",
        "rollout DB stale row sample": [
          "/Users/shaswat/.codex/sessions/2025/09/23/rollout-2025-09-23T12-24-04-c4679dde-dc1d-42f2-9613-ab0f2524fe4c.jsonl",
          "/Users/shaswat/.codex/sessions/2025/09/23/rollout-2025-09-23T12-24-31-01997808-e0ca-7a80-8e7a-813cdd935e16.jsonl",
          "/Users/shaswat/.codex/sessions/2025/09/23/rollout-2025-09-23T12-25-33-01997809-d148-7883-82c9-283b5cc83c66.jsonl",
          "/Users/shaswat/.codex/sessions/2025/09/24/rollout-2025-09-24T11-38-02-01997d04-ad27-7d40-9c5e-a27779e946e1.jsonl",
          "/Users/shaswat/.codex/sessions/2025/09/24/rollout-2025-09-24T18-55-39-01997e95-5414-76d1-acaf-79d52ac01763.jsonl"
        ],
        "rollout DB stale rows": "2949"
      },
      "issues": [
        {
          "severity": "warning",
          "cause": "state DB rows point at missing or unusable rollout files",
          "measured": "2949 stale rows",
          "expected": "every state DB rollout path is a file on disk",
          "remedy": null,
          "fields": []
        }
      ],
      "remediation": null,
      "durationMs": 3420
    },
    "system.disk": {
      "id": "system.disk",
      "category": "disk",
      "status": "ok",
      "summary": "sufficient free disk space (618.7 GiB)",
      "details": {
        "CODEX_HOME available": "618.7 GiB",
        "failure threshold": "1.0 GiB",
        "warning threshold": "5.0 GiB",
        "worktree available": "618.7 GiB"
      },
      "remediation": null,
      "durationMs": 0
    },
    "system.environment": {
      "id": "system.environment",
      "category": "system",
      "status": "ok",
      "summary": "OS language en-US",
      "details": {
        "EDITOR": "set",
        "LANG": "en_US.UTF-8",
        "LESS": "set",
        "PAGER": "set",
        "VISUAL": "set",
        "os": "Mac OS 26.5.1 [64-bit]",
        "os language": "en-US",
        "os type": "Mac OS",
        "os version": "26.5.1"
      },
      "remediation": null,
      "durationMs": 6
    },
    "terminal.env": {
      "id": "terminal.env",
      "category": "terminal",
      "status": "ok",
      "summary": "terminal metadata was detected",
      "details": {
        "COLORTERM": "truecolor",
        "TERM_PROGRAM": "Orca",
        "color output": "disabled (stdout is not a terminal)",
        "effective locale": "en_US.UTF-8",
        "stderr is terminal": "false",
        "stdin is terminal": "false",
        "stdout is terminal": "false",
        "terminal": "unknown",
        "terminal size": "80x24",
        "terminal version": "1.4.190"
      },
      "remediation": null,
      "durationMs": 8
    },
    "terminal.title": {
      "id": "terminal.title",
      "category": "title",
      "status": "ok",
      "summary": "terminal title default",
      "details": {
        "terminal title activity": "true",
        "terminal title items": "activity, project-name",
        "terminal title project source": "cwd",
        "terminal title project value": ".codex",
        "terminal title source": "default"
      },
      "remediation": null,
      "durationMs": 0
    },
    "updates.status": {
      "id": "updates.status",
      "category": "updates",
      "status": "ok",
      "summary": "update configuration is locally consistent",
      "details": {
        "cached latest version": "0.150.1",
        "check for update on startup": "true",
        "last checked at": "2026-08-27T17:26:50.054342Z",
        "latest version": "0.150.1",
        "latest version status": "current version is not older",
        "npm update target": "/opt/homebrew/lib/node_modules/@openai/codex",
        "update action": "npm install -g @openai/codex",
        "version cache": "/Users/shaswat/.codex/version.json"
      },
      "remediation": null,
      "durationMs": 286
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archiving

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions