fix(codex-desktop): preserve the initial prompt when a new turn is stopped immediately
Summary
Codex Desktop on macOS can retain a thread title and generated description derived from a new thread's initial prompt while omitting that prompt from both the visible transcript and the persisted rollout. In the observed case, the user stopped the first turn about one second after turn/start, returned later, and sent go on. Because the stored thread contained no real first user message, the agent could not recover the LM Studio task identified by the title and instead guessed from unrelated repository state.
Steps to reproduce
Known affected sequence:
- Open Codex Desktop on macOS and start a new local thread with a substantive prompt. The affected prompt requested creation of an LM Studio agent skill from its documentation and public repositories.
- Click the Stop button immediately, before the first assistant message or tool call appears. In the affected run,
turn/startreturned andturn/interruptcompleted about 1.17 seconds later; the UI displayedYou stopped after 0s. - Leave the thread and return to it later.
- Confirm that the generated thread title still describes the initial task but that the initial prompt is not visible.
- Send
go on. - Observe that the agent has no stored task prompt to continue and attempts to infer the task from nearby workspace or thread state.
This is one forensically confirmed occurrence. A clean-room repetition has not been attempted, so the smallest remaining reproduction fact is whether stopping during each pre-sampling startup phase triggers the failure consistently or only during a narrower extension-contribution window.
Expected behavior
- Stopping a turn must cancel generation without deleting or failing to persist the user input that started the turn.
- The initial user message must remain visible and must be returned by thread history after the interrupted turn.
- The thread title, description, transcript, and persisted rollout must agree about the existence of the initial request.
- A later continuation such as
go onmust receive the interrupted task prompt in conversation history.
The red/green regression check is to start a new thread with extensions/apps enabled, interrupt it at each pre-sampling startup phase, resume it, and verify that exactly one real userMessage containing the submitted prompt exists before the interrupted-turn marker and is present in the resumed model context.
Actual behavior
- The thread index retained the title
Create LM Studio agent skilland the app retained a generated description of the LM Studio authoring task. - The first persisted turn contained session metadata, injected developer/user context, world state, turn context, and a
turn_abortedevent, but no real user message containing the submitted request. - On the next turn, the only real user input in the rollout was
go on. - The agent consequently guessed that the interrupted task concerned an unrelated Ollama skill and inspected unrelated repository state.
- The screenshot and
thread/readresult were therefore consistent with the persisted rollout rather than merely hiding an otherwise intact prompt in the renderer.
Affected area
- Codex Desktop for macOS: new-thread submission, immediate Stop, transcript reconstruction, and resume behavior.
- Bundled Codex app-server/core: preservation of submitted user input when cancellation occurs before pre-sampling setup completes.
Runtime or environment
- Codex Desktop bundle:
26.810.52044(CFBundleVersion6662, bundle identifiercom.openai.codex) - Bundled Codex CLI/app-server:
0.148.0-alpha.9 - Subscription: ChatGPT subscription; the exact tier was not exposed by the inspected local diagnostics
- Platform:
Darwin 25.5.0 arm64 arm; macOS26.5.2(25F84), Apple Silicon - Affected thread:
01a00bcd-dc10-7533-b912-17c791b7f23d - Affected initial turn:
01a00bd1-2797-7e13-9718-1d488a2314a1 - Observed date: 2026-08-16
Evidence
Sanitized local event timeline:
18:24:11.586Z: Codex Desktop logged creation of the affected conversation.18:24:11.672Z:turn/startreturned successfully.18:24:11.744Z: the rollout recordedsession_metaandtask_started.18:24:12.245Z: injected developer/user context, world state, and turn context were persisted. The only user-role item at this point contained plugins, repository instructions, and environment context; it did not contain the LM Studio request.18:24:12.838Z:turn/interruptreturned successfully, approximately 1.17 seconds afterturn/start.18:24:21.734Z: the separate thread-title generation completed successfully.18:24:21.766Z: the app stored the titleCreate LM Studio agent skill, despite the absent prompt in the rollout.19:46:57.839Z: the thread resumed with its prior turn marked interrupted.19:47:01.328Z:go onwas persisted as the first real user message available in the thread.
The affected rollout contained 44 JSONL records and had SHA-256 2b05e162e18fa8a8782c31bec2d6ba528f06b438d4e4c3282f7611a604c8770f at inspection time. The raw rollout and desktop log are not attached because they contain private prompts, repository context, local paths, and unrelated thread data.
After filing this report, the exact original prompt was recovered from Codex Desktop's separate global composer history (electron-persisted-atom-state -> prompt-history.global). Two independently stored copies—the current global-state file and its backup—contained byte-for-byte identical prompt text, while the affected thread rollout still did not contain it. The prompt itself is intentionally not included here. This further localizes the failure: the app accepted and retained the submission outside the thread, but did not preserve it in the thread history used for transcript reconstruction and model resume.
The exact bundled CLI version maps to the public rust-v0.148.0-alpha.9 source tag at commit 9392c3fa5bcda342b5b96a1a04d67b2f781617c2. That source provides a plausible input-loss mechanism:
run_turnperforms pre-sampling setup before callingrun_hooks_and_record_inputsfor the submitted input. Ifbuild_skills_and_pluginsreturnsNone, it returns successfully without the input-recording fallback: https://github.com/openai/codex/blob/9392c3fa5bcda342b5b96a1a04d67b2f781617c2/codex-rs/core/src/session/turn.rs#L230-L247- Extension contribution converts cancellation into
Nonethrough.or_cancel(cancellation_token).await.ok()?: https://github.com/openai/codex/blob/9392c3fa5bcda342b5b96a1a04d67b2f781617c2/codex-rs/core/src/session/turn.rs#L883-L934 - Codex previously fixed the same invariant for interruption during MCP startup in https://github.com/openai/codex/pull/34839. That change explicitly says submitted input must remain in history before the turn-aborted marker.
The same unguarded ordering remained on inspected Codex main at commit ed32158e90ef872c5eef96baf2f14feac70aee6e on 2026-08-16. However, the closed-source Desktop request body is not logged, so the evidence cannot distinguish conclusively between two mechanisms: Desktop may have sent an empty turn/start input while retaining the prompt for title generation, or it may have sent the prompt and the bundled core may have dropped it when cancellation reached the extension-contribution path. The persisted prompt loss and broken resume behavior are confirmed either way; the exact renderer-to-app-server boundary remains an inference.
Related reports are similar but do not have the same red signal and closure check:
- https://github.com/openai/codex/issues/10786 includes an immediate-stop path followed by globally spinning submissions, but it does not document a title-retained, prompt-missing interrupted thread.
- https://github.com/openai/codex/issues/24287 covers prompts or traces becoming invisible while backend work continues and Stop fails. Here Stop succeeded, no task work was persisted, and the initial prompt itself was absent from durable history.
- https://github.com/openai/codex/issues/19951 covers submission errors, delayed duplicates, and an empty/idle conversation, not a successfully interrupted first turn that later resumes without its prompt.
No issue with the same red signal and closure condition was found in openai/codex using searches for Codex Desktop/macOS, immediate Stop, interrupt/resume, initial prompt, first prompt, user message, missing, lost, and title/transcript disagreement.
Impact
The thread becomes misleading and non-recoverable through ordinary conversation continuation: its title claims a task exists, while the model-visible durable history does not contain that task. A short follow-up such as go on can then make the agent infer the wrong work from unrelated repository state, risking wasted time and unintended edits unless the user notices the mismatch. The separate global composer history may retain the submitted text, as it did in this occurrence, but that hidden recovery path does not restore the thread or make the prompt available to the resumed model.
Additional context
This is a Codex macOS app and bundled Codex core/app-server problem. The most useful fix or regression test would restore the invariant already stated by PR #34839: every accepted non-empty user submission survives interruption and is recorded before the aborted-turn marker, including cancellation during extension/skill/plugin contribution and immediate first-turn Stop.
Until that invariant is verified in a released Codex Desktop build, a practical diagnostic is to compare the generated title with the visible first user message after an immediate Stop. If the title exists but the prompt does not, do not send an ambiguous continuation; resend the original task explicitly in a new message.
1 Comment
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action