Cold start scales badly with large ~/.codex state: 419 MB logs DB + 625 MB sessions cause 1–5 min startup on WSL2

Resolved 💬 3 comments Opened Jun 14, 2026 by 0proof1 Closed Jun 24, 2026

What version of Codex CLI is running?

codex-cli 0.139.0

What subscription do you have?

ChatGPT Plus

Which model were you using?

gpt-5.5

What platform is your computer?

WSL2 Ubuntu on Windows Linux 6.6.114.1-microsoft-standard-WSL2 x86_64 x86_64

What terminal emulator and version are you using (if applicable)?

Windows Terminal with WSL2 Ubuntu, bash shell. No tmux/screen/zellij multiplexer.

Codex doctor report

Not available.

`codex doctor --json` is affected by the same cold-start issue. On this machine, `codex doctor` can take several minutes on a cold page cache, and in earlier attempts it appeared to hang or exceeded practical timeout limits. I included separate `codex doctor` timing measurements in the issue body instead.

What issue are you seeing?

On a cold page cache, full-init Codex commands such as codex exec, codex doctor, and the TUI can block for 1-5 minutes before doing useful work. This makes the CLI appear hung, especially to humans or wrappers using short timeouts.

Auth, network, websocket, and model access appear healthy. The delay appears to come from cold-cache startup I/O over accumulated local state in ~/.codex, especially logs_2.sqlite and sessions/.

Observed timings:

| Command | Warm cache | Cold cache |
|---|---:|---:|
| codex doctor | ~13 s | ~292 s |
| codex exec "say OK" | 4-5 s plus model time | ~57 s |

Accumulated ~/.codex state:

| Item | Size |
|---|---:|
| logs_2.sqlite | 419 MB |
| logs_2.sqlite-wal | 74 MB |
| sessions/ | 625 MB |
| .tmp/plugins/ | 79 MB, 175 plugin.json files |
| history.jsonl | 1.8 MB |
| other sqlite files | small |

What steps can reproduce the bug?

  1. Use Codex long enough for ~/.codex to accumulate large local state. In my case:
  • logs_2.sqlite: 419 MB
  • logs_2.sqlite-wal: 74 MB
  • sessions/: 625 MB
  • .tmp/plugins/: 79 MB / 175 manifests
  1. Drop the page cache:

sync
echo 3 | sudo tee /proc/sys/vm/drop_caches

  1. Run:

codex doctor

or:

codex exec --skip-git-repo-check "say OK"

  1. Observe a long silent startup delay before useful output.

I bisected the cold startup cost by moving one candidate aside, dropping the page cache, timing cold codex doctor, and then restoring the candidate.

| Removed before cold doctor | Cold doctor time | Delta |
|---|---:|---:|
| nothing, full ~/.codex | 291.9 s | -- |
| .tmp/plugins/ only, 79 MB / 175 manifests | 280.1 s | -12 s |
| logs_2.sqlite only, 419 MB | 140.2 s | -152 s |
| both .tmp/plugins/ and logs_2.sqlite | 115.6 s | -176 s |

This strongly suggests that the largest startup cost is associated with accumulated local state, especially the telemetry logs DB and the sessions directory. The plugin catalog contributes, but it is not the primary cause in this environment.

I also tested whether features.plugins=false explains the issue. It does not explain the main cold-start delay.

| Command | Plugins ON | Plugins OFF |
|---|---:|---:|
| warm doctor | 13.42 s | 13.32 s |
| cold doctor | 234.68 s | 240.53 s |
| warm exec | 29.40 s, model-time noisy | 4.44 s |
| cold exec | 56.54 / 59.47 s | 41.46 / 32.34 s |

Interpretation:

  • For doctor, plugins ON/OFF makes almost no difference.
  • The decisive difference is warm vs cold cache.
  • For exec, plugins add some secondary cost, but even with plugins disabled cold exec is still much slower than warm exec.

What is the expected behavior?

Codex should start in a few seconds even when local history, telemetry, sessions, or plugin catalogs have grown large.

Large append-only or historical state should not block CLI startup unless the user explicitly opens that state.

If startup must do expensive local-state work, the CLI should print early progress such as "loading local state", "loading sessions", or "loading plugin catalog", so a slow cold start is not mistaken for a hang.

Additional information

Ruled out:

  • Not the binary: codex --version returns immediately.
  • Not auth/network/websocket/model: codex doctor reports healthy connectivity.
  • Not a /mnt/c DrvFs/9p mount: ~/.codex is on native WSL2 ext4.
  • Not config size: copying the real config.toml into a clean CODEX_HOME remains fast.
  • Not primarily the plugin catalog: removing it only saves about 12 s on cold doctor; disabling plugins has almost no effect on doctor.

Secondary observations:

  1. codex doctor appears to ignore features.plugins=false.

With plugins disabled, doctor timing is effectively unchanged. Physically moving the plugin catalog directory does change timing, which suggests doctor may still scan plugin-related state even when the feature is disabled.

  1. Plugin and skill manifests appear to be parsed multiple times per process.

In one RUST_LOG=info codex exec run, the same manifest warning for one plugin was logged 6 times, and a set of skill icon warnings was logged 24 times.

Example repeated warnings:

codex_core_plugins::manifest: ignoring interface.defaultPrompt[0]: prompt must be at most 128 characters
path=.../.tmp/plugins/plugins/ngs-analysis/.codex-plugin/plugin.json

codex_core_skills::loader: ignoring interface.icon_small/icon_large: icon path with '..'

One internal startup phase also logged approximately:

duration_ms=14502

Suggested fixes:

  1. Avoid loading or scanning large accumulated state on the startup hot path.
  2. Open telemetry logs lazily or asynchronously.
  3. Load session history only when a specific session is opened.
  4. Add retention, rotation, or vacuuming for logs_2.sqlite, WAL files, and sessions/.
  5. Cache parsed plugin and skill manifests by mtime/hash.
  6. Ensure each manifest is parsed and validated at most once per process.
  7. Make codex doctor honor features.plugins=false.
  8. Print early startup progress so long cold starts are not mistaken for a hang.

Local mitigation:

Using a clean CODEX_HOME with only auth/config avoids the delay, which further supports that the problem is accumulated local state rather than auth, network, or the binary itself.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗