Skip to content

Double Esc rewind can leave terminal rendering broken after exit #21345

@RealmX1

Description

@RealmX1

What version of Codex CLI is running?

codex-cli 0.128.0

What subscription do you have?

Not relevant / not captured.

Which model were you using?

Not model-specific.

What platform is your computer?

macOS / Darwin on Apple Silicon (aarch64-apple-darwin binary from Homebrew cask).

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

Original terminal details were not captured. The failure appears tied to the TUI alternate-screen/backtrack flow rather than model output.

What issue are you seeing?

After using the Codex CLI double-Esc rewind/backtrack flow, terminal rendering can remain broken after exiting Codex. The shell prompt appears to render over stale TUI content / with an incorrectly restored screen state, requiring a terminal reset or a new terminal session to recover cleanly.

This looks like Codex can exit while the transcript/backtrack overlay has used the alternate screen, but process-level terminal restoration does not defensively leave the alternate screen. There is also a plausible redraw-cache issue when leaving the transcript overlay: the inline viewport is restored, but the terminal diff buffer can still contain the previous alternate-screen frame, allowing the next normal-buffer draw to be computed against stale overlay state.

What steps can reproduce the bug?

  1. Start an interactive Codex CLI session.
  2. Send at least one user message so there is a rewind target.
  3. Press Esc once to prime backtrack.
  4. Press Esc again to open the transcript/backtrack overlay.
  5. Exit Codex from this flow, or close the overlay and then exit.
  6. Observe the shell/terminal after Codex exits.

What is the expected behavior?

After Codex exits, the terminal should always be restored to a normal shell-rendering state:

  • not left in the alternate screen,
  • alternate-scroll mode disabled,
  • cursor visible/default,
  • no stale Codex overlay content affecting subsequent shell rendering.

What happens instead?

The terminal can remain visually corrupted after exit, with shell output/prompt rendering over stale Codex TUI content or otherwise appearing as if the screen state was not fully restored.

Additional information

I inspected codex-rs/tui/src/tui.rs and found two likely hardening points:

  1. restore_common(...) currently restores bracketed paste, focus, raw mode, keyboard reporting, and cursor state, but does not defensively emit DisableAlternateScroll / LeaveAlternateScreen. If the app exits while an overlay or alternate-screen transition is active, the parent shell may inherit the wrong screen state.
  2. Tui::leave_alt_screen() restores the saved inline viewport but does not invalidate the terminal diff buffer. Since the alternate-screen overlay and normal inline UI use different backing screen contents, the next normal-buffer draw should be forced to repaint rather than diffing against the overlay frame.

A local minimal patch that appears appropriate is:

// in restore_common(...)
if let Err(err) = execute!(stdout(), DisableAlternateScroll, LeaveAlternateScreen) {
    first_error.get_or_insert(err);
}

// in Tui::leave_alt_screen(), after restoring alt_saved_viewport
self.terminal.invalidate_viewport();

Local validation on a checkout of openai/codex main:

cargo fmt --manifest-path codex-rs/Cargo.toml --all
cargo test --manifest-path codex-rs/tui/Cargo.toml app_backtrack --lib
cargo check --manifest-path codex-rs/Cargo.toml -p codex-tui

Results:

  • cargo test --manifest-path codex-rs/tui/Cargo.toml app_backtrack --lib: passed, 8 tests.
  • cargo check --manifest-path codex-rs/Cargo.toml -p codex-tui: passed.
  • cargo fmt completed; stable rustfmt emitted existing warnings about the repository's nightly-only imports_granularity setting.

Per docs/contributing.md, external PRs are by invitation only, so I am opening this issue first with the repro, root-cause hypothesis, and patch outline instead of sending an unsolicited PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions