codex - 💡(How to fix) Fix Codex Desktop high CPU from unbounded active thread metadata and local history/list processing

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Codex Desktop can sustain high CPU/GPU usage when the local profile contains a large number of active threads with large title / preview / first_user_message metadata in ~/.codex/state_5.sqlite.

This appears to be a thread-list / sidebar / local-history scalability issue. The usage pattern is high-volume, but it is within expected Codex workflows: long local sessions, repeated agent/review/automation runs, and many project threads.

The hottest path we observed was not model inference. It was local state enumeration and metadata handling around active thread listing.

Root Cause

So the query starts from archived=0, scans a very large active set, and then sorts for the sidebar/list path. The cost is amplified because selected columns include large text metadata used as title/preview/first-user-message.

Fix Action

Fix / Workaround

lines: 22,546
function_call: 4,879
function_call_output: 4,875
thread_goal_updated: 3,998
token_count: 3,459
reasoning: 1,894
message: 1,061
agent_message: 1,002
custom_tool_call: 388
custom_tool_call_output: 388
patch_apply_end: 374
context_compacted: 28

Workaround / Mitigation Script

I also prepared a local mitigation script that may help other affected users diagnose and temporarily reduce the active-list load.

Code Example

active threads: 9,456
active metadata payload chars: 317,838,640
archived threads: 3,264
archived metadata payload chars: 328,436,582

---

active threads: 12,712
active metadata payload chars: ~403 MiB
one repeated review/agent group: 3,256 rows, ~201 MiB

---

SELECT ...
FROM threads
WHERE archived = 0
  AND preview <> ''
  AND model_provider IN (?)
  AND created_at_ms < ?
ORDER BY created_at_ms DESC
LIMIT ?

---

SEARCH threads USING INDEX idx_threads_archived (archived=?)
USE TEMP B-TREE FOR ORDER BY

---

thread id: <redacted local thread id>
created: 2026-05-25 22:26:26 KST
still active in state DB at inspection time
cwd: /Users/.../<project>
rollout JSONL size: ~38.7 MB and still growing
state DB tokens_used: 511,046,356
state DB has_user_event: 0

---

lines: 22,546
function_call: 4,879
function_call_output: 4,875
thread_goal_updated: 3,998
token_count: 3,459
reasoning: 1,894
message: 1,061
agent_message: 1,002
custom_tool_call: 388
custom_tool_call_output: 388
patch_apply_end: 374
context_compacted: 28

---

exec_command: 3,408
write_stdin: 1,271
update_plan: 196
get_goal: 3
create_goal: 1

---

thread_goal_updated count: 3,998
median interval: 6.148 seconds
p95 interval: 33.085 seconds
p99 interval: 54.032 seconds
largest observed gap: 5,015.697 seconds

---

write_stdin call
thread_goal_updated status=active tokens=13,127,963 seconds=34,696
function_call_output
token_count

---

time window: 2026-05-26 09:24:47-09:27:22 KST
rows: 923
estimated bytes: 10,259,493
largest row: 781,177 bytes
top target: codex_client::transport|TRACE
top target bytes: 9,016,481 across 12 rows
process: codex resume <same thread id>

---

codex resume <same redacted thread id>
child: python scripts/<project-audit>.py --skip-fetch --force
child CPU at inspection: ~100%
cwd: /Users/.../<project>

---

python3 scripts/codex_state_batch.py batch --policy config/sample-policy.json

---

python3 scripts/codex_state_batch.py batch --policy config/sample-policy.json --apply

---

candidate archive threads: 1,000
candidate metadata payload chars: 140,384,001
dynamic groups detected: 10
representative manifest entries planned: 5
cold archive candidates: 2,447 rollout JSONL files, 813,736,111 bytes
RAW_BUFFERClick to expand / collapse

Codex Desktop app-server high CPU from unbounded active thread metadata / thread-list path

Summary

Codex Desktop can sustain high CPU/GPU usage when the local profile contains a large number of active threads with large title / preview / first_user_message metadata in ~/.codex/state_5.sqlite.

This appears to be a thread-list / sidebar / local-history scalability issue. The usage pattern is high-volume, but it is within expected Codex workflows: long local sessions, repeated agent/review/automation runs, and many project threads.

The hottest path we observed was not model inference. It was local state enumeration and metadata handling around active thread listing.

Environment

  • Codex Desktop: 26.519.41501
  • Platform: macOS 26.4.1
  • Hardware: Apple Silicon
  • Local state DB: ~/.codex/state_5.sqlite
  • Local sessions: ~/.codex/sessions/.../rollout-*.jsonl

Observed Symptoms

  • Codex Desktop / codex app-server keeps using CPU even when no intentional user task is running.
  • Desktop renderer/GPU can also become warm depending on where the bottleneck surfaces.
  • Restarting Codex may temporarily change the active PID, but the expensive local-state path returns.
  • The problem correlates with large active local thread metadata and repeated thread-list/sidebar/reconnect activity, not with a single running model call.

Local Diagnostics

Current redacted profile statistics after one manual cleanup pass:

active threads: 9,456
active metadata payload chars: 317,838,640
archived threads: 3,264
archived metadata payload chars: 328,436,582

Before that cleanup, the profile had roughly:

active threads: 12,712
active metadata payload chars: ~403 MiB
one repeated review/agent group: 3,256 rows, ~201 MiB

The slow active thread-list query shape observed locally:

SELECT ...
FROM threads
WHERE archived = 0
  AND preview <> ''
  AND model_provider IN (?)
  AND created_at_ms < ?
ORDER BY created_at_ms DESC
LIMIT ?

Query plan:

SEARCH threads USING INDEX idx_threads_archived (archived=?)
USE TEMP B-TREE FOR ORDER BY

So the query starts from archived=0, scans a very large active set, and then sorts for the sidebar/list path. The cost is amplified because selected columns include large text metadata used as title/preview/first-user-message.

Long-running Goal Session Evidence

One long-running goal session also showed that active local sessions can keep the history/logging path warm for a long time.

Redacted local session:

thread id: <redacted local thread id>
created: 2026-05-25 22:26:26 KST
still active in state DB at inspection time
cwd: /Users/.../<project>
rollout JSONL size: ~38.7 MB and still growing
state DB tokens_used: 511,046,356
state DB has_user_event: 0

Rollout JSONL event counts at inspection time:

lines: 22,546
function_call: 4,879
function_call_output: 4,875
thread_goal_updated: 3,998
token_count: 3,459
reasoning: 1,894
message: 1,061
agent_message: 1,002
custom_tool_call: 388
custom_tool_call_output: 388
patch_apply_end: 374
context_compacted: 28

Tool-call distribution:

exec_command: 3,408
write_stdin: 1,271
update_plan: 196
get_goal: 3
create_goal: 1

The thread_goal_updated events were emitted very frequently:

thread_goal_updated count: 3,998
median interval: 6.148 seconds
p95 interval: 33.085 seconds
p99 interval: 54.032 seconds
largest observed gap: 5,015.697 seconds

Near the end of the sample, the rollout was still appending events such as:

write_stdin call
thread_goal_updated status=active tokens=13,127,963 seconds=34,696
function_call_output
token_count

So this was not just a large historical file. The active goal session was still emitting progress/heartbeat-like events and polling a running command.

logs_2.sqlite also showed a short retained window for this same thread:

time window: 2026-05-26 09:24:47-09:27:22 KST
rows: 923
estimated bytes: 10,259,493
largest row: 781,177 bytes
top target: codex_client::transport|TRACE
top target bytes: 9,016,481 across 12 rows
process: codex resume <same thread id>

In a 15 second observation window, the rollout file continued to grow by 2,627 bytes. The log table appeared to be subject to retention/pruning, so row counts can decrease while the max timestamp continues advancing.

Important confounder: this specific session also still had a real child task running under the Codex resume process:

codex resume <same redacted thread id>
child: python scripts/<project-audit>.py --skip-fetch --force
child CPU at inspection: ~100%
cwd: /Users/.../<project>

That means this particular long-goal sample should not be described as an entirely idle Codex session. It does show, however, that very long active goals can keep Codex's rollout/log/session-sync surfaces hot, and it can be hard for a user to tell from the Desktop UI which old goal/session is still driving local work.

Why This Looks Like A Product Scalability Bug

The trigger is heavy local usage, but the usage itself is not exotic for Codex:

  • users can create thousands of threads
  • some threads can be very long
  • agent/review/automation flows can create many repeated sessions
  • long-running goals can stay active for many hours and continue writing local progress/log events
  • sidebar, resume, reconnect, and archive reconciliation should have bounded cost regardless of total local history size

The app appears to treat local conversation history more like directly coupled UI metadata than like a large local product database. The list/sidebar path should probably operate on bounded metadata projections and lazy-load full history only when a specific thread is opened.

Related Issues

These seem adjacent or overlapping:

  • #21007 macOS Desktop UI lag with excessive codex disk writes despite low system resource pressure
  • #20435 Codex Desktop renderer spins at high CPU while codex MCP servers are idle
  • #12709 Codex Desktop on macOS becomes progressively slow and causes system-wide lag during long MCP-heavy sessions
  • #12644 Codex desktop app generates excessive file I/O, causing severe CPU load
  • #22283 Codex App becomes choppy when session history contains a large user message
  • #21211 Thread navigation/loading slows from unbounded metadata and eager large-history hydration
  • #22411 app-server loads ALL session files on every thread/list call
  • #18693 Desktop performance collapses in profiles with a few very large local conversation histories
  • #22053 Codex Desktop main Electron process pegs CPU while app-server is idle
  • #23849 Codex Desktop on macOS loses message hover after long session; main/renderer/GPU stay hot
  • #23851 Desktop: thread.archived can be reset by reconciliation after direct DB archive

This report may be the same family as #21211 / #22411, but the local evidence here points specifically at active state_5.sqlite metadata and query/index shape.

Workaround / Mitigation Script

I also prepared a local mitigation script that may help other affected users diagnose and temporarily reduce the active-list load.

It does not patch Codex itself. It is a user-side workaround.

Script gist:

https://gist.github.com/kangminlee-maker/f933aade364a02b176d899e5c8a2486d

The script:

  • reports active thread metadata size from ~/.codex/state_5.sqlite
  • detects repeated high-volume active thread groups dynamically
  • keeps one real active representative thread per group
  • archives older sibling threads
  • writes archive_groups.jsonl so archived siblings can be searched/restored
  • can create optional helper SQLite indexes for the observed thread-list query
  • can copy/move old archived rollout JSONL files to cold storage
  • defaults to dry-run and backs up state_5.sqlite before applying changes

Safety notes:

  • Do not use this for SQLite corruption or migration checksum mismatch issues.
  • Run the report/dry-run first.
  • Close Codex before applying changes.
  • Keep the generated backup.
  • Direct SQLite edits are unsupported and may interact with Codex reconciliation.

Example dry-run:

python3 scripts/codex_state_batch.py batch --policy config/sample-policy.json

Example apply after closing Codex:

python3 scripts/codex_state_batch.py batch --policy config/sample-policy.json --apply

Dry-run result on my affected profile:

candidate archive threads: 1,000
candidate metadata payload chars: 140,384,001
dynamic groups detected: 10
representative manifest entries planned: 5
cold archive candidates: 2,447 rollout JSONL files, 813,736,111 bytes

The mitigation is attached as a small script package. It is meant as diagnostic evidence and a temporary local workaround, not as an official fix.

Expected Behavior

Codex Desktop should keep thread-list/sidebar/reconnect paths bounded:

  • list views should read small metadata projections only
  • very large title / preview / first_user_message fields should be capped or summarized
  • thread history should be hydrated lazily
  • active sidebar queries should use indexes that satisfy both filtering and ordering
  • archive state should remain stable across reconciliation
  • heavy local profiles should not keep app-server / renderer / GPU hot while idle

Actual Behavior

Large active local metadata causes expensive repeated local processing. Depending on the profile and app state, the visible bottleneck can appear in SQLite, app-server CPU, Electron main/IPC, renderer, or GPU, but the common source is the unbounded local-history/list path.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING