openai / openai/codex-plugin-cc
Rescue tasks intermittently hang forever: stale shared broker reused without a health check; headless app-server inherits desktop MCP servers
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 33.3k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
Rescue tasks intermittently hang forever; shared broker is reused without a health check, and headless app-server inherits interactive/desktop MCP servers
Environment
- Plugin:
codex@openai-codexv1.0.6 (repoopenai/codex-plugin-cc) codex-cli0.144.4- macOS (arm64), Claude Code
- Codex desktop app installed but not running (had crashed earlier; only orphan crashpad handlers present)
Summary
codex:codex-rescue tasks intermittently hang indefinitely with no output. The job log reaches Turn started and then goes completely silent — no item/*, no turn/completed. The foreground task process blocks until its internal wait elapses. It is intermittent: the same trivial prompt hangs on one run and completes in ~5 s on the next.
Reproduction
- Run a trivial read-only rescue:
node scripts/codex-companion.mjs task "Reply with exactly PONG. Do not read files or run commands." - Intermittently, it hangs. Job log:
Starting Codex Task. Starting Codex task thread. Thread ready (<thread-id>). Turn started (<turn-id>). <no further lines; process blocks ~2 min until killed> - Clear the persisted broker and kill stray processes:
rm -f ~/.claude/plugins/data/codex-openai-codex/state/<workspace>/broker.json pkill -f app-server-broker; pkill -f "codex app-server" - Re-run the identical command → completes in ~5.6 s (
PONG).
What is NOT the cause (verified)
codex app-serverprotocol is fine: a raw direct turn completes in ~4 s and emitsturn/started/item/completed/turn/completedwith the exact shapes the companion's state machine expects.- Driving a turn through the broker socket by hand also completes in ~4 s.
/codex:setupreports fully green (node, codex, ChatGPT auth).- Broker code is byte-identical between plugin 1.0.1 and 1.0.6, so this is not a recent plugin regression.
Root cause 1 — shared broker reused on a shallow liveness check, with fragile teardown
ensureBrokerSession() (scripts/lib/broker-lifecycle.mjs) reuses an existing broker when isBrokerEndpointReady() succeeds — but that only probes whether the unix socket accepts a connection (150 ms), never whether the app-server behind it still responds. A broker whose backing app-server has wedged (stuck prior turn, slow MCP startup, drift after a codex CLI update underneath a long-lived process) still passes the probe, gets reused, and the next task connects and blocks forever.
Teardown only happens in the SessionEnd hook (scripts/session-lifecycle-hook.mjs). It does not run on crash / kill -9 / force-quit / hook timeout, so wedged brokers and their session dirs are orphaned (observed: leftover cxc-* dirs in $TMPDIR whose teardown never ran). Those orphans are exactly what root cause 1 then reuses. The broker being long-lived, detached, and shared across Claude Code sessions widens this window considerably.
Suggested fix 1
- Before reusing a broker, do a real bounded health round-trip (e.g.
initializeoraccount/readwith a short timeout), not just a socket-accept probe. On failure, tear down and respawn. - Add a bounded timeout on
turn/start→ first notification insidecaptureTurn/withAppServer, and fall back todisableBrokerdirect mode on timeout (the existingshouldRetryDirectpath only coversBROKER_BUSY/ENOENT/ECONNREFUSED, not a silent wedge). - Make teardown more robust than SessionEnd alone — e.g. a stale-broker sweep on SessionStart, or a heartbeat/last-used timestamp with reap-on-connect.
Root cause 2 — headless rescue inherits interactive/desktop MCP servers
SpawnedCodexAppServerClient runs spawn("codex", ["app-server"]) with no config scoping, so the app-server reads the user's full ~/.codex/config.toml. That file is shared with the Codex desktop app, which registers automation MCP servers there — notably node_repl (browser/computer-use bridge) with startup_timeout_sec = 120. These start on every thread, including pure code-rescue turns that never use a browser. When the desktop bridge is unhealthy, a code task can stall on it — an observed hang was ~117 s, right at the 120 s node_repl timeout.
A code-review/rescue turn should not depend on desktop-app automation components being healthy.
Suggested fix 2
- Spawn the app-server for
task/reviewwith a scoped config that excludes interactive/desktop MCP servers (e.g. a dedicated profile or-c mcp_servers.<x>.enabled=falseoverrides), or otherwise opt out of MCP startup the rescue path doesn't need. - At minimum, document the coupling and give a supported way to run the plugin's app-server without inheriting desktop-injected MCP servers.
Impact
Users experience the plugin as "randomly unreliable" — long hangs with no error — with no obvious recovery beyond manually deleting broker.json and killing processes. It worsens after codex CLI auto-updates and after desktop-app crashes, both of which raise the odds of a stale/wedged broker or an unhealthy inherited MCP server.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with scripts/lib/broker-lifecycle.mjs, scripts/session-lifecycle-hook.mjs, and the SpawnedCodexAppServerClient path; reproduce the issue with scripts/codex-companion.mjs task and inspect the broker health and teardown flow. Trace captureTurn/withAppServer and the app-server spawn configuration. Done means stale or wedged brokers and unnecessary desktop MCP startup no longer leave rescue tasks hanging indefinitely, with the documented recovery paths working.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- backend, cli, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 50/100