Codex app accumulates stale subagents in cache/UI and they cannot be closed reliably

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

What version of the Codex App are you using (From “About Codex” dialog)?

Versión 26.527.31326 (3390)

What subscription do you have?

Plus Plan

What platform is your computer?

Darwin 25.5.0 arm64 arm

What issue are you seeing?

Summary

In a long-running Codex desktop session that uses many subagents, the app appears to accumulate stale subagent entries in the UI/cache. Completed or already-closed agents can remain visible, and closing them is not always reconciled cleanly with backend state. Over time, this makes it difficult to tell which subagents are actually still alive.

Actual behavior

After repeated spawn/complete/close cycles:

  • many old subagents remain visible long after completion
  • some close attempts return shutdown
  • some close attempts return not found
  • some agents appear completed but still remain listed
  • the visible subagent count can grow very large (in my case, 100+)

Why this seems like an app bug

This does not appear to be tied to a specific repo workflow. In my case, the stale subagent buildup was separate from the actual project state, and some close attempts returning not found suggest the app UI/cache and backend agent state can drift out of sync.

Suggested debugging angles

  • UI cache vs backend state reconciliation for agent lifecycle
  • pruning/GC of completed subagents
  • handling of close_agent for already-completed or already-evicted agents
  • stale thread/agent handles remaining visible after shutdown
  • whether this only affects the UI list or also impacts future spawning

Screenshot

<img width="309" height="299" alt="Image" src="https://github.com/user-attachments/assets/e23f2b1a-623e-41cb-9fed-922eaaf8b995" />

What steps can reproduce the bug?

  1. Start a long Codex desktop session in a repo and use subagents heavily over time.
  2. Spawn many subagents across multiple roles (for example: researcher, planner, reviewer, coder, trainer).
  3. Let many of them finish normally.
  4. Close completed subagents from the agent controls and/or via tool-driven close requests.
  5. Continue spawning and closing more subagents in the same long-running session.
  6. Revisit the subagent list/sidebar after enough cycles.

Observed

  • many old subagents are still shown
  • some can no longer be closed cleanly
  • some close attempts return not found
  • some already-completed agents remain visible as if still retained in cache/UI
  • the visible count can grow very large (in my case, 100+)

What is the expected behavior?

Completed or explicitly closed subagents should no longer remain in the active visible subagent list.

The app should reconcile UI state with backend state reliably:

  • if an agent is completed, it should appear as completed and be removable/archived cleanly
  • if an agent is closed, it should disappear from the live list or move to a clearly separate historical section
  • if an agent no longer exists, the UI should not keep showing it as lingering cached state

Repeated spawn/complete/close cycles in a long session should not cause the visible subagent count to grow indefinitely with stale entries.

Additional information

_No response_

View original on GitHub ↗

23 Comments

github-actions[bot] contributor · 3 months ago

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

  • #23930
  • #23931
  • #24756
  • #23700

Powered by Codex Action

cnbetter · 2 months ago

Additional diagnostic evidence from another affected Codex Desktop macOS install.

Environment:

  • Codex Desktop: 26.609.41114 (build 3888)
  • macOS: 15.7.5 (24G624)
  • Long-running parent thread using repeated multi-agent/subagent workflows

Observed behavior:

  • The right-side Subagents panel in the parent thread showed roughly 383 stale subagent entries.
  • Opening visible entries still showed historical work records, so from the UI they looked like they had not been released.
  • Attempts to close known visible subagent IDs from the multi-agent tool layer returned agent ... not found, suggesting the live agent registry no longer had those handles.
  • The thread archive API also could not archive one visible subagent child thread from the parent context and returned No AppServerManager registered for conversationId: ....

Local state observations, sanitized:

  • state_5.sqlite.thread_spawn_edges initially had 184 rows for the affected parent thread; all were status = 'closed'.
  • The corresponding 184 threads rows were still visible enough to keep contributing to UI clutter until manually marked archived.
  • After clearing those DB edges and archiving those thread rows, the UI still showed stale subagents.
  • A full scan of rollout JSONL session_meta.source.subagent.thread_spawn.parent_thread_id found 386 subagent rollout files associated with the same parent thread:
  • 184 already represented by SQLite thread rows/edges
  • 202 additional orphan subagent rollout files under the normal sessions tree with no matching row in state_5.sqlite.threads
  • This suggests the Desktop UI/replay layer can reconstruct the parent subagent list from rollout/session files, not only from thread_spawn_edges.

Why this matters:

  • The user-visible subagent count can grow into the hundreds in a single long-running thread.
  • Completed/closed subagents remain visible as if they are still attached to the parent.
  • There appears to be no safe user-facing cleanup action that reconciles all layers: live agent registry, thread_spawn_edges, threads.archived, rollout JSONLs, and renderer cache.

Expected behavior:

  • Completed/closed subagents should be clearly separated from active subagents or hidden/collapsible as history.
  • A parent thread should have a reliable cleanup action for stale closed subagents.
  • Cleanup should reconcile durable state consistently across SQLite and rollout/session files.
  • Orphan subagent rollout files that are no longer indexed by threads should not be reattached to the parent UI as active/current subagents.

I avoided including local paths, project names, thread IDs, or transcript contents here. I can provide more specific diagnostics if there is a private/debug-safe channel.

ricardo-larosa · 2 months ago

Adding another datapoint from Codex Desktop/macOS with an uploaded feedback thread.

Uploaded feedback thread: 019ee572-2862-7903-8fa5-15d4c747fbcc

Environment:

  • Component: Codex app / desktop UI, subagents
  • Codex app bundled CLI: 0.142.0-alpha.6
  • Local Codex CLI: 0.141.0
  • Model: gpt-5.5
  • Platform: Darwin 25.0.0 arm64 arm, macOS 26.0.1

Observed behavior:

  • The Codex app UI still listed completed subagents in the Subagents picker after resuming the parent thread.
  • The active agent/runtime said it had no active subagent handles.
  • So the app chrome still surfaced stale subagent entries, while the current assistant turn could not list, inspect, steer, or close them.

Local evidence:

  • Parent thread observed locally: 019edeb1-707c-7fc2-9ad4-81d1aed871f9
  • Thread title: Build d3 iOS app
  • Local session logs showed these subagents reached task_complete, but the UI still surfaced them under Subagents:
  • Parfit: 019ee5a9-5b49-7ce1-91ef-51ec1d127a7f
  • Kierkegaard: 019ee5a9-5cad-7fc2-9fb7-97aa9c6b619d
  • Boyle: 019ee5a9-5e6b-77c0-8e43-ca9be5492fa9
  • Cicero: 019ee5a9-60af-7590-911f-fdb3781d36bc
  • Copernicus: 019ee5a9-6344-7031-8c23-789a0c61700e
  • Epicurus: 019ee5a9-be0d-70b1-81b0-f2d73cd8f34e

Expected:

  • Completed subagents should either be hidden from active subagent controls, clearly marked completed/closed, or rehydrated into the runtime as addressable handles with accurate status.

Note:

  • codex doctor --json was run from a sandboxed Codex session and included expected network reachability failures from the sandbox. The local state inventory itself reported rollout DB parity as OK.
ehendrix23 · 1 month ago

Seen same issue. Feedback: 019f04ff-b2ce-7302-be1a-b511e0ee7cc1

PurpleDevX · 1 month ago

Compaction purges the subagents IDs from the context, and there's no tool that can be used to get those IDs back, so Codex has no way of closing the subagents.

In a long orchestration agent session, eventually the subagent limit is reached due to the leak and then all further subagents fail to be created.

nima20002000 · 1 month ago

Additional reproduction from a long-running Linux Codex session (Codex CLI 0.145.0):

  • Generic native delegation reported a thread-limit error when spawning a new Terra reviewer, even though only the root and one active reviewer were relevant to the current work.
  • The live-agent tree retained completed/interrupted historical children, and there was no exposed close/lifecycle control to reclaim their slots.
  • The deferred catalog contained no multi_agent_v1__* lifecycle tools.
  • This made the required independent final review impossible without starting a new root session; no commit was made.

Impact: capacity accounting appears to include stale completed/interrupted children, so a review-fix-review workflow can dead-end late in a task. Expected behavior: completed or interrupted children should stop consuming spawn capacity, or callers should have a reliable close/prune control and an accurate capacity/status API.

Separately, I attempted the documented isolated codex exec reviewer fallback. It launched with the requested model/effort and read-only sandbox, but repeatedly emitted a large tool transcript without a usable final review verdict, so it could not substitute for the final review gate. This may be a related fallback/reporting issue.

grtninja · 1 month ago

Windows corroboration from a long-running /goal session on July 23, 2026.

A single Codex Desktop screen showed:

  • parent goal state: Paused;
  • elapsed time: about 5d 10h 46m;
  • Subagents panel: 5 working, 373 done;
  • account state: out of Codex and Work usage;
  • goal card still at Step 1 / 8;
  • many repeated automatic-compaction events immediately above.

The screenshot cannot prove whether the five working children were truly live or stale UI/cache entries. That is precisely the lifecycle ambiguity described here: after the parent is paused and unable to continue, the app still presents children as working without exposing authoritative backend handles, pause-propagation results, or a stale/historical classification.

A separate state-reconciliation report was filed as #35052 because the same screen also shows the parent pause, usage gate, step counter, and subagent counts disagreeing. This comment is the narrower cross-platform corroboration for stale/untrustworthy subagent UI state. The exact Desktop build was not captured; private goal/repository names are omitted.

koksny · 1 month ago

Additional Windows evidence with a direct correlation between the stale UI card, the child's terminal rollout event, persistent SQLite state, and the renderer's lazy thread/read reconciliation.

Environment

  • Codex Desktop package: 26.721.4979.0
  • Local Codex CLI: codex-cli 0.145.0
  • Windows 11 Pro 10.0.26200
  • Long-running Desktop parent thread with repeated native subagent delegation
  • Parent thread: 019f63c1-aa87-73b1-84ad-a52bbdb047d2

No artificial reproduction was run. This evidence comes from the existing affected thread, other existing sessions, state_5.sqlite, rollout JSONL files, logs_2.sqlite, and Desktop renderer logs.

Screenshot timeline

Two screenshots were captured immediately before interacting with the stale card:

  • 2026-07-26 16:36:27 local: the Subagents summary showed 1 working / 40 done (1 w toku / 40 Gotowe).

<img width="506" height="136" alt="Image" src="https://github.com/user-attachments/assets/9919f7d2-b291-4cf2-8c74-82d3c1c0a3c2" />

  • 2026-07-26 16:36:32 local: the only active card was Bench model audit, status Working (Pracuje), elapsed 7d 14h 57m 7s.

<img width="1262" height="163" alt="Image" src="https://github.com/user-attachments/assets/548f6eac-e834-4cea-aad4-5191711c7a0a" />

The displayed elapsed time matches the child's creation timestamp almost exactly. The corresponding child was created locally on July 19 at 01:39 and had actually reached task_complete at 01:44. The UI timer therefore appears to have continued measuring from creation while relying on stale active state, rather than reflecting a recent heartbeat or model request.

Direct lifecycle-state evidence

Current thread_spawn_edges state:

| Status | Count |
|---|---:|
| open | 2,067 |
| closed | 28 |

Age of children whose edge is still open, based on the child thread's last update:

| Last child update | Count still open |
|---|---:|
| More than 1 hour ago | 2,067 |
| More than 1 day ago | 2,057 |
| More than 7 days ago | 1,689 |
| More than 30 days ago | 13 |

The affected parent alone has 35 child edges, all persisted as open.

Representative completed children from that parent:

| Child | Nickname | Terminal event | Edge | threads.tokens_used |
|---|---|---|---|---:|
| 019f63c3-b2d2-71c1-8ffe-05528872f15b | Kierkegaard | task_complete at 2026-07-15T03:23:51.832Z | open | 25,285,561 |
| 019f7799-4beb-7732-8eb0-f9de4ed5bb69 | Turing | task_complete at 2026-07-18T23:44:24.795Z | open | 188,044,240 |
| 019f8abe-4efd-7d32-a307-9803cbf7f48c | Kepler | task_complete at 2026-07-22T16:56:14.093Z | open | 245,676,686 |

Each rollout ends normally with:

agent_message phase=final_answer
response_item role=assistant phase=final_answer
token_count
task_complete

A correctly closed child inspected for comparison ends with the same sequence. The terminal rollout event therefore does not reliably propagate into the durable spawn-edge status.

This is not isolated to one parent. For the eight parent threads with the largest cumulative token counts under open children, I inspected the highest-token open child from each. Seven of the eight rollouts ended with task_complete in their final lines while the persistent edge remained open.

Lazy reconciliation of the seven-day-old card

The child matching the stale screenshot is Turing:

child thread: 019f7799-4beb-7732-8eb0-f9de4ed5bb69
created locally: 2026-07-19 01:39:22
last child update locally: 2026-07-19 01:44:24
rollout terminal event: task_complete
persistent edge after completion and after UI interaction: open

At the moment the card was interacted with, the Desktop log recorded:

2026-07-26T14:36:44.758Z (16:36:44 local) thread/read
  conversationId=019f7799-4beb-7732-8eb0-f9de4ed5bb69

2026-07-26T14:36:45.032Z (16:36:45 local) thread/read
  conversationId=019f63c1-aa87-73b1-84ad-a52bbdb047d2

2026-07-26T14:36:45.104Z (16:36:45 local) thread/list

The card then moved from working to completed. There was no thread/resume or turn/start for the child around this interaction, and its rollout and updated_at did not change. This strongly suggests that the renderer initially used stale lifecycle state and reconciled the child only after a lazy per-card thread/read.

An earlier parent-view activation also showed resumeState=needs_resume, followed by thread/resume, and then maybe_resume_success with both latestTurnStatus=completed and markedStreaming=true. No model turn started in that sequence, but it demonstrates ambiguous rehydration state that may explain why terminal children initially render as working.

Token-volume evidence and limitation

The 35 open children under this parent have a combined:

threads.tokens_used = 4,975,576,030

This is almost exactly five billion raw cumulative tokens. It is not a billing statement and does not prove post-completion execution. For the child observed during the card interaction, the logs show no new model turn or rollout write.

So the evidence confirms stale lifecycle state and lazy UI reconciliation, but does not confirm that hovering or loading the card re-executed the child. The high historical volume may have accumulated during the original runs and been amplified by repeated long-context/model-cycle behavior described in #35050 and #32503. Internal request/quota telemetry is needed to determine whether any completed child ID was scheduled after its original task_complete.

Expected behavior

  • task_complete should atomically transition the durable parent/child lifecycle out of open, or persist a distinct terminal state rendered as completed.
  • Loading a parent should reconcile all child states before rendering the working count, not wait for pointer hover or per-card thread/read.
  • working should only be shown when the backend confirms a live child handle with an active turn.
  • Renderer restoration must never schedule a token-consuming child turn without an explicit pending submission/turn ID.
  • Diagnostics should distinguish persisted edge state, rollout terminal state, live registry state, renderer/cache state, last model-request time, and restore-only versus execution-producing thread/resume.

Related: #35052 corroborates the Windows UI-state ambiguity; #25426 demonstrates durable/live registry divergence; #17832 links incomplete subagent teardown with leaked MCP processes and memory. #35050/#32503 concern a different layer and are best treated as possible cost amplifiers, not the root cause of the stale open edge.

JeanKadang · 20 days ago

Additional Windows reproduction from Codex Desktop 26.803.5235.0.

Environment:

  • Windows x64
  • Codex Desktop 26.803.5235.0
  • Long-running parent thread using repeated subagent-driven implementation and review cycles

Observed behavior:

  • The Subagents panel showed 22 agents under Active, all labelled Working, with timers continuing from roughly 5 to 9 hours.
  • Fourteen were from one completed issue workflow; eight were older generic implementer/reviewer/verifier agents.
  • The current live-agent registry did not expose these children, and targeted interrupt attempts returned not found.
  • After recovering child thread IDs from the parent thread history, direct thread reads showed status notLoaded and completed turns, while the UI continued to label the same cards Working and increment their timers.
  • Archiving all recovered child thread IDs returned archived=true. The panel reconciled only partially: Active changed 22 -> 21 -> 8, and the remaining eight timers continued increasing.
  • Repeating archived=true for the remaining eight still did not immediately clear their Working cards.

This is strong evidence of renderer/parent-tree lifecycle state diverging from authoritative child thread state. It also demonstrates that the displayed timer is age since creation, not proof of a live turn or heartbeat.

Expected:

  • A completed child turn should atomically leave Active and stop its timer.
  • Parent-thread restoration should reconcile every child against authoritative thread/turn state before rendering Working.
  • Archiving a child should reliably invalidate the parent Subagents panel cache.
  • The UI should distinguish live execution from historical completed records.

No evidence of post-completion token execution was observed; the defect is that the UI presents completed/notLoaded children as actively working. Screenshots of the 22, 21, and 8 Active states are available if maintainers need them.

Fire-Dragons · 19 days ago

Additional macOS Desktop evidence showing that durable open state is overwhelmingly stale and does not represent live subagent execution.

Environment

  • Codex Desktop: 26.730.61639 (build 6234)
  • Bundled CLI: 0.147.0-alpha.1.2
  • macOS 26.5.2 (25F84), arm64
  • Long-running parent threads with repeated native subagent workflows

Current durable lifecycle state

The active state_5.sqlite contains 644 thread_spawn_edges rows:

| Edge state | Count |
|---|---:|
| closed | 382 |
| open | 262 |

Joining those edges to the child thread's last update time:

  • 256 of 262 open children had no update for more than 1 hour
  • 242 of 262 open children had no update for more than 24 hours
  • only 6 open children had any update in the previous hour

At sampling time, the running Codex app-server had only four subagent rollout files open, despite 262 durable edges being marked open.

Three representative long-lived parents showed:

  • parent A: 179 children = 151 closed + 28 open; all 28 open children were stale for more than 1 hour
  • parent B: 114 children = 99 closed + 15 open; 9 of the open children were stale for more than 1 hour
  • parent C: 49 children = 41 closed + 8 open; all 8 open children were stale for more than 24 hours

The Desktop catalog reported the first two parents as active and the third as notLoaded. From the user surface, many historical children remain listed while attempts to steer, message, or close them are frequently unavailable or unsuccessful. The state distribution confirms that this is not just a large amount of legitimate concurrent work.

Expected behavior

  • A terminal child event should atomically transition the durable spawn edge out of open.
  • Restoring a parent thread should reconcile child edges against terminal rollout state and the live agent registry before rendering Active/Working.
  • Sending or closing should return an authoritative terminal state instead of leaving an unaddressable child listed as open.
  • The parent UI should provide a reliable bulk action to reconcile or archive stale completed children.
  • Active counts should be based on a live turn/handle, not merely a persisted historical edge.

The same audit found that stale/closed child rollout retention had grown active session storage to 405 GiB. The sanitized storage attribution and fork amplification evidence is here: https://github.com/openai/codex/issues/30779#issuecomment-5229666803

No transcript content, project identifiers, thread IDs, task titles, or machine-specific absolute paths are included.

Fire-Dragons · 19 days ago

One important clarification about the causal loop behind the large stale-agent count: the workflow is explicitly instructed to prefer reusing an existing subagent instead of spawning a new one. The high count is therefore not intentional fan-out.

The observed sequence is:

  1. A parent thread already has a suitable existing subagent and tries to reuse it for follow-up work.
  2. Sending or steering the follow-up to that child is unavailable or fails because the child is no longer addressable through the live agent registry.
  3. Attempts to stop or close the same child are also unavailable or unsuccessful.
  4. The old child continues to appear as Running/Working, and its durable spawn edge can remain open, even though it is not doing useful work.
  5. To finish the requested work, the orchestrator creates a replacement subagent.
  6. The replacement can later enter the same state, so repeated reuse failures convert into an ever-growing list of apparently running children.

This explains why a single long-lived parent can reach roughly 100-200 child entries despite having a reuse-first policy. It also links the lifecycle bug to the storage amplification reported in https://github.com/openai/codex/issues/30779#issuecomment-5229666803: every forced replacement can materialize another large child rollout while the previous stale child remains retained.

Expected behavior:

  • Reuse should resolve an existing child by durable child thread identity after compaction, resume, or renderer reload.
  • A follow-up send should either schedule the child or return an authoritative terminal result that allows immediate reconciliation.
  • Close should be idempotent: closing an already-completed/evicted child should transition the durable edge and UI out of Running instead of failing while leaving stale state.
  • Before spawning a replacement, orchestration should reconcile the intended reusable child against terminal rollout state, durable edge state, and the live registry.
  • The UI should distinguish “historical but not addressable” from genuinely live Running/Working children.

No child IDs, parent IDs, task names, prompt text, or transcript content are included.

Fire-Dragons · 19 days ago

A second direct reproduction path is worth recording because it does not depend on passive UI restoration:

  1. In the affected long-running main thread, the user explicitly sends an instruction to clean up and close historical subagents.
  2. The main agent can see or infer that historical subagents exist, but the close operation cannot successfully address and close them.
  3. The cleanup request completes unsuccessfully or reports that the historical children cannot be closed.
  4. Those same historical entries remain visible as Running/Working instead of moving to a terminal or historical state.
  5. Later reuse attempts still cannot message or steer them, so replacement subagents are spawned and the list continues growing.

This shows the defect is not only stale rendering after restart. It is also reproducible through an explicit user-initiated cleanup/close command from the owning parent thread. The parent has enough durable history to display the children, but apparently lacks authoritative live handles or an idempotent reconciliation path to close them.

Expected behavior for a main-thread cleanup command:

  • enumerate all children attached to that parent from durable state;
  • reconcile each child against its terminal rollout event and live registry state;
  • idempotently mark already-completed or evicted children closed;
  • stop genuinely active children;
  • return a per-child result such as active-stopped, already-terminal, closed, or failed with a recoverable reason;
  • update the Active/Done UI immediately so closed history no longer remains labeled Running.

This is the same reuse/close failure loop described in my previous comment, now with an explicit parent-thread cleanup command as the trigger. No task text, IDs, project data, or transcript content are included.

RoshanDev · 18 days ago

Additional quantitative Windows evidence from Codex Desktop 26.803.5235.0.

This was collected read-only from an actively running, long-lived Goal. I did not edit SQLite/session files, restart Desktop/app-server, archive children, or interrupt the Goal.

Authoritative current state

The parent had just started exactly three fresh read-only acceptance subagents. Direct thread/read results showed all three child threads with current inProgress turns. The parent's current turn also contained exactly three corresponding subAgentActivity(kind=started) items.

Durable edge state for the same parent

state_5.sqlite.thread_spawn_edges contained 279 child rows for that parent, and all 279 were still status = 'open'.

Joining every edge to its child rollout and inspecting the tail produced this exact partition:

| Child rollout state | Count |
|---|---:|
| terminal task_complete present | 257 |
| terminal turn_aborted present | 19 |
| no terminal marker | 3 |

The three rollouts without a terminal marker were exactly the same three children currently reported inProgress. Therefore:

  • authoritative live children: 3
  • completed/aborted children still persisted as open: 276

Additional durable-state facts:

  • 97 of the 279 child thread rows were already archived;
  • 182 were not archived;
  • 276 had no update for more than one hour;
  • 275 had no update for more than seven days.

Projection evidence

Before the three current children were spawned, recent full world_state snapshots had state.environments.subagents = null. The next three snapshots advanced cleanly from one to two to three named subagents as the fresh children started. This indicates the current environment projection can represent the real live set accurately, while the durable thread_spawn_edges.status = open population remains unreconciled and can still drive an incorrect Active/Working UI count.

Suggested owning-layer invariant

  1. A terminal child event (task_complete, aborted/interrupted/stopped) must idempotently transition its spawn edge out of open.
  2. Parent restore/read should reconcile durable edges against terminal rollout state and the live registry before rendering Active/Working.
  3. Active count should require an authoritative live handle with a current inProgress turn; historical edge presence alone is insufficient.
  4. Add a regression covering: spawn many children -> complete/abort them -> compact/reconnect/restore parent -> spawn three new children -> Active count is exactly three, while older children remain terminal history.

This dataset cleanly distinguishes stale UI/durable lifecycle state from actual ongoing subagent work: the only three non-terminal rollouts are the only three currently live children.

nathanposton · 18 days ago

Corroborating this on Windows with a concrete UI/backend state divergence.

Environment

  • Codex/ChatGPT desktop app: 26.803.5235.0
  • Windows x64
  • Long-running local task with heavy subagent use

Observed

  • Subagent panel shows 111 Active entries with continuously increasing timers and 13 Done entries.
  • Restarting the desktop app does not clear or reconcile the Active entries.
  • The live collaboration registry reports only the root agent running and zero live subagents.
  • Therefore the 111 Active rows do not represent live executions.

Persisted-session evidence

  • Session JSONL size: approximately 278.2 MB
  • Recorded collaboration calls:
  • spawn_agent: 117
  • wait_agent: 827
  • send_message: 214
  • followup_task: 74
  • interrupt_agent: 13
  • list_agents: 205
  • The coincidence between 13 explicit interrupts and 13 Done rows suggests that some terminal lifecycle transitions are persisted while naturally completed, pruned, or compacted agents remain marked Active in the UI.

Impact

  • Users cannot distinguish real agents from stale entries.
  • Timers imply ongoing execution/cost even though the live registry is empty.
  • The task's desktop renderer reached roughly 0.86–0.97 GB working set, with all renderer processes totaling over 1.1 GB. The large transcript and continuously updated stale-agent rows appear to contribute.
  • Moving to a new task/session is the only practical recovery found so far.

Expected

  • On app startup and periodically thereafter, reconcile the displayed agent list against the authoritative live registry.
  • Mark missing agents terminal/stale instead of continuing their timers.
  • Keep historical agents in a separate collapsed/archived section and stop timer updates.
  • Provide a user-visible “resync/prune stale agents” control.

This appears to be persisted task-state/UI reconciliation rather than currently executing orphan processes.

RoshanDev · 18 days ago
Corroborating this on Windows with a concrete UI/backend state divergence. Environment Codex/ChatGPT desktop app: 26.803.5235.0 Windows x64 Long-running local task with heavy subagent use Observed Subagent panel shows 111 Active entries with continuously increasing timers and 13 Done entries. Restarting the desktop app does not clear or reconcile the Active entries. The live collaboration registry reports only the root agent running and zero live subagents. Therefore the 111 Active rows do not represent live executions. Persisted-session evidence Session JSONL size: approximately 278.2 MB Recorded collaboration calls: spawn_agent: 117 wait_agent: 827 send_message: 214 followup_task: 74 interrupt_agent: 13 list_agents: 205 The coincidence between 13 explicit interrupts and 13 Done rows suggests that some terminal lifecycle transitions are persisted while naturally completed, pruned, or compacted agents remain marked Active in the UI. Impact Users cannot distinguish real agents from stale entries. Timers imply ongoing execution/cost even though the live registry is empty. The task's desktop renderer reached roughly 0.86–0.97 GB working set, with all renderer processes totaling over 1.1 GB. The large transcript and continuously updated stale-agent rows appear to contribute. Moving to a new task/session is the only practical recovery found so far. Expected On app startup and periodically thereafter, reconcile the displayed agent list against the authoritative live registry. Mark missing agents terminal/stale instead of continuing their timers. Keep historical agents in a separate collapsed/archived section and stop timer updates. Provide a user-visible “resync/prune stale agents” control. This appears to be persisted task-state/UI reconciliation rather than currently executing orphan processes.

One additional restart/reconnect reproduction may help narrow the owning layer.

Observed sequence

  1. Open a long-running task containing many historical subagents.
  2. Fully close and reopen the Codex Desktop app.
  3. Immediately after startup, historical subagents initially appear under Active / Working.
  4. Over time, the displayed Active count gradually decreases and entries move to Done.
  5. If network connectivity is interrupted while this transition is still in progress, the entries that have not yet moved remain stuck under Active / Working.
  6. Restoring connectivity does not reliably resume or complete the reconciliation; their timers continue even though they are not live agents.

This complements the live-registry divergence reported above and suggests that startup reconciliation is incremental and can be interrupted before reaching a stable terminal projection.

Expected behavior:

  • persisted terminal state should be applied before rendering historical agents as Active;
  • reconciliation should resume idempotently after reconnect;
  • temporary transport failure should not leave unreconciled historical entries permanently marked Working;
  • Active timers should only run for agents confirmed by the authoritative live registry.
roman-dubko · 17 days ago

Windows corroboration (Codex App 26.803.10989.0)

I can reproduce the stale Active-list state on Windows 11 in a long-running coordination session.

Observed

  • The Subagents panel reports Active: 29 and labels many historical agents as “Working”, even though their useful work and result collection completed hours or days earlier.
  • The currently reachable coordinator registry sees only the parent as running, two children as completed, and one old child stuck at pending_init.
  • Sending the supported interrupt request to that clearly stale pending_init record returned previous_status: pending_init, but the record remained pending_init and the UI count did not reconcile.
  • The current callable tool surface does not expose a close operation for those historical handles, so the parent cannot safely repair the already-stale UI state. Interrupt is not equivalent to close.

Expected

  • “Active” should be derived only from genuinely live running/queued child state.
  • Completed, errored, interrupted, or evicted children should move to “Done” or a historical section automatically.
  • On app startup and after stop/close operations, the UI should reconcile against backend agent state and drop stale handles from the active count.

The attached screenshot is from the affected session. Repository contents, credentials, source code, and private payloads are omitted.

<img width="3440" height="1398" alt="Image" src="https://github.com/user-attachments/assets/808865dd-2e21-4841-bace-48986020610a" />

ataleb52 · 16 days ago

Additional macOS Desktop data point, likely the same lifecycle/UI reconciliation family.

Environment:

  • ChatGPT/Codex desktop app 26.803.61601 (build 6396)
  • macOS on Apple Silicon
  • Long-running local Codex task using subagents

Observed:

  • The Subagents pane shows 52 Active entries and several Done entries.
  • Visible Active entries include workers whose completed results were already returned to the parent.
  • The parent-side live agent registry reports zero child agents.
  • Attempting to target a visible worker through the available orchestration control surface returns not_found.
  • Restarting the local Codex host after a controlled termination did not reconcile the displayed active entries. It only crashed/restarted the app; the stale Active list persisted.
  • The UI provides no usable per-agent stop/close action for these entries.

Impact:

  • It is impossible to distinguish real work from stale state.
  • The user cannot confidently start new multi-agent work or recover capacity.
  • Archiving the parent thread is not documented as a safe agent-close operation.

Expected:

  • Completed or interrupted children should reconcile to Done or Closed.
  • A visible Active agent must have an addressable stop/close control.
  • The app should offer a safe resync or close-finalized-agents action that does not require users to edit local state files or terminate app processes.

I can provide redacted screenshots of the 52-active pane and the control-plane mismatch if useful.

stevepryde · 16 days ago

Additional reproducible evidence from Codex Desktop 26.803.61601 (build 6396), macOS 26.5.2 arm64:

  • In one long-running parent task, the visible UI reported 19 subagents working after the agents had completed.
  • Before spawning any new work, the live collaboration API listed only the root agent as running.
  • Local persisted state for that parent contained 19 stale child rows in thread_spawn_edges, all still marked open.
  • Spawning four new agents and then explicitly interrupting them left 23 child edges marked open, even though the live API reported those four as interrupted.
  • Calling the official thread archive operation for all 23 child thread IDs succeeded and set every child thread to archived, but every corresponding thread_spawn_edges.status value remained open.

This makes the drift concrete: child lifecycle/archive state and the parent-child edge status are not reconciled. A counter derived from open spawn edges can therefore continue reporting completed/interrupted/archived agents as working.

Expected: completion, interruption, or successful archival should transactionally close the corresponding spawn edge, and loading a parent task should reconcile stale open edges against current child state.

roman-dubko · 16 days ago

Windows follow-up: stale Working UI persists with zero open spawn edges

This adds a second failure mode to the open-edge drift described above.

Environment:

  • Codex Desktop: 26.803.10989.0
  • Windows x64
  • Long-running coordination tasks with completed subagents

After a full application exit and relaunch (confirmed by fresh Codex process start times), the Subagents panel still displayed 39 historical children as Working.

A read-only post-restart check of persisted lifecycle state showed:

  • global thread_spawn_edges: closed=335, open=0
  • affected parent descendants: total=39, closed=39, open=0
  • a second long-running parent: total=45, closed=45, open=0
  • the application task reader exposed no independently active child task

So stale open spawn edges are one reproducible cause, but they are not sufficient to explain every stale Active/Working list. In this Windows case, every persisted edge was already terminal and the stale UI survived a clean restart.

This suggests the panel can also be rehydrated from another historical projection (for example rollout/world-state replay or renderer state) without applying the terminal edge state as the authoritative result.

Expected: on parent-task load, if the authoritative lifecycle store and live registry both contain no open child, the Active/Working list must be empty; historical children may remain only under Done/history.

No local paths, task IDs, repository contents, credentials, transcript contents, or project payloads are included. No cache, SQLite, rollout, transcript, history, or repository file was changed for this follow-up.

Silveroboros-dev · 15 days ago

Additional macOS reproduction: 76 Active in UI, zero running children in live registry

This appears to be the same lifecycle/UI reconciliation defect.

Environment

  • ChatGPT/Codex Desktop 26.803.61601 (build 6396)
  • Bundled codex-cli 0.147.0-alpha.6.5
  • macOS 26.5.1 (25F80), Apple Silicon (arm64)
  • Long-running parent task with repeated native subagent workflows

Observed

  • The expanded Subagents pane reports Active · 76 and 9 done.
  • Every visible Active row is labeled Working; displayed timers range from roughly 1 day 7 hours to more than 5 days 20 hours.
  • Multiple rows are workers whose final results had already been returned to the parent days earlier.
  • The authoritative live collaboration registry currently reports zero running child agents (only the root is running; the currently addressable children are terminal).
  • A read-only local process audit found no corresponding test, server, or worker processes and no zombie processes. This does not by itself rule out remote model work.

Persisted-state evidence (read-only)

For the affected parent, thread_spawn_edges contains:

  • 82 direct child edges;
  • all 82 still marked open;
  • 81 children with no thread update for more than 1 hour;
  • 78 children with no thread update for more than 1 day;
  • 0 archived child rows.

The UI's 76 Active count therefore does not match either the live registry (0 running children) or the direct persisted-open count (82). No SQLite/session files were edited, no processes were killed, and no cleanup workaround was attempted.

Possible usage impact — correlation, not proven causation

The account's weekly Codex usage allowance has appeared to deplete unusually quickly over the last couple of days. I cannot establish that stale UI entries caused this: UI timers are not inference telemetry, and local persisted token counters are not billing records. It would be useful for OpenAI to correlate the affected parent/child lifecycle with server-side request and quota telemetry and determine whether any child received model work after its terminal event.

Expected

  • Active / Working should require an authoritative live handle with an in-progress turn.
  • Terminal children should move to Done/history and stop their timers.
  • Parent restore should reconcile spawn edges, terminal rollout events, and live registry state before rendering counts.
  • A safe resync/prune control should be available without editing local state or killing processes.

Screenshots are available, but are not attached here because their task titles contain private project context. A redacted version or private feedback session can be provided if useful.

MrSmokiMo · 2 days ago

Additional Windows reproduction: 17 ghost cards, backend has zero handles

I can reproduce this issue on the current Windows Codex Desktop app with a stronger UI/backend mismatch.

Environment

  • Codex Desktop package: OpenAI.Codex_26.820.7780.0_x64
  • Desktop executable: ChatGPT.exe
  • Embedded Chromium file/product version: 151.0.7922.170
  • Windows x64, build 22631
  • Surface: expanded Subagents section in a long-running parent task

Reproduction and observed state

  1. Use one long-running parent task across several bounded subagent waves.
  2. Let the subagents complete and close them through the supported agent close API.
  3. Continue using the parent task and repeat.
  4. Expand the parent task's Subagents section.
  5. In this case, 17 historical cards remained visible.
  6. Recover the exact 17 agent IDs from the parent rollout's historical world_state.payload.state.environments.subagents.
  7. Call the supported close operation for every exact visible ID.
  8. The backend returns not-found for 17/17 IDs.
  9. Repeat for the five agents from the most recent wave after explicit completion/close: 5/5 not-found.
  10. Re-navigate to the same parent task through the supported task navigation API; it returns navigated=true.
  11. The user can still observe the same stale cards.

None of the visible cards had a live “working” indicator, but they remain in the ordinary Subagents list rather than a separate historical section. No SQLite or rollout files were modified.

Expected

  • The active Subagents list should reconcile against current backend lifecycle state.
  • If close_agent(id) returns not-found, that exact ID should not remain in the active/open list.
  • Completed/closed/evicted agents should disappear or move to an explicitly historical, clearable section.
  • Reopening or navigating back to the parent task should invalidate stale subagent-list cache/state.

Additional diagnostic clue

The displayed ID/name pairs remain in historical rollout world_state ... environments.subagents snapshots even though the live agent registry no longer resolves them. This suggests the UI may be rendering a persisted historical relationship/snapshot without a terminal reconciliation event.

Potential areas:

  • live registry vs persisted world_state.environments.subagents reconciliation;
  • stale parent-child/spawn-edge GC;
  • close(not-found) not generating a UI-removal lifecycle event;
  • navigation/reload not invalidating the subagent list selector/cache;
  • active and historical cards sharing the same sidebar model.

Impact

The user cannot trust the list to determine whether work or concurrency slots remain active, and repeated supported close attempts cannot repair the UI. This has occurred multiple times in the same long-running parent task.

I have retained a sanitized local report and two screenshots. Full task IDs, agent IDs, repository details, prompts, and local paths are intentionally omitted from this public comment, but can be supplied through a private maintainer channel if useful.

Suggested regression test: spawn/complete/close multiple waves, assert backend count zero, persist/reload/navigate parent, and assert the active Subagents section is empty—including the case where a repeated close returns not-found.

XiaoWenZz · 2 days ago

Additional macOS reproduction: UI shows 180 Working while live registry has no child running

Environment:

  • Codex / ChatGPT Desktop: 26.818.61809 (build 7019)
  • Bundled CLI: codex-cli 0.149.0-alpha.4.3
  • macOS 27.0 (26A5416b), Apple Silicon (arm64)

Observed:

  • The Subagents UI shows Working · 180 in one long-running parent task.
  • The authoritative live collaboration registry reports only the root/Owner running.
  • The only two currently addressable child records are terminal: one completed / DONE, one completed / BLOCKED.
  • There is no corresponding population of live worker processes.

Read-only persisted-state evidence:

  • Global thread_spawn_edges: 861 total, 714 open, 147 closed.
  • For the affected parent: 242 direct edges still marked open.
  • Of those 242 child threads, 240 are already archived and only 2 are non-archived.
  • The displayed 180 therefore matches neither the live registry (0 running children) nor the persisted direct-open count (242).
  • No SQLite/session state was modified and no cleanup workaround was attempted.

Assessment:
This appears to be a lifecycle reconciliation defect. Archived and terminal child threads can retain thread_spawn_edges.status = open, and the UI renders a third inconsistent Working count. This is UI/accounting state, not evidence of active model work.

Expected:

  • Derive Active/Working from authoritative live execution state.
  • Transactionally close the spawn edge when a child completes, blocks, is interrupted, or is archived.
  • Reconcile stale edges on parent load/startup.
  • Move terminal children to Done/history and stop their timers.
  • Provide a supported resync/prune operation so users never need to edit local state manually.

The current desktop automation interface explicitly refuses to control the Codex app itself, so I could not submit the same report through the in-task /feedback dialog. This public comment contains only sanitized counts and version information; no task IDs, prompts, repository content, credentials, logs, or database files are included.

JohnDiBernardi · 1 day ago

Still reproducible in Codex Desktop on macOS as of 2026-08-26.

In a long-running project task that repeatedly spawned bounded review subagents:

  • each known child was explicitly closed;
  • subsequent close attempts for those same handles returned agent not found, indicating no live manager object remained;
  • nevertheless, completed/closed subagent entries continued to be retained and shown by the desktop task UI;
  • the agent-facing lifecycle controls available in the task exposed close, but no supported list/delete/remove/prune/GC operation for stale historical child records.

This leaves the UI and live manager state demonstrably out of sync. The user has encountered the accumulation repeatedly over a long period and is specifically concerned about memory/resource degradation from retained subagent records. We did not measure RAM or disk growth in this reproduction, so that part is reported as impact/concern rather than a confirmed causal measurement.

Requested behavior:

  1. reconcile UI child records after close/not-found;
  2. distinguish Active vs Done/History clearly;
  3. provide a supported bulk archive/delete/prune action for completed child threads;
  4. expose an authoritative active-agent list;
  5. ensure historical child records are lazy-loaded/bounded so repeated subagent rounds cannot grow UI memory indefinitely.

No private repository content or task/agent IDs are included here.