core-agent-ide/docs/tui-alternate-screen.md
Helmut Januschka 7daaabc795
fix: add tui.alternate_screen config and --no-alt-screen CLI flag for Zellij scrollback (#8555)
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>
2026-01-09 18:38:26 +00:00

130 lines
4.9 KiB
Markdown

# 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:
1. The TUI runs in alternate screen mode (fullscreen)
2. Zellij disables scrollback in alternate screen buffers (per xterm spec)
3. 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:
```bash
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:
```rust
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:
```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:
1. Many Zellij users don't care about scrollback and prefer the fullscreen experience
2. Some users may use tmux inside Zellij, creating a chain of multiplexers
3. Provides user choice without requiring manual configuration
## Related Issues and References
- **Original Issue:** [GitHub #2558](https://github.com/openai/codex/issues/2558) - "No scrollback in Zellij"
- **Implementation PR:** [GitHub #8555](https://github.com/openai/codex/pull/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
1. **Implement custom scrollback in TUI:** Would require significant architectural changes to buffer and render all historical output
2. **Request Zellij to add a config option:** Not viable—Zellij maintainers explicitly chose this behavior to follow the spec
3. **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:
```bash
reset
```