Skip to content

Desktop app (macOS): idle node_repl visualization kernels accumulate (60–70 concurrent, ~600 MB), causing severe input lag #39816

Open

Description

@willtmc

What happened

During normal interactive use of Codex in the ChatGPT macOS desktop app, the embedded Codex engine accumulates dozens of idle cua_node/bin/node_repl processes — the sandboxed Node kernels spawned for the visualizations feature. Within ~45 minutes of app launch I observed 67 concurrent node_repl kernels, all at 0% CPU, ~10 MB RSS each (~580–700 MB combined), each wrapped in its own codex sandbox supervisor process, so the app's total process tree reached 138 processes / ~6.5 GB RSS.

Combined with the UI renderer growing to ~1.6 GB and staying busy (~40% CPU), this produced severe keyboard input lag in the app — keystrokes visibly queue. The machine (24 GB RAM) was pushed deep into swap (5.7 GB of 6 GB used within 45 minutes of a reboot).

Kernel reaping appears to exist but is far too slow: the count drifted 67 → 60 over about a minute of idle observation, while most kernels showed elapsed times of 18–20 minutes after their originating work had completed. At least one kernel had been alive 48+ minutes — the entire lifetime of the app process — suggesting some are never reaped. During an active session the spawn rate easily outpaces the reaper.

Evidence

Process count and per-kernel detail (usernames/paths redacted):

$ ps ax | grep -c "[n]ode_repl"
67    # later 61, 60 — slow drain while idle

$ ps -axo pid,ppid,%cpu,rss,etime,command | grep "[n]ode_repl" | head
  256 18253   0.0  10752    19:54 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
 7604 18253   0.0  10768    06:44 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
 8355 18253   0.0  10768    19:31 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
 8593 18253   0.0  10768    19:23 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
14346 18253   0.0   8000    48:29 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl   <-- alive since app launch
...
579 MB across 57 node_repl kernels (all 0.0 %CPU)

All kernels are children of the main codex engine process (pid 18253 above, itself at ~812 MB RSS). Each kernel also has an accompanying codex sandbox wrapper of the form:

/Applications/ChatGPT.app/Contents/Resources/codex sandbox \
  -c default_permissions="node_repl" \
  -c permissions.node_repl={filesystem = {..., "~/.codex/visualizations/2026/08/20/<uuid>" = "write", "<workspace dir>" = "write", ...}, network = {enabled = false}} \
  -- .../cua_node/bin/node --experimental-vm-modules /var/folders/.../kernel.js --session-id <id> --working-dir <workspace dir>

The ~/.codex/visualizations/<date>/<uuid> write grants indicate one kernel per visualization/REPL artifact.

Aggregate app footprint at the time:

ChatGPT/Codex total: 244% CPU, 6.5 GB RSS across 138 procs
  67  cua_node/bin/node_repl        (idle kernels)
  25  Codex Framework helpers       (Chromium; renderer at 1.6 GB RSS, ~40% CPU, 10+ min CPU time in 42 min)
  16  Resources/codex               (engine + sandbox wrappers)
  14  ~/.codex/computer-use/Codex
  10  cua_node/bin/node

Expected behavior

Visualization kernels should be terminated promptly (seconds, not tens of minutes) once their visualization/REPL work completes, or a small bounded pool should be reused. Idle kernels should never survive for the lifetime of the app.

Impact

Severe keyboard/input lag in the desktop app during and after heavy Codex use; system-wide memory pressure (swap exhaustion) on a 24 GB machine. Fully quitting and relaunching the app clears it, which is the current workaround.

Environment

  • ChatGPT macOS desktop app 26.818.22352 (6872), bundled Codex Framework 151.0.7922.170
  • macOS 26.5.2 (25F84), Apple Silicon (14-core), 24 GB RAM
  • No codex exec CLI runs were active — this is entirely the desktop app.

Activity

  1. lemonluck01 commented on Aug 24, 2026

    @lemonluck01

    Confirming this on macOS 26.6, ChatGPT.app 26.818.21641 (6849), Codex CLI 0.149.1.

    Same symptom, two additions:

    1. Not desktop-app-specific. Some of the leaked pairs here were children of a standalone codex CLI process (installed via @openai/codex npm package, /opt/homebrew/lib/node_modules/@openai/codex/...), not just ChatGPT.app's bundled Codex Framework. Different PPIDs, same leak pattern.

    2. Paired with an MCP stdio server, not just the node_repl kernel. Every leaked cua_node/bin/node_repl had a matching orphaned MCP server process (a user-configured stdio MCP server, spawned via the same session) sitting alongside it — same lifecycle, same non-reaping. So this isn't isolated to the visualization kernel; whatever spawns/tracks per-session child processes for code-mode sessions generally isn't reaping them.

    3. Zero drain, not slow drain. Where the original report saw a slow drift (67 → 60) over ~1 minute of idle observation, mine showed literally zero reaping across multiple checks spanning the investigation — and the oldest surviving pair dated to Wednesday, roughly 4-5 days of continuous accumulation, not just one 45-minute session.

    $ ps aux | grep -iE "ai-memory-mcp/server.mjs|cua_node/bin/node_repl" | grep -v grep | wc -l
    116
    
    $ ps aux | grep -iE "..." | awk '{sum+=$6} END {print sum/1024 " MB"}'
    689.8 MB
    
    # oldest surviving pair: spawned Wed 10AM, killed today (~4-5 days old)
    # all confirmed 0.0% CPU - genuinely idle, not doing background work
    

    Manual kill on the matched PIDs freed ~690 MB immediately with no ill effect on the live ChatGPT app or an active CLI session — consistent with this report's workaround, just without needing a full app restart.

    Environment: macOS 26.6 (25G72), Apple Silicon.

  2. Sergic commented on Aug 28, 2026

    @Sergic

    Additional reproduction data from a later build

    I can reproduce this on:

    • ChatGPT macOS app: 26.825.32147 (build 7303)
    • Bundled Codex CLI: 0.150.0-alpha.12.2
    • macOS 15.7.7 (24G720), arm64
    • MacBookPro18,1, 10 cores, 32 GB RAM

    Before a full app quit/relaunch (app uptime: ~2d 13h):

    • 122 cua_node/bin/node_repl processes
    • ~618 MiB combined node_repl RSS
    • Oldest observed kernel: ~1d 20h
    • Entire ChatGPT/Codex descendant tree: 807 processes and ~16.8 GiB summed per-process RSS
    • Main bundled codex process: ~2.4 GiB RSS and roughly 20–26% CPU
    • 432 generic Node processes consuming ~5.95 GiB combined RSS

    Large numbers of MCP-related processes had also accumulated:

    • 36 firecrawl-mcp
    • 39 server-sequential-thinking
    • 34 mcp-gitlab
    • 25 xcodebuildmcp
    • 8 figma-console-mcp

    The Electron sampler eventually logged Failed to collect child process snapshot because it attempted to invoke ps -p with hundreds of child PIDs.

    After fully quitting with Cmd-Q and relaunching, the app updated from 26.818.41509 to 26.825.32147:

    • At ~3 minutes: 4–5 node_repl; process tree ~38 processes / 4.0 GiB summed RSS
    • At ~8 minutes: 6 node_repl; process tree 51 processes / 5.1 GiB summed RSS
    • At ~18 minutes: 7 node_repl

    The count increased during consecutive code-mode/programmatic tool calls and did not return to baseline during observation.

    turn/start routing remained fast (64–83 ms), and after relaunch there were no workspace-auth or pubsub reconnect errors, but visible UI/system lag still occurred when Codex began processing a message. This suggests the lag is local runtime/process growth rather than model or network latency.

    The fresh launch also produced 48 MCP startup timeouts across multiple configured servers, which may amplify the process/resource growth.

    A full app quit clears the accumulated tree, but only temporarily. Archiving tasks does not affect the process leak.

  3. belongwithme commented on Sep 3, 2026

    @belongwithme

    Additional reproduction: serial title updates still accumulate node_repl processes

    I encountered what appears to be the same issue on macOS with 16 GB of RAM.

    Reproduction steps

    1. Fully quit and relaunch the Codex desktop app.
    2. Run a large number of conversation-title updates using the Codex app tool.
    3. Set concurrency to exactly 1.
    4. Wait for each set_thread_title call to complete before starting the next one.
    5. Inspect the process list after the operations finish.

    There was no Promise.all, worker pool, or parallel batch execution in the final reproduction.

    Actual behavior

    Even with strictly serial execution, the helper processes continued to accumulate:

    • node_repl processes: 102
    • Combined node_repl RSS: approximately 637 MB
    • Combined Codex-related RSS: approximately 1.56 GB
    • The system had entered significant memory compression and had very little free memory remaining.

    This suggests that limiting concurrency only reduces the transient peak. It does not prevent the leak because some node_repl processes are not reclaimed after the associated tool call completes.

    Fully quitting Codex releases the processes, but they accumulate again after continued tool usage.

    Expected behavior

    After a tool call completes, its node_repl helper should either:

    1. terminate promptly;
    2. return to a small bounded reusable pool; or
    3. be reclaimed after a short idle timeout.

    The number of helper processes and their total memory usage should remain bounded, especially when tool calls are executed strictly one at a time.

    Additional observation

    The tool call returns only a success or failure result and does not expose a process identifier or lifecycle handle. Therefore, clients cannot safely clean up the corresponding helper process without risking termination of a process still used by another task.

    This reproduction indicates that the problem is not limited to parallel execution; it also occurs during sequential tool calls.

  4. gjwang commented on Sep 6, 2026

    @gjwang

    Confirming this on a much newer build — and the leak here is significantly worse than what's described above, so leaving a data point in case it's useful for prioritization.

    Environment

    • ChatGPT macOS desktop app, bundled Codex Framework 152.0.7977.64
    • Bundled codex-cli 0.153.0-alpha.5
    • Plugin: unified-computer-use@openai-bundled (manifest version 26.901.20858)

    What happened

    Left the app running in the background (not actively interacting with it) for ~24 hours. Checked the process tree and found 440 leaked child processes, not just node_repl — the entire cua_repl MCP server unit (launch.mjs + node_repl + server.mjs + an artifact-template-picker helper) gets re-spawned as a fresh group roughly every 10 minutes, and none of the previous groups are ever reaped. So this isn't limited to REPL kernels from actual visualization use — it reproduces from the plugin's own idle/keepalive cycle with zero user interaction.

    $ ps -eo pid,ppid,etime,rss,stat,command | grep 'cua_node/bin/node' | wc -l
    440
    
    $ ps -eo pid,ppid,etime,rss,command | grep 'cua_node/bin/node' | sort -k3 | tail -6
      <pid>  <pid>  01-00:04:22   7.5M  .../cua_node/bin/node .../unified-computer-use/<ver>/scripts/launch.mjs
      <pid>  <pid>  01-00:04:22   7.7M  .../cua_node/bin/node_repl
      <pid>  <pid>  01-00:04:22   7.9M  .../cua_node/bin/node ./server.mjs
      <pid>  <pid>  01-00:14:22   4.6M  .../cua_node/bin/node .../unified-computer-use/<ver>/scripts/launch.mjs
      <pid>  <pid>  01-00:14:22   7.7M  .../cua_node/bin/node_repl
      <pid>  <pid>  01-00:14:22   7.8M  .../cua_node/bin/node ./server.mjs
    

    All 440 were in S (sleeping) state, combined CPU usage across all of them was ~7% (i.e. genuinely idle, not doing work), total combined RSS 9.2 GB. All were direct children of the main codex ... app-server process (the one hosting mcp_servers.codex_app / codex-app-tools).

    Unlike the original report's "slow drain" (67 → 60 over a minute of idle observation), in this case zero reaping occurred over the full 24-hour window — count only ever went up. Manually kill-ing the whole group of 440 processes was the only way to reclaim the memory; within seconds the app-server transparently respawned a fresh single group (3–6 processes), confirming the spawn side works fine and the problem is purely on the reap/lifecycle side.

    Expected behavior

    Same as above — idle cua_repl kernel groups from unified-computer-use should be terminated once their keepalive/health-check cycle completes, or the plugin shouldn't spawn a brand new group every ~10 minutes at all when there's no active REPL/visualization work outstanding.

    Impact

    Unbounded background memory growth (confirmed multi-GB within a day) with the app merely open in the background — no active Codex usage required to reproduce. Same workaround as above: fully quitting and relaunching the app (or manually killing the leaked process group) reclaims the memory until it reaccumulates.

  5. HashimTheArab commented on Sep 22, 2026

    @HashimTheArab

    Additional diagnostic data from a newer build; the controlled tests did not reproduce a worker leak.

    Environment: ChatGPT desktop 26.915.31945 (9922), bundled Codex 0.155.0-alpha.9.2, macOS 26.5.1, Apple Silicon, 36 GiB RAM.

    After ~19 hours of normal use across multiple tasks: 16 renderers (~3.15 GiB summed RSS), 11 CUA launchers, 11 app-tools servers, and 22 node_repl workers. RSS includes shared pages. The 11 worker groups matched startup events for persisted, unarchived tasks; hidden-thread accumulation was not established.

    Controlled checks: created two disposable tasks, each running one Python print command, then archived them and checked their specific worker PIDs. Both main worker groups exited; additional transient REPL workers were gone within 72 seconds of archival. A separate switch-away test retained four workers after 137 seconds, then released them on archival. No processes were manually killed.

    The installed desktop bundle has a three-hour inactivity TTL and a limit of ten eligible inactive tasks before unsubscribing; active/followed tasks are excluded. The full TTL/cap was not tested.

    Archive cleanup worked in these tests. Renderer memory and longer-term retention remain unexplained; this does not establish that the original issue is fixed.

  6. 0xdevalias commented on Sep 22, 2026

    @0xdevalias

    One useful distinction from a current macOS Desktop 26.903.71938 / Codex 0.153.4 audit: the many node_repl processes were downstream of retained loaded sessions, rather than independently owned kernels. One completed non-window task's node_repl and MCP fleet exited naturally about 60 s after thread/unsubscribe when the caller was apparently the final owner.

    That workaround is not universal: four completed ordinary tasks and one completed automation all returned unsubscribed yet remained in thread/loaded/list beyond 60 s, indicating another hidden owner. I have not reproduced this issue's exact visualization path, so this is a candidate diagnostic/workaround rather than a claim that it fixes visualization accumulation: map a kernel to its task, protect all UI/history/agent/approval owners, unsubscribe, wait >=60 s, and confirm the exact process exits. The missing product capability is subscriber diagnostics plus an explicit unload RPC.

  7. anon5376 commented on Sep 23, 2026

    @anon5376

    Same leftover-helper class on current macOS desktop, idle, no running thread and no built-in browser session.

    App 26.915.31945 (build 9922), Codex Framework 153.0.8010.48, Darwin 25.4.0 arm64 arm.

    ChatGPT/Codex helpers still held ~3.87 GB RSS across 68 processes. That includes many leftover cua_node node / node_repl children plus SkyComputerUseService at ~173 MB after Computer Use / the built-in browser was already closed.

    Closed #47519 in favor of this thread for the helper-reaping part.

  8. Isaac-b-ux commented on Oct 1, 2026

    @Isaac-b-ux

    Adding a data point from a newer build, where retained subagent threads look like the main driver.

    Environment: ChatGPT macOS desktop, Codex Framework 154.0.8037.57, bundled app-server; macOS 26 (Darwin 25.6.0); Apple Silicon, 16 cores, 128 GB RAM.

    After about 24h of app uptime (one app-server process):

    • 913 direct children of the desktop codex app-server, about 22.8 GB RSS. The whole ChatGPT tree was about 1,150 processes and 38 GB.
    • 115 retained per-thread MCP groups. Each group is 3× SkyComputerUseClient (computer-history mcp, messages mcp, event-stream mcp), node server.mjs for the code-review / codex-app-tools / openai-developers plugins, an mcp/server.mjs, and a cua-repl node_repl. That is roughly 8 processes per thread, started whether or not the thread ever calls those tools.
    • 68 of the 115 groups were 12–24h old. 44 groups started in the same minute (one subagent fan-out) and were still alive about 18h later.
    • In the same 24h the desktop created 113 subagent threads and 65 user threads, per session_meta.source in the rollouts.
    • Machine effect: load average 230–490 on 16 cores, about 40% of CPU time in the kernel, and a sluggish UI. Quitting ChatGPT clears it temporarily, but it rebuilds within hours with normal subagent use.

    Likely cause: the desktop's inactive-thread release path only unsubscribes conversations the window resumed and owns. Subagent and agent-created threads never qualify, and the app-server only unloads threads with no subscribers, so those threads and their MCP groups live until the app quits. Plugin MCP servers are also started eagerly per thread instead of on first tool use.

    Requests: (1) unload completed subagent and agent-created threads, or cap retained inactive threads; (2) start plugin MCP servers lazily; (3) add a config setting to cap loaded threads or MCP runtimes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingperformance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions