Codex Desktop session list appears to drop existing local transcripts after index rebuild/filtering
Summary
Codex Desktop showed many older working sessions as missing even though the underlying local transcript files still existed on disk.
This looks like a session index / sidebar visibility issue rather than transcript deletion.
Observed behavior
- The Desktop session sidebar appeared to lose a large number of older sessions.
- Local transcript files were still present in the normal Codex sessions directory.
- The visible session index contained substantially fewer entries than the transcript files on disk.
Local evidence, sanitized
I intentionally am not including any session titles, prompts, transcript contents, usernames, project names, or full filesystem paths.
On one affected machine:
- Local transcript files found:
461JSONL files total across active and archived session storage. - Normal session transcript files:
448. - Archived session transcript files:
13. - Visible session index entries:
245JSONL lines, representing237unique IDs. - Transcript files not represented in the visible session index:
224. - Of the normal session transcript files missing from the index:
223. - Most missing normal transcript files appeared to be internal approval-reviewer / guardian-subagent runs rather than user-facing working sessions:
217 / 223missing normal transcript files contained approval-reviewer / guardian policy markers.- About
6unindexed files looked more like real work or subagent investigation sessions.
The session index rows had this shape:
{"id":"...","thread_name":"...","updated_at":"..."}
The missing transcript files themselves were valid JSONL transcripts and included session_meta; they did not appear corrupt.
Expected behavior
One of these should be true:
- User-facing working sessions that still have valid local transcript files should remain visible in the Desktop session list, or
- Internal approval-reviewer / subagent transcripts should be consistently excluded and never appear as normal working sessions, or
- If the app intentionally hides/archive-filters old or internal sessions, the UI should make that state clear and avoid making it look like sessions were randomly deleted.
Why this is confusing
From the user's perspective, older sessions seemed to disappear randomly. The data was still present locally, but the UI/index no longer surfaced many entries. Because most of the missing transcripts look like internal approval-reviewer runs, this may be a cleanup or filtering behavior, but there were also a few apparent non-reviewer sessions missing from the index.
Suggested fix
- Audit how
session_index.jsonlis rebuilt or filtered. - Ensure internal reviewer/subagent sessions are either never shown or clearly classified separately.
- Ensure valid user-facing transcript files are not omitted from the visible index during migration/backfill.
- Consider a repair/backfill command that can rebuild the visible session index from local transcript files without exposing internal reviewer sessions as normal user sessions.
Environment
- Codex Desktop on macOS.
- Affected transcripts span multiple recent Codex Desktop alpha versions, including
0.129.0-alpha.15,0.130.0-alpha.5,0.131.0-alpha.9, and0.133.0-alpha.1.
Happy to provide more aggregate diagnostics if useful, but I would prefer not to share raw transcript contents because they may contain personal or sensitive session data.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
1|# Codex #24521: Desktop Session List Drops Local Transcripts After Index Rebuild
2|
3|## Issue Summary
4|
5|Codex Desktop showed many older working sessions as missing even though the underlying local transcript files still existed on disk. This is a session index / sidebar visibility issue rather than transcript deletion.
6|
7|Evidence: 461 JSONL transcript files on disk, but only 245 visible in the session index (237 unique IDs). 224 transcript files not represented in the visible index. 217/223 missing files contained approval-reviewer/guardian policy markers.
8|
9|## Root Cause Analysis
10|
11|### Primary Cause: Index Filtering Over-Exclusion
12|
13|The session index rebuild process appears to filter out internal approval-reviewer / guardian-subagent transcripts. However, the filtering logic is too aggressive:
14|1. It excludes 217/223 files that are indeed internal guardian runs (correct behavior)
15|2. But it also excludes ~6 files that are real user-facing work or subagent investigation sessions (incorrect)
16|
17|The filtering likely uses heuristic markers (e.g., session metadata containing "approval-reviewer" or "guardian" strings) but doesn't properly distinguish between:
18|- Pure guardian runs: Internal-only sessions that should be hidden
19|- Mixed sessions: User-facing sessions that happened to trigger guardian review
20|
21|### Secondary Cause: Index-File Count Mismatch
22|
23|The session index has 245 entries representing 237 unique IDs — meaning 8 entries are duplicates. This suggests the index rebuild doesn't properly deduplicate entries, and the deduplication logic may be dropping valid entries.
24|
25|## Proposed Fix
26|
27|### Fix 1: Improve Filtering Logic to Distinguish Internal vs Mixed Sessions
28|
29|``
typescript`30|interface SessionFilterResult {
31| shouldShow: boolean;
32| reason: string;
33|}
34|
35|function shouldShowSession(transcript: TranscriptFile): SessionFilterResult {
36| const meta = transcript.session_meta;
37|
38| // Pure guardian/approval-reviewer runs: hide from user session list
39| if (meta.agent_role === 'approval-reviewer' || meta.agent_role === 'guardian') {
40| // But show if this session also contains user-facing messages
41| const hasUserMessages = transcript.messages.some(
42| m => m.role === 'user' && !m.content.includes('[guardian]')
43| );
44| if (hasUserMessages) {
45| return { shouldShow: true, reason: 'mixed-session-with-user-content' };
46| }
47| return { shouldShow: false, reason: 'pure-internal-session' };
48| }
49|
50| // Subagent investigation sessions: show if they have meaningful output
51| if (meta.agent_role === 'subagent') {
52| const hasOutput = transcript.messages.some(m =>
53| m.role === 'assistant' && m.content.length > 100
54| );
55| return { shouldShow: hasOutput, reason: hasOutput ? 'subagent-with-output' : 'empty-subagent' };
56| }
57|
58| // Default: show all user-facing sessions
59| return { shouldShow: true, reason: 'user-session' };
60|}
61|
`62|
63|### Fix 2: Fix Index Deduplication
64|
65|
typescript`66|function rebuildSessionIndex(transcriptFiles: TranscriptFile[]): SessionIndex {
67| const seen = new Map<string, SessionIndexEntry>();
68|
69| for (const file of transcriptFiles) {
70| const meta = file.session_meta;
71| const id = meta.id || file.id;
72|
73| // Keep the most recent entry for each session ID
74| const existing = seen.get(id);
75| if (!existing || (meta.updated_at > existing.updated_at)) {
76| seen.set(id, {
77| id,
78| thread_name: meta.thread_name || file.title,
79| updated_at: meta.updated_at,
80| file_path: file.path,
81| is_archived: meta.archived || false,
82| should_show: shouldShowSession(file).shouldShow
83| });
84| }
85| }
86|
87| return { entries: Array.from(seen.values()) };
88|}
89|
`90|
91|### Fix 3: Add Index Integrity Verification
92|
93|
typescript${missingFromIndex.length} transcript files missing from index94|// Periodic check: compare disk files vs index entries
95|async function verifySessionIndexIntegrity() {
96| const diskFiles = await findTranscriptFiles();
97| const indexEntries = await loadSessionIndex();
98|
99| const indexedIds = new Set(indexEntries.map(e => e.id));
100| const missingFromIndex = diskFiles.filter(f => !indexedIds.has(f.id));
101|
102| if (missingFromIndex.length > 0) {
103| console.warn(
);`104| // Auto-rebuild for missing files
105| for (const file of missingFromIndex) {
106| const entry = buildIndexEntry(file);
107| if (entry.should_show) {
108| await addToIndex(entry);
109| }
110| }
111| }
112|}
113|
`114|
115|### Fix 4: Add User-Facing "Show Hidden Sessions" Toggle
116|
117|
typescript``118|// In session list UI
119|interface SessionListConfig {
120| showInternalSessions: boolean; // Default: false
121| showArchivedSessions: boolean; // Default: false
122|}
123|
124|// Allow users to see all sessions including filtered ones
125|function getSessionList(config: SessionListConfig): SessionIndexEntry[] {
126| const allEntries = loadSessionIndex();
127| return allEntries.filter(e => {
128| if (!config.showInternalSessions && e.is_internal) return false;
129| if (!config.showArchivedSessions && e.is_archived) return false;
130| return true;
131| });
132|}
133|
134|
135|## Implementation Priority
136|
137|1. P1 (Important): Improve filtering logic — prevents over-exclusion of valid sessions
138|2. P1 (Important): Fix index deduplication — prevents duplicate/dropped entries
139|3. P2 (Enhancement): Index integrity verification — auto-recovery from index corruption
140|4. P2 (Enhancement): User-facing toggle — gives users control over visibility
141|
142|## Testing Plan
143|
144|1. Filtering tests: Verify guardian-only sessions are hidden, mixed sessions are shown
145|2. Dedup tests: Verify index has exactly one entry per session ID
146|3. Integrity tests: Verify missing files are detected and re-indexed
147|4. Regression tests: Verify existing visible sessions remain visible
148|
149|## Impact
150|
151|- User impact: HIGH — Users lose access to their session history
152|- Data loss risk: LOW — Files exist on disk, just not visible in UI
153|- Scope: Medium — Affects all users with many sessions (especially heavy automation users)
154|- Fix complexity: LOW — Filtering logic + dedup, ~150 lines total
155|
Adding another concrete data point from Codex Desktop on macOS.
This looks like the same class of issue: a completed, user-facing project session has a valid local JSONL transcript, but it is not discoverable in the Codex Desktop project thread list or via the thread search/list API.
Environment
26.527.608180.136.0-alpha.2vscodeCodex Desktopthread_source:user~/Developer/...Missing session
019e86c3-ee54-7fa1-a2af-0f4e80917d27~/.codex/sessions/2026/06/02/rollout-2026-06-02T10-47-28-019e86c3-ee54-7fa1-a2af-0f4e80917d27.jsonl2026-06-02T05:17:28Z2026-06-02T05:39:24Z1.2 MB519The transcript ends normally with
task_complete, followed by a finalsession_metarecord. It does not look corrupt or incomplete.What makes this one useful to debug
This was not an old historical session after an app update. It was a fresh session created and completed on the same day.
The session:
The final transcript metadata still has the same thread id and cwd, with updated git branch metadata.
App/API search behavior
The Codex app thread search/list API returned no results for exact searches including:
019e86c3-ee54-7fa1-a2af-0f4e80917d27Nearby sessions for the same project and with the same
source: "vscode"are visible/searchable, sosource: "vscode"alone does not explain this.Expected
A completed
thread_source: "user"session with:should be visible under the project, or at minimum discoverable by exact thread id.
Actual
The local transcript exists and the code changes exist, but the session is missing from normal project navigation and search/list results. From the user perspective it looked like the completed Codex session had disappeared.
This seems like a local transcript persistence vs app/project thread index mismatch, potentially triggered by branch/project metadata changes during the session or by index filtering after completion.
Adding another concrete data point, this time from Codex Desktop on Windows/WSL.
This looks like the same class of issue: user-facing local project threads are still present locally and can be loaded by exact thread id, but they are not discoverable through the Desktop/project thread search/list path.
Environment:
Codex Desktop0.136.0-alpha.2vscodethread_source:userObserved:
Fix #<issue> ...disappeared from the Desktop thread list/search and were not in the archived view.session_index.jsonl.sessions/, notarchived_sessions/.Hidden but valid examples:
019e60a8-34db-7932-b815-2165a9d7881e—Fix #14861 waiting019e6036-d736-72c0-aec9-3803910d63d5—Fix #69192 waiting019e61f4-e49e-72a3-97ec-6f7c1d74475e—Fix #50621 waiting019e6e4c-afd2-7eb2-8cd5-de6f78d5c8aa—Fix #70903 waitingControl examples from the same project that remained discoverable:
Fix #78492 waitingFix #62432 waitingFix #61569 conflictFix #66936 waitingThis makes the failure look narrower than transcript loss: the canonical/local data is present and readable, but Desktop sidebar/search/list hydration omits some valid non-archived user threads. A useful fix would be for sidebar/search to paginate or query the canonical local thread/session source directly, and for direct thread-id recovery to refresh project/sidebar membership instead of requiring manual pinning.