Escape Codes and the Search for Standards
ANSI escape codes are how terminal emulators and the programs running inside them exchange information that doesn't fit into normal text. They handle everything from cursor movement and text color to mouse reporting, clipboard access, and bracketed paste.
These codes have a reputation for being unreliable and hard to debug. Part of the reason is that escape codes are invisible — when they fail, you see nothing, or worse, you see stray text like ^[[D when you press the left arrow key. The other reason is that they aren't fully standardized.
What an Escape Code Is
Escape codes begin with the escape character, written variously as ESC, \x1b, \E, \033, or ^[. There are two categories:
- Input codes — sent by the terminal emulator for keypresses and mouse events that don't map to Unicode. The left arrow key is
ESC[D; Ctrl+left arrow might beESC[1;5D; mouse clicks can be something likeESC[M :3. - Output codes — printed by programs to color text, move the cursor, clear the screen, enable mouse reporting, set the window title, or copy text to the system clipboard (a capability known as OSC 52).
ECMA-48: The Baseline Standard
The foundational standard for escape codes is ECMA-48, first published in 1976. It does two things:
- Defines general formats for escape sequences — CSI codes (
ESC[plus content) and OSC codes (ESC]plus content). - Defines specific codes, such as "cursor left" (
ESC[D) andSELECT GRAPHIC RENDITIONfor setting text attributes like color (ESC[31mfor red).
The formats are extensible, leaving room for other parties to define new codes. Many codes in common use today, such as those for mouse input, are not defined in ECMA-48.
xterm: The De Facto Reference
Beyond ECMA-48, many widely used escape codes come from xterm and are documented in XTerm Control Sequences. This document covers mouse reporting, bracketed paste, OSC 52 for clipboard access, and more. It is not a formal standard, but xterm's influence has made it an important reference that other terminal emulators largely follow.
terminfo: Solving the Compatibility Problem
In the 1980s, terminal emulators varied enormously in which escape codes they supported. The terminfo database was created to manage this variance. Its standard is X/Open Curses, which defines the database format and a C library interface ("curses") for accessing it.
The database contains the escape codes for every terminal type the system knows. On most modern systems, terminfo is managed by ncurses. A program can query the database based on the TERM environment variable to find the correct codes for the current terminal emulator.
Two Approaches: terminfo vs. Hardcoded Common Codes
Terminal applications generally take one of two approaches to escape codes:
- Use the terminfo database to generate the correct codes based on
TERM— for example, fish does this. - Hardcode a "single common set" of escape codes believed to work across enough terminal emulators.
Several well-known projects have moved toward approach #2, including kakoune, python-prompt-toolkit, linenoise, libvaxis, and chalk. One fish maintainer has written an extended argument against terminfo, acknowledging that the terminfo authors did important work that "no longer is" relevant.
The Case for terminfo
Despite the trend away from terminfo, it still has value in 2025:
- The
TERMvariable is a convention that lets users control program behavior, as withTERM=dumb. There is no standard replacing it. - Terminal variation still exists: graphical terminals, the Linux framebuffer console, serial console sessions, and Emacs shell mode all behave differently.
- There is currently no agreed-upon definition of the "single common set." Some programs employ codes that aren't widely supported.
The User Agent Analogy
Using TERM to select escape codes resembles how web servers used browser user agents to serve different content. Terminals have responded similarly to browsers: iTerm2 identifies itself as xterm-256color, just as Safari's user agent claims to be Mozilla-compatible.
On the web, the industry moved away from user agent detection toward standardization — serving the same HTML/CSS to every browser. Whether an equivalent shift happens for the terminal is unclear. The terminal ecosystem is more fragmented than the web's, and less well funded.
Additional Documents and Standards
Several other documents touch on escape codes without being formal standards:
- The Linux console_codes man page, documenting codes supported by the Linux console.
- The VT100 user guide chapter on escape and control sequences.
- The kitty keyboard protocol, plus Kitty's graphics protocol and its use of OSC 8 for hyperlinks.
- A community adoption report for OSC 8.
- A summary of ANSI standards maintained in the tmux source code.
- The iTerm2 feature-reporting specification, which proposes a mechanism for terminals to advertise supported features.
- Sixel graphics for variable-precision imaging in the terminal.
The terminal is sometimes dismissed as outdated, but incremental standards work could change that. The web went through a similarly chaotic period before HTML and CSS conventions became reliable enough for cross-browser development. ECMA-48 has been around for almost five decades, and the landscape is still fragmented. Whether that changes depends on whether the community can coordinate more than it has so far.



