Skip to main content

BSU/ESU Protocol

The explicit frame synchronization protocol for modern terminal applications.
╔═══════════════════════════════════════════════════════════════════════════════╗
║  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

┌─────────────────────────────────────────────────────────────────────────────────┐
│  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?

┌─────────────────────────────────────────────────────────────────────────────────┐
│  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

┌─────────────────────────────────────────────────────────────────────────────────┐
│  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

┌─────────────────────────────────────────────────────────────────────────────────┐
│  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

┌─────────────────────────────────────────────────────────────────────────────────┐
│  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?
┌─────────────────────────────────────────────────────────────────────────────────┐
│  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?
┌─────────────────────────────────────────────────────────────────────────────────┐
│  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

╔═══════════════════════════════════════════════════════════════════════════════╗
║  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.

Next Steps