openai / openai/codex-plugin-cc
Rescue runs launched via the harness's background Bash die silently when the shell tree is reaped — job wedges at "running" with companion, broker, and app-server all killed mid-turn
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 33.3k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
Summary
A /codex:rescue task can be killed out from under the plugin by Claude Code's own background-shell cleanup, leaving the job wedged at status: "running" forever. This is a specific, reproducible trigger behind the "stuck running" reports in #391 / #377 (item 2) / #367, with a full forensic timeline. It also explains part of the background-mode silent loss in #395.
The trap: agents/codex-rescue.md tells the subagent to "prefer background execution" for long tasks, but nothing pins down which background. In practice the subagent (a Claude model) frequently satisfies this by setting run_in_background: true on its Bash tool call while invoking codex-companion.mjs task in foreground mode — instead of passing the companion's own --background flag. The two are not equivalent:
- Companion
--background:spawnDetachedTaskWorkercreates a detached, unref'd worker that survives its launcher. This is the designed-for path. - Harness
run_in_background: the foreground companion lives inside a Claude Code-tracked background shell. The rescue subagent then exits immediately (its instructions forbid it from polling or collecting). The shell is now orphaned, and when Claude Code later cleans it up, it kills the whole process tree — companion, the broker (still parent-linked as the companion's child, despitedetached: true), and the broker'scodex app-serverchild. All die mid-turn via signal, so thecatchthat would writestatus: "failed"never runs. The job record is frozen atrunningand, per #377 item 2, no PID-liveness check ever notices.
Forensic timeline (observed 2026-07-04, macOS)
| Time (UTC) | Event |
|---|---|
| 20:47:38 | Main session spawns codex:codex-rescue subagent for a review-only task |
| 20:48:26 | Subagent runs one Bash call with run_in_background: true → harness shell ID assigned; inside it, codex-companion.mjs task … runs in foreground mode |
| 20:48:27–29 | Job task-mr6u418r-9wu0t3 recorded (phase: starting, pid = companion); thread ready, turn started |
| 20:48:34.31 | Codex assistant message captured; rollout shows a function_call (first shell exec) + tool_search_call issued |
| 20:48:34 | Subagent returns its stub ("launched in background… Awaiting completion") and exits |
| 20:48:34.44 | Last write ever to the job log, the shell's output file, and the Codex rollout — no function_call_output, no error, no further events |
| ~20:49–21:11 | Background shell tree reaped by harness cleanup (exact moment unobservable; survival tests show it is not instantaneous at subagent exit) |
| 21:11:29 | ps confirms zero codex processes (no companion, no broker, no app-server); no crash reports in DiagnosticReports; state file still says running, phase: starting, stale pid |
| 21:12:28 | Identical prompt re-run as a foreground Bash call: fresh broker spawned, completes normally in 3m06s |
Key negative results: the Codex rollout ends with a client-pending exec and never records a timeout or abort event (rules out exec timeout / turn abort); no crash logs (rules out app-server crash); a controlled test of spawn(..., {detached: true}) from a subagent's Bash call shows detached-and-reparented processes do survive subagent exit — the incident tree died because companion + broker + app-server were still parent-linked when the tree-kill walked it.
Impact
- Job wedged at
runningindefinitely;/codex:statusandstatus --waitreport a corpse as live work (no liveness probe — #377 item 2). - The stale record then blocks follow-ups:
resolveLatestTrackedTaskThreadthrows "Task … is still running. Use /codex:status before continuing it.", and the Stop hook nags about a job that died days ago. - The orchestrating Claude session dutifully waits on the state file; the user eventually has to notice and nudge. Intermittency is confusing: foreground rescues always work, backgrounded ones fail only when cleanup wins the race against job completion.
Environment
- Plugin:
codex1.0.1 (marketplaceopenai-codex) - Codex CLI: 0.142.4 · Claude Code: 2.1.197 (desktop app, local agent mode) · macOS 15.x (arm64)
Proposed fixes (layered; any one helps, all three are cheap)
- Close the instruction gap — in
agents/codex-rescue.mdandskills/codex-cli-runtime/SKILL.md, state explicitly: never set the Bash tool'srun_in_backgroundwhen invoking the companion; for long tasks pass the companion's--backgroundflag (foreground Bash call returns quickly with the job stub). This removes the trigger with a docs-only change. - Make the runtime reap-proof — have the foreground companion path (or the broker spawn) fully detach the broker into its own session (double-fork /
setsid-equivalent) so a tree-kill of the shell can't take the shared broker and app-server down with it; optionally add a SIGTERM handler in the companion/worker that flushesstatus: "failed", error: "terminated by signal"before exit. - Stop trusting the state file (= #377 item 2, seconding it with this real-world postmortem) —
buildSingleJobSnapshot/statusshould probeprocess.kill(pid, 0)and transition ESRCH'd jobs tofailedso a dead job can never present asrunning.
Happy to provide the raw logs (job log, rollout jsonl, session transcript excerpts) if useful.
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 agents/codex-rescue.md and skills/codex-cli-runtime/SKILL.md to trace how background execution is instructed. Then inspect spawnDetachedTaskWorker, buildSingleJobSnapshot, and status to compare the proposed instruction, process-detachment, and PID-liveness fixes. Done means the selected fix prevents silent loss or reports a dead job as failed instead of leaving it running.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bash, javascript
- Domain
- devtools, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100