Codex Desktop: completed subagents restore as Active after reload

Open 💬 15 comments Opened Aug 5, 2026 by molamola-git
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Version and platform

  • Codex Desktop for Windows x64
  • Store package OpenAI.Codex 26.730.8199.0
  • Installed app.asar SHA-256: acba5f408b7c6c909ffbfdf3c7d3f10660897bfbbb10f916a78505986b44b772

Bug

After Desktop reloads a task with a long subagent history, completed child agents are restored under Active instead of Done.

This is not a small count drift. In one reproducible parent task:

| Evidence | Count |
|---|---:|
| Direct child spawn edges | 126 |
| Child rollout ends in task_complete | 117 |
| Child rollout ends in turn_aborted | 6 |
| Nonterminal or unresolved | 3 |
| Desktop panel shows Active | 109 |
| Desktop panel shows Done | 17 |

At least 100 durably completed children are therefore displayed as active.

The underlying child records are not lost. A direct thread/read for an affected child returns thread.status = notLoaded and a latest turn whose status is completed.

Reproduction

  1. Open a Desktop task.
  2. Spawn and complete enough subagents for the parent to retain several historical children.
  3. Restart Desktop or otherwise cold-hydrate that task.
  4. Open the Subagents panel.
  5. Observe completed children under Active.
  6. Directly read one of those children: the runtime thread status is notLoaded, while its latest durable turn is completed.

Root cause

The shipped renderer's descendant discovery uses:

thread/list
ancestorThreadId=<parent>
sourceKinds=["subAgentThreadSpawn"]
useStateDbOnly=true

Stored children that are not loaded in the current app-server process correctly arrive with runtime ThreadStatus.notLoaded. The renderer then combines that with the parent's historical subAgentActivity state. Parent activity has started, interacted, and interrupted, but no durable completed activity kind. As a result, the stale parent-side running reference wins and the child is projected as Active.

The renderer already has a correct latest-turn fallback for descendants that were observed but missing from thread/list: it reads turn history and maps terminal latest turns away from Active. That fallback is not applied to descendants that were successfully returned by the state-DB list, which is exactly the cold-reload case above.

thread_spawn_edges.status = open is not a runtime status and should not be changed or interpreted as Active/Done.

Minimal safe fix

During descendant discovery, hydrate only listed children whose runtime status is notLoaded:

thread/turns/list
threadId=<child>
cursor=null
limit=1
sortDirection=desc
itemsView=notLoaded

Projection:

  • latest completed -> Done
  • latest failed or interrupted -> existing failure/interruption policy; never Active
  • latest inProgress returned by the current app-server -> Active; the server normalizes stale non-running inProgress turns to interrupted, so this represents the list-to-live race
  • no turn/read failure -> remain unknown and stay out of Active; do not guess Done
  • already loaded runtime active, idle, or systemError records are not queried or overwritten
  • live thread/status/changed=active evidence wins over the hydrated historical snapshot

To keep the large-history path bounded:

  • use one class-wide semaphore to cap concurrent latest-turn reads (a local patch uses 8),
  • deduplicate only simultaneous in-flight reads for the same (threadId, updatedAt),
  • remove settled results so second-resolution updatedAt cannot make same-second lifecycle changes stale and the cache cannot grow without bound,
  • return only one latest turn over the wire,
  • do not repurpose spawn-edge status.

Performance caveat: in the current legacy app-server path, thread/turns/list limit=1 still reconstructs the child's full rollout internally before truncating the response. A renderer-only correction therefore performs up to one full replay per cold notLoaded child and can repeat that work on later discovery cycles. The production fix should expose an indexed latest lifecycle projection in descendant listing or use indexed turn metadata; the renderer candidate must not be presented as performance-proven on a 126-child live history until that cost is measured.

Regression coverage requested

  1. Cold restart: parent has only started/interacted; child runtime is notLoaded; latest turn is completed -> Done 1, Active 0.
  2. A list-to-live race returns latest inProgress from the current app-server -> Active 1, Done 0.
  3. Latest turn is interrupted or failed -> not Active; keep the terminal turn available to the existing UI policy.
  4. Missing/corrupt history -> unknown, not guessed Done.
  5. A same-second empty/interrupted read followed by completed is reread and projected Done.
  6. Simultaneous reads for the same generation are deduplicated, but a later discovery rereads it.
  7. Loaded runtime active, idle, and systemError are never queried or overwritten.
  8. Two simultaneous large discovery calls share a global concurrency cap of 8.
  9. Mixed 126-child fixture -> Done 117, Active 2, interrupted excluded 6, unknown excluded 1.
  10. Real legacy 126-child hydration -> measure wall time, peak memory, and renderer responsiveness, or use an indexed backend projection that avoids full rollout replay.

A byte-guarded local renderer patch passes a regression that executes the exact injected production hydration methods, the shipped HFs projection, and the shipped side-panel Done/Active predicates. The 126-child fixture produces Done 117 and Active 2; six interrupted and one unknown child stay out of Active. The signed Store package was not modified.

View original on GitHub ↗

15 Comments

github-actions[bot] contributor · 23 days ago

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

  • #37041

Powered by Codex Action

BoddhaBuddha · 23 days ago

Confirmed on macOS. After restarting or reloading a task, 223 completed historical subagents remain displayed as Active despite no live workers. The affected child threads return notLoaded, while their latest durable turns are completed, matching the diagnosis in this issue.

HiveTender · 19 days ago

I’m experiencing the same issue on Codex for Windows 26.803.5235.0.

Historical subagents can be moved from Working to Done by opening each one, but after fully quitting and relaunching Codex, the panel reconstructs the same incorrect state: 14 Working and 2 Done. The 14 displayed runtimes then continue increasing.

This persists after setting:

[agents]
enabled = false

The setting is loaded successfully and no multi-agent tools are available, so this appears to be a persisted-status/UI reconciliation problem rather than active agent execution.

Feedback ID: 019fd8ce-77e5-7cd0-8303-bb92cc9ed4ed

disbitski · 19 days ago

Confirmed on macOS 26.6.1 arm64 with Codex Desktop 26.803.41515 (build 6321).

A long-running task displayed 112 historical subagents under Active / Working, including entries with elapsed times exceeding three days. An authoritative agent-tree check showed only the parent task running; the recent child audits were completed. Attempting to interrupt one displayed historical child returned not_found.

A read-only process check also found the normal Codex application processes—not 112 active workers—and account utilization remained stable. This supports the issue’s diagnosis that completed historical children are being reconstructed as Active rather than actually executing.

No project names, repository paths, prompts, thread IDs, account information, or screenshots are included because the local labels contain private project context.

timsoret · 15 days ago

Independent reproduction on Codex Desktop for Windows, observed 2026-08-13.

In a long-running parent task with many historical delegation waves, the Subagents panel showed:

  • 82 working
  • 18 done

At the same time, an authoritative runtime status query returned the parent as the only running agent and every listed child as completed. The completed children had already returned final results; no child work remained active.

This makes the Working counter entirely non-authoritative for the affected task and strongly matches the stale/cold-hydrated lifecycle projection described here. The practical impact is that users cannot tell whether background work or concurrency slots are genuinely active.

A cropped screenshot showing only the Subagents counters was captured; it contains no project or conversation data.

ADABman · 14 days ago

Additional reproduction on Arch Linux, observed 2026-08-13.

This is the unofficial AUR repackaging of the Codex Desktop bundle, so I am including the exact versions:

  • Desktop package: openai-codex-desktop 26.803.81509-8
  • Bundled core: codex-cli 0.147.0-alpha.6.6

In a long-running parent task, the Subagents panel showed 209 Active / Working and 41 Done after a full host reboot.

A sampled child still displayed as Working had authoritative state thread.status = notLoaded and latest turn.status = completed; its turn had completed roughly 11 hours earlier. The machine had rebooted after that completion, so it could not be a surviving worker process. A read-only process-tree check showed the normal Desktop app-server/renderer processes, not a corresponding population of live workers.

The parent had 231 direct persisted spawn edges whose edge status was open. I am reporting that only as persistence-shape evidence; consistent with this issue, I did not interpret or modify spawn-edge status as runtime state.

Restart/reboot did not reconcile the panel. This appears to confirm the same cold-hydration/status-projection mismatch on Linux and on the newer bundled core.

No task names, repository paths, prompts, thread IDs, account data, or screenshots are included.

Sythos · 14 days ago

Just asking but, isn't this issue a duplicate of the following one?

#37041

derongliang · 11 days ago

Additional Windows reproduction, observed 2026-08-16, confirms that this issue still persists in the newer Desktop build.

  • Platform: Windows x64
  • Microsoft Store package: OpenAI.Codex 26.810.7004.0
  • A long-lived parent task shows 115 Running and 7 Done in the Subagents panel.
  • A direct read reports the affected parent as idle; its latest parent turn is completed.
  • The parent rollout contains 118 unique subagent thread IDs. Its canonical parent-side activity events contain 118 started, 182 interacted, 10 interrupted, and no completed activity kind, matching the stale-projection signature described in this issue.
  • Sampled children represented by the historical activity return thread.status = notLoaded with latest turn.status = completed.
  • Fully quitting and relaunching the app does not reconcile the panel; the same 100+ historical children remain under Running.
  • A read-only process check shows only the normal Desktop/app-server/renderer process set, not a corresponding population of live workers.

This confirms the cold-hydration bug is still reproducible on Windows after the originally reported 26.730 build and remains present in 26.810.7004.0.

No project names, repository paths, prompts, thread IDs, account data, local state files, or screenshots are included. No cache, database, task, or project data was modified during diagnosis.

shleder · 11 days ago

This is a strong persisted-lifecycle control case for codex-rescue. The interesting part is that the child rollouts are durable and terminal, while the UI projects them as Active after cold reload. I’m field-testing whether Rescue can inspect parent/child session evidence and classify completed vs. genuinely unfinished work conservatively without trusting stale UI state.

If you still have an affected parent task locally, could you run:

pipx install codex-rescue
codex-rescue sessions
codex-rescue doctor --latest

A healthy/no-damage result is useful here too; the tool should not infer corruption merely from the Active counter. If it does report an unfinished state, I’d want the sanitized finding and exit code before any salvage attempt.

Please don’t post raw rollouts/SQLite, prompts, child IDs, credentials, or private paths. Repo: https://github.com/shleder/codex-rescue

zeefine · 10 days ago

Reproduced on macOS with Codex Desktop 26.810.41047.

After fully quitting and relaunching Codex, the Subagents panel shows three historical child agents as Running.

Observed behavior:

  1. The parent task completes normally and receives the final results from all three child agents.
  2. After restarting Codex, the sidebar shows “3 Running”.
  3. Opening the Subagents panel shows all three agents as processing.
  4. Opening their details reveals that they are already completed.
  5. After opening the details, the sidebar updates them to Done.
  6. Fully quitting and relaunching Codex restores the same incorrect Running state again.

Read-only local evidence:

  • The parent rollout contains three sub_agent_activity entries with kind=started and one kind=interacted, but no completed activity kind.
  • Each child rollout ends with task_complete.
  • A runtime list_agents query reports all three children as completed.
  • The parent rollout also contains the three FINAL_ANSWER inter-agent messages, so the parent correctly received their results.
  • No continued child-agent execution was observed.

This appears to match the cold-hydration/status-projection issue described here: completed child turns are durable, but the Desktop sidebar reconstructs them as Running after restart.

Raw rollout files are omitted because they contain private project paths, prompts, and task content.

laizeyu1997 · 7 days ago

I can reproduce the same user-visible bug on a newer Windows build, and in this case it affects both local tasks and tasks running through Remote SSH.

User-visible problem

Several parent tasks in the main Codex sidebar show badges indicating that multiple subagents are still processing.

However:

  • those parent tasks are no longer using any subagents;
  • all of the displayed child agents have already completed or been interrupted;
  • no affected child has an active execution turn;
  • the live-agent registry contains no corresponding running children;
  • fully quitting and reopening Codex does not clear the indicators.

This makes the sidebar look as though multiple background agents are still consuming resources, even though no such child execution exists.

Environment

  • Codex Desktop for Windows: 26.818.3698.0 (x64)
  • Remote Linux app-server/CLI: 0.148.0
  • Affected task backends:
  • local Windows
  • Linux through Remote SSH

Scope of the affected tasks

The stale processing state was found on three separate parent tasks:

  • one local Windows parent;
  • two Remote SSH parents.

Their recorded child relationships contained 48 child threads in total:

  • 6 local children;
  • 42 Remote SSH children.

Every one of those 48 child threads was queried individually from its actual host.

Results:

| Child location | Count | Runtime thread status | Latest turn status |
|---|---:|---|---|
| Local Windows | 6 | 6 notLoaded | 5 completed, 1 interrupted |
| Remote SSH | 42 | 42 notLoaded | 41 completed, 1 interrupted |
| Total | 48 | 48 notLoaded | 46 completed, 2 interrupted |

There were zero children with an active runtime status.

One parent task itself was still active, but it had no active child agents. The sidebar was therefore conflating parent activity or persisted child history with live subagent execution.

Persisted-state evidence

The local and remote Codex state databases were inspected separately.

Remote state database:

  • 42 rows existed in thread_spawn_edges;
  • all 42 rows had status='open';
  • they matched the same 42 Remote SSH child threads verified above as notLoaded;
  • their latest turns were already terminal.

Local state database:

  • 67 rows had status='open';
  • 6 belonged to the affected visible local parent and matched the six individually verified notLoaded children;
  • the other 61 pointed to already archived historical child threads.

Therefore, the persisted spawn-edge state disagreed with both the latest child-turn state and the live-agent registry.

Why restarting does not fix it

The stale open rows survive application shutdown.

After Codex starts again, the sidebar restores the parent/child relationships from persistent state. The children are either terminal or not loaded, but they are still projected as processing instead of being reconciled against their latest turn status.

The observed state flow is:

child finishes or is interrupted
→ latest child turn becomes completed/interrupted
→ child runtime becomes notLoaded
→ no child remains in the live-agent registry
→ persisted spawn edge remains open
→ Desktop restore/sidebar presents the historical child as processing
→ full application restart reloads the same stale indicator

An open spawn edge may be intended to preserve resumability or history. The problem is that open or notLoaded is being presented as active execution without checking the child’s latest turn.

Expected behavior

  • “Processing,” “Active,” or “Working” should mean that the child currently has an active execution turn.
  • A completed or interrupted latest turn must never be counted as actively processing.
  • notLoaded must not default to Active.
  • On startup or parent-task restoration, Codex should reconcile all descendant children in one batch instead of requiring users to open them individually.
  • Resumable or historical children can remain inspectable, but they should be displayed separately from actually running agents.
  • A parent task that is active without active children must not inherit a false active-subagent count.

This provides current-version Windows plus Remote SSH evidence for the same state-reconciliation mechanism described in this issue, and also appears related to #37916, #37876, and #33700.

privacyguy123 · 5 days ago

I've seen this problem since ChatGPT/Codex app merge inception on Windows.

Sythos · 5 days ago
I've seen this problem since ChatGPT/Codex app merge inception on Windows.

not just windows, seen also on macosx and on last linux gui app too, the source is sort of deeper than the platform UI

pomazanbohdan · 5 days ago

Cross-case Windows evidence: after child rollouts reached task_complete and no child remained in the live registry, reopening the parent projected the same children as Active/Working again. Historical parent activity plus notLoaded child state matches the projection gap here and connects the UI symptom to #38364, #37916, and the capacity failure in #39694.

shleder · 1 day ago

One cross-check for people gathering evidence here: the panel renders projection state, while rollouts are canonical. vetto rescue --json scan reads only the JSONL layer, so diffing its session list against what the Subagents panel restores is a quick way to demonstrate the mismatch is derived-state-only.