macOS Computer Use leaks SkyComputerUseClient turn-ended helpers
Codex Computer Use leaks SkyComputerUseClient turn-ended helper processes on macOS
Summary
Codex Desktop / Computer Use on macOS leaves SkyComputerUseClient helper processes running after turns complete. The leaked helpers include orphaned processes whose parent is PID 1 (launchd) and nested chains of:
SkyComputerUseClient turn-ended --previous-notify <json>
/bin/bash .../codex-notify.sh turn-ended -- SkyComputerUseClient turn-ended <json>
SkyComputerUseClient turn-ended <json>
This accumulates over time and survives normal Codex turns/sessions. The command payload contains turn metadata, so examples here are redacted.
Environment
- Host: macOS 27.0, build 26A5353q, arm64
- Codex.app currently installed: 26.616.32156, build 4157
- Originally observed version from the report: 26.608.12217
codexCLI:codex-cli 0.130.0- Computer Use bundle:
~/.codex/computer-use/Codex Computer Use.app - Computer Use bundle version:
CFBundleShortVersionString=1.0,CFBundleVersion=829 - Service executable:
.../Codex Computer Use.app/Contents/MacOS/SkyComputerUseService - Client executable:
.../SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClient
Reproduction
- Enable/use Codex Desktop Computer Use or any Codex path that installs the
SkyComputerUseClient turn-endednotifier. - Run several Codex turns or Computer Use actions.
- Check helper counts and parentage:
ps -Ao ppid,comm | awk '/SkyComputerUseClient/{print $1}' | sort | uniq -c | sort -rn
ps -Ao comm | grep -c SkyComputerUseClient
ps -Ao etime,pid,ppid,comm | grep SkyComputerUseClient | sort -r | head
ps -Ao pid,ppid,etime,comm | grep -E 'SkyComputerUseService|MacOS/Codex$'
Expected
After the relevant Codex turn/session ends, all per-turn SkyComputerUseClient helpers should exit. If the service exits, it should terminate and/or reap all children it spawned. A broken --previous-notify command should not leave the client process alive indefinitely.
Actual
Helpers remain alive for hours/days. On this machine, a previous run observed 1,422 simultaneous SkyComputerUseClient processes. In the current reproduction before cleanup:
ps -Ao comm | grep -c SkyComputerUseClientreturned22.ps -Ao ppid,comm | awk '/SkyComputerUseClient/{print $1}' ...showed7clients parented by PID1.- The oldest current helpers were over
02:13:00old. - The service process was alive as a child of Codex:
/Applications/Codex.app/Contents/MacOS/Codex
~/.codex/computer-use/Codex Computer Use.app/Contents/MacOS/SkyComputerUseService
Unified logs showed turn-end events with no active lock-screen threads while helper processes remained:
SkyComputerUseService: Received lock-screen turn end ... activeThreadCount=0 autoUnlockedThreadCount=0
Evidence
Info.plistidentifies the service ascom.openai.sky.CUAServiceand the nested client ascom.openai.sky.CUAService.cli.- Entitlements show both service and client share the
2DC432GLL2.com.openai.sky.CUAServiceapp group. - The bundled Computer Use plugin launches the MCP server via:
{
"command": "./Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClient",
"args": ["mcp"]
}
- The leaked process command lines were
turn-endednotifier invocations, not active UI interaction commands. - The local
~/.codex/config.tomlhad been rewritten to:
notify = [ "SkyComputerUseClient", "turn-ended", "--previous-notify", "[...codex-notify.sh..., ...SkyComputerUseClient..., turn-ended]" ]
This creates a self-wrapped notifier chain when an existing wrapper already preserves the original SkyComputerUseClient turn-ended notifier.
Probable root cause
There are two lifecycle gaps:
SkyComputerUseClient turn-endedcan block indefinitely after spawning/invoking the previous notifier chain. Its parent exits or detaches, leaving the helper reparented tolaunchd.- The Computer Use service / installer wraps the existing Codex notify command without detecting that the previous notifier chain already includes
SkyComputerUseClient turn-ended, creating a nested self-wrapper. The service also does not reap staleturn-endedhelpers after turn completion.
Local mitigation installed
I installed a local, age-filtered mitigation:
- Reset
~/.codex/config.tomlto call the local notify wrapper first, then the originalSkyComputerUseClient turn-ended. - Hardened
~/.config/dev-knowledge/hooks/codex-notify.sh: - strips recursive
SkyComputerUseClient --previous-notifychains, - runs the original notifier with a bounded timeout (
DK_CODEX_NOTIFY_ORIGINAL_TIMEOUT_SECONDS, default20), - logs timeout/recursion warnings explicitly.
- Added
/Users/jeremy/.local/bin/codex-computer-use-reaper. - Default threshold:
3600seconds. - Matches only the exact
SkyComputerUseClientexecutable path. - Redacts turn JSON in logs.
- Added and loaded LaunchAgent:
/Users/jeremy/Library/LaunchAgents/com.jeremy.codex-computer-use-reaper.plist- Runs at load and every 300 seconds.
Verification after mitigation:
- Dry-run found
16helpers,14older than 3600 seconds,2skipped as fresh. - Real run reaped
14stale helpers and left the2fresh helpers untouched. launchctl print gui/501/com.jeremy.codex-computer-use-reapersucceeds and reports interval300seconds.- Wrapper timeout test exits
124when a notifier exceeds the configured timeout; pass-through notifier test exits0.
Requested upstream fix
- Make
SkyComputerUseClient turn-endedalways exit after notifying the service and/or invoking--previous-notify, with a bounded timeout for the previous notifier. - Detect and reject recursive
--previous-notifychains that already includeSkyComputerUseClient turn-ended. - Ensure
SkyComputerUseServicetracks all spawned helper PIDs and tears them down on turn end/service exit. - Add a stale-helper guard in the service: cap concurrent helpers and terminate old
turn-endedhelpers safely.
3 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Same self-nesting notify chain reproduces on Windows (ARM64), not just macOS - with the Windows Computer Use helper
codex-computer-use-arm64.exe. Adding the platform data point plus a measured growth rate and a workaround that stops it.Environment
| | |
|---|---|
| OS | Windows 11, ARM64 |
| Package |
OpenAI.Codex_26.810.6296.0_arm64__2p2nqsd0c76g0|| Version resource |
Codex 151.0.7922.137|| Helper |
...\AppData\Local\OpenAI\Codex\runtimes\cua_node\<hash>\bin\node_modules\@oai\sky\bin\windows\codex-computer-use-arm64.exe|What
~/.codex/config.tomllooked likeLine 11 was a single
notifyentry wrapped inside itself 4 times, each level re-escaping the previous one as--previous-notify:| Metric | Value |
|---|---|
| Line length | 1,966 characters |
|
--previous-notifylevels | 4 || Longest consecutive backslash run | 32 |
Structure (elided):
Note the two levels reference different runtime hashes (
45b665c9b82ad082at the outer levels,be1d88aa93cd4c41at the innermost), so the chain has survived at least one runtime upgrade - the wrapper keeps pointing at helper binaries from older runtime directories.It grows on app start, and that is measurable
config.tomlmtime tracked the app launch exactly. Timeline from one session:09:08:50- app relaunched ->notifygained another nesting levelWorkaround that actually stops the re-injection
Deleting the
notifyline alone is not enough - it comes back on the next launch. What stopped it was disabling the feature as well:After that change, the app rewrote
config.tomltwice more (mtimes09:54:06and10:00:28, confirming it does rewrite the file at startup) andnotifywas not re-injected either time. Thecomputer_use = falseline was preserved across both rewrites.Related config left behind by Computer Use on Windows, for reference:
Suggested fixes
turn-endednotifier, detect that the currentnotifyvalue already points atcodex-computer-use*and replace it rather than wrapping it. The existing wrapper already preserves the original command, so re-wrapping is always redundant.notifyvalue beyond a sane length.Note
I found this while investigating an unrelated (and much larger) performance problem on the same machine - sustained ~1 GB/s of logical file reads from the Electron main process. I want to be explicit that I have not established any causal link between the notify nesting and that read storm; at 1,966 characters this line is far too small to account for it. Reporting the nesting purely as its own bug.
this is slowing down my mac to a crawl impossible to use desktop please reset tibo as compensation lmao