Windows desktop retains inactive task runtimes and Browser renderers, causing persistent main-process CPU

Resolved 💬 2 comments Opened Aug 15, 2026 by smigolsmigol Closed Aug 15, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Windows desktop retains inactive task runtimes and Browser renderers, causing persistent main-process CPU

Summary

Codex desktop on Windows retains inactive owner task runtimes and normal task Browser sessions.
Each loaded task eagerly owns its MCP runtime and child processes. The desktop declares a maximum
of four inactive owner threads and computes the overage, but the candidate function returns only
threads whose one-hour TTL expired. The overage is never enforced. Tasks left with active or
inProgress metadata are also excluded from TTL retirement.

Detached Browser pages separately accumulate to a hard-coded budget of 32 and remain live because
the budget check only suspends pages when the count is greater than 32. Together these defects left
the Electron main process consuming more than one core with no useful model work and caused visible
mouse and desktop jank.

Environment

  • Windows 11
  • Codex desktop package 26.810.4967.0
  • 32 logical processors
  • Built-in Browser used from multiple Codex tasks during one app session

The production manifest later named 26.810.7004.0, but the app's Store update checks still
reported NoUpdates, so this report is bound to 26.810.4967.0.

Reproduction

  1. Resume at least six Codex tasks during one desktop session.
  2. Complete the turns and switch away so only one task has an active view.
  3. Use built-in Browser pages in some tasks, then close the visible Browser tabs.
  4. Leave the other tasks idle beyond the intended grace period.
  5. Measure the process tree and inspect task unsubscribe plus Browser lifecycle diagnostics.

Observed result

  • final Codex process tree: 142 processes, 8.04 GiB private, 7.52 GiB working set
  • 17 repeated node_repl and KB launcher instances, plus 44 Python worker processes
  • oldest retained repeated helper: nearly 14 hours old
  • Electron main process used 1.47 cores in the final five-second idle sample
  • a WPR trace attributed 48.7 percent of process CPU samples to the initial browser main thread
  • physical disk throughput stayed near idle, with a near-zero queue
  • Browser persistence contained 74 pages across 19 conversations
  • lifecycle log contained 84 records with disposeAfterSessionActivity=false, 0 with true, and

0 tab-budget suspension events

The same app lifetime reached 21 repeated per-thread runtime sets. Eleven successful inactive
unsubscribe events across seven conversations later reduced the repeated sets from 21 to 17 and
the tree from 172 to 142 processes. No unsubscribe RPC error or shutdown timeout was found. The
Electron main process still used 1.47 cores, so successful late cleanup reduced the multiplier but
did not clear the hot loop.

Renderer creation times matched Browser webview attachment waves. Closing a Browser page emitted
the expected close event, but completed and idle normal task sessions did not retire their routes.

Shipped mechanism

Inspection of the installed desktop package shows:

  • inactive thread TTL: one hour;
  • maximum inactive owner threads: four;
  • over-budget count is calculated but not included in returned unsubscribe candidates;
  • active runtime status and stale inProgress turns suppress retirement;
  • a live detached Browser page budget of 32;
  • a 30-minute selected-tab protection window;
  • budget enforcement returns while the live detached count is less than or equal to 32;
  • normal task Browser routes default to disposeAfterSessionActivity=false;
  • session idle releases control but only disposes routes explicitly marked disposable.

This creates two stable bad states. The inactive-task budget is inert until TTL expiry, while stale
active state can bypass the TTL. The Browser system never crosses the threshold that would select
a page for suspension at exactly 32 live detached pages.

Expected result

Inactive owner tasks should unsubscribe after a short grace period and the app-server should retire
their MCP runtimes. Idle detached Browser pages should be suspended or destroyed after protected
work ends. Archiving or deleting a task should remove its persisted Browser state. An idle desktop
with one active task and no Browser control should not keep one CPU core busy.

Suggested acceptance test

  1. Resume six owner tasks, end all turns, and keep only one task view active.
  2. Assert that the two oldest inactive owners are unsubscribed without waiting one hour.
  3. Wait for app-server unload and assert retirement of their MCP child-process sets.
  4. Materialize 32 detached Browser pages, end control, and wait beyond protection.
  5. Assert renderer count falls below the budget without opening a 33rd page.
  6. Assert low Electron main-process CPU during a fixed idle sample.
  7. Archive half the tasks and assert removal of their persisted Browser page records.

The inactive-owner candidate set should be the de-duplicated union of the oldest over-budget IDs
and TTL-expired IDs. Stale active or inProgress state also needs a real-work lease or watchdog.
For Browser pages, a lower or pressure-aware Windows budget, >= enforcement at the limit, and
route disposal when no protected page or active control remains address the second failure.

A supported diagnostic should show loaded tasks, subscriber state, MCP runtime count, Browser
pages, and renderer count, with safe unload and close-stale-pages actions.

Scope boundary

The public app-server already implements thread/unsubscribe, bounded shutdown, MCP runtime
shutdown, archive teardown, and idle unload after subscribers leave. The inactive-owner policy and
Browser manager are in the proprietary desktop shell. Evicting subscribed threads in the public
app-server would violate the client contract, so the primary fix belongs in Codex desktop.

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 12 days ago

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

  • #38714
  • #38751
  • #38716
  • #38308

Powered by Codex Action

smigolsmigol · 12 days ago

After reviewing the suggested duplicates and the existing main-process investigation, this report combines several already tracked failures:

  • Electron main-process CPU and system-wide mouse stutter: #38716 and #38518
  • retained Code Mode and node_repl workers: #38714
  • eager restoration and retention of persisted Browser pages: #38751
  • related Browser cleanup crash behavior: #38308

The new source-level worker-retirement evidence has been moved to #38714. The Browser budget and disposal evidence has been moved to #38751. I am closing this issue as an umbrella duplicate so maintainers have one owner for each failure path.