Skip to content

Terminal Standards ​

50 years of terminal protocols β€” from teletypes to GPU-rendered emoji

There is no single terminal standard β€” what exists is layers. Some are formal standards (ECMA-48, Unicode), others are hardware reference manuals (VT100–VT510), implementation documents (xterm ctlseqs), or protocol proposals (Kitty extensions). All shaped how terminals work, with different levels of authority. See the glossary for acronyms.

The Layers of Terminal Standards ​

There is no single authoritative standard for modern terminals. What exists is a stack of layers, each building on the one before it, with increasing levels of vendor-specificity and decreasing levels of formal standardization.

At the base is ECMA-48 (1976) β€” the grammar. It defines how escape sequences are structured: CSI, OSC, DCS, and the parameter syntax that every terminal speaks. Above that sits DEC's VT series (1978–1993) β€” the implementations that made the grammar real. The VT100 became so dominant that "ANSI terminal" effectively means "VT100-compatible." Then comes xterm (1996-present) β€” Thomas Dickey's three-decade project that extended the VT model with truecolor, mouse tracking, and clipboard access. Finally, modern protocols like the Kitty keyboard protocol and inline graphics (Kitty, Sixel) push terminals beyond what the original standards ever imagined.

The messy truth: most of what developers call "ANSI escape codes" aren't ANSI at all. ANSI withdrew their terminal standard (X3.64) in 1994. What we actually use is a patchwork of ECMA-48 grammar, DEC private extensions, xterm innovations, and modern protocol proposals β€” held together by decades of copy-the-leader compatibility.

Example Sequences by Standard ​

StandardExample SequenceEffect
ECMA-48ESC[1mBoldESC[0mBold β€” SGR text styling
VT100ESC[5;10HCursor to row 5, col 10
VT220ESC[2PDelete 2 characters at cursor
XtermESC[38;2;255;0;0mRedESC[0mRed β€” truecolor
KittyESC[>1uUnambiguous keyboard mode
OSCESC]8;;url\x07LinkESC]8;;\x07Hyperlinks

Standards ​

ECMA-48 (1976) β€” The Grammar That Started Everything ​

In the early 1970s, European computer manufacturers needed a common language for terminal control β€” each vendor had proprietary sequences, and interoperability was impossible. ECMA's Technical Committee 1, working in parallel with ANSI's X3L2 committee, produced what became the universal grammar. First published by ECMA International in 1976 (5th edition 1991), ECMA-48 defines the CSI (Control Sequence Introducer) grammar that every escape sequence uses. The ESC [ prefix, the parameter syntax, the SGR (Select Graphic Rendition) codes for text styling β€” all of it flows from this one document. It also defines cursor movement (CUP, CUU, CUD), erase operations (EL, ED), and scroll control.

Here's the irony: developers universally call these "ANSI escape codes," but the ANSI standard (X3.64) that referenced this work was withdrawn in 1994. The surviving standard is ECMA-48, maintained by ECMA International. ISO/IEC 6429 is the ISO equivalent. None of them have been updated since 1991 β€” the standard is frozen, while terminals continue extending the parameter space with vendor innovations.

At a glance

Introduced:

  • The ESC [ (CSI) grammar β€” the universal escape sequence prefix
  • SGR codes for text styling (bold, underline, color)
  • Cursor movement primitives (CUP, CUU, CUD, CUF, CUB)
  • Erase operations (EL, ED) and scroll control

Still matters:

  • Every terminal escape sequence uses ECMA-48's CSI parameter syntax
  • SGR codes are the universal way to style terminal text
  • The ? private-mode prefix that DEC exploited is defined here

"ANSI escape codes" aren't ANSI

ANSI published the X3.64 terminal standard in 1979, then withdrew it in 1994 in favor of the international ECMA-48 / ISO 6429. The name "ANSI escape codes" persists from 1979 β€” referring to a standard that no longer exists. What we actually use is ECMA-48 grammar with decades of vendor extensions.

VT100 (1978) β€” The Terminal That Won ​

Some vendors argued the new ANSI standard was "beyond the state of the art" and couldn't be implemented affordably β€” the VT100 proved them wrong at $1,800. The DEC VT100 ran on an Intel 8080 CPU with limited RAM, yet it defined terminal computing for the next five decades. It implemented the ECMA-48 escape grammar, adding scroll regions (DECSTBM), character sets, and the private mode namespace (CSI ?) that terminals still use today. When software says it's "VT100-compatible," it's promising support for a specific set of behaviors that this $1,800 box established in 1978.

The VT100's dominance wasn't accidental β€” DEC shipped it with the rising tide of Unix, VAX/VMS, and networking. Every competitor had to emulate it. That gravity persists: every terminal emulator today is, at its core, a VT100 emulator with extensions.

At a glance

Introduced:

  • Scroll regions (DECSTBM) β€” status bars, split panes
  • The CSI ? private mode namespace for vendor extensions
  • Character set switching (G0/G1, line-drawing characters)
  • 80/132 column mode switching

Still matters:

  • "VT100-compatible" is still the baseline every terminal must meet
  • Scroll regions power every full-screen TUI (vim, tmux, htop)
  • Line-drawing characters render box UIs in every terminal

Why is your terminal 80 columns wide?

IBM's 80-column punch card format (1928) set the width for the IBM 3270 terminal (1971), which the DEC VT100 adopted in 1978. The 24-row default comes from fitting 1,920 characters (80 x 24) into early memory architectures. Nearly 50 years later, 80x24 remains the default terminal size.

VT100 in action
bash
# Scroll region: lines 2-23 scroll, line 1 stays (status bar)
printf '\e[2;23r'
# Cursor to row 5, column 10
printf '\e[5;10H'
# Save cursor position
printf '\e7'
# Restore cursor position
printf '\e8'

VT220 (1983) β€” Editing Operations Arrive ​

The VT220's keyboard layout (LK201) popularized the inverted-T arrow cluster and navigation key arrangement that later became standard on PC keyboards β€” the layout that dominates to this day. The VT220 added the insert/delete operations (ICH, DCH, IL, DL) that make full-screen terminal applications practical. Without VT220 editing sequences, programs like vim and tmux would have to redraw the entire screen for every character insertion. The VT220 also introduced 8-bit control codes, user-defined keys, and national replacement character sets.

These editing sequences are so fundamental that it's hard to imagine terminals without them β€” but they weren't in the VT100. The jump from VT100 to VT220 was the jump from a display terminal to an interactive editing terminal.

At a glance

Introduced:

  • Insert/delete character (ICH, DCH) and line (IL, DL) operations
  • 8-bit control codes and national replacement character sets
  • The LK201 keyboard layout (inverted-T arrows, navigation cluster)

Still matters:

  • Every full-screen editor (vim, nano, emacs) depends on ICH/DCH/IL/DL
  • tmux and screen use editing sequences for efficient pane updates
  • The keyboard layout from the LK201 is still the PC standard
VT220 editing
bash
# Insert 3 blank characters at cursor
printf '\e[3@'
# Delete 2 characters at cursor
printf '\e[2P'
# Insert a blank line
printf '\e[L'

Sixel (1983, Revived) β€” Inline Graphics ​

Sixel originated not as a terminal feature but as a printer protocol β€” DEC designed it for the LA50 dot-matrix printer in 1983. When DEC built the VT240 graphics terminal that same year, they repurposed the printer protocol for screen display. The name comes from encoding 6 vertical pixels per character. The format encodes raster images as printable ASCII characters, where each character represents a 1x6 pixel column, and DEC included Sixel support in the VT240 and VT340 terminals for displaying charts and diagrams.

Sixel was largely dormant for decades until modern terminals (xterm, foot, WezTerm, mlterm, contour) revived it as a way to display inline images using only standard escape sequences β€” no terminal-specific protocol required. The Sixel vs. Kitty graphics debate is one of the liveliest in the terminal ecosystem: Sixel is older and more widely supported; Kitty graphics is more capable and purpose-built.

At a glance

Introduced:

  • Inline raster graphics encoded as printable ASCII characters
  • 6-vertical-pixel columns (the "six" in Sixel) for compact encoding
  • A terminal graphics protocol that predates all modern alternatives

Still matters:

  • Widest inline image support among modern terminals (xterm, foot, WezTerm, mlterm)
  • Only graphics protocol that works over plain SSH without special setup
  • Active competitor to Kitty graphics in the terminal image display debate

VT510 (1993) β€” DEC's Late VT Reference ​

By 1993, hardware terminals were already losing to PCs running terminal emulator software. The VT510 was among the last dedicated terminals anyone would build β€” but its reference manual outlived the hardware. The VT520 and VT525 followed before DEC was acquired by Compaq in 1998. No modern terminal implements the full VT510 spec, but specific features like DECTCEM (cursor visibility) and DECSCNM (reverse video) became universal. The VT510 Reference Manual remains the most cited document for terminal implementors β€” it's the closest thing to a comprehensive reference for DEC escape sequences.

At a glance

Introduced:

  • The most comprehensive DEC escape sequence reference manual
  • Consolidated documentation of all prior VT-series features
  • Multiple pages and session management

Still matters:

  • The VT510 Reference Manual is the go-to document for terminal implementors
  • DECTCEM (cursor show/hide) is used by virtually every TUI application
  • DECSCNM (reverse video) remains a supported mode in modern terminals

DEC Private Modes (1978+) β€” The Negotiation Protocol ​

The ? prefix was DEC's escape hatch β€” ECMA-48 reserved it for vendor-specific extensions, and DEC used it so aggressively that their "private" modes became the most important public feature of terminal control. DEC private modes use the ? prefix in CSI sequences to toggle terminal behaviors: CSI ? Pm h (DECSET) to enable, CSI ? Pm l (DECRST) to disable. This namespace is the primary mechanism for feature negotiation between applications and terminals. Cursor visibility (?25), auto-wrap (?7), alternate screen (?1049), mouse tracking (?1000–1006), bracketed paste (?2004), focus events (?1004) β€” all controlled via DEC private modes.

The "private" designation means vendor-defined: any terminal can allocate new mode numbers without conflicting with ECMA-48's standard modes. This extensibility is why DEC private modes remain the backbone of terminal feature control.

At a glance

Introduced:

  • DECSET/DECRST (CSI ? h / CSI ? l) β€” the toggle mechanism for terminal features
  • Alternate screen buffer (?1049) β€” lets apps draw without destroying scrollback
  • Bracketed paste (?2004) β€” safe paste handling that prevents code injection
  • Mouse tracking modes (?1000-1006) β€” click and drag reporting to applications

Still matters:

  • Every TUI app uses alternate screen, cursor visibility, and auto-wrap modes
  • Bracketed paste is a security-critical feature enabled by default in most shells
  • Mouse tracking powers interactive terminal UIs (lazygit, btop, TUI file managers)
DEC modes in action
bash
# Enable bracketed paste (your terminal wraps pasted text in markers)
printf '\e[?2004h'
# Enable mouse tracking (clicks reported to your app)
printf '\e[?1000h'
# Switch to alternate screen (vim, htop, less do this)
printf '\e[?1049h'
# Switch back
printf '\e[?1049l'

Unicode (1991+) β€” The Width Problem ​

Before Unicode: The Character Set Wars ​

Before Unicode, every language needed its own character encoding β€” and they were mutually incompatible:

EncodingRegionCharactersBytes
ASCIIUS/UK128 characters (A-Z, 0-9, symbols)7-bit
ISO 8859-1 (Latin-1)Western Europe256 characters (adds àéñü etc.)8-bit
Shift-JISJapan~7,000 kanji + kana1-2 bytes
GB2312China~6,700 simplified Chinese characters2 bytes
EUC-KRKorea~2,350 hangul syllables + hanja1-2 bytes
KOI8-RRussiaCyrillic alphabet8-bit

A Japanese terminal couldn't display Chinese text. A German terminal couldn't display Russian. Emails between countries garbled characters. The web was a mess of Content-Type: text/html; charset=iso-8859-1 headers that were wrong half the time.

Unicode solved this by assigning a unique number (code point) to every character in every writing system β€” currently over 149,000 characters across 161 scripts. UTF-8 encodes these code points in 1–4 bytes, is backward-compatible with ASCII, and is now the dominant encoding on the web and in terminals.

The Unix connection

Unicode emerged from the same world as Unix terminals. Joe Becker (Xerox), Lee Collins (Apple), and Mark Davis (Apple) drafted the initial proposal in 1987. UTF-8 β€” the encoding that made Unicode practical β€” was designed by Rob Pike and Ken Thompson (creators of Unix and Plan 9) on a placemat in a New Jersey diner in 1992. It was adopted by Plan 9, then Linux, then the web. The people who built Unix also built the encoding that terminals use today.

The Width Problem ​

Unicode's challenge for terminals isn't character encoding β€” UTF-8 is universal. The challenge is width calculation. East Asian characters (CJK ideographs) and many emoji occupy two terminal columns ("wide" or "fullwidth"), while most Latin/Cyrillic/Arabic characters occupy one. UAX #11 defines width classes, but terminals must also handle combining characters, variation selectors, zero-width joiners, and emoji sequences.

Incorrect width calculation causes cursor positioning errors, text misalignment, and broken TUI layouts. It's one of the hardest problems in terminal emulation because the Unicode Standard keeps adding new characters, and terminals, libraries, and the C wcwidth() function all update at different rates.

At a glance

Introduced:

  • A single encoding (UTF-8) replacing dozens of incompatible regional character sets
  • East Asian width classes β€” characters that occupy 1 or 2 terminal columns
  • Combining characters, variation selectors, and zero-width joiners
  • Emoji sequences (skin tones, ZWJ families, flags)

Still matters:

  • Width calculation disagreements between app and terminal break TUI layouts
  • wcwidth() implementations lag behind new Unicode versions by years
  • Emoji rendering is the most common source of terminal alignment bugs today
  • Nerd Fonts and Powerline glyphs are the backbone of modern shell prompts
The width problem in practice

This table is supposed to be aligned β€” but depending on your terminal and font, the columns may be off:

Name        β”‚ Status β”‚ Score
────────────┼────────┼──────
Alice       β”‚ βœ“ done β”‚ 98%
Bob         β”‚ βœ— fail β”‚ 42%
η”°δΈ­ε€ͺιƒŽ    β”‚ βœ“ done β”‚ 95%     ← CJK: each char = 2 columns
JosΓ© GarcΓ­a β”‚ βœ“ done β”‚ 88%     ← combining accent (Γ©) = 1 column? 2?
πŸ‘¨β€πŸ’» DevBot   β”‚ ~ wait β”‚ 77%     ← emoji: 2 columns? more?

If your terminal calculates any character's width differently from the application, the β”‚ separators won't line up. This is the core problem: every terminal, every font, and every TUI library must agree on every character's width β€” and they don't.

Powerline and Prompt Art ​

Unicode didn't just solve the character encoding problem β€” it enabled a new artform: terminal prompt customization.

The Powerline project (2012) pioneered the use of custom Unicode glyphs to create visually striking shell prompts with angled separators, branch indicators, and status icons. These characters live in Unicode's Private Use Area (PUA, U+E000–U+F8FF) and require patched fonts to display.

Nerd Fonts took this further by patching popular programming fonts (Fira Code, JetBrains Mono, Hack, Iosevka) with thousands of additional glyphs: file type icons, git symbols, weather icons, and more. A modern shell prompt might use:

GlyphUnicodeUse
(U+E0B0)U+E0B0Powerline right arrow separator
(U+E0B2)U+E0B2Powerline left arrow separator
(U+E0A0)U+E0A0Git branch symbol
(U+F115)U+F115Folder icon (Nerd Font)
(U+F0E7)U+F0E7Lightning bolt (command duration)

Tools like Starship, Powerlevel10k (Zsh), Oh My Posh, and Tide (Fish) build elaborate prompts that show git status, language versions, cloud context, and execution time β€” all using these custom glyphs. The result is that terminal prompts have become a form of personal expression, with developers sharing screenshots of their setups and customizing every detail.

Nerd Fonts and terminal compatibility

Powerline and Nerd Font glyphs are Private Use Area characters β€” they're not part of the Unicode standard and won't render without the right font. If you see boxes or question marks instead of arrows and icons, you need to install a Nerd Font and configure your terminal to use it.

Xterm Extensions (1984/1996+) β€” Thomas Dickey's 30-Year Legacy ​

xterm began as a summer project in 1984 β€” Mark Vandevoorde, a student of Jim Gettys, wrote it as a terminal emulator for the VAXStation 100. As Gettys later noted, "part of why xterm's internals are so horrifying is that it was originally intended that a single process be able to drive multiple displays." One person β€” Thomas Dickey β€” maintains xterm, ncurses, AND the terminfo database. He's been doing it since 1996. The xterm control sequences document (ctlseqs) is the single most important reference for terminal developers, documenting not just xterm's behavior but the de facto standards the rest of the ecosystem follows.

Xterm became the reference for many widely deployed extensions, including 256-color support, the alternate screen buffer with cursor save, four mouse tracking modes, focus reporting, bracketed paste, OSC 8 hyperlinks, and OSC 52 clipboard access. Most features that developers think of as "standard" were actually xterm innovations that other terminals copied.

At a glance

Introduced:

  • 256-color and truecolor (24-bit RGB) SGR extensions
  • Focus reporting (?1004) β€” apps know when the terminal gains/loses focus
  • OSC 52 clipboard access β€” programmatic read/write of the system clipboard
  • OSC 8 hyperlinks β€” clickable URLs in terminal output

Still matters:

  • Truecolor is now expected by every modern TUI (delta, bat, lazygit)
  • The xterm ctlseqs document is the de facto spec every terminal implementor references
  • Most "standard" terminal features were xterm innovations first
One person maintains the terminal stack

Thomas Dickey has single-handedly maintained xterm, ncurses, and the terminfo database since 1996 β€” nearly 30 years. His xterm control sequences document (ctlseqs) is the de facto specification that every terminal implementor references. Most of what developers call "standard" terminal behavior was defined by one maintainer in one text file.

OSC β€” Operating System Commands (1976+) ​

The distinction is architectural: CSI sequences control what the terminal displays (cursor, colors, modes). OSC sequences communicate with the terminal as a program β€” setting its window title, accessing its clipboard, reporting its current directory. It's the terminal talking to itself. OSC (Operating System Command) sequences use ESC ] for this communication between applications and the terminal as an application. They talk to the host: window title (OSC 0/2), clipboard access (OSC 52), hyperlinks (OSC 8), color palette queries (OSC 4/10/11), semantic prompt markers (OSC 133), and notification (OSC 9/777).

The OSC namespace is open-ended β€” any terminal can define new number codes without conflicting with CSI-based controls. This makes it the preferred extension point for modern terminal features that don't fit the CSI model.

At a glance

Introduced:

  • Window title setting (OSC 0/2) β€” the tab label in every terminal
  • Semantic prompt markers (OSC 133) β€” shells tell the terminal where prompts are
  • Color palette queries (OSC 4/10/11) β€” apps can detect and adapt to the theme
  • An open-ended namespace for out-of-band terminal communication

Still matters:

Kitty Extensions (2017) β€” The Modern Revolution ​

Kovid Goyal, already known as the creator of Calibre (the e-book manager), built Kitty out of frustration with existing terminal limitations. The keyboard protocol was born from a specific pain: writing a Vim-like editor where Ctrl+I and Tab needed to be different keys. Kitty introduced protocols that solve fundamental limitations of the 1978-era terminal model. The Kitty keyboard protocol provides unambiguous, modifier-aware key reporting β€” solving exactly that problem: Ctrl+I and Tab are the same byte (0x09) in traditional terminals. With the Kitty protocol, they're distinct events, and key-up events are reportable for the first time.

The keyboard protocol has seen broad adoption β€” Ghostty, WezTerm, foot, and others now implement it, making it the closest thing to an emerging standard for terminal input. The Kitty graphics protocol enables inline image display via chunked base64 transfer, though its adoption is narrower: WezTerm and Kitty itself support it, but Ghostty does not. Kitty also defined extended underline styles (curly, dotted, dashed) with independent underline colors, which have seen wide adoption across modern terminals.

At a glance

Introduced:

  • Unambiguous keyboard protocol β€” Ctrl+I and Tab are finally distinct events
  • Key-release reporting β€” apps can detect when a key is released, not just pressed
  • Kitty graphics protocol β€” chunked base64 inline image display
  • Extended underline styles (curly, dotted, dashed) with independent colors

Still matters:

  • The keyboard protocol is adopted by Ghostty, WezTerm, foot, and others
  • Extended underlines power squiggly-line error indicators in terminal editors
  • Kitty graphics is the highest-fidelity inline image protocol available

Why Kitty matters

Kitty significantly advanced terminal input by documenting key-release reporting and a comprehensive keyboard protocol. Earlier efforts like xterm's modifyOtherKeys and Leonerd's CSI u/fixterms addressed parts of this problem. The keyboard protocol has been widely adopted (Ghostty, WezTerm, foot, and others), making it the closest thing to an emerging standard for terminal input. The graphics protocol has narrower adoption β€” supported by Kitty and WezTerm, but not by Ghostty, which chose not to implement it.