BSU/ESU Protocol
The explicit frame synchronization protocol for modern terminal applications.Copy
╔═══════════════════════════════════════════════════════════════════════════════╗
║ BSU/ESU = BEGIN SYNCHRONIZED UPDATE / END SYNCHRONIZED UPDATE ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ BSU = "Hey terminal, I'm about to make multiple changes" ║
║ ESU = "Okay terminal, I'm done - you can render now" ║
║ ║
║ ┌─────────────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ BSU ─────────── All changes go here ─────────── ESU │ ║
║ │ │ │ │ ║
║ │ │ │ │ ║
║ │ Start Finish │ ║
║ │ buffering and render │ ║
║ │ │ ║
║ └─────────────────────────────────────────────────────────────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
The Escape Sequences
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ BSU/ESU BYTE SEQUENCES │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ BSU (Begin Synchronized Update) │
│ ═══════════════════════════════ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ESC [ ? 2 0 2 6 h │ │
│ │ ─── ─ ─ ─ ─ ─ ─ ─ │ │
│ │ 0x1B 5B 3F 32 30 32 36 68 │ │
│ │ │ │
│ │ In text: \x1b[?2026h │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ESU (End Synchronized Update) │
│ ═════════════════════════════ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ESC [ ? 2 0 2 6 l │ │
│ │ ─── ─ ─ ─ ─ ─ ─ ─ │ │
│ │ 0x1B 5B 3F 32 30 32 36 6C │ │
│ │ │ │
│ │ In text: \x1b[?2026l │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Note: 'h' = high = enable, 'l' = low = disable │
│ 2026 = private mode number for synchronized updates │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Why Mode 2026?
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ DECSET/DECRST MODE 2026 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Terminal escape sequences have "private modes" for features. │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Mode Meaning │ │
│ │ ──── ─────── │ │
│ │ ?1 Application cursor keys │ │
│ │ ?25 Cursor visibility │ │
│ │ ?1049 Alternate screen buffer │ │
│ │ ?2004 Bracketed paste mode │ │
│ │ ?2026 Synchronized output (BSU/ESU) ← THIS ONE │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ 2026 was chosen by terminal developers as a "private" mode number. │
│ It doesn't conflict with existing standards. │
│ │
│ First implemented in: Kitty terminal │
│ Now supported by: Alacritty, iTerm2, WezTerm, Monolex, and more │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
How MonoTerm Detects BSU/ESU
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ BSU/ESU DETECTION FLOW │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Incoming bytes │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Scan for pattern: 0x1B 5B 3F 32 30 32 36 [68|6C] │ │
│ │ ESC [ ? 2 0 2 6 [h |l ] │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ├───────────────────┬───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ BSU │ │ ESU │ │ Neither │ │
│ │ found │ │ found │ │ found │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Start │ │ Flush │ │ Process │ │
│ │ buffering │ │ buffer │ │ normally │ │
│ │ mode │ │ to screen │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ Note: Detection happens at BYTE level, before VTE parsing! │
│ This is for maximum reliability. │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
BSU/ESU vs Cursor Pattern
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ COMPARISON: BSU/ESU vs CURSOR HIDE/SHOW │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ BSU/ESU Cursor Pattern │
│ ═══════ ══════════════ │
│ │
│ Type Explicit protocol Implicit heuristic │
│ │
│ Meaning "I want sync" "I don't want cursor visible" │
│ │
│ Reliability 100% intentional 95% reliable │
│ │
│ Side effects None Cursor actually hidden │
│ │
│ Support Modern terminals All terminals │
│ │
│ Sequence ESC[?2026h/l ESC[?25l/h │
│ │
│ ═══════════════════════════════════════════════════════════════════════════ │
│ │
│ MonoTerm supports BOTH: │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Priority 1: BSU/ESU (if detected) │ │
│ │ Priority 2: Cursor pattern (if no BSU/ESU) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ This means: Works with old apps AND new apps! │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Frame Buffering During BSU
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ WHAT HAPPENS DURING BSU MODE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Time ─────────────────────────────────────────────────────────────────▶ │
│ │
│ │
│ Input: BSU ──── data1 ──── data2 ──── data3 ──── ESU │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ Buffer: [empty] → [data1] → [data1+data2] → [all data] → [empty] │
│ │ │
│ │ Flush! │
│ ▼ │
│ Screen: [old] [old] [old] [old] [ALL NEW DATA!] │
│ │
│ │
│ ════════════════════════════════════════════════════════════════════════════ │
│ │
│ Notice: │
│ • Screen doesn't change until ESU │
│ • All data appears at once │
│ • No intermediate states visible │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Timeout Protection
What if ESU never comes?Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ BSU TIMEOUT MECHANISM │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ PROBLEM: Program sends BSU, then crashes │
│ ───────────────────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ BSU ───── data ───── data ───── [crash!] ───── ESU never sent │ │
│ │ │ │ │
│ │ └── Buffer grows... screen frozen... waiting forever? │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ │
│ SOLUTION: 16ms Timeout │
│ ───────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ BSU ───── data ───── [16ms passes] ───── TIMEOUT! ───── Flush │ │
│ │ │ │ │ │
│ │ └── Start timer └── Timer fires, force flush buffer │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ 16ms = approximately 1 frame at 60 FPS │
│ If no ESU within 16ms, assume something went wrong and render anyway. │
│ │
│ │
│ WHY 16MS? │
│ ───────── │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ 60 FPS = 16.67ms per frame │ │
│ │ │ │
│ │ If a well-behaved app is drawing frames at 60 FPS, │ │
│ │ it WILL send ESU within 16ms. │ │
│ │ │ │
│ │ If no ESU in 16ms, something is wrong. │ │
│ │ Better to show partial content than freeze forever. │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Nested BSU/ESU
Can BSU appear inside another BSU?Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ NESTED BSU/ESU HANDLING │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ SCENARIO: Library A uses BSU, calls library B which also uses BSU │
│ ────────────────────────────────────────────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ BSU (A) ── BSU (B) ── data ── ESU (B) ── more data ── ESU (A) │ │
│ │ │ │ │ │ │ │
│ │ └─ outer └─ inner └─ inner closes └─ outer closes │
│ │ │ │ │
│ │ Only render when outermost closes ─┘ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ │
│ HOW MONOLEX HANDLES NESTING: │
│ ──────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Monolex automatically tracks nested BSU/ESU pairs. │ │
│ │ │ │
│ │ • Inner ESU does NOT trigger rendering │ │
│ │ • Only the OUTERMOST ESU flushes the frame │ │
│ │ • This happens transparently - you don't need to manage it │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ Result: Proper handling of nested synchronization │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Which Apps Use BSU/ESU?
Terminals Supporting BSU/ESU
- Kitty (original implementer)
- Alacritty
- iTerm2
- WezTerm
- Contour
- Monolex
Apps Sending BSU/ESU
- Neovim (when TERM supports it)
- Helix editor
- tmux (passthrough mode)
- rich (Python library)
- textual (Python TUI framework)
Summary
Copy
╔═══════════════════════════════════════════════════════════════════════════════╗
║ BSU/ESU SUMMARY ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ WHAT: Explicit frame synchronization protocol ║
║ ║
║ HOW: ESC[?2026h (begin) ... content ... ESC[?2026l (end) ║
║ ║
║ WHY: 100% reliable frame boundaries (unlike cursor heuristics) ║
║ ║
║ SAFETY: 16ms timeout prevents infinite buffering ║
║ ║
║ NESTING: Automatic handling of nested BSU/ESU pairs ║
║ ║
║ ════════════════════════════════════════════════════════════════════════ ║
║ ║
║ MonoTerm combines BSU/ESU + Cursor pattern for maximum compatibility: ║
║ ║
║ ┌───────────────────────────────────────────────────────────────────┐ ║
║ │ Modern apps (neovim, etc.) → BSU/ESU │ ║
║ │ Classic apps (npm, yarn) → Cursor pattern │ ║
║ │ Very old apps → Implicit timeout │ ║
║ │ │ ║
║ │ ALL get smooth, atomic rendering! │ ║
║ └───────────────────────────────────────────────────────────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
Automatic compatibility. You don’t need to configure anything. Monolex automatically detects whether apps use BSU/ESU or cursor patterns and handles both seamlessly.