Fixes #2558 Codex uses alternate screen mode (CSI 1049) which, per xterm spec, doesn't support scrollback. Zellij follows this strictly, so users can't scroll back through output. **Changes:** - Add `tui.alternate_screen` config: `auto` (default), `always`, `never` - Add `--no-alt-screen` CLI flag - Auto-detect Zellij and skip alt screen (uses existing `ZELLIJ` env var detection) **Usage:** ```bash # CLI flag codex --no-alt-screen # Or in config.toml [tui] alternate_screen = "never" ``` With default `auto` mode, Zellij users get working scrollback without any config changes. --------- Co-authored-by: Josh McKinney <joshka@openai.com>
4.9 KiB
TUI Alternate Screen and Terminal Multiplexers
Overview
This document explains the design decision behind Codex's alternate screen handling, particularly in terminal multiplexers like Zellij. This addresses a fundamental conflict between fullscreen TUI behavior and terminal scrollback history preservation.
The Problem
Fullscreen TUI Benefits
Codex's TUI uses the terminal's alternate screen buffer to provide a clean fullscreen experience. This approach:
- Uses the entire viewport without polluting the terminal's scrollback history
- Provides a dedicated environment for the chat interface
- Mirrors the behavior of other terminal applications (vim, tmux, etc.)
The Zellij Conflict
Terminal multiplexers like Zellij strictly follow the xterm specification, which defines that alternate screen buffers should not have scrollback. This is intentional design, not a bug:
- Zellij PR: https://github.com/zellij-org/zellij/pull/1032
- Rationale: The xterm spec explicitly states that alternate screen mode disallows scrollback
- Configurability: This is not configurable in Zellij—there is no option to enable scrollback in alternate screen mode
When using Codex's TUI in Zellij, users cannot scroll back through the conversation history because:
- The TUI runs in alternate screen mode (fullscreen)
- Zellij disables scrollback in alternate screen buffers (per xterm spec)
- The entire conversation becomes inaccessible via normal terminal scrolling
The Solution
Codex implements a pragmatic workaround with three modes, controlled by tui.alternate_screen in config.toml:
1. auto (default)
- Behavior: Automatically detect the terminal multiplexer
- In Zellij: Disable alternate screen mode (inline mode, preserves scrollback)
- Elsewhere: Enable alternate screen mode (fullscreen experience)
- Rationale: Provides the best UX in each environment
2. always
- Behavior: Always use alternate screen mode (original behavior)
- Use case: Users who prefer fullscreen and don't use Zellij, or who have found a workaround
3. never
- Behavior: Never use alternate screen mode (inline mode)
- Use case: Users who always want scrollback history preserved
- Trade-off: Pollutes the terminal scrollback with TUI output
Runtime Override
The --no-alt-screen CLI flag can override the config setting at runtime:
codex --no-alt-screen
This runs the TUI in inline mode regardless of the configuration, useful for:
- One-off sessions where scrollback is critical
- Debugging terminal-related issues
- Testing alternate screen behavior
Implementation Details
Auto-Detection
The auto mode detects Zellij by checking the ZELLIJ environment variable:
let terminal_info = codex_core::terminal::terminal_info();
!matches!(terminal_info.multiplexer, Some(Multiplexer::Zellij { .. }))
This detection happens in the helper function determine_alt_screen_mode() in codex-rs/tui/src/lib.rs.
Configuration Schema
The AltScreenMode enum is defined in codex-rs/protocol/src/config_types.rs and serializes to lowercase TOML:
[tui]
# Options: auto, always, never
alternate_screen = "auto"
Why Not Just Disable Alternate Screen in Zellij Permanently?
We use auto detection instead of always disabling in Zellij because:
- Many Zellij users don't care about scrollback and prefer the fullscreen experience
- Some users may use tmux inside Zellij, creating a chain of multiplexers
- Provides user choice without requiring manual configuration
Related Issues and References
- Original Issue: GitHub #2558 - "No scrollback in Zellij"
- Implementation PR: GitHub #8555
- Zellij PR: https://github.com/zellij-org/zellij/pull/1032 (why scrollback is disabled)
- xterm Spec: Alternate screen buffers should not have scrollback
Future Considerations
Alternative Approaches Considered
- Implement custom scrollback in TUI: Would require significant architectural changes to buffer and render all historical output
- Request Zellij to add a config option: Not viable—Zellij maintainers explicitly chose this behavior to follow the spec
- Disable alternate screen unconditionally: Would degrade UX for non-Zellij users
Transcript Pager
Codex's transcript pager (opened with Ctrl+T) provides an alternative way to review conversation history, even in fullscreen mode. However, this is not as seamless as natural scrollback.
For Developers
When modifying TUI code, remember:
- The
determine_alt_screen_mode()function encapsulates all the logic - Configuration is in
config.tui_alternate_screen - CLI flag is in
cli.no_alt_screen - The behavior is applied via
tui.set_alt_screen_enabled()
If you encounter issues with terminal state after running Codex, you can restore your terminal with:
reset