[Windows Desktop] Hidden subagent threads remain archived=0 and accumulate in state_5.sqlite
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
Summary
Codex Desktop creates internal rows with thread_source='subagent', but completed subagent rows can remain archived=0 indefinitely. They are hidden from the normal thread UI and have no user event, yet remain in the active portion of state_5.sqlite.
In one long-lived Windows Desktop + WSL profile, this accumulated to more than 4,400 hidden active rows. An offline archival update reduced that population, but additional unarchived subagent rows appeared afterward, showing that the workaround is not durable.
Environment
- Codex Desktop on Windows with the agent running in WSL
- Observed across Desktop-managed CLI versions from the
0.129through0.142series - SQLite state store:
%USERPROFILE%\.codex\state_5.sqlite
The report intentionally omits thread IDs, rollout paths, working directories, titles, prompts, repository details, and database files.
Confirmed database observations
This aggregate query is sufficient to expose the condition:
SELECT archived, COUNT(*)
FROM threads
WHERE thread_source = 'subagent'
GROUP BY archived;
Before mitigation, the result was:
archived=0: more than 4,400
archived=1: 35
All sampled aggregate groups had has_user_event=0. The active rows had no corresponding visible user chat in the Desktop UI.
Additional checks confirmed that the rows were not merely transient entries from a currently running subagent: their creation times spanned weeks, while archived remained false and archived_at remained null.
Offline mitigation and recurrence
With Desktop fully closed, after backing up the database, the following update archived the stale internal rows:
BEGIN IMMEDIATE;
UPDATE threads
SET archived = 1,
archived_at = CAST(strftime('%s', 'now') AS INTEGER)
WHERE archived = 0
AND thread_source = 'subagent';
COMMIT;
The bulk update changed more than 4,400 rows. A later aggregate check found 23 newly created subagent rows still at archived=0, plus a small number of older active rows. This confirms recurrence after cleanup.
Direct database editing is not an appropriate product workaround and requires a fully closed app plus a backup; it is included only as lifecycle evidence.
Expected behavior
When an internal subagent reaches a terminal state, Desktop/app-server should do one of the following consistently:
- mark its thread row archived and set
archived_at; - remove it if subagent persistence is unnecessary; or
- store it outside user-visible/active thread metadata paths.
Existing stale rows should receive a one-time migration or bounded cleanup.
Actual behavior and impact
- Completed internal subagent rows remain
archived=0. - The normal UI hides them, so users cannot inspect or archive them through supported controls.
- The active thread table can grow by thousands of invisible rows.
- This was discovered while investigating Desktop startup and thread-list latency. The lifecycle/storage bug is confirmed; I have not isolated a wall-clock benchmark proving how much latency these rows add.
Suggested regression coverage
- Create a parent thread that launches several subagents.
- Let every subagent reach a terminal state.
- Assert that no completed
thread_source='subagent'row remains active indefinitely. - Assert that active thread-list queries either exclude internal subagents at the SQL layer or operate on a bounded indexed set.
- Exercise cleanup across app restart and abrupt parent-thread termination.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the app-server/Desktop lifecycle for rows with thread_source='subagent' in state_5.sqlite, focusing on terminal completion and parent-thread termination. Use the suggested regression coverage to verify that completed subagent rows do not remain active indefinitely, cleanup survives restart, and active thread-list queries stay bounded or exclude internal rows.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- databases, desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100