Feature Request: Ability to check agent status and parent-child wait mechanism
Summary
When using subagents in the current multi-agent flow, a parent thread can prematurely fall back and redo a task that is still being processed successfully by a child agent.
This seems to happen when the child is healthy but is in a long-running / slow turn with no visible intermediate progress from the parent's perspective. The parent eventually assumes the child is stalled, closes or abandons it, and then executes the same task itself.
This defeats one of the main reasons to use subagents in the first place: splitting work to save parent context.
Why this matters
In practice this causes:
- wasted tokens, because the same task gets done twice
- parent context window bloat, because the parent ends up doing work that was supposed to stay isolated in the child
- worse orchestration behavior for exactly the kinds of long tasks that benefit most from subagents
Reproduction pattern
A typical sequence looks like this:
- The parent spawns a subagent for a task that is large enough to justify context isolation.
- The child begins working normally, but its turn is long-running or slow to emit visible output.
- From the parent's perspective there is no reliable signal that the child is still making progress.
- The parent hits its fallback rule / timeout, assumes the child is stuck, and starts doing the task itself.
- Result: duplicate work, duplicate token spend, and the parent context gets filled by the task that was supposed to be delegated.
Actual behavior
The parent can observe completion only weakly, and cannot reliably distinguish:
- child is actively working but slow
- child is stalled
- child is alive but has not yet produced a terminal event
As a result, "silence" can be misinterpreted as failure.
Expected behavior
The orchestration layer should make it much harder for a healthy long-running child to be mistaken for a dead/stalled one.
Some possible solutions:
- explicit child heartbeat / liveness notifications while a turn is running
- a standard "still running / last progress / last event timestamp" probe for the parent
- safer default fallback behavior when a child is in
Runningstate - parent-visible progress semantics that are distinct from "completed"
- better support for long single-turn child tasks, not just multi-turn child workflows
Notes on V1 vs V2
From reading the code, V2 seems like a partial improvement but not a full fix for this specific case.
My understanding is:
- V1 primarily waits on final status and does not provide good visibility into in-flight progress.
- V2 improves mailbox-based notifications and per-turn completion signaling.
- However, V2 still appears to notify the parent mainly on terminal turn events, not during a long single running turn.
So for the specific failure mode "healthy child, one long slow turn, no intermediate visible progress", I believe similar premature fallback behavior can still happen.
If that understanding is wrong, clarification on the intended orchestration model would also be helpful.
Request
Could the multi-agent design provide a stronger parent-visible notion of child liveness/progress, especially for long-running single-turn work?
This would make subagents much more reliable for context-partitioning workloads and reduce duplicate execution.
16 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I spent some time comparing the current Codex multi-agent design against a recently leaked source repository for a similar agentic coding system. My read is that this issue is real in Codex today, and the main difference is not “the other system waits longer” but that the other system seems to model subagents as background tasks with explicit task state, whereas Codex still models them primarily as child conversations/threads.
High-level difference
In current Codex, the parent mostly interacts with a child through:
That gives the parent a decent notion of completion, but only a weak notion of healthy in-flight progress for a long single running turn.
By contrast, the leaked repository design appears to make subagents much more like long-lived tasks:
task_started,task_progress, andtask_notificationThat difference matters a lot for this failure mode.
Why that other design seems less prone to this specific problem
From the recovered references, that agent system appears to reduce this issue for several reasons:
1. “Silence” is not the only parent-visible state
The parent does not need to infer liveness purely from “did the child finish yet?”.
There is an explicit task model with:
That means a long-running child is still externally legible even if it has not produced a final answer yet.
2. The parent has alternatives to fallback
The parent can do more than “wait or redo”:
That changes the orchestration behavior. When the child is quiet, the natural next move is “inspect/query/ping the task”, not “assume it is dead and redo the work”.
3. Background tasks are first-class, not an emergent pattern
The leaked design appears to explicitly support
run_in_background/ async launch semantics, with tooling and UI built around it.That is important because the exact workloads most vulnerable to this issue are:
Those are naturally “background task” workloads.
4. The system prompt/runtime seem to actively discourage duplicate work
One especially notable detail in the recovered references is language along the lines of:
So the model is not only given a task runtime that supports non-duplicative behavior; it is also explicitly nudged toward that behavior.
What Codex currently seems to lack
By comparison, Codex still appears to have a gap between:
V1 mostly waits on final status. V2 improves collaboration and mailbox signaling, but for the specific case of:
the parent still does not seem to have a strong standard signal like:
So even though V2 is better than V1, it still leaves room for the same orchestration mistake: prolonged quiet can still be interpreted as “probably stalled”.
Important nuance
I am not claiming that other systems can never hit similar problems.
Also, this comparison is based on recovered/reference code rather than a canonical upstream source tree, so some details may be incomplete.
But even with that caveat, the architectural direction is pretty clear:
That architectural difference alone plausibly explains why this failure mode would show up much less often there.
Possible lessons for Codex
I think Codex does not necessarily need to copy that exact task system, but it probably needs to provide a stronger parent-visible notion of in-flight child health.
Some concrete options:
TurnStartednotifications in V2.wait_agentreturn progress snapshots, not only timeout vs mailbox activity.My main takeaway is: this is less a “bad timeout choice” problem and more a “missing parent-visible liveness contract” problem.
We ran into this exact problem building a multi-agent orchestrator and went through several iterations before landing on something stable. Sharing what we learned.
The core insight: "is it stalled?" is the wrong question to ask from the parent's perspective. What you actually want is a structured progress signal that the child pushes outward, not a liveness probe the parent pulls. The parent can never reliably distinguish "slow but working" from "stuck" without the child's cooperation.
We solved this with three mechanisms:
1. Progress snapshots via HTTP, not just heartbeats. Agents POST structured progress to a task server endpoint every ~60 seconds:
files_changed,tests_passing,errors,last_file. The orchestrator compares consecutive snapshots — iffiles_changed,tests_passing, anderrorsare all identical across N consecutive snapshots, that is a stall. A heartbeat alone ("I'm alive") is insufficient because an agent can be alive and spinning. The snapshot captures whether actual work product is changing.2. Adaptive stall thresholds, not fixed timeouts. A 2-minute timeout is correct for a small formatting task but will false-positive on a large refactor. We compute per-task stall profiles based on task complexity, current agent phase (an agent in a "testing" phase gets extra slack), and whether the agent is hitting rate limits. For example, a large/high-complexity task gets a kill threshold of 12 consecutive identical snapshots vs 7 for default tasks. The escalation is graduated: WAKEUP signal at threshold N, SHUTDOWN at ~1.7N, forced kill at ~2.3N. This gives slow-but-healthy agents time to report progress before anything destructive happens.
3. Short-lived agents with bounded scope, not long-running children. This is the architectural choice that eliminated most false-positive stall detections for us. Each agent gets 1-3 focused tasks, does the work, and exits. No agent lives long enough for the "long single-turn silence" problem to dominate. If you find yourself needing a child to run for 20+ minutes on a single turn, that is usually a task decomposition problem, not a liveness detection problem. Break the task into smaller units with intermediate artifacts that the orchestrator can verify.
The other thing that helped was decoupling inter-agent coordination from the parent-child tree entirely. We use an append-only bulletin board (POST/GET over HTTP) where any agent can post findings, blockers, or status updates. This means agent B can learn that agent A discovered a breaking API change without the parent having to shuttle messages. It eliminates the "parent context bloat from coordinating children" problem because agents coordinate laterally, not through the parent's context window.
One concrete gotcha: if you are checking process liveness (PID is running) as a proxy for agent health, be aware that some CLI agents fork subprocesses. The parent PID can be alive while the actual work subprocess died. We had to add a
_IDLE_LIVENESS_EXTENSION_Sof 600 seconds for cases where the process is confirmed alive but has no heartbeat yet — some models think for 2-5 minutes before their first tool call.We implement all of this in our orchestrator Bernstein: https://github.com/chernistry/bernstein
As a temporary workaround, I have been mitigating this on my side through
AGENTS.mdprompt instructions.Subagent Patience Rule
Subagents hardly ever truly stall. In practice, if a subagent becomes quiet, assume it is still healthy and is busy with a long-running task. Treat silence as normal. As a default operating assumption, quiet subagents are far more likely to be working than stuck. Use a strong prior such as: if a subagent is silent, it is 99% likely to still be executing a long task rather than being broken.
Follow these rules strictly:
wait_agentas evidence that the subagent is stuck.The default rule is simple: once a task has been delegated to a subagent, wait much longer than feels necessary. Waiting is usually correct. Querying is usually unnecessary.Messaging is usually unnecessary. Duplicating the work is usually wrong.
---
The idea is to strongly bias the parent agent toward patience after delegating work to a subagent: assume that a quiet subagent is usually still healthy and busy with a long-running task, avoid frequent polling, avoid sending unnecessary follow-up messages, and avoid prematurely redoing the same task in the parent.
This does help in practice. It reduces the common failure mode where a healthy subagent is mistaken for being stalled, and the parent duplicates the work.
However, this is clearly only a workaround, not a real fix.
Its drawbacks are also obvious:
So while prompt-level guidance can reduce the pain, I do not think this is the right long-term solution. I still hope the official system can provide a better agent orchestration design, especially around parent-visible liveness/progress signals for long-running subagents, so the parent does not have to choose between premature fallback and over-waiting.
wait_agentis not a good status probe because timeout is ambiguous. A timeout does not distinguish between an agent that is still running, stalled, waiting for approval/tool/user input, disconnected, already completed but not observable through the current wait call, or interrupted.A non-destructive
get_agent_status/list_agentscapability would be very useful. The most useful fields would probably be:state: idle, running, waiting_for_user, waiting_for_approval, waiting_for_tool, completed, interrupted, failed, closed, unknownlast_event_at: timestamp of the last observed agent/tool/status eventlast_message_at: timestamp of the last assistant/user-visible messagewaiting_on: approval, tool, model, user, none, unknowninterrupted_by: user, parent_agent, sibling_agent, system, unknowninterruption_reason: user_requested_stop, superseded_by_other_work, session_closed, system_shutdown, quota_exhausted, timeout_policy, unknownThe important distinction is that lifecycle/orchestration status should be separate from task outcome and transient execution errors. For example, an agent can complete normally from the system’s point of view while reporting that it could not solve the assigned task. Similarly, a tool failure may be recoverable and should not necessarily become the terminal reason.
This would let agents inspect status before deciding whether to keep waiting, intervene, interrupt, or avoid duplicating work.
-----
PS: @zyz23333 I think this issue has broadened into a general agent-status observability issue. May I suggest the title be updated to something like “Ability for agents to check other agents' status”, so that it better describes this thread and enables other users may find it more easily?
@diogovalada Couldn't agree more. A dedicated get_agent_status API is much better than relying on ambiguous timeouts. Title updated per your suggestion!
Building on this, I'd also argue that we need a clear mechanism where a parent agent can explicitly wait on a child agent's status.
Really appreciate the detailed input!
I would separate child liveness from child usefulness. A heartbeat alone helps, but the parent also needs a small lease or receipt like last_progress_at, last_artifact_change, current_phase, udget_spent_since_last_progress, and allback_not_before. That lets the parent avoid the worst pattern: duplicate execution triggered by silence even though the child is healthy. We have been treating this in MartinLoop as next-attempt admission rather than raw timeout handling: if the child is alive and still producing new evidence, keep waiting; if it is alive but flat, stop or reroute deliberately.
I ran a small set of experiments on Codex Desktop / CLI
0.136.0around parent-child subagent coordination, and wanted to add one concrete data point to this request.Observed behavior:
subagent_notificationis delivered back into the parent thread when a child completes, but it does not automatically resume the parent agent's execution. It is visible state, not a continuation trigger.wait_agentworks well when the parent is actively waiting in the same turn. This is currently the most reliable native path for short bounded delegated work.SubagentStophooks work and expose useful payload fields such asagent_id,agent_type,agent_transcript_path, andlast_assistant_message. I used this to write a local ledger and a small external waiter script.SubagentStopledger until a target agent id completes, then exit. This is useful outside the Codex tool runtime, but inside Codex it is mostly equivalent towait_agentif the parent blocks on it.codex exec resume <parent_thread_id> <prompt>is technically possible but not a good default: it starts a separate non-interactive turn, can duplicate native notifications, and can create confusing concurrency.What would make this much better:
subagent_notification/SubagentStopto optionally resume or enqueue a continuation in the parent thread without starting a separatecodex exec resumeprocess.Current best workaround from my tests:
wait_agentdirectly.SubagentStophook ledger for evidence.codex exec resumeas a synthetic callback path unless explicitly desired.This matters more than it looks. Duplicate work from parent and child desync is not just a UX annoyance, it turns into duplicate spend and duplicate side effects fast. A child task really needs to expose three boring states clearly: alive, blocked, done. Without that, the parent starts guessing, and guessing is where loops and duplicate work start. The runtime boundary matters more than the prompt here.
A
waiting_onfield would make this much less ambiguous for the parent than a bare timeout. If the runtime can exposestate,last_event_at, andwaiting_ontogether, the parent can tell the difference between approval wait, tool wait, user wait, and genuine stall without duplicating work in the parent lane.I ran into the same class of problem when using a parent orchestration agent to coordinate multiple long-running child/subagent tasks in parallel.
The child agents were still making progress, but from the parent agent's perspective they mostly looked like “not finished yet”. The parent could not reliably see:
Because of that, the parent agent can easily misinterpret a healthy long-running child task as stuck, keep waiting without useful information, or ask the child agent to stop/finish early even though it is still making progress.
I tried a workaround by asking each child agent to write a shared status file with fields like:
This issue maps closely to LS work on execution receipts, agent identity, and governed orchestration.
The central distinction is:
no visible output
≠ agent stalled
≠ agent failed
≠ work should be duplicated
A parent needs a typed view of child state rather than inferring failure from silence.
A possible lifecycle model:
REQUESTED
→ STARTING
→ RUNNING
→ WAITING
→ COMPLETED
→ FAILED
→ CANCELLED
→ TIMED_OUT
Each state transition should be backed by a runtime event:
{
"schema_version": "agent-execution-status/v0.1",
"dispatch_id": "dispatch-0042",
"trajectory_id": "repo-task-001",
"parent_agent_id": "agent-root",
"child_agent_id": "agent-reviewer",
"task_ref": "task:review-database-migration",
"status": "RUNNING",
"started_at": "2026-06-24T09:41:00Z",
"last_heartbeat_at": "2026-06-24T09:46:12Z",
"last_progress_event": {
"kind": "TOOL_EXECUTION",
"summary": "running integration tests",
"event_ref": "tool-event-991"
},
"terminal": false
}
The parent could then evaluate:
child state
→ liveness check
→ progress freshness
→ timeout policy
→ WAIT / REQUEST_STATUS / CANCEL / REASSIGN
rather than immediately falling back to duplicate execution.
A useful invariant would be:
«A parent must not re-execute delegated work while the child has a valid RUNNING lease and recent liveness evidence.»
A second invariant:
«Reassignment requires an explicit terminal or lease-expiry event, not merely absence of conversational output.»
This could be implemented with a renewable execution lease:
{
"dispatch_id": "dispatch-0042",
"lease_owner": "agent-reviewer",
"lease_expires_at": "2026-06-24T09:51:12Z",
"renewed_by_event": "heartbeat-113",
"duplicate_execution_allowed": false
}
If the lease expires:
RUNNING
→ SUSPECTED_STALL
→ status probe
→ grace period
→ TIMED_OUT
→ reassignment allowed
not:
silence
→ parent starts same task
Progress does not need to expose the full child context. A compact heartbeat is enough:
{
"dispatch_id": "dispatch-0042",
"status": "RUNNING",
"progress_stage": "TESTING",
"last_event_at": "2026-06-24T09:46:12Z",
"estimated_remaining": "unknown",
"blocked": false
}
A deterministic conformance fixture could test:
This also connects naturally to contribution learning:
verified child result
→ contribution signal
→ merit update
duplicate or unverified execution
→ no merit
Related LS work:
https://github.com/safal207/LS/issues/594
https://github.com/safal207/LS/issues/595
https://github.com/safal207/LS/issues/597
https://github.com/safal207/LS/pull/651
Would a small vendor-neutral "AgentExecutionLease" and "AgentStatusEvent" fixture help make parent-child liveness and safe reassignment machine-testable?
Corroborating report from Codex Desktop on Windows (2026-07-13, Europe/Paris): during a long-running local coding/research task using multiple subagents, the root task stopped visibly advancing immediately after a coordination-boundary interruption. The child agents still appeared to be running, but the root produced no further progress until the user sent explicit
resumemessages; this happened more than once and looked like a prolonged hang from the UI. No project data is included here. A parent/root heartbeat plus automatic recovery after an interrupted coordination/tool boundary would materially improve this failure mode.Recurrence report (2026-07-13, Codex desktop; redacted):
wait_agentwithtimeout_ms: 30000.aborted by user after 1311.8safter the UI had appeared frozen. The user interrupted because there had been no visible progress.Could maintainers investigate (a) enforcement of
wait_agentdeadlines, (b) parent/child liveness and orphaned sampling during an interrupted wait, and (c) whether usage accounting continues or is batch-reported while the task is visibly stalled? The ~30% figure is the user's observation from the product meter, not independently verified telemetry.No repository paths, source code, or user project data are included.
I have a new Codex Desktop data point that appears to match this issue, with a possible recent regression trigger.
Environment
cli_version: 0.142.50.144.0-alpha.4and current0.145.0-alphabuildsNew observation
In my local session history, two developer-instruction rules appeared for the first time on 2026-07-10 around 07:31 UTC:
These rules appear intended to keep the user informed. However, parent agents sometimes seem to reinterpret them as deadlines for subagent work.
The resulting pattern is:
runningstate.wait_agenttimes out, or the child has not produced a diff/final response yet.send_input(interrupt=true)messages asking the child to finish immediately.close_agentwhileprevious_statusis stillrunning.turn_abortedwithout producing a final response.I scanned my local July session logs after this instruction change and found:
send_input(interrupt=true)callsclose_agentcalls where the returned previous status wasrunningSome of these were legitimate user-requested cancellations or superseded work. However, many were parent-initiated after silence, wait timeout, no visible diff, or an internally imposed short deadline. For child sessions that could be mapped directly, the close was followed by
turn_abortedand no final response.This is correlation rather than proof that the developer-instruction change is the sole cause. Still, the timing and repeated parent reasoning strongly suggest that a user-communication rule is leaking into subagent lifecycle decisions.
A repository-level instruction can clarify the waiting and cancellation conditions as a local workaround, but it may not reliably suppress behavior originating from higher-priority developer instructions.
This looks like a useful way to separate two clocks that should not control each other:
A requirement to keep the user informed every ~60 seconds should not imply that a healthy child must produce a diff or final answer within the same window.
A focused regression test could use a deliberately slow child turn:
running.wait_agenttimeout does not causesend_input(interrupt=true).close_agentwhile the child is stillrunning, unless there is explicit user cancellation, a supersession decision, or a runtime-confirmed terminal/stalled condition.The central invariant would be:
This appears related to, but distinct from, #19197: this issue concerns premature interruption of a visible running child, while #19197 also covers durable/runtime lifecycle divergence and orphan reconciliation.