Codex.app GUI: MCP child processes not reaped after task completion — 1300+ zombies, 37GB memory leak
Codex.app GUI: MCP child processes not reaped after task completion — 1300+ zombies, 37GB memory leak
What version of Codex CLI is running?
codex-cli 0.98.0 (Codex.app GUI wrapper)
What subscription do you have?
ChatGPT Pro
Which model were you using?
o3 (via Codex.app GUI)
What platform is your computer?
macOS 26.3 (25D125), Apple M4 Max, 64GB RAM, arm64
What issue are you seeing?
Codex.app spawns codex exec --full-auto worker processes for each worktree but never reaps them or their MCP child processes when tasks complete. Over multiple audit sessions, this accumulated 1,319 zombie Codex processes and 1,537 node processes consuming \~37GB RSS + 40GB swap on a 64GB machine, causing severe system-wide slowdown.
Root cause analysis
Each Codex.app task creates:
- 1×
codex exec --full-auto --skip-git-repo-check --json -(CLI worker) - 4×
oh-my-codexMCP servers (state, memory, trace, code-intel) - 1× Serena MCP server (via
uv tool uvx) - 1×
uvprocess for Serena
≈ 7 processes per task. None are killed when the task completes.
With 12 git worktrees created by Codex.app (detached HEAD, pointing at old commits), this produced:
- 12 worktrees × \~110 child processes = \~1,320 sleeping processes
- Combined RSS: \~37GB (mostly npm/node/uv MCP servers)
- Swap usage: 39.4GB (on 64GB physical RAM)
When Codex.app (PID 19947) was killed, 2 additional codex exec workers (launched Friday and Saturday) were reparented to launchd (PPID=1), confirming they were never properly cleaned up.
Process tree snapshot (before cleanup)
Codex.app (PID 19947, 279MB)
├── codex exec --full-auto (PID 19970, 123MB)
│ └── 880× node/npm/uv children (27GB total)
│ ├── npm (236MB each, ×2)
│ ├── npm (140MB each, ×4)
│ ├── uv (91MB each, ×2)
│ └── node (77MB each, ×dozens)
├── Codex Helper Renderer (PID 20018, 602MB)
└── Codex Helper (PID 19971, 101MB)
Orphaned (PPID=1, reparented from dead Codex.app sessions):
├── codex exec --full-auto (PID 59326, Fri 23:59)
│ ├── oh-my-codex/state-server.js
│ ├── oh-my-codex/memory-server.js
│ ├── oh-my-codex/trace-server.js
│ ├── oh-my-codex/code-intel-server.js
│ └── serena start-mcp-server
└── codex exec --full-auto (PID 59747, Sat 22:05)
└── (same MCP stack)
Memory impact
<!-- linear:table-colwidths:200,200,200,200 -->
| Metric | Before cleanup | After cleanup | Delta |
| -- | -- | -- | -- |
| Swap used | 39.4 GB | 8.0 GB | -31 GB |
| Codex processes | 1,319 | 0 | -100% |
| Node processes | 1,537 | 17 | -99% |
| Free pages | 82K | 2.3M | ×28 |
Worktree state at time of discovery
All 12 worktrees were detached HEAD on old commits (2+ phases behind current main), confirming tasks had completed long ago:
/Users/drg/.codex/worktrees/0585/medical-ai 627d44e (detached HEAD)
/Users/drg/.codex/worktrees/0b7b/medical-ai 627d44e (detached HEAD)
/Users/drg/.codex/worktrees/2a60/medical-ai 4d53e7d (detached HEAD)
... (12 total, all on 2 old commits)
Current HEAD: 71aefff — none of the worktrees were anywhere near current.
What steps can reproduce the bug?
- Use Codex.app GUI to run multiple tasks on a git repository (especially with MCP servers configured via oh-my-codex)
- Let tasks complete normally
- Wait a few hours / run more tasks
- Check process count:
ps aux | grep -c codex - Check memory:
ps aux | grep codex | awk '{sum+=$6} END {printf "%.0f MB\n", sum/1024}'
Accumulation is proportional to number of tasks × MCP servers configured.
What is the expected behavior?
When a Codex.app task completes:
- The
codex execworker process should be terminated - All MCP child processes (oh-my-codex servers, Serena, uv) should be killed via process group signal
- The git worktree should be cleaned up if the task is done (or at minimum, child processes should not persist)
What is the actual behavior?
- Worker processes and their entire MCP subtree remain alive indefinitely
- No cleanup occurs on task completion, app quit, or even app crash (reparented to launchd)
- Memory grows unboundedly with each task
Relationship to existing issues
- CLI-494 (fixed, Oct 2025):
start_kill()withoutwait()inexec.rs— same root cause pattern (missing process reaping), but fix only covered timeout/Ctrl+C in CLI, not GUI lifecycle - CLI-3017 (Jan 2026): CLI memory leak causing crashes
- [#12414](<https://github.com/openai/codex/issues/12414>) (Feb 2026, open): Unbounded memory growth when idle on v0.104.0
This issue is distinct because it specifically affects Codex.app GUI and its interaction with MCP server child processes — the GUI spawns long-lived codex exec workers that themselves spawn MCP servers, creating a deeper process tree that the existing cleanup logic does not handle.
Suggested fix
- Process group kill:
codex execworkers should usesetsid()/ process groups so all children (MCP servers) can be killed with a singlekillpg()on task completion - Worktree lifecycle: Codex.app should track active worktrees and clean up stale ones on startup (e.g., remove worktrees whose tasks are no longer active)
- Heartbeat/watchdog: MCP servers spawned by
codex execshould monitor their parent and self-terminate if the parent dies (check PPID periodically, or use a pipe/fd that breaks on parent death)
26 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I put up a draft fix for this path: https://github.com/openai/codex/pull/12505
Scope is intentionally narrow and low-risk:
features.thread_listener_cleanupas an experimental flag (default off)I am currently seeing memory pressure in app usage with 5+ concurrent threads, so this is aimed at reducing retained in-memory thread/listener state without changing default behavior.
Given the updated contribution policy (invitation-only PRs), #12505 is currently a draft patch proposal to make discussion concrete. If this direction aligns with maintainer intent, would someone from the team be willing to explicitly invite that PR (or suggest a narrower scope)? I can provide additional repro/profiling details from macOS sessions where memory pressure climbs with 5+ concurrent threads.
Experiencing this on Linux / codex-cli 0.106.0
Reproducing the same issue. Here's a breakdown of the two distinct leak patterns I'm seeing:
Environment:
Crash:
failed to spawn thread: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }Two distinct leak patterns observed:
waitpid): A single long-running codex session accumulated 41 zombie<defunct>children — all from a Python stdio MCP server. The MCP server forks subprocesses for tool calls, but the codex parent never callswaitpid()to reap them.pstreeoutput:``
``codex,49983
|-(MainThread,105811) <defunct>
|-(MainThread,125138) <defunct>
|-(MainThread,131433) <defunct>
... (41 total zombies)
The combination of both leaks led to thread exhaustion and the crash. This appears to be the same root cause as #4726 (closed) and #6201 (closed) — neither of which fully resolved the lifecycle management for stdio MCP servers.
I can confirm a very similar issue on macOS, and I captured a full CLI process snapshot on March 11, 2026.
Environment
26.305.95014.3.1 (23D60)context7,stripe,playwrightWhat I observed
607total processes5760threads15G used,74M unused6608M compressor6342612swapins8519545swapoutsapp-serverPID:codex app-serverPID6030660306:7372were MCP launchers24 x npm exec @upstash/context7-mcp24 x npm exec @stripe/mcp --tools=all24 x npm exec @playwright/mcp@latest148processes totalThis does not look like a bounded “currently active work only” baseline. It looks like repeated MCP launcher accumulation over time under the same long-lived
codex app-server.Long-lived duplicated MCP launcher examples
8hold:npm exec @playwright/mcp@latestnpm exec @stripe/mcp --tools=allnpm exec @upstash/context7-mcp4hold:playwright/stripe/context73hold:1hold:50mold:20h+old:app-serverImportant distinction
#12333that duplicate MCP instances may be expected while subagents/threads are active.codex app-serverPID over many hoursThis feels closely related to:
#12491#11324#12976#10710Question for maintainers
#10710have covered this desktop app path as well?Thanks for taking a look. The snapshot seems to point to unbounded MCP process accumulation over time rather than short-lived fanout from currently active work, so hopefully it helps narrow the cleanup path.
This looks related to
#11324, but I wanted to add a narrower app-server angle that may help isolate root cause.I traced a reproducible case where the leaking MCP children are not orphaned from dead workers; instead they remain attached to the long-lived desktop
codex app-serverprocess after conversations are no longer active.The key detail from source review is that MCP servers are conversation-scoped and the intended unload path is
thread/unsubscribe. When the last subscriber unsubscribes, the app-server shuts down the thread and unloads it. However, on connection removal the current app-server code path retains zero-subscriber threads instead of unloading them, so theirMcpConnectionManagers never drop and the stdio MCP child processes stay alive.I posted the fuller write-up and evidence here:
#11324comment: https://github.com/openai/codex/issues/11324#issuecomment-4066938546So this may be the same family of leak as this issue, but specifically through desktop thread lifecycle / unload behavior rather than only worker reaping.
Same bug family on my Mac
@masvelio and @gabrielbryk this looks very close to what I hit. @RemarkRemedy also makes sense to me here, but i think there is one more phase after that app-server retention phase.
My setup
26.311.21342 (build 993)when this built upDarwin 25.3.0on Apple Silicon2.5 days18separate conversations/tasks in that windowcontext7,playwright,chrome-devtools,webflow mcp-remote, and one custom Python MCPWhat I saw
Each conversation was leaving its own MCP bundle under the long-lived
Codex.app -> codex app-servertree. Finished conversations were not going back to a small baseline.The extra part on my side
The main thing i did not see called out clearly yet is what happened on quit.
When I quit Codex from the Dock on March 17, 2026, most children died, but cleanup was only partial:
100to about10PID 1 / launchdMarch 9, 2026chrome_crashpad_handlerprocesses still alive fromMarch 9andMarch 14I also saw what looks racey. In one spawn generation, most siblings from that batch were gone, but one
twitterapi-docs-mcpsurvivor was still there by itself.Why I think this matters
#10710makes me think the stdio process-group cleanup on drop exists already. So maybe there are two gaps:One control point from the same machine: Claude Code via Superset.app only had about
11MCP processes from3active sessions, and those were cleaned up normally. So this did not look like a generic macOS "too many MCPs" problem.Small timing clarification on my earlier comment
One detail i want to tighten up from my earlier note here:
The orphan set i described was real right after
Cmd+QonMarch 17, 2026.At that moment, most Codex child processes died, but i still had a small
PID 1 / launchdresidue:Later, after I reopened Codex and closed it again, most of those leftovers finally disappeared.
So my main point is not "every orphan stayed forever".
It is: one quit cycle still left a small orphan set when the expected number should have been zero.
That still feels consistent with the two-part picture @gabrielbryk and @RemarkRemedy were circling around:
Fix implementation available
I hit this exact issue on a 16GB RAM Linux machine — running multiple Codex sessions with MCP servers (desktop-commander, context7, playwright, exa) accumulated 562 orphaned processes consuming 26GB of swap, triggering OOM kills and complete system freezes.
After investigating the source, I traced the root cause and implemented a fix. The branch is here:
👉 https://github.com/whatsgrowth/codex/tree/fix/mcp-process-cleanup (diff)
Root cause
McpConnectionManagerholds aHashMap<String, AsyncManagedClient>but has no explicit cleanup. Wrapped inArc<RwLock<>>insideSessionServices, theArc<Session>reference count may never reach zero (held by spawned tasks, event channels, etc.), soProcessGroupGuard::drop()never fires — and MCP server processes live forever.The low-level cleanup already works correctly:
ProcessGroupGuardinrmcp_client.rsproperly implementsDropwithkillpg(SIGTERM)→ 2s grace →killpg(SIGKILL). The problem is simply that it's never triggered.The fix (48 additions, 0 deletions, 2 files)
1.
core/src/mcp_connection_manager.rs— Addshutdown()method:2.
core/src/codex.rs— Call it inSession::shutdown():3.
core/src/mcp_connection_manager.rs— Safety netDrop:4.
core/src/codex.rs— Also clean up inrefresh_mcp_servers_inner:Verified
cargo check -p codex-core✅cargo test -p codex-core --lib -- shutdown— 7/7 pass ✅pgrepconfirmed all MCP processes were killed on exit ✅Could not open a PR directly (repo restricted to collaborators), so posting the fix here. Happy to rebase if needed.
Additional macOS desktop-app evidence for this issue on April 6, 2026.
I verified a live Codex.app session where this is happening with exactly one configured Playwright MCP server in
~/.codex/config.toml:Current live parent process:
/Applications/Codex.app/... codex app-server --analytics-default-enabled68203All leaking Playwright MCP descendants are parented to that single live app-server, not to old dead app instances.
Observed process tree totals:
55npm exec @playwright/mcp@latestwrapper processes55node .../playwright-mcpchild processes110total Playwright MCP descendantsObserved RSS:
241.6 MB106.8 MB348.4 MBImportant details:
This looks consistent with an app-side stdio MCP lifecycle/reaping bug rather than a user config problem or a one-off stale subtree.
Related issue that also seems relevant from the Playwright side: #14773.
Still reproducing on latest versions as of 2026-04-15.
Environment
0.119.0-alpha.28codexCLI0.120.0(invoked ascodex mcp-serverby an external client)Evidence —
ps -eo pid,etime,command:4
playwright-mcpchildren, oldest at 11h29m. 4codex mcp-serverparents, oldest at 11h34m. None correspond to an active session; they are leaked from sessions that ended hours ago./tmp/codex-playwright-mcp-cacheat 253 MB.Consistent with the 2026-04-06 Playwright-MCP comment above — still present on 0.119/0.120.
Still reproduces on v0.120.0 / Codex Desktop 26.409.20454. We observed 213 leaked
@playwright/mcpprocess pairs (426 processes, 13.6 GB RSS). Filed as #17832.PR #17223 (linked to #16895, merged April 10) fixed WebSocket client disconnect only. Subagent MCP teardown remains broken. See also #17574.
Root cause analysis with proposed fix: #17832 (comment)
https://github.com/openai/codex/issues/17832#issuecomment-4247026597
Update (2026-04-19): patch ready on branch
RedesignedRobot:codex:fix/mcp-subprocess-cleanup, rebased on currentmain,cargo check -p codex-core -p codex-mcpclean. 2 files, +23/-2, covers both theOp::Shutdownpath and thesubmission_loopchannel-close fallthrough. Awaiting invitation to open as PR per the invitation-only contribution policy.I get the memory leak on the Linux codex app port as well https://github.com/EvickaStudio/codex-app-linux-port
It spawns zombie MCP processes that eat 8gb of ram, my system regularly has to kill my browser tabs to keep the system from crashing. I think it's related to playwright as I have playwright as well.
To reproduce:
hit the same class of leak running a bunch of stdio MCP servers on macOS. the real culprit is process group handling, if you spawn the child without setsid/setpgid the parent can't send SIGTERM to the whole tree on exit, so npm/uv wrappers leak their node grandchildren. also node/npm wrappers don't forward SIGTERM to the real mcp binary by default, you need to exec the server directly or wrap with tini. and any stdio mcp needs an EOF-on-stdin watchdog inside the server so it self-exits if the parent dies without signaling. zombie reaping is table stakes but won't fix the reparented-to-launchd survivors, only pgid teardown does.
<img width="2481" height="1169" alt="Image" src="https://github.com/user-attachments/assets/49a0f852-aec3-4693-9f0a-8672ed531ce5" />
I got a new codex client so this is a different reproducibility process.
Note: Chromium is running on my system as a flatpak and codex isolates the codex renderer and MCP processes.
Personally I just disabled the oh my codex MCP servers to save memory and slow down the accumulation of zombie processes. As for every conversation it spawns more duplicate zombie MCP processes that never get freed. This is a bug where for each conversation it just creates MCP servers, but it should be shared between conversations on start.
I’m seeing what looks like the same Codex Desktop MCP lifecycle leak on macOS.
Environment:
/Applications/Codex.app/Contents/Resources/codex app-serverchrome-devtools-mcp,gitnexus mcp, Codexnode_replSymptoms:
Observed before cleanup:
chrome-devtools-mcp: about 368 matching processesgitnexus mcp: about 186 matching processesnode_repl: about 93 matching processeschrome-devtools-mcpalone was roughly 19 GB RSS in one snapshotgitnexus mcpwas roughly 8 GB RSS in one snapshotRelevant process pattern:
Manual cleanup results:
chrome-devtools-mcp,gitnexus mcp, andnode_replprocesses immediately reduced the process count.chrome-devtools-mcp: 0 initially, later restarted only when neededgitnexus mcp: 2node_repl: 1Expected behavior:
Actual behavior:
+1 confirming this is still active on Codex Desktop 26.422.x as of 2026-04-26, with a different MCP/feature manifestation worth naming explicitly: the Computer Use subsystem under
codex app-server. This reinforces what @bingyizhou6u flagged on 2026-04-25 with concrete pid-tree numbers.Environment
codex app-server --analytics-default-enabledparentProcess tree at peak
Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient(4–16 MB RSS each)Codex.app/Contents/Resources/node_repl(4–7 MB RSS each)codex app-serverpid (not adopted by launchd, not detached)Why Activity Monitor shows 24+ GB for "Codex"
The individual RSS numbers above are tiny — the headline number is macOS's compressor pool, not resident memory.
vm_statshowed:\
\\\Free: 1.0 GB
Active: 14.2 GB
Inactive: 14.1 GB
Wired: 8.0 GB
Compressor: 25.7 GB ← here
Swap I/O: 66K in / 399K out
\
\Compressed pages get attributed back to whichever process owned them — so 100+ small worker working sets that got compressed under pressure and never freed showed up as a single 24.5 GB "Codex" attribution and triggered the macOS "Your system has run out of application memory" Force-Quit dialog.
Workaround (narrowly-targeted, does NOT touch
Codex.app,codex app-server, the active worker pool, or any other process)\
\\bash\pkill -f 'Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient'
pkill -f 'Codex.app/Contents/Resources/node_repl'
\
\After running, free RAM moved 1.0 → 2.7 GB instantly; Codex respawned the correct ~4 workers from the active pool. Confirms these are leaked, not active.
Repro signal (one-liner check):
\
\\bash\ps -axo pid,command | grep -cE 'SkyComputerUseClient|node_repl'
\
\Healthy: 4–8. Leak active: 20+ and growing with uptime. Counts grow monotonically with Computer Use automation runs over time.
Suggested fix surface (consistent with #18881 and #17832): whatever invokes the Computer Use MCP tool needs to
child.wait()/ SIGTERM the spawned worker pair when the tool call resolves, the same lifecycle gap the broader MCP-reaping issue describes — Computer Use is just one more affected MCP host in the same pattern.Adding evidence on two more stdio MCPs in the same leak family on Codex Desktop.
Environment
26.422.30944on macOS Darwin 24.6.0, 10-core arm64, 24 GB RAMcodex app-server --analytics-default-enabledparent (PID 9529)playwright,lighthouse(local),supabase,herokuAffected MCPs (in addition to those already reported)
heroku(heroku mcp:start):bash heroku mcp:start→ 3 levels of bash wrappers →node run mcp:start→node heroku-mcp-server.mjsheroku plugins:inspect @heroku/plugin-aias part of plugin discovery on every startupheroku mcp:startbash wrappers parented to app-serverheroku-mcp-server.mjsnode processesnpm exec heroku@latest --replheroku plugins:inspect @heroku/plugin-aiprocesses — many with PPID=1 (parent bash chain died, signals not propagated; orphans reparented to launchd)setsid/killpg, Heroku's bash wrapper chain detachesplugins:inspectfrom the process group, so existing orphans wouldn't be cleaned up retroactively. New spawns under a process group would be fine.lighthouse(local stdio MCP):node /Users/steve/.codex/lighthouse-mcp-local/server.jsconfiglighthouse-mcp-local/server.jsprocesses + 7Codex.app/Contents/Resources/node_replprocesses, all parented to the live app-servernode_replappears paired with a lighthouse spawn — confirms whatbingyizhou6uandleojkwanreported aboutnode_replbeing part of the stdio MCP host patternSystem impact at peak
Workaround applied
enabled = falseon[mcp_servers.heroku]and[mcp_servers.lighthouse]in~/.codex/config.tomlpkill -f "lighthouse-mcp-local/server.js", same for heroku patternslaunchdjob) that detects duplicates of allowlisted MCP commands and kills all but the newest PID, until the upstream fix landsNotes for the suggested fix
The
m13vcomment on this issue covers the right surface. Adding two practical points from the heroku case:setsid+killpgin Codex would solve it cleanly — even with Heroku's leaky bash chain, every descendant inherits the process group at fork time.exec, an EOF-on-stdin watchdog inside the MCP server (perm13v) is the only thing that will reliably kill currently-running orphans whose parent died ungracefully.setsid/killpgis the right primary fix; the EOF watchdog is a robustness backstop.Happy to provide more raw
psoutput or repro logs if useful.I can reproduce a closely related variant of this on macOS, but specifically with the bundled Computer Use helper processes.
Environment:
26.422.30944(2080)26.3.1(25D2128)arm64computer-use@openai-bundled/computer-useplugin version1.0.758What I observed on April 28, 2026:
~/.codex/config.tomlhadplugins."computer-use@openai-bundled".enabled = true107instances of:./Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClient mcp/Applications/Codex.app/Contents/MacOS/Codex->
/Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabled-> many
SkyComputerUseClient mcp~/.codex/plugins/cache/openai-bundled/computer-use/1.0.758/.../SkyComputerUseClientSkyComputerUseClientprocesses alone was about1.26 GB(average ~11.8 MBeach).2026-04-28 08:10, so these were not short-lived one-shot helpers.Important narrowing signal:
pkillagainstSkyComputerUseClient/SkyComputerUseService.pwd,date,sed ... package.json) and repeatedly re-checked process counts.0, and neitherSkyComputerUseClientnorSkyComputerUseServiceimmediately came back.That makes this look narrower than “all Codex activity leaks MCP children”.
It looks more like a lifecycle / teardown bug in the bundled
computer-useplugin path, or in howapp-servermanages that MCP/helper subtree after the helper has been activated.So this may be the same general cleanup class as this issue, but with a more specific reproduction target:
computer-use@openai-bundledSkyComputerUseClient mcpcodex app-serverafter prior usage instead of being reapedIf helpful, I can also provide a process-tree snapshot and exact command output showing the parent/child relationships.
Additional repro: Computer Use /
SkyComputerUseClientCPU fanoutI hit what looks like the same MCP lifecycle/leak family, but with a narrower Computer Use-specific trigger that may help isolate one upstream fix surface.
Environment
26.506.31421(CFBundleVersion2620)26.3.1(25D771280a)25.3.0,arm64computer-use@openai-bundledSymptom
Codex Desktop would spike into the 200-300% CPU range on normal prompt completions. CPU temps went over 220°F and the machine became close to unusable.
At peak I observed:
In one spike, the MCP/process fanout under the same
codex app-serveralso multiplied:The local Codex log DB was also writing heavily during the spike:
Failure mode 1:
SkyComputerUseClientinserted intoturn-endedMy
~/.codex/config.tomlhad been rewritten into this shape:That means ordinary prompt completions were routed through
SkyComputerUseClientbefore reaching the lightweight previous notifier.As a result, this path could fire on every normal response:
That seems like the wrong place for
SkyComputerUseClient. The user-facingnotifyhook is a high-frequency lifecycle hook for normal prompt completions. It should stay lightweight and bounded.Workaround for failure mode 1
I backed up
~/.codex/config.tomland restorednotifyto a lightweight wrapper:Then I fully restarted Codex Desktop to clear the already-spawned MCP/process tree.
After restart and another prompt:
Initially, this stopped the largest runaway. Computer Use could remain enabled for a short test. The critical fix for this first failure mode was removing
SkyComputerUseClientfrom theturn-endednotify wrapper path.Failure mode 2: Computer Use fanout even after
notifystays cleanAfter more testing, I reproduced a second related failure mode.
notifystayed clean:But with
computer-use@openai-bundledenabled, normal prompt/session activity still caused Computer Use-related children to respawn undercodex app-server:This points to a deeper Computer Use / MCP lifecycle problem, not a general claim that all user MCP servers are bad. The important narrowing signal is:
notifywrapper is one reproducible triggernotify,computer-use@openai-bundledcan still recreateSkyComputerUseClient/ MCP child-process fanoutSkyComputerUseClientfanout in my local containment testSo I think
SkyComputerUseClientshould only wake for explicit Computer Use actions. It should not be started by normal prompt completion or ordinary session lifecycle work.Suggested upstream fix
I think there are three related fixes here:
SkyComputerUseClientintonotify = ["...", "turn-ended"].turn-endedfires after normal prompt completions. It should not bootstrap Computer Use / MCP plumbing unless a Computer Use action was explicitly requested.If Codex sees:
``
toml
``notify = [".../SkyComputerUseClient", "turn-ended", "--previous-notify", "..."]
it should unwrap it back to the previous lightweight notifier, or at minimum warn the user and refuse to use
SkyComputerUseClientas a lifecycle notify handler.codex app-server.When
computer-use@openai-bundledis enabled,SkyComputerUseClient mcpinstances should converge back to a small stable baseline after tool/session work. If normal prompt activity can create repeated Computer Use client stacks, those children need explicit ownership, teardown, and process-group cleanup.This seems related to the broader MCP child lifecycle issue in this thread. The additional narrowing here is that Computer Use /
SkyComputerUseClientcan reproduce the runaway both through a badnotifywrapper and through plugin lifecycle/fanout even afternotifyis corrected.Quick user-side check
Anyone hitting this can check:
If
notifystarts withSkyComputerUseClient, try backing up the config, restoringnotifyto the previous lightweight notifier, and fully restarting Codex Desktop.If
notifyis clean butSkyComputerUseClient mcpkeeps multiplying, try disabling onlycomputer-use@openai-bundledas a containment test. I would not treat unrelated MCP servers as the first suspect unless their own process counts are also multiplying.The bug reported by the OP has been fixed. If you are seeing a similar behaviors in the latest version of the app, please open a new bug report.
Update after deeper local repro/debugging:
I want to correct the likely root-cause framing from my earlier comment. The Computer Use / MCP child-process fanout may have amplified the issue, but the strongest evidence now points to a huge text-like workspace artifact triggering the Electron/V8 hot path.
In the affected workspace, there was a generated embedded HTML file around 205MB. After moving that file out of the Codex-watched project root, the behavior improved substantially. The file was not an .xlsx issue; the Excel files in the project were small and Codex did not appear to have them open.
My current working theory is:
So I would reframe this as a possible Electron/workspace-ingestion bug involving very large text-like artifacts. MCP fanout may make the failure worse, but it may not be the original cause in this repro.
Suggested product-side guardrails:
This seems especially important for creative/game projects where generated HTML boards, embedded asset boards, image references, and exported visual docs can easily become hundreds of MB.
Additional sanitized macOS evidence matching this issue's MCP-child lifecycle failure.
Environment
Mac16,11, 24 GiB RAMObserved process tree after reboot
Within about 29 minutes of app/session recovery:
The earlier Jetsam snapshot recorded four active
codexworkers. Their ChatGPT/Codex coalition contained 1,201 active processes and about 48.89 GiB aggregate footprint.A normal AppleScript quit request returned successfully but the ChatGPT root and Codex worker remained alive. I then captured the exact ChatGPT tree and terminated only those 502 members, rechecking process name and start time before any forced signal. Without rebooting:
This machine also experienced a watchdog kernel panic after compressor segments reached 100% with 69 swapfiles. Another agent application contributed additional MCP trees, but the captured ChatGPT/Codex tree and the targeted before/after cleanup isolate a substantial Codex-side contribution.
The behavior appears proportional to active/restored workers multiplied by the global local-MCP set. Please consider process-group ownership/cleanup for each worker, parent-death signaling for MCP children, startup reconciliation of stale workers, and a regression test that verifies all MCP descendants exit after a task/app closes.
No username, hostname, IP address, absolute path, command argument, environment variable, credential, MCP server name, conversation content, session ID, UUID, PID, or raw core data is included.
A deterministic child-reaping mechanism was found in Codex CLI 0.144.1 and is still present in the current source. It is now tracked in #32219.
ProcessHandle::terminate() kills the child and then aborts wait_handle, while that wait task owns the child and is the only code that calls wait. This affects the PTY/pipe exec helper and is separate from the stdio MCP shutdown path addressed by #19753.
The deterministic reaping problem needs an owned process-tree lifecycle, not just best-effort cleanup at task end.
I would model every spawned Codex/MCP process with: owning task/session id, process group, child pids, startup receipt, heartbeat, terminal reason, reap attempt, and reap receipt. The critical invariant is that completion of the visible task must not be considered final until owned subprocess cleanup has either succeeded or produced a visible cleanup-failed state with enough ids for repair.
I maintain Better Agent (https://github.com/ofekron/better-agent), where detached runners and helper processes are tracked as durable owner state for crash/restart recovery. If useful, a star helps other desktop-agent builders find it.