Topic · A9
CSI 2026 / DECSET Synchronized Output: The Terminal Spec That Powers Modern AI CLIs
CSI 2026 synchronized output is the terminal control sequence behind flicker-free TUI rendering in modern AI coding CLIs. Claude Code, pi-tui, frankentui, and most serious 2026 terminal UIs use it. Here's what it does, the Claude Code issues that made it famous, and how to use it correctly.
If you've used Claude Code in tmux and watched the terminal flicker while the agent reasons, you've met the problem CSI 2026 was designed to solve.
This page is the technical reference. What the sequence does, why it became famous in 2026, which terminals support it, and how to use it correctly in your own TUI. The audience is developers building or debugging terminal UIs — particularly the AI CLI category that's grown explosively in the last year (see /topic/cli-everything-wave).
What CSI 2026 actually does
CSI 2026 is two ANSI control sequences that wrap a region of terminal output:
\x1b?2026h Begin synchronized update
... your screen draws here ...
\x1b[?2026l End synchronized update
When the terminal emulator sees the begin sequence, it stops applying writes to the visible screen and starts buffering them in memory. When it sees the end sequence, it applies the entire buffered batch in one atomic frame. The user sees no intermediate state.
The mechanism is called synchronized output in the canonical spec, written by Christian Parpart, the maintainer of Contour terminal. The gist is at [gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 — it's a short read and is the source the rest of the ecosystem cites.
A few details that matter:
- The number 2026 is arbitrary. It's a DEC private-mode parameter. The DEC private-mode parameter space uses integers; 2026 was free when the spec was assigned. The collision with the calendar year is coincidence.
- Terminals that don't support it ignore it cleanly. This is part of the ANSI standard — unknown private modes are no-ops. Your program won't break on older terminals; it just won't get the flicker reduction.
- There's an inactivity timeout. If a program writes the begin sequence and then crashes or hangs, the terminal automatically exits sync mode after a fixed timeout (typically 150-300ms depending on emulator) so the screen doesn't lock up. This is by design.
Why this became famous in 2026
CSI 2026 isn't new — Parpart's spec dates to 2020. What changed in 2026 is that AI coding CLIs needed it, and broke spectacularly without it.
The two Claude Code issues that made it visible:
anthropic/claude-code#37283 — filed against Claude Code's behavior inside tmux. The agent's reasoning output redrew status lines, progress indicators, and tool-call summaries frequently enough that the terminal couldn't keep up. Inside tmux specifically (because tmux multiplexes terminal output across its own rendering layer), the flicker was severe. The fix involved correctly emitting CSI 2026 sync sequences around the redraw regions. anthropic/claude-code#41965 — filed against Claude Code v2.1.89, which regressed and broke the sync sequences. Same flicker came back. The fix was re-fixing the regression.These two issues — the original flicker fix and the regression — are why CSI 2026 became part of the AI CLI conversation. They surfaced the spec to a wider audience and made "your terminal needs CSI 2026 support" a real installation criterion.
Beyond Claude Code, the ecosystem now standardizes on the sequence:
@earendil-works/pi-tui— the README explicitly cites CSI 2026 sync as the foundation of its atomic screen update model.Dicklesworthstone/frankentui— "minimal, high-performance terminal UI kernel with diff-based rendering, inline mode, and RAII terminal cleanup" — uses sync mode for its differential rendering pipeline.- WezTerm had a flicker issue tied to sync handling in February 2026 that the maintainers fixed.
- Modern Bubble Tea, Ratatui, Ink, notcurses all emit sync sequences when targeting compatible terminals.
Which terminals support it
As of May 2026, the terminals that support CSI 2026 in stable releases:
- iTerm2 (macOS) — full support
- WezTerm — full support, post-Feb 2026 fixes
- Alacritty — full support
- Kitty — full support
- Ghostty — full support (designed around it)
- Windows Terminal — full support in current builds
- Warp — full support (it's a hard requirement for Warp 2.0's agent surface)
- Contour — full support (Parpart's own terminal, where the spec originated)
- tmux — supports it in current versions. Older versions don't. Version mismatch between your tmux and your terminal is the most common silent failure source.
- GNU Screen — limited support depending on build.
- Basic xterm — no support, but ignores the sequence cleanly.
- VTE-based terminals (GNOME Terminal, older builds) — varies by version.
How to use it correctly
For most developers, the answer is "use a library." Bubble Tea, Ratatui, Ink, notcurses, pi-tui, and frankentui all handle sync mode for you when you enter their "frame" or "atomic update" or "redraw" API. Don't hand-roll if you don't have to.
If you're writing the sequences directly:
import sys
def begin_sync(): sys.stdout.write("\x1b?2026h") sys.stdout.flush()
def end_sync(): sys.stdout.write("\x1b[?2026l") sys.stdout.flush()
# Around any region that updates more than one cell begin_sync() draw_status_line() draw_progress_bar() draw_tool_call_summary() end_sync()
A few correctness notes:
- Pair every begin with an end. Forgetting the end sequence is the most common bug. The terminal's inactivity timeout will save you eventually, but the UX in those 150-300ms is bad.
- Don't nest. Most terminals don't track nested sync regions correctly. If you need composition, batch your updates at the outermost layer.
- Flush after each write. Buffered stdio can defer the begin sequence past the actual screen updates, defeating the purpose.
- Test inside tmux. tmux is where sync issues are most visible. If it works in tmux, it works.
Where this fails / what we don't know
- The 150-300ms timeout varies. Spec leaves it implementation-defined. We don't have a canonical table of per-terminal timeout values.
- No quantitative latency data. Sync mode reduces flicker; we don't have public measurements of how much it costs in render latency (probably none in modern terminals, but unverified).
- Older multiplexer behavior. The exact threshold at which a tmux/screen version is "too old" to support sync correctly isn't well-documented. The honest answer is "test it."
- Mobile terminals. SSH clients on iOS and Android (Termius, Blink Shell, etc.) have varying sync support that we have not audited.
What to read next
- [/topic/cli-everything-wave — the broader AI CLI trend that made CSI 2026 mainstream
- /topic/warp-2-agentic-terminal — Warp 2.0's agentic terminal, which depends on sync mode
- /topic/agentic-engineering — the workflow context for why TUIs matter again
- /for/claude-code — Claude Code-targeted rulesets
- /for/pi-coding-agent — pi-tui-based agent tools
Sources
- Christian Parpart, "Synchronized Output" canonical spec — gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036. The reference spec everyone in the ecosystem cites.
- earendil-works/pi-tui README — github.com/earendil-works/pi/blob/main/packages/tui/README.md. "CSI 2026 for atomic screen updates (no flicker)."
- Dicklesworthstone/frankentui — github.com/Dicklesworthstone/frankentui. High-performance terminal UI kernel with differential rendering.
- Anthropics/claude-code issue #37283 — github.com/anthropics/claude-code/issues/37283. tmux flicker original report.
- Anthropics/claude-code issue #41965 — github.com/anthropics/claude-code/issues/41965. v2.1.89 regression.
- WezTerm issue #7465, sync mode flicker — github.com/wezterm/wezterm/issues/7465. February 2026.
- Contour terminal — contour-terminal.org. Parpart's reference implementation.
Related GitHub projects
Frequently asked
- What is CSI 2026 synchronized output?
- CSI 2026 is a terminal control sequence — specifically the ANSI codes `CSI ? 2026 h` (begin sync) and `CSI ? 2026 l` (end sync) — that tells the terminal emulator to buffer screen updates and apply them atomically. It eliminates the flicker that happens when a TUI program redraws part of the screen and the terminal renders the intermediate state. Christian Parpart wrote the canonical spec gist. The number 2026 is a private-mode parameter assigned to this feature; it has nothing to do with the year.
- Why does my TUI flicker without CSI 2026?
- Without sync mode, every escape sequence the program writes is applied to the visible screen immediately. If your TUI clears a region and then redraws it 50ms later, the user sees the cleared region for those 50ms. With CSI 2026 sync, the terminal buffers all writes between the begin and end sequences and renders them as one atomic update. The flicker disappears.
- Which terminals support CSI 2026?
- Modern terminals that support it include iTerm2, WezTerm, Alacritty, Kitty, Ghostty, Windows Terminal, and Warp. Older terminals (basic xterm builds, some VTE-based terminals) don't, and gracefully ignore the sequence — your program won't break, just won't get the flicker reduction. tmux specifically had issues for years and now supports CSI 2026 in current versions, but version mismatches still cause real bugs (see the Claude Code issues).
- Why is this famous for Claude Code users?
- Two GitHub issues made CSI 2026 part of the Claude Code lore. Issue #37283 documented severe flicker when Claude Code ran inside tmux — the agent's status updates redrew the screen so often the terminal couldn't keep up. The fix involved correctly emitting CSI 2026 sync sequences. Then issue #41965 reported a regression in Claude Code v2.1.89 that broke the sync sequences again. The cycle of 'flicker fixed → flicker regression → flicker re-fixed' made CSI 2026 visible to non-terminal-nerds.
- How do I use CSI 2026 in my own TUI?
- Write the begin sequence (`\x1b[?2026h`), do all your screen updates, write the end sequence (`\x1b[?2026l`). Most TUI libraries (notcurses, Ratatui, Bubble Tea recent versions, Ink, the pi-tui kernel, frankentui) handle this for you when you tell them to enter an 'atomic update' mode. Hand-rolling it is fine for small programs; for anything complex, use a library.
- Is CSI 2026 related to the year 2026?
- No. It's a coincidence. The number 2026 was assigned to this feature as a private-mode parameter long before 2026 the year. The DEC private mode parameter space uses arbitrary integers; 2026 happened to be free when Parpart's spec was assigned.