Codex task shows only the first turn after reopening because thread history projection is stuck before `task_complete`
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
- Codex CLI: `0.145.0
What subscription do you have?
plus
Which model were you using?
gpt 5.6 sol
What platform is your computer?
Linux x86_64 x86_64
What terminal emulator and version are you using (if applicable)?
Codex Desktop integrated terminal connected to an Ubuntu 22.04 remote host over Remote SSH. Shell: Bash (/bin/bash). TERM=dumb. No screen, tmux, or zellij multiplexer was in use. Codex Desktop app version is unavailable from the remote CLI.
Codex doctor report
{
"schemaVersion": 1,
"generatedAt": "1788490320s since unix epoch",
"overallStatus": "fail",
"codexVersion": "0.145.0",
"checks": {
"app_server.status": {
"id": "app_server.status",
"category": "app-server",
"status": "warning",
"summary": "background server socket is stale or unreachable",
"details": {
"app-server version": "unavailable (failed to connect to control socket)",
"control socket": "/root/.codex/app-server-control/app-server-control.sock",
"daemon state dir": "/root/.codex/app-server-daemon",
"mode": "ephemeral",
"pid file": "/root/.codex/app-server-daemon/app-server.pid (missing)",
"settings": "/root/.codex/app-server-daemon/settings.json (missing)",
"status": "stale or unreachable",
"update-loop pid file": "/root/.codex/app-server-daemon/app-server-updater.pid (missing)"
},
"remediation": "Run codex app-server daemon version for more details.",
"durationMs": 0
},
"auth.credentials": {
"id": "auth.credentials",
"category": "auth",
"status": "ok",
"summary": "auth is configured",
"details": {
"auth file": "/root/.codex/auth.json",
"auth storage mode": "File",
"stored API key": "false",
"stored ChatGPT tokens": "true",
"stored agent identity": "false",
"stored auth mode": "chatgpt"
},
"remediation": null,
"durationMs": 0
},
"config.load": {
"id": "config.load",
"category": "config",
"status": "ok",
"summary": "config loaded",
"details": {
"CODEX_HOME": "/root/.codex",
"config.toml": "/root/.codex/config.toml",
"config.toml parse": "ok",
"cwd": "/data/SkillEmpirical",
"model": "gpt-5.6-sol",
"model provider": "openai",
"sqlite home": "/root/.codex"
},
"remediation": null,
"durationMs": 0
},
"git.environment": {
"id": "git.environment",
"category": "git",
"status": "ok",
"summary": "git version 2.34.1",
"details": {
"repo detected": "true",
"repo root": "/data/SkillEmpirical",
"selected git": "/usr/bin/git",
"git version": "git version 2.34.1"
},
"remediation": null,
"durationMs": 113
},
"installation": {
"id": "installation",
"category": "install",
"status": "ok",
"summary": "installation looks consistent",
"details": {
"managed by npm": "true",
"managed by bun": "false",
"managed by pnpm": "false",
"managed package root": "/usr/lib/node_modules/@openai/codex",
"npm update target": "/usr/lib/node_modules/@openai/codex"
},
"remediation": null,
"durationMs": 151
},
"network.provider_reachability": {
"id": "network.provider_reachability",
"category": "reachability",
"status": "fail",
"summary": "one or more required provider endpoints are unreachable over HTTP",
"details": {
"ChatGPT base URL": "https://chatgpt.com/backend-api/ connect failed (required)",
"reachability mode": "ChatGPT auth"
},
"remediation": "Check proxy, VPN, firewall, DNS, and custom CA configuration.",
"durationMs": 37
},
"network.websocket_reachability": {
"id": "network.websocket_reachability",
"category": "websocket",
"status": "warning",
"summary": "Responses WebSocket failed; HTTPS fallback may still work",
"details": {
"DNS": "lookup failed (Operation not permitted (os error 1))",
"auth mode": "chatgpt",
"connect timeout": "15000 ms",
"handshake transport error": "network error: Operation not permitted (os error 1)",
"model provider": "openai",
"provider name": "OpenAI",
"supports websockets": "true",
"wire API": "responses"
},
"remediation": "Check proxy, VPN, firewall, DNS, custom CA, and WebSocket policy support.",
"durationMs": 140
},
"runtime.provenance": {
"id": "runtime.provenance",
"category": "runtime",
"status": "ok",
"summary": "running npm on linux-x86_64",
"details": {
"commit": "unknown",
"install method": "npm",
"platform": "linux-x86_64",
"version": "0.145.0"
},
"remediation": null,
"durationMs": 0
},
"state.paths": {
"id": "state.paths",
"category": "state",
"status": "ok",
"summary": "state paths and databases are inspectable",
"details": {
"CODEX_HOME": "/root/.codex (dir)",
"state DB": "/root/.codex/state_5.sqlite (file)",
"state DB integrity": "ok",
"thread history DB": "/root/.codex/thread_history_1.sqlite (file)",
"thread history DB integrity": "ok",
"log DB": "/root/.codex/logs_2.sqlite (file)",
"log DB integrity": "ok"
},
"remediation": null,
"durationMs": 1518
},
"state.rollout_db_parity": {
"id": "state.rollout_db_parity",
"category": "threads",
"status": "ok",
"summary": "rollout files and state DB thread inventory agree",
"details": {
"rollout DB active files": "72",
"rollout DB active rows": "72",
"rollout DB archived files": "10",
"rollout DB archived rows": "10",
"rollout DB duplicate rollout thread ids": "0",
"rollout DB missing active rows": "0",
"rollout DB missing archived rows": "0",
"rollout DB scan errors": "0",
"rollout DB sources": "exec=37, vscode=29, subagent:other=16",
"rollout DB stale rows": "0"
},
"remediation": null,
"durationMs": 145
},
"system.environment": {
"id": "system.environment",
"category": "system",
"status": "ok",
"summary": "OS language C",
"details": {
"LANG": "en_US.UTF-8",
"LC_ALL": "C.UTF-8",
"os": "Ubuntu 22.4.0 (jammy) [64-bit]",
"os type": "Ubuntu",
"os version": "22.4.0"
},
"remediation": null,
"durationMs": 30
},
"terminal.env": {
"id": "terminal.env",
"category": "terminal",
"status": "fail",
"summary": "TERM=dumb - colors and cursor control are disabled",
"details": {
"SSH_CLIENT": "present",
"SSH_CONNECTION": "present",
"TERM": "dumb",
"stderr is terminal": "false",
"stdin is terminal": "false",
"stdout is terminal": "false",
"terminal size": "80x24"
},
"remediation": null,
"durationMs": 13
}
}
}
What issue are you seeing?
A multi-turn Codex task on a remote SSH host displayed only its first conversation turn after the task was closed and reopened.
The later turns were not deleted. They were still present in the rollout JSONL, and Codex could continue using their context. However, the Codex UI and task-history API returned only the first turn and incorrectly marked it as inProgress.
Affected thread ID:
01a0609d-f30e-7f21-aa14-89e24a45e114
The raw rollout contained five completed turns, with valid task_started and task_complete events. However, thread_history_1.sqlite initially contained only one projected turn and two projected message items.
The projection cursor was stuck immediately before the first valid task_complete event:
thread_history_projection_state.next_rollout_byte_offset = 91671
thread_history_projection_state.next_rollout_ordinal = 10
The logs repeatedly reported:
codex_thread_store::local::thread_history_materialization
skipping rejected rollout line while projecting: invalid type: map, expected f64
Renaming the task updated its title and sidebar recency but did not rebuild the missing history.
As a local recovery workaround, I backed up the SQLite database and reconstructed this thread's thread_turns and thread_items projection rows from the intact rollout JSONL. After the projection refreshed, all five completed turns became visible again.
The rollout JSONL itself was never modified.
What steps can reproduce the bug?
- Connect the Codex desktop app to an Ubuntu workspace using Remote SSH.
- Create a Codex task and complete the first user/assistant turn.
- Leave or close the task.
- Reopen the same task later.
- Continue the task for several additional turns.
- Close and reopen the task again.
- Observe that only the first turn is displayed.
- Inspect the rollout JSONL and confirm that all later turns and
task_completeevents are still present. - Inspect
thread_history_1.sqliteand observe that the history projection has stopped before the firsttask_complete.
Affected thread ID:
01a0609d-f30e-7f21-aa14-89e24a45e114
What is the expected behavior?
All completed conversation turns stored in the rollout JSONL should be restored and displayed when the task is reopened.
A completed turn must not remain marked as inProgress.
If the history projector encounters an incompatible or unrecognized event field, it should either migrate or safely skip that field without preventing all subsequent valid turns from being projected.
Codex should also provide a supported command or UI action to rebuild a task's history projection from its rollout JSONL.
Additional information
Environment:
- Codex CLI: 0.145.0
- Model: gpt-5.6-sol
- Host OS: Ubuntu 22.04, Linux x86_64
- Connection: Codex desktop app connected through Remote SSH
- Thread source recorded in state database: vscode
- History mode: paginated
- Workspace: /data/SkillEmpirical
- Affected thread ID: 01a0609d-f30e-7f21-aa14-89e24a45e114
The affected rollout JSONL was valid newline-delimited JSON with contiguous event ordinals.
At diagnosis, it contained five complete task boundaries, ending at ordinals 11, 46, 169, 198, and 260. The task-history API nevertheless returned one turn, marked inProgress, with hasMore=false.
The same projection database contained only one inProgress turn for each of three local Codex threads, which may indicate a broader projection or migration problem.
Impact:
- Users may incorrectly believe their conversation history has been deleted.
- Completed analysis and decisions become inaccessible through the UI.
- New turns can continue to be appended while the visible history remains stuck.
- There is no documented recovery or reindex command.
Requested fixes:
- Make the history projector tolerate or migrate incompatible rollout field variants.
- Safely advance past non-history events that cannot be decoded.
- Correctly reconcile
task_completeevents. - Add a supported history rebuild/reindex command.
- Display a warning when the projection cursor falls behind the rollout file.
I can provide the rollout JSONL, relevant SQLite rows, and log records privately after redaction. I am not attaching the raw rollout publicly because it contains prompts, local file paths, and command output.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with codex_thread_store::local::thread_history_materialization and compare the affected rollout JSONL with thread_history_1.sqlite, especially thread_history_projection_state. Trace the rejected field and the cursor around the first task_complete event. Done means all completed turns are projected, completed turns are not marked inProgress, and later valid events remain visible after reopening.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100