Codex Desktop hides existing workspace threads on macOS

Open 💬 9 comments Opened Mar 11, 2026 by mikebmod
💡 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)?

Version 26.305.950 (863)

What subscription do you have?

Enterprise

What platform is your computer?

Darwin 25.3.0 arm64 arm

What issue are you seeing?

Codex Desktop on macOS only shows 1 thread for workspace but the local store contains 16 threads for that exact cwd, 15 active.

What steps can reproduce the bug?

Verified locally:

  • ~/.codex/state_5.sqlite has 16 rows for cwd=/path/to/project
  • raw rollout files exist under ~/.codex/sessions and ~/.codex/archived_sessions
  • cache reset did not fix it
  • full state rebuild did not fix it
  • reinstalling Codex Desktop did not fix it

What is the expected behavior?

_No response_

Additional information

_No response_

View original on GitHub ↗

9 Comments

github-actions[bot] contributor · 4 months ago

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

  • #14162
  • #13713
  • #13740

Powered by Codex Action

bixinhaner · 4 months ago

I can reproduce the same bug on macOS: Codex App shows only a small subset of workspace threads, while local data is intact.

Date: 2026-03-12
Platform: macOS (Darwin arm64)
CLI version on this machine: codex-cli 0.111.0
Workspace: /Users/like/Desktop/ReportHub

What I see

In Codex App UI, this workspace only shows 3 threads.

But local sqlite has many more rows for the exact same cwd:

SELECT COUNT(*), MIN(datetime(created_at,'unixepoch','localtime')), MAX(datetime(created_at,'unixepoch','localtime'))
FROM threads
WHERE cwd='/Users/like/Desktop/ReportHub';
-- 67 | 2026-01-13 00:54:29 | 2026-03-09 20:14:44

SELECT source, COUNT(*)
FROM threads
WHERE cwd='/Users/like/Desktop/ReportHub'
GROUP BY source;
-- cli 59
-- vscode 7
-- exec 1

The visible count (3) even matches this subset query:

SELECT COUNT(*)
FROM threads
WHERE cwd='/Users/like/Desktop/ReportHub'
  AND source='vscode'
  AND created_at >= strftime('%s','2026-03-01');
-- 3
Important evidence: hidden threads are still resumable
Threads that do not appear in App sidebar can still be resumed via CLI:

019c863d-7fd6-79f1-af96-337b9e9466ce (vscode)
019c1228-21e2-7a53-b3b1-890a31e978b3 (cli)
codex resume <thread_id> -C /Users/like/Desktop/ReportHub loads them normally.

So this looks like a desktop listing/filtering bug, not data loss.

Already tried (no fix)
Rebuilt ~/.codex/state_5.sqlite from sessions.
Reset ~/.codex/.codex-global-state.json.
Forced local mode in global state:
codexCloudAccess = "disabled"
selected-remote-host-id = null
Restarted Codex App after each step.
No change in sidebar result.

Could you check what exact thread/list filters/params Desktop sends for workspace thread list in this scenario?
talvinder · 4 months ago

I can reproduce this on the macOS desktop app and have a stronger signal for the failure mode.

App build on my machine:

  • Codex app 26.311.21342 (CFBundleVersion 993)
  • macOS Darwin arm64

What I found locally:

  • Threads were still present in ~/.codex/state_5.sqlite
  • The missing-sidebar behavior was not data loss
  • The metadata being used for listing was pathological: many rows had threads.title = first_user_message
  • Those title values were often the entire multiline opening prompt, not a short label
  • Example malformed rows were 3548 and 3877 characters long
  • While the app remained open, it continued inserting new rows with this same pattern

Representative sqlite evidence:

SELECT COUNT(*) AS total_threads,
       SUM(CASE WHEN title = first_user_message THEN 1 ELSE 0 END) AS title_eq_first_user_msg,
       MAX(LENGTH(title)) AS max_title_len
FROM threads;
-- total_threads=5083, title_eq_first_user_msg=43, max_title_len=3877

SELECT id, LENGTH(title) AS title_len,
       SUBSTR(REPLACE(title, char(10), ' '), 1, 120) AS title_preview
FROM threads
WHERE title = first_user_message
ORDER BY updated_at DESC
LIMIT 4;

Example previews from those malformed rows:

  • You are the review and verification agent for Linear ticket \TAL-33\ ... (3877 chars)
  • You are the review and verification agent for Linear ticket \TAL-31\ ... (3548 chars)

I manually normalized the stored titles to short single-line labels and rebuilt ~/.codex/session_index.jsonl; after that, the sidebar threads became visible again. But while the desktop app stayed open, it kept writing new bad rows.

So this looks less like a generic "thread list filter" bug and more like a desktop app write-path bug where new threads are persisted with title = first_user_message instead of a derived short title, which then breaks or degrades the sidebar listing path.

If useful, I can also provide the exact normalization query/script I used as a temporary local workaround.

bixinhaner · 4 months ago

I have a stronger repro now. This does not look like data loss. It looks like the Desktop sidebar is effectively gated by local sqlite updated_at ordering/truncation.

Environment:

  • Date: 2026-03-18
  • Platform: macOS arm64
  • Workspace: /Users/like/Desktop/Trae/ReportHub

Local sqlite state for this exact workspace:

SELECT COUNT(*), MIN(datetime(created_at,'unixepoch','localtime')), MAX(datetime(created_at,'unixepoch','localtime'))
FROM threads
WHERE cwd='/Users/like/Desktop/Trae/ReportHub';
-- 69 | 2026-01-13 00:54:29 | 2026-03-17 22:57:27

SELECT source, COUNT(*)
FROM threads
WHERE cwd='/Users/like/Desktop/Trae/ReportHub'
GROUP BY source;
-- cli 59
-- vscode 9
-- exec 1

SELECT archived, COUNT(*)
FROM threads
WHERE cwd='/Users/like/Desktop/Trae/ReportHub'
GROUP BY archived;
-- archived=0 for all 69 rows
The app only showed a few recent threads. I tested several hypotheses:

1. cli_version is NOT sufficient
I picked a hidden thread:

thread id: 019cbe98-1245-7122-aeb5-3f95b420403c
title: Is attaching files to emails still unavailable in the report writing function?
source: vscode
original cli_version: 0.107.0
I changed only:

rollout session_meta.payload.cli_version
sqlite threads.cli_version
from 0.107.0 to 0.115.0-alpha.27

Then I fully restarted Codex Desktop.

Result:

the thread still did not appear in the sidebar.
2. updated_at DOES affect visibility
I then restored cli_version and changed only sqlite threads.updated_at for the same hidden thread, pushing it to the newest row for that workspace:

UPDATE threads
SET updated_at = <latest timestamp>
WHERE id='019cbe98-1245-7122-aeb5-3f95b420403c';
After fully restarting Codex Desktop:

this previously hidden thread appeared in the ReportHub sidebar.
3. Important implication
This strongly suggests the Desktop sidebar is not enumerating all matching workspace threads.
It appears to be showing only a recent subset ordered by sqlite updated_at, or applying a truncation/pagination bug on top of that ordering.

This is not just “old sessions are unreadable”:

hidden threads still exist in sqlite
hidden threads are resumable by id
changing only sqlite updated_at makes a hidden thread visible
For comparison, changing rollout file mtime alone was not enough.

Can you check whether Desktop’s workspace thread list is:

applying an unintended hard limit,
failing to paginate past the first few rows,
or using a stale cursor/window over updated_at-sorted results?
meyer-carl · 3 months ago

I have one additional macOS data point that may be relevant here.

In a few affected threads I checked locally, the raw rollout in ~/.codex/sessions/.../rollout-<thread-id>.jsonl still contained the newer conversation, and the matching row in ~/.codex/state_*.sqlite was also current. But the derived metadata was stale:

  • the row in ~/.codex/session_index.jsonl still had an older updated_at
  • the thread was also sometimes missing its workspace hint in ~/.codex/.codex-global-state.json

In those cases the symptom was not only “missing from the sidebar.” The thread could also sort as if it were old, or open to what looked like an older state even though newer rollout data still existed on disk.

One reason I think this is worth separating from the existing updated_at workaround comments is that in my case updating SQLite alone was not the relevant repair. What helped was repairing the per-thread derived metadata instead: the stale session_index.jsonl row and the missing workspace hint in .codex-global-state.json. When stale rendering persisted after that, the only reliable workaround was creating a recovered copy from the recent tail of the canonical rollout.

A narrow per-thread repair helped more than broad rebuilds:

  • update only that thread’s session_index.jsonl row so updated_at matches the rollout / sqlite timestamp
  • add or repair only that thread’s workspace hint in .codex-global-state.json
  • if the thread still rendered stale content, create a recovered copy from the recent tail of the canonical rollout rather than rebuilding global state

I’m not claiming this is the only root cause. The recent-subset / pagination explanation in the other comments may still explain many cases. This is just one additional pattern I observed locally: the canonical rollout and sqlite state were current, but per-thread derived metadata was not.

For version context: this was observed on Codex Desktop 26.409.20454 (CFBundleVersion 1462) on macOS 26.4.1 (25E253), Darwin arm64. I observed the stale/missing-thread behavior on April 12-13, 2026 as well as the preceding week, and it persisted across full app restarts, as well as Codex and macOS updates.

lizhelang · 3 months ago

I can reproduce this on a newer Codex Desktop build with additional evidence that points to the Desktop sidebar using a global recent-thread window rather than querying per workspace.

Environment:

  • Codex Desktop: 26.415.40636
  • macOS: 26.4.1 (25E253), Darwin arm64
  • Workspace: /Users/lzl/FILE/gitea/SheetMetalUnroll/ASMU-HTJ

Local state is intact:

SELECT COUNT(*)
FROM threads
WHERE cwd = '/Users/lzl/FILE/gitea/SheetMetalUnroll/ASMU-HTJ'
   OR cwd LIKE '/Users/lzl/FILE/gitea/SheetMetalUnroll/ASMU-HTJ/%';
-- 582

SELECT COUNT(*)
FROM threads
WHERE cwd LIKE '/Users/lzl/.codex/worktrees/%/ASMU-HTJ'
   OR cwd LIKE '/Users/lzl/.codex/worktrees/%/ASMU-HTJ/%';
-- 14

But the Desktop UI still showed effectively no historical workspace threads. I also rebuilt ~/.codex/.codex-global-state.json thread-workspace-root-hints from ~/.codex/state_5.sqlite and verified 596/596 matching thread ids mapped to the workspace root. After restarting Codex Desktop, that file was overwritten back to the small stale hint set (22 total hints, only 3 for this workspace), so manually repairing the hint file while Desktop is running is not a durable workaround.

The stronger signal is from the app itself:

  • ~/Library/Logs/com.openai.codex/... reports thread_count_total=50 and thread_count_loaded_recent=50 in app state snapshots.
  • On this machine, the newest 50 unarchived rows in ~/.codex/state_5.sqlite contain only 1 row for this workspace.
  • Therefore the workspace group can be empty or nearly empty even though hundreds of matching threads exist in sqlite.

I inspected the local app bundle and the app-server protocol:

  • thread/list supports limit, cursor, sortKey, archived, and cwd filters.
  • The generated schema says cwd is an exact session-cwd filter and limit is optional.
  • The Rust app-server clamps page size to THREAD_LIST_MAX_LIMIT = 100, but it can paginate.
  • The packaged Electron code in app.asar appears to use a global recent-thread list with hard-coded page size 50:
refetchThreadList(...) {
  this.listRecentThreads({ limit: 50 * this.pageCount, cursor: null })
}

loadNextThreadListPage(...) {
  this.listRecentThreads({ limit: 50, cursor: this.nextCursor })
}

listRecentThreads({ cursor, limit }) {
  return this.requestClient.sendRequest('thread/list', {
    limit,
    cursor,
    sortKey: this.sortKey,
    modelProviders: null,
    archived: false,
    sourceKinds: w
  })
}

Notably, that request does not include a cwd filter. It looks like Desktop first loads a global recent list, then groups/filters those already-loaded threads by workspace. That makes older but valid workspace threads invisible until enough global pages have been loaded. A workspace with many historical sessions can show only a tiny subset if other projects have newer activity.

Expected behavior:

  • The workspace sidebar should not depend only on the first global recent-thread page.
  • For each visible workspace root, Desktop should fetch a bounded per-workspace page, e.g. thread/list({ cwd, archived: false, sortKey: 'updated_at', limit: 30 }), or otherwise keep a per-project recent quota.
  • Global recent chats can still be shown separately, but workspace groups should be populated from workspace-scoped queries.

This still looks like a Desktop listing/pagination issue rather than data loss: the sqlite rows and rollout files exist, and thread/list already has the protocol support needed for a workspace-scoped query.

davezfr · 2 months ago

Adding another macOS datapoint here because this matches what I’m seeing very closely.

I can confirm this looks like a sidebar / project-thread visibility bug rather than actual history loss.

What I’m seeing in the Desktop app:

  • under one local project root, the Projects sidebar only shows a single visible thread
  • older threads for that same project stop appearing after some time
  • the data does not appear to be deleted locally

What I verified locally:

  • raw session rollout files still exist under ~/.codex/sessions
  • ~/.codex/session_index.jsonl still contains the missing thread IDs
  • ~/.codex/state_5.sqlite still contains the missing threads for the exact same cwd
  • these rows are not archived

Concrete example from my machine:

  • one local project root has 26 unarchived rows in the threads table for the same cwd
  • of those, 11 are top-level threads (not child/spawned sub-threads)
  • but the project sidebar is only showing 1 thread for that project

I also checked a few other local project roots and the behavior seems consistent with the sidebar only surfacing a recent subset of top-level threads. More recent project threads remain visible, while older top-level threads stop appearing in the Projects view even though they still exist on disk and in SQLite.

One extra detail:

  • some missing rows are child/subagent threads, so I understand those may not be expected to show as normal project chats
  • however, this does not explain the whole issue, because multiple older top-level, unarchived threads for the same project are also missing from the sidebar

So in my case this looks very close to:

  • project/workspace sidebar not loading the full local thread set
  • or applying an overly aggressive “recent only” filter in the project view

If useful, I can provide:

  • a redacted screenshot of the project sidebar
  • a redacted SQLite query result for threads where cwd=...
  • confirmation that the missing thread IDs still exist in both session_index.jsonl and state_5.sqlite
Dailin521 · 2 months ago

Windows reproduction with additional evidence that this is not data loss and not provider-specific.

Environment:

  • Codex Desktop app: OpenAI.Codex 26.422.3464.0
  • Codex CLI: codex-cli 0.125.0
  • OS: Windows 11 Pro 10.0.26200, x64
  • Affected workspace: D:\GitHubProject\oss-maintainer-hub

Observed behavior:

  • The Desktop Projects sidebar shows the workspace, but displays No conversations / empty history.
  • codex resume -C D:\GitHubProject\oss-maintainer-hub shows the previous sessions normally.
  • The raw local history is present; this is not data loss.
  • Switching model_provider between a custom provider and openai does not fix the Desktop UI. CLI still sees the sessions.

Local diagnostics from ~/.codex/state_5.sqlite and rollout metadata:

D:\GitHubProject\oss-maintainer-hub:
interactive threads: 12
providers: openai: 12
initial global updated_at ranks: 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 77
initial first recent page hit count: 0/50

That matches the recent-window hypothesis from #14751: the workspace has valid local threads, but none of them are in the initial global recent page.

I also tested two mitigations locally:

  1. Promote the 12 workspace rows in SQLite so their updated_at_ms / updated_at ranks move into the first global recent page.
  2. Normalize Windows verbatim cwd values from \\?\D:\... to normal D:\... paths so exact cwd matching succeeds.

Immediately after those changes, diagnostics showed the data was in the state that Desktop should be able to display:

D:\GitHubProject\oss-maintainer-hub:
interactive 12
first page 12/50
ranks 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13
exact cwd 12/12
verbatim cwd 0
providers openai: 12

However, after restarting/relogging into Codex Desktop, the project still showed empty in the sidebar. The Desktop/app-server then appeared to reindex/rewrite local SQLite metadata back to the old shape:

D:\GitHubProject\oss-maintainer-hub:
interactive 12
first page 0/50
ranks 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 77
exact cwd 0/12
verbatim cwd 12
providers openai: 12

So this looks like two related Desktop-side issues on Windows:

  • The project sidebar still seems to depend on a global recent conversation window instead of querying the workspace by cwd.
  • Desktop/app-server reindexing can restore Windows verbatim cwd paths and old ordering, undoing manual SQLite-only repairs.

Expected behavior:

  • Expanding a project/workspace should query local threads for that workspace root directly, e.g. with thread/list({ cwd, archived: false, sortKey: 'updated_at', ... }), and paginate that workspace-scoped query.
  • A project should not show as empty when matching unarchived local threads exist and are resumable from CLI.
  • Windows cwd normalization should be durable across Desktop/app-server reindexing; D:\... and \\?\D:\... should not split visibility.

This is a serious blocker for long-running Codex projects on Windows because the Desktop UI can report "no conversations" even though all local conversations still exist and are resumable from CLI.

alexangelzhang · 1 month ago

Additional macOS reproduction with a narrower root-cause signal: existing project history can be hidden by the Desktop/app-server model provider filter.

Environment:

  • Codex Desktop app: macOS app, current local install (About dialog version not captured before recovery)
  • OS: Darwin 24.6.0 arm64 arm
  • Local Codex home: default ~/.codex
  • Affected storage:
  • ~/.codex/state_5.sqlite
  • ~/.codex/sessions/.../rollout-*.jsonl

Observed behavior:

  • Several mounted projects in Codex Desktop showed empty history / no conversations.
  • The historical threads were not lost. They still existed in state_5.sqlite and the matching rollout JSONL files.
  • Restarting Codex Desktop did not fix it.
  • Newly created threads appeared, but older project history stayed hidden.

Key diagnostic result:

  • The current Desktop provider was mify.
  • Many older threads for the same project roots had different model_provider values, including headroom, custom, cfjwl, api111, and openai.
  • Calling the app-server thread/list path with modelProviders: null returned only the current-provider (mify) threads.
  • Calling the same path with modelProviders: [] returned threads across providers, including the older hidden history.

So, at least in this reproduction, modelProviders: null appears to be interpreted as "current provider only", not "no provider filter". The Desktop sidebar therefore hides existing local project threads whose stored provider differs from the currently selected/default provider.

This is not data loss, but it is a severe history visibility regression: the UI makes it look like project history disappeared even though the local SQLite rows and JSONL transcripts are still present.

Local workaround that restored visibility:

  • Backed up state_5.sqlite and the affected rollout JSONL files first.
  • For affected unarchived user threads in several project roots, normalized the provider metadata to the current Desktop provider (mify) in both places:
  • threads.model_provider in state_5.sqlite
  • session_meta.payload.model_provider in the matching rollout JSONL
  • After updating both SQLite and JSONL, the previously hidden project history appeared again in Codex Desktop.

Important detail: changing only SQLite is not necessarily sufficient because Desktop/app-server may recover or reconcile metadata from the JSONL session metadata. Both metadata sources had to agree for the workaround to be stable.

Expected behavior:

  • The project/sidebar history view should show existing unarchived local threads for the workspace regardless of provider.
  • Provider compatibility should be handled when opening/resuming/forking a thread, not by hiding the thread from the history list.
  • If provider filtering is intentional, the UI should make it explicit and provide a "show all providers" option.

Potential fix directions:

  • Have the Desktop sidebar request project history without provider filtering, e.g. modelProviders: [], or otherwise query all providers for history discovery.
  • Or change app-server semantics so modelProviders: null / omitted means no provider restriction, while a non-empty array means explicit filtering.
  • Or add a migration/compatibility layer for provider renames/default-provider changes so older local threads remain visible.

This looks related to the broader issue reported here, but with provider filtering as a concrete additional failure mode beyond recent-window/cwd matching.