openai / openai/codex

/agent thread switching emits stale completion notifications during replay

Open Beginner friendly
#38,192 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI subagent
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

Codex version

codex-cli 0.147.0

Platform

Linux, Ghostty, Codex running in long-lived dtach sessions.

What issue are you seeing?

Selecting a parent or child thread with /agent can emit a fresh terminal AgentTurnComplete notification for a completion that happened earlier and is merely being replayed.

If the terminal notification method is OSC 9, this appears as a stale desktop popup containing an old final message. With the BEL backend, it becomes a stale tab bell instead. Changing the backend therefore mitigates the disruption but does not suppress the erroneous event.

This is distinct from a real completion occurring while the selected thread is in the foreground: the notification is emitted at thread-selection/replay time, even when newer text already exists below the historical completion and the user just selected the thread manually.

Steps to reproduce
  1. Start a parent thread and let a turn finish with final message A.
  2. Spawn a subagent whose thread inherits or forks the parent history.
  3. Continue until newer content exists in the parent and/or child.
  4. Use /agent to switch from the parent to the child, or back and forth.
  5. Observe a terminal completion notification containing old message A at thread-selection time.

This was reproduced with multiple child threads.

Expected behavior

Replay, whether caused by resume or by selecting another agent thread, may reconstruct transcript and UI state but must not emit a fresh external completion notification.

Actual behavior

Historical task_complete events replayed while selecting a thread cause Notification::AgentTurnComplete to be emitted again.

Source-level diagnosis

The current source path passes replay state into task completion handling:

  • handle_turn_completed_notification passes replay_kind.is_some() to on_task_complete(..., from_replay).
  • on_task_complete guards several replay-only side effects with !from_replay.
  • The terminal completion notification is still emitted without that guard:
if !follow_up_started && !active_goal_continuing {
    self.notify(Notification::AgentTurnComplete { ... });
}

A likely minimal fix is to include !from_replay in this notification guard. A regression test should cover /agent selection of a child whose inherited history contains an earlier task_complete.

Local rollout evidence

At child creation time, the child rollout begins with inherited historical task_complete events from the parent before the child's newer content. Selecting the child replays those events and emits the old notification. The same inherited event shape exists in rollouts created by 0.146.0, suggesting that the unguarded replay side effect predates 0.147.0.

Related upstream activity
  • Related issue: #17487 discusses stale final-message state during resume/replay. This report is narrower: an external terminal notification is emitted directly by replay during /agent selection.
  • PR #35693 added background discovery of descendants absent from the current TUI navigation state. That appears to make this latent replay bug much easier to encounter after upgrading to 0.147.0, but the PR is likely an exposure amplifier rather than the root defect.
Possibly separate symptom

Live completion of an unselected background subagent can also produce a terminal notification. That may be a separate notification-policy issue and is not required to reproduce the replay bug described here.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at handle_turn_completed_notification and on_task_complete, tracing replay_kind into from_replay and inspecting the existing replay-only side-effect guards. Add a regression test covering /agent selection of a child with an inherited task_complete event; done means replay reconstructs the thread without emitting a fresh AgentTurnComplete notification.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.