SkyComputerUseClient processes spawned for turn-ended events remain alive as PPID=1 orphans
Summary
Codex Desktop appears to leave SkyComputerUseClient helper processes alive after turn-ended / agent-turn-complete events. On my machine these processes accumulate as PPID=1 orphans and are not tied to active Computer Use work.
This is different from simply having many active sessions. The process command lines show that these helpers were launched with a turn-ended event payload, including type: "agent-turn-complete", client: "codex_exec", cwd, thread-id, turn-id, input-messages, and last-assistant-message.
The accumulated helpers coincide with degraded Codex Desktop responsiveness, including laggy output streaming, elevated renderer/app-server CPU, and large local state/log databases.
Related but distinct from #24510, which covers large active history/list behavior. This issue is specifically about helper process lifecycle / reap behavior for turn-ended event handling.
Environment
- App: Codex Desktop
- Version observed in process list:
26.527.31326/ Electron helper version149.0.7827.54 - OS: macOS 26.4.1
25E253 - Machine: Apple Silicon Mac
- Local state paths involved:
~/.codex/state_5.sqlite~/.codex/logs_2.sqlite~/.codex/computer-use/Codex Computer Use.app/.../SkyComputerUseClient
Observed process state
At the time of investigation:
SkyComputerUseClient total: 287
PPID=1 orphans: 285
current app-server child: 1
other transient shell/rg match: 1
All meaningful orphaned processes had command lines shaped like:
/Users/.../.codex/computer-use/Codex Computer Use.app/.../SkyComputerUseClient turn-ended {
"type": "agent-turn-complete",
"thread-id": "...",
"turn-id": "...",
"cwd": "/Users/kangmin/cowork/onto-mcp",
"client": "codex_exec",
"input-messages": [...],
"last-assistant-message": "..."
}
They were not active children of the current Codex app-server. Most were inherited by launchd:
by_ppid [(1, 285), (48524, 1)]
by_type [('agent-turn-complete', 285)]
by_client [('codex_exec', 285)]
Distribution by workspace
The stale helpers mostly came from high-volume codex_exec review runs:
/Users/kangmin/cowork/onto-mcp 255 processes
/Users/kangmin/Documents/excel-workbook-editing 19 processes
/Users/kangmin/Documents/FCeditor-pipeline-stabilization 8 processes
/Users/kangmin/cowork/onto-mcp-claude 3 processes
Time clustering also suggests they were created during turn-completion bursts rather than a single app crash:
Mon Jun 1 11:00 /Users/kangmin/cowork/onto-mcp 85
Mon Jun 1 14:00 /Users/kangmin/cowork/onto-mcp 58
Mon Jun 1 13:00 /Users/kangmin/cowork/onto-mcp 52
Mon Jun 1 12:00 /Users/kangmin/cowork/onto-mcp 38
Tue Jun 2 09:00 /Users/kangmin/Documents/excel-workbook-editing 12
The current Codex Desktop app instance had started later than most of these helpers, so they were not freshly created by the current session:
Current Codex app start: Wed Jun 3 09:58:03 2026
Orphan helper starts: Sat May 30, Mon Jun 1, Tue Jun 2
Impact observed
During the same investigation window, Codex Desktop became visibly sluggish:
- assistant output streaming lagged in the UI
- renderer CPU spiked
- app-server CPU spiked
- GPU/service process also showed repeated CPU bursts
Example process samples:
Renderer PID 48668: up to ~140% CPU, RSS ~1.7-1.8 GB
app-server PID 48524: up to ~190% CPU, RSS ~790-820 MB
GPU/service PID 48495: up to ~48% CPU
Codex main PID 48458: 10-20% range during the lag window
Local DB sizes were also large at the time:
~/.codex/state_5.sqlite 1.3 GB
~/.codex/logs_2.sqlite 2.0 GB
~/.codex/logs_2.sqlite-wal 33 MB
Active thread state had grown again:
active threads: 10,379
active preview: 188.64 MB
active text total: 566.38 MB
archived threads: 6,970
archived preview: 181.41 MB
Largest active contributors:
/Users/kangmin/cowork/onto-mcp
3,052 rows / 128.77 MB preview
/Users/kangmin/cowork/wireframe_editor_v2-segment-split
5,280 rows / 28.35 MB preview
The large active history likely contributes to UI/server pressure, but the orphaned SkyComputerUseClient processes appear to be a separate lifecycle leak.
How I inspected it
Representative commands:
pgrep -fl 'SkyComputerUseClient' | wc -l
ps -axo ppid,comm \
| rg 'SkyComputerUseClient' \
| awk '{count[$1]++} END{for (p in count) print p,count[p]}' \
| sort -k2 -nr
ps -ww -axo pid=,ppid=,lstart=,etime=,rss=,command= \
| rg 'SkyComputerUseClient'
ps -ww -axo command= \
| rg 'SkyComputerUseClient' \
| rg -o 'turn-ended|agent-turn-complete|codex_exec|client":"[^"]+"|cwd":"[^"]+'
I also sampled the app-server and renderer during the lag window:
/usr/bin/sample 48668 3 -file /tmp/codex-renderer-48668.sample
/usr/bin/sample 48524 3 -file /tmp/codex-app-server-48524.sample
The renderer sample was mostly V8/JS/string/stream related. The app-server sample showed many tokio-runtime-worker and sqlx-sqlite-worker threads with SQLite I/O mixed in.
Expected behavior
A helper spawned for turn-ended / agent-turn-complete should not remain alive indefinitely after the event is handled.
At minimum, one of the following should happen:
- the helper exits after successfully handling the event
- the parent app-server reaps it
- the helper has a lease/TTL and self-exits when stale
- the helper exits when its parent app-server is gone
- Codex Desktop startup reaps stale orphan helpers from prior runs
Actual behavior
The helpers remain alive for days with PPID=1, while still carrying their original turn-ended JSON payload in the command line.
This suggests one of:
- the event handler process is never exiting
- the parent loses ownership after spawning it
- cleanup is only implemented on normal paths and misses turn/event completion paths
- stale helper reaping is missing on app-server or app startup
Why this matters
This can silently accumulate across high-volume codex_exec workloads. In my case, hundreds of stale helpers were left behind, mostly from one workspace. Even if individual helpers are idle, the accumulation makes diagnosis hard and may contribute to degraded Desktop performance when combined with large local state/history.
The command-line payloads also contain large prompt and assistant-message data, so these orphan processes retain potentially large per-turn context in process arguments for much longer than needed.
Suggested fix direction
Treat SkyComputerUseClient event helpers as leased resources rather than fire-and-forget child processes:
- include an owner app-server/session/turn id
- ensure parent-death detection or explicit parent heartbeat
- add a short TTL for
turn-endedhandlers - reap stale helper processes on Codex Desktop/app-server startup
- avoid keeping full
input-messages/last-assistant-messagein long-lived process argv if the helper can outlive the event
The key invariant should be:
A turn-ended helper may outlive the turn briefly, but it should not outlive its owner indefinitely.
6 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Adding related issues I found after filing this:
launchd.codex exec/ MCP child processes unreaped after task completion.This issue seems to be in the same broad lifecycle/reaping family, but the leaked process class is different:
The part that may be useful for debugging here is that these
SkyComputerUseClientprocesses are not just generic Computer Use workers. Their argv still contains the original turn completion event payload:So this may share the same root cleanup problem as the MCP helper leaks, but it appears to hit the
turn-endedevent path specifically.Adding an independent confirmation on a newer Codex Desktop build, with a smaller synthetic repro.
Environment
25.5.0arm64com.openai.codex26.602.71036build3685codex-cli 0.137.0-alpha.4codex:codex-cli 0.135.0com.openai.sky.CUAService.cli1.0build809Observed behavior
After a set of headless Codex review/council sessions completed, 21 stale matching processes were still alive. The user originally noticed these PIDs hours after the work had completed:
A stricter process sweep found 21 total
SkyComputerUseClient turn-ended ...clients at the time of cleanup. They were not active reviewer workers. They were orphaned underlaunchd, sleeping, and retained the completed turn payload in argv.Representative observations:
ps -ww -o pid,ppid,pgid,stat,etime,time,lstart,command -p ...showedPPID=1,STAT=S, and about0:00.01CPU for each stale helper.lsof -a -p <pid>showed stdio redirected to/dev/null, no child work, and the Computer Use client executable.sample <pid> 3showed the main thread blocked inCFRunLoopRun, with another thread blocked inxpc_pipe_receive/mach_msg2_trap.Synthetic repro
Invoking the raw client directly with a minimal
agent-turn-completepayload reproduced the hang:Expected: the command returns promptly after delivering or rejecting the event.
Actual: the foreground client process remained alive after the service had accepted the notification path. Unified logs for
SkyComputerUseServiceduring the synthetic probe showed the service sending the notification request and receiving HTTP status202, but the client process still did not exit.The stuck probe had the same blocked stack shape as the older orphaned helpers (
CFRunLoopRun/ XPC receive). It needed to be killed manually.Impact / privacy note
The leaked processes keep the original
turn-endedJSON payload in command-line arguments. For real sessions, that can include user prompt text and the last assistant message, so the leak is both a process-lifecycle issue and a data-retention-in-argv issue.Local mitigation used
As a local workaround, I installed a small wrapper around the configured
notifycommand. It does not parse the payload; it forwards all args toSkyComputerUseClient, waits a short bounded timeout, then sendsSIGTERM/SIGKILLif the client does not exit. With a 3s timeout, repeated installed-path smokes kill the hung client and leave no lingeringSkyComputerUseClient turn-endedrows afterward.This workaround is intentionally at the Codex notify boundary. The upstream invariant should still be that a
turn-endedhelper exits promptly after handling the event, or that Codex bounds/reaps that helper itself.Related public workaround PR for reference: https://github.com/ericlitman/crucible/pull/9
Can confirm, with some additional data points from a clean reproduction today:
codex execturn with the legacynotifyhook pointing atSkyComputerUseClient— oneturn-endedorphan per turn, never exits (observed 30s+, oldest survivor ~18h; ~18 accumulated over one day of heavy exec use).SkyComputerUseServiceis running and freshly launched — so it does not appear to be "receiver not running".com.openai.sky.CUAServicenorcom.openai.sky.CUAService.cliever registers with macOS Notification Center (checkedcom.apple.ncprefs), and launching the .app directly spawns no GUI/permission prompt — so the dispatch path seems to never complete on machines where the Computer Use app was installed but never onboarded.notify = [...]line from~/.codex/config.toml→ zero new orphans. Independent of the client-side fix, it would be nice if codex reaped or applied a timeout to notify children (hooks/src/legacy_notify.rs) so a misbehaving notifier can't accumulate.Confirming this still reproduces on a newer build, and adding a data point where the leak escalated from "degraded responsiveness" to a full system OOM that took down WindowServer.
Environment
26.611.61753(Electron helper149.0.7827.115)SkyComputerUseService(persistent) + leakedSkyComputerUseClient turn-endedclients26.2(25C56)SkyComputerUseClient turn-ended {...}helper that reparents tolaunchd(PPID 1) and never exits.Escalation: orphan accumulation → OOM → WindowServer watchdog kill
Over one afternoon the orphan count climbed steadily (sampled from the kernel
JetsamEventsnapshots):At 18:16 the machine hit a memory-pressure
JetsamEvent(2,746 processes, ~82 GB resident demand on 24 GB physical; compressor ~7 GB, free pages near zero). Jetsam began culling processes, and ~34s laterWindowServerwas killed by the watchdog:The user-visible result was a hard UI freeze followed by a forced graphics/login-session restart (looks like a crash/logout). The 477 orphans were each 0% CPU — pure retained memory with no useful work after their turn completed. After the session restart the count dropped to 2.
This looks like the same lifecycle bug as the original report (and overlaps #25744), just observed at the point where the retained memory is large enough to OOM a smaller-RAM machine rather than merely lag.
Workaround
Since the
turn-endedhelpers do nothing after the turn completes, reaping them is safe. A periodic launchd job clears them:A proper fix would have the
turn-ended/agent-turn-completenotifier exit (or be reaped by the app-server) instead of being inherited by launchd.Adding a note in support of the process-class distinction @kangminlee-maker drew above, since it turns out there is a third class worth separating.
On a current build (Codex Desktop 26.727.51351, CLI
0.146.0-alpha.9.2, CU runtime26.727.1000550) I seeSkyComputerUseClientaccumulating with zeroPPID=1orphans — so this machine is not hitting the leak described here, despite having theturn-endednotifier configured:Instead the accumulation is entirely
SkyComputerUseClient event-stream mcp, retained as live children of the app-server, each holding ongoing periodic work (~1.0–1.33% of a core apiece, constant regardless of age). Details and measurements: https://github.com/openai/codex/issues/35659#issuecomment-5196161230So the taxonomy looks like three distinct paths off the same binary:
Noting it here in case it helps narrow whether these share a reaping root cause or are genuinely separate lifecycle bugs — the fact that one install can have the notifier configured and still show zero orphans while leaking heavily via
event-streamsuggests they may be independent.