Archived session storage should fail fast and support deep archive/cold storage
Summary
Codex's archived-session storage contract is brittle for users with very large historical thread stores. If archived rollout files are symlinked to another drive to save local disk, recent Desktop builds can spin or lock up when old/archived threads are listed, read, continued, or unarchived. Even if symlinking internal app storage is not officially supported, Codex should fail fast and avoid app-wide lockups, and it likely needs a first-class "deep archive" / cold-storage workflow for massive long-running thread histories.
Environment
- Codex Desktop:
26.611.62324 - Bundle version:
4028 - macOS app bundle modified:
2026-06-17 22:08 +0700 - App-server process:
/Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabled - Source checkout inspected:
openai/codexmain
Local store shape from the affected machine:
~/.codex/archived_sessionsis a real directory.- It contains
1272symlinked rollout files pointing to an external drive. - It contains
476regular rollout files. state_5.sqlitecontains1627archived thread rows and2929active thread rows.
Observed behavior
Historically, the user archived massive long-running Codex threads to reduce local disk pressure by moving archived rollout files to a separate drive and symlinking them back into ~/.codex/archived_sessions.
In recent Desktop builds, attempts to continue/message old threads, or otherwise interact with archived thread state, can spin forever and lock the entire app. This started surfacing in the last roughly 48 hours on the affected machine after a Desktop update.
There are two separate concerns:
- Symlinks in
~/.codex/archived_sessionsare not compatible with the current archive/unarchive implementation. - Even if the symlink layout is unsupported, a bad/slow/missing archived rollout path should not be able to lock the whole Desktop app.
Relevant source pointers
codex-rs/thread-store/src/local/archive_thread.rs:
- Around
archive_thread.rs:30-49, archive resolves a canonical path under~/.codex/sessions, creates~/.codex/archived_sessions, then usesstd::fs::rename()to move the rollout into the archive directory. - Around
archive_thread.rs:55-58, the state DB is updated to mark the thread archived at the archived path.
codex-rs/thread-store/src/local/unarchive_thread.rs:
- Around
unarchive_thread.rs:21-40, unarchive locates the archived rollout and validates it withscoped_rollout_path()under~/.codex/archived_sessions. - Around
unarchive_thread.rs:56-71, it computes the restored~/.codex/sessions/YYYY/MM/DDpath and usesstd::fs::rename()from the canonical archived path back into sessions.
This means symlinked archived files are fragile in two ways:
- Canonicalization can resolve the file outside
~/.codex/archived_sessions, violating the expected managed-root containment check. rename()can fail across devices or against symlink/cold-storage layouts.
codex-rs/thread-store/src/local/read_thread.rs:
- Around
read_thread.rs:179-199, wheninclude_archivedis true, read paths still locate the actual thread path and then fall back tofind_archived_thread_path_by_id_str(...).
codex-rs/thread-store/src/local/list_threads.rs:
- Around
list_threads.rs:119-150, archived listing can use a state-DB-only path when requested, but non-DB-only archived listing still reads from the archive collection.
Expected behavior
Codex Desktop should remain responsive even when archived rollout files are symlinks, missing, slow, or otherwise invalid.
At minimum:
- List/read/resume/unarchive should fail fast for invalid archived rollout paths.
- A single bad archived entry should be skipped or surfaced as a per-thread error, not cause an app-wide spinner.
- The UI should distinguish "archived but restorable" from "deep archived / external / unavailable".
- Docs or diagnostics should warn that
~/.codex/archived_sessionsis an app-managed root and should not contain symlinks if Codex is expected to continue/unarchive those threads.
Suggested product direction
Codex likely needs a first-class cold-storage/deep-archive flow for large historical sessions:
- "Archive" keeps the thread app-managed and restorable, using real files under Codex's managed archive root.
- "Deep archive" or "export" moves/copies rollout files outside the managed root and removes them from normal read/resume/unarchive paths.
- The Desktop UI can still show a lightweight manifest row if desired, but it should not treat deep-archived files as immediately continuable.
- Restore should copy the file back as a real local file before Codex tries to read or continue it.
That would preserve disk relief for users with very large long-running threads without relying on filesystem symlinks inside an app-owned storage directory.
Reproduction outline
- Archive several large Codex threads.
- Move the archived rollout files to another volume.
- Symlink the files back into
~/.codex/archived_sessions. - Open Codex Desktop and interact with the archived thread list or try to continue/unarchive one of those old threads.
- Observe slow/spinning/locked Desktop behavior instead of a bounded per-thread error.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗