Local workaround scripts for making missing Codex Desktop sidebar threads visible again.
Korean version: README.ko.md
If a user pastes only this repo URL and asks you to fix their Codex Desktop sidebar:
- Critical: do NOT run the script from inside Codex Desktop's integrated terminal. The script force-kills the
Codexprocess; if your terminal is a child of Codex, it will die mid-update and leave the database in a partial state. Use Terminal.app, iTerm, or any terminal not spawned by Codex. - Confirm the symptoms match
## Why this existsbelow. - Clone the repo and run:
Or target one specific project:
git clone https://github.com/chenjingdev/codex-sidebar-refresher.git cd codex-sidebar-refresher ./scripts/refresh-visible-workspaces.sh --threads-per-root 20./scripts/refresh-visible-workspaces.sh \ --only-root /absolute/path/to/project \ --threads-per-root 30
- The script auto-restarts Codex. Verify the sidebar now lists the threads.
- If the script reports
rolloutFilesTouched: 0, something is wrong — investigate before retrying.
Use this when:
- Codex CLI can still see older conversations, but the Desktop App sidebar cannot
- a workspace should contain more conversations than the app currently shows
- pinning makes a hidden thread appear, but unpinning and restarting hides it again
Based on local investigation of the current Codex Desktop App behavior, the sidebar does not appear to render a workspace's full local history directly.
Instead, it appears to combine:
- saved workspace roots from local app state
- a startup-loaded recent thread subset
That means an older thread can still exist locally and remain visible in Codex CLI, but still fail to appear in the Desktop App sidebar if it falls outside the app's initial recent window.
In the app version investigated for this repo, the Desktop App appears to request something equivalent to:
thread/list(limit=50, sortKey=updated_at)
on startup.
So a workspace thread can still exist in local storage, but fail to show up in the sidebar when:
- its global recent rank is too low
- it is not included in the startup preload set
- the sidebar ends up grouping only that loaded subset
This is an implementation observation, not a public API contract, so future app versions may behave differently.
This tool expects a local Codex layout roughly like this:
~/.codex/state_5.sqlite- SQLite database containing thread metadata
- this tool reads fields such as
id,cwd,title,updated_at, andsource
~/.codex/sessions/.../*.jsonl- session event logs containing the actual conversation content
~/.codex/.codex-global-state.json- app UI state, including saved workspace roots used by the Desktop sidebar
In short:
sessions/*.jsonl= conversation log datastate_5.sqlite= thread metadata and recent ordering.codex-global-state.json= saved workspace roots and sidebar-related UI state
This repo reads state_5.sqlite and .codex-global-state.json, and modifies threads.updated_at plus the mtime of the matching sessions/*.jsonl files. It does not rewrite conversation contents inside those JSONL files.
refresh-visible-workspaces.sh does the following:
- Reads
electron-saved-workspace-rootsfrom the global state file. - Falls back to
active-workspace-rootsif saved roots are empty. - Finds direct threads whose
cwdexactly matches those roots. - Excludes
execsessions and subagent threads. - Excludes already pinned threads.
- Rewrites selected
threads.updated_atvalues to newer timestamps. - Touches the corresponding
sessions/.../*.jsonlrollout files viaos.utime()so their mtime matches the newupdated_at. - Restarts the Codex app so those threads move back into the startup recent set.
In the app version investigated, Codex Desktop appears to re-derive threads.updated_at from the rollout file mtime on startup. If the script only updates the SQLite row, Codex overwrites it back with the file mtime when it relaunches and the promotion has no visible effect.
So the script touches both. The output JSON includes rolloutFilesTouched so you can confirm the file side actually ran.
So this is not "conversation recovery." It is closer to:
- leave the conversation data alone
- change
updated_atinstate_5.sqliteand the matching rollout file mtime - make the Desktop App load already-existing local threads again
scripts/refresh-visible-workspaces.sh- promotes matching direct threads by updating
updated_at - force-restarts the Codex app without showing the quit confirmation dialog
- promotes matching direct threads by updating
- macOS
- local Codex Desktop App installation
- local Codex data directory
- default:
~/.codex
- default:
sqlite3/usr/bin/python3
CODEX_HOME- default:
~/.codex
- default:
CODEX_APP_PATH- default:
/Applications/Codex.app
- default:
CODEX_APP_CMD- default:
$CODEX_APP_PATH/Contents/MacOS/Codex
- default:
CODEX_APP_PROCESS_NAME- default:
Codex
- default:
- Do not run from inside the Codex Desktop App's integrated terminal. The script force-kills the
Codexprocess; if your shell is a child of that process, it will be killed mid-update and leave the database in a partial state. Use Terminal.app, iTerm, or any terminal not spawned by Codex. - The script terminates and relaunches Codex without a quit-confirmation prompt.
- A SQLite + state JSON backup is created before any changes are applied (under
~/.codex/repair-backups/). Rollout file mtimes are not backed up — runstat -f "%m" <file>first if you need to restore them later. - The script rewrites
threads.updated_atinstate_5.sqliteAND the mtime of the correspondingsessions/.../*.jsonlrollout files. Conversation contents are not modified, but recent ordering and file mtimes do change. - Already pinned threads are excluded from promotion.
- If Codex Desktop changes its internal loading behavior, this workaround may become less useful.
./scripts/refresh-visible-workspaces.sh --threads-per-root 3./scripts/refresh-visible-workspaces.sh --total-threads 50By default, the script uses electron-saved-workspace-roots and falls back to active-workspace-roots if needed. The Codex app is restarted automatically after the update.
./scripts/refresh-visible-workspaces.sh \
--only-root /absolute/path/to/project \
--threads-per-root 5Example:
./scripts/refresh-visible-workspaces.sh \
--only-root /Users/chenjing/dev/project \
--threads-per-root 5refresh-visible-workspaces.sh:
- reads saved workspace roots or explicit
--only-rootvalues - selects direct threads whose
cwdexactly matches the root - excludes
exec, subagent, and pinned threads - rewrites
threads.updated_atso they rank higher in recents - touches the matching rollout file mtime so Codex does not revert
updated_aton next startup - does not modify app state JSON beyond reading it
- does not modify session log contents