Background subprocesses/subagents do not wake the calling agent on completion

Open 💬 12 comments Opened Mar 25, 2026 by zoox101
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.116.0

What subscription do you have?

API Key

Which model were you using?

gpt-5.3-codex medium

What platform is your computer?

Linux 6.8.0-101-generic x86_64 x86_64

What terminal emulator and version are you using (if applicable)?

tmux

What issue are you seeing?

Long-running background sub-processes and sub-agents do not inform the calling agent when they complete. Instead the calling agent must either:

  1. Block the message thread by continuously polling for a result; or
  2. Wait for the user to request an update

What steps can reproduce the bug?

In interactive mode, prompt the agent with:

Use `exec_command` to run the following script in a background terminal: `sleep 15; echo "print the whale emoji"`

or

Run a subagent in the background with the following prompt: `wait for 15 seconds then respond with the whale emoji"`

In both cases, the agent spins up the sub-task, responds to the user, and then does nothing after the sub-task returns.

What is the expected behavior?

Agents should be informed when long-running sub-processes return so they can take autonomous action.

Additional information

In other agent harnesses, watcher scripts can be used to automate agent actions. An agent can run a script in the background that polls an external endpoint without blocking the main interaction loop. When the script returns, the agent is able to respond autonomously without user intervention. Codex agents cannot implement this pattern because sub-processes do not appear to queue a message for the agent.

View original on GitHub ↗

12 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #14314
  • #14303
  • #15461

Powered by Codex Action

JaysonGeng · 3 months ago

Candidate fix pushed in my fork. Compare link: https://github.com/openai/codex/compare/main...JaysonGeng:codex:fix/auto-wake-on-async-completion

GitHub shows the branch as cleanly mergeable, but this repo is invitation-only for PRs from non-collaborators.

Root cause:

  1. Background unified_exec completions were only surfaced through write_stdin, so if the originating turn had already ended and nobody polled, the session stayed idle forever.
  2. 2. Sub-agent completion notifications used trigger_turn = false, so an idle parent never woke up.

Patch summary:

  1. The async watcher now claims unseen background completions, injects a synthetic function_call_output into the next turn, and wakes the idle session.
  2. 2. write_stdin and the watcher coordinate with an atomic claim to avoid double delivery.
  3. 3. Sub-agent completion notifications now use trigger_turn = true.

Local validation: targeted unified-exec/subagent tests, just fmt, just fix -p codex-core, and git diff --check.

This should also cover #15461, #14314, and #14303.

cipher982 · 3 months ago

I hit what looks like the same issue, and my logs make the boundary a bit clearer.

In my case, the child subagents did complete successfully. The important detail was:

  • the parent turn had already emitted task_complete
  • afterward, the child completion was still injected back into the parent

thread as a <subagent_notification>

  • but no new assistant turn was started to consume or synthesize that result

So from the user side it looked like: the child finished and the parent technically received the result, but nothing visibly happened until I manually prompted the parent again

That makes this feel like more than “background work has no notification”. The completion did land, but the calling agent was not really resumed/woken in a user-visible way. I think the ideal agent UX is that the parent gets triggered to msg a response so i dont sit there going 'hey check again plz' over and over.

janbernloehr · 2 months ago

See also #13733 for the token cost angle

tristan666666 · 1 month ago

I hit this same class of long-run handoff problem from the user side: background work finishes or a window becomes usable again, but the selected user-facing session does not reliably move forward unless I manually poke it.

I built a small macOS userland bridge around this workflow for Claude/Codex, mainly to keep long runs observable and resumable: running / waiting for me / stuck are shown in the MacBook notch, and a selected session can receive a configured continuation prompt when it is ready to continue.

Not a core fix for this issue. I agree the proper solution is still a real wake/resume event in Codex, like the trigger_turn = true direction described above. Leaving it here as related prior art / workaround:
https://github.com/tristan666666/agent-island

Necmttn · 29 days ago

The wake should be runtime-owned, not model-discovered.

When a background process or subagent completes, the runtime can enqueue a completion receipt: origin id, parent turn id, exit status, output ref, finished_at, and whether it should trigger a new assistant turn. The model should consume that receipt only after something changed.

That keeps completion separate from polling. A child finishing should be able to wake the parent once, while a still-running child with no new output stays local and costs no extra model turn.

---

_Generated with ax._

tristan666666 · 29 days ago

@Necmttn agreed. The important distinction is "completion as data" vs "completion as a prompt to poll again".

A runtime-owned receipt also gives Codex a safer dedupe/recovery boundary. The parent should not need to rediscover child state by reading logs; it should receive one structured event with something like:

  • child id / origin id
  • parent turn id
  • terminal state: completed / failed / cancelled
  • finished_at
  • bounded output ref or summary
  • whether this receipt should trigger a new turn
  • delivery state, so it is not injected twice after reconnect/resume

That also keeps token cost under control. A long-running child can stay invisible while nothing changes, then wake the parent exactly once when there is a terminal transition worth acting on.

ilyes-i-ben · 18 days ago

+1

StatPan · 7 days ago

A completion-driven continuation needs a little more than a notification. Completion notifications should be delivered as durable, deduplicated session events and trigger exactly one continuation turn only when the owning session is idle. If the session is busy, defer and coalesce completion events until a safe turn boundary.

This avoids both polling and a burst of redundant model turns when several background processes or subagents finish close together. A receipt should at least preserve the origin ID, parent turn/session ID, terminal status, completion time, and a bounded result or output reference so delivery can be safely recovered after reconnect or resume.

15230745073 · 6 days ago

Adding a Codex Desktop / ChatGPT integration perspective: I have encountered the same orchestration gap in multi-step, DAG-style workflows.

Sub-agent delegation itself works well, but if the parent agent finishes its turn or becomes idle while a child is still running, the child’s terminal event does not reliably resume the parent workflow. This affects successful completion, timeout, failure/exception, and abnormal termination. The child result may be available, but the next dependent step is not scheduled until the user sends another message.

For reliable multi-agent workflows, terminal child-task events should durably notify and, when appropriate, wake the owning parent/orchestrator so it can evaluate dependency/join conditions and continue without manual intervention. This should be idempotent to avoid duplicate downstream execution.

Claude Code’s event-driven background-task lifecycle handling is a useful UX reference here: completion, timeout, failure, and sub-agent events promptly return control to the coordinating agent. Comparable behavior in Codex would make long-running and DAG-based workflows much more reliable.

StatPan · 4 days ago

Consolidated PoC update for an explicit, one-shot subagent completion callback:

The PoC adds a separate register_completion_callback function. It returns immediately; when the watched subagent reaches a terminal state, its existing bounded completion envelope is queued for the registering parent and the existing pending-work scheduler starts exactly one continuation once that parent is idle. This avoids both unconditional wake-up on every child completion and explicit wait_agent polling.

The public-path integration test covers:

spawn child → register callback → parent becomes idle
→ child completes → one parent continuation starts without user input

A live TUI/service smoke test also completed that sequence without calling wait_agent.

Validation caught an important issue in the first draft: it modified the reserved collaboration.wait_agent schema and the live API rejected the request with HTTP 400. That change was removed. The corrected branch preserves all reserved collaboration tool schemas and exposes callback registration as an ordinary function.

Current scope is deliberately limited to the direct parent/subagent completion path. Registration is still in memory and does not survive restart/resume, so this is a behavior PoC rather than a production-ready durability design. No upstream PR has been opened.

StatPan · 3 days ago

Follow-up after implementing and live-testing the PoC: this supersedes the explicit register_completion_callback approach described in my previous comment.

The cleaner contract is runtime-owned completion delivery rather than asking the model to discover and call a separate registration tool:

  • A terminal subagent or opted-in background exec produces one bounded completion receipt.
  • Delivery is deduplicated and starts exactly one continuation when the owning session is idle.
  • If the session is still busy, delivery waits for a safe turn boundary.
  • write_stdin and the async watcher share a claim state so polling cannot race with, or duplicate, automatic delivery.
  • Reserved collaboration tool schemas remain unchanged.

For unified exec, the PoC uses an explicit on_exit: wake policy. This keeps callbacks optional, while making the requested callback a runtime guarantee rather than a prompt to poll again.

One important correctness case is ordinary POSIX background syntax. When the model honors a background-work request by emitting a normal cmd &, the outer shell can exit before the actual job. Watching only the outer shell therefore loses the meaningful completion boundary and produces surprising behavior: a foreground long command wakes correctly, while the equivalent background command does not.

The callback contract should therefore include the ordinary & form that the model naturally uses:

(sleep 10; echo 'SHELL BACKGROUND CALLBACK DONE') & echo "PID=$!"

The validated sequence is:

PID/session returned promptly -> parent turn completes
-> no polling and no user input
-> shell background job finishes
-> exactly one parent continuation starts with the completion result

The implementation detects the shell background operator syntactically, rather than using a string match, so &&, quoted ampersands, redirections such as 2>&1, and arithmetic expressions are not misclassified.

This is not intended to supervise processes that the user explicitly fully detaches with mechanisms such as nohup, disown, or setsid; those need a different ownership contract. The scope here is the normal background syntax Codex itself is likely to generate while promising a completion callback.

The direct subagent flow, unified-exec completion flow, and the raw POSIX & flow all passed integration coverage and a live TUI test with no wait_agent/write_stdin polling. Restart/resume durability is still outside this PoC, so I would stage an upstream implementation as runtime receipt/wake semantics first, unified-exec opt-in delivery second, and POSIX & lifecycle correctness as acceptance coverage for that exec contract.

No upstream PR has been opened.