Show abnormal-interruption marker for running turns without terminal event after app restart

Open 💬 2 comments Opened Jul 8, 2026 by Bowie601

What version of the Codex App are you using (From "About Codex" dialog)?

codex-cli 0.142.5 from /Applications/Codex.app/Contents/Resources/codex --version

What subscription do you have?

Pro

What platform is your computer?

macOS

What issue are you seeing?

When Codex Desktop has multiple local/worktree threads running in parallel, the renderer can occasionally stop updating or become effectively unusable. In that state, the only practical recovery is to restart the app.

After restart, it is hard to tell which previously running tasks finished normally and which ones were interrupted or detached by the app/render restart. The transcript may show old progress, but there is no explicit bottom-of-conversation marker saying that a turn was still running and never recorded a terminal lifecycle event.

This is not a request for a "warn before close" confirmation dialog. The desired behavior is a post-restart recovery/audit marker on each affected conversation.

Related but broader issues:

  • #25779 tracks a wider Desktop/session/app-server meta-bug around freezes, unbounded state, and active-turn ownership.
  • #23035 describes an orphan lifecycle case where task_started without task_complete poisons reopen/resume.
  • #20754 and #24287 describe user-visible cases where UI running/thinking state can disagree with actual backend progress.

This issue is narrower: when a prior local turn has no authoritative terminal event after an app restart, Codex should surface that uncertainty clearly in the conversation UI.

What steps can reproduce the bug?

  1. Start several Codex Desktop local or worktree tasks in parallel.
  2. Let one or more tasks remain active long enough to be in a running / streaming state.
  3. Hit a Desktop renderer freeze, stuck UI update, or other state where restarting the app is the only practical recovery.
  4. Restart Codex Desktop.
  5. Open the previously active conversations.

Current result:

  • It is unclear which turns completed normally, which were cancelled, which failed, and which were interrupted or detached during the restart.
  • The user has to infer from partial transcript text, side effects in the repo, or logs.
  • In parallel-task workflows, this creates a high risk of assuming a task finished when it actually stopped halfway through.

What is the expected behavior?

Codex should persist enough turn lifecycle state to reconcile prior active turns after restart.

Suggested lifecycle states:

running
completed
failed
cancelled
abnormally_interrupted
unknown

Suggested behavior:

  1. When a turn starts, persist a durable record keyed by threadId, turnId, and the current app/client run id.
  2. Update that record on lifecycle events such as turn/started, turn/completed, turn.failed, explicit cancellation, or app-server errors.
  3. On app startup, scan recent threads for turns left as running from a previous app/client run.
  4. If there is no terminal event such as turn/completed, turn.failed, or explicit cancellation/interrupt completion, mark the turn as abnormally_interrupted or unknown.
  5. Show a bottom-of-conversation recovery card, for example:
Previous task may have been interrupted unexpectedly
Codex did not record a completion, failure, or cancellation event for the last running turn before the app restarted.

[Continue this task] [View last recorded event] [Mark as resolved]

Important distinctions:

  • If the turn has turn/completed, show it as completed.
  • If the user explicitly cancelled/interrupted and that reached a terminal state, show it as cancelled.
  • If there is a failure event, show it as failed.
  • If it is a cloud task, reconcile against cloud task status instead of marking it interrupted purely from local app restart.
  • Only show the abnormal marker when the prior local turn has no authoritative terminal event.

Additional information

This marker would make restart recovery safer for parallel Codex workflows. It would also make renderer/app-server lifecycle problems easier to debug because each conversation would show whether the last known turn ended cleanly, failed, was cancelled, or became detached during restart.

The implementation could live around the app/app-server lifecycle boundary rather than the renderer-only state, since renderer memory may be exactly the part that is stale or frozen.

View original on GitHub ↗

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