Primary Sources
Where terminal behavior is actually specified — and, more usefully, which documents to read and which to ignore.
The central fact: there is no single authoritative specification for a modern terminal. There is a formal standard nobody implements exactly (ECMA-48), a de-facto standard that documents reality (xterm's
ctlseqs), a capability database that papers over the differences (terminfo), and a set of recent proposals that are becoming standard by adoption. Knowing which to trust for which question is a real skill.
The Tier List
| Tier | Document | Verdict |
|---|---|---|
| Read it | XTerm Control Sequences (ctlseqs) | The operative specification. Everything claims xterm compatibility. |
| Read it | Paul Williams' VT500 parser state diagram (vt100.net) | The state machine you will implement, drawn |
| Read it | man 3 termios, man 4 tty, man 7 pty, man 2 ioctl_tty | Short, authoritative, on your machine |
| Read it | kitty's protocol extension docs | Everything post-2015 |
| Skim | ECMA-48 | Formally correct; describes a world nobody implements |
| Skim | POSIX "General Terminal Interface" | The termios semantics, formally |
| Reference | man 5 terminfo, man 5 term | Capability names, when you need one |
| Reference | DEC VT100/VT220/VT510 manuals | When you need to know what DEC meant |
| Reference | Unicode UAX #11 (East Asian Width), UAX #29 (grapheme clusters) | Width and clustering, authoritatively |
1. XTerm Control Sequences — the reference
Find it: shipped with xterm as ctlseqs.txt; also at invisible-island.net/xterm/ctlseqs/ctlseqs.html.
# It is probably already on your machine:
locate ctlseqs 2>/dev/null
ls /usr/share/doc/xterm/ctlseqs.txt* 2>/dev/null
man 7 xterm 2>/dev/null
Why it is the real spec: essentially every terminal claims TERM=xterm-256color, and programs
therefore emit what xterm's terminfo entry advertises. What xterm does is the compatibility target,
whatever ECMA-48 says.
How to read it: not front to back. Use it as a lookup — search for the final byte (J, m, h)
or the mode number. Its structure is: C1 controls → VT100 sequences → CSI → DEC private modes → OSC →
DCS. It is exhaustive, pedantic, and honest about which sequences are xterm inventions.
Note: Thomas Dickey has maintained xterm and this document since 1996. Where it says "this is a DEC feature" or "this is an xterm extension," believe it — the provenance annotations are more reliable than any secondary source.
2. vt100.net — the parser and the DEC manuals
vt100.net/emu/dec_ansi_parser — Paul Williams' state diagram for the VT500 parser.
This is the document for Section 2. It
gives every state, every transition, and every action as a table you can transcribe directly into
code. vte, termwiz, foot, kitty, and Ghostty all implement variants of it.
Read: the diagram, the state descriptions, and the notes on why ESC aborts unconditionally.
vt100.net/docs/ — scanned DEC manuals (VT100, VT220, VT320, VT510).
Use these when you need to know what DEC intended, especially for the private modes. The VT510 Programmer Information is the most complete. They are also the only place some behaviors are written down at all — DECAWM's deferred wrap, for instance.
3. The Manual Pages — already on your machine
The most under-read authoritative sources in the whole list.
| Page | Covers | Read when |
|---|---|---|
man 3 termios | Every flag, every control character, tcgetattr/tcsetattr/cfmakeraw | Section 1 — read it fully, it is short |
man 4 tty / man 4 tty_ioctl | The tty device and its ioctls (Linux) | Looking up TIOCSCTTY, TIOCGWINSZ |
man 2 ioctl_tty | The same, better organized (Linux) | The definitive ioctl list |
man 7 pty | The PTY model, /dev/ptmx, devpts | Before Lab 2 |
man 3 posix_openpt / grantpt / unlockpt / ptsname | The allocation sequence | Lab 2 |
man 3 openpty / forkpty | The BSD convenience wrappers | After Lab 2, for the diff |
man 2 setsid / setpgid / tcsetpgrp | Sessions and process groups | The job-control chapter |
man 7 signal | Signal semantics, async-signal-safety, the safe-function list | Lab 3 |
man 2 poll / epoll / kqueue | Multiplexing | Lab 3 |
man 5 terminfo | Capability names and the database format | Milestone 14 |
man 3 tput / man 1 infocmp | Querying capabilities from the shell | Any time |
man 3 termios | wc -l # ~600 lines. Read it. Once. Properly.
infocmp # your terminal's full capability list
infocmp -1 xterm-256color | head -40
tput clear | xxd # what "clear" actually is on your terminal
Tip: Linux and macOS man pages differ meaningfully here — macOS's are BSD-derived and shorter. If you are on macOS, read the Linux
man 2 ioctl_ttyonline as well; it is more complete, and the ioctls are largely the same.
4. ECMA-48 — read it, but do not implement it
ecma-international.org → "Control Functions for Coded Character Sets," 5th edition (1991).
The formal standard behind ANSI X3.64. It defines the grammar (CSI, parameters, intermediates, final bytes) rigorously, and that grammar is genuinely worth reading once — it is the thing your parser implements.
What it gets you: the structure of escape sequences; the C0 and C1 control definitions; the canonical names (CUU, CUD, ED, EL, SGR) that this book uses.
Why you must not implement it faithfully:
| ECMA-48 says | Reality |
|---|---|
8-bit C1 controls (0x9B = CSI) are valid | In UTF-8 they are continuation bytes. Honoring them corrupts text. |
| Dozens of sequences (SPA, EPA, DAQ, PLD, PLU, …) | Nothing emits them |
| No mouse reporting, no OSC 8, no bracketed paste, no 256 colors | All of which are mandatory in practice |
SGR 21 is double underline | Several terminals used it for bold-off |
Precise IRM/SIMD interactions | Widely ignored |
The rule: use ECMA-48 for the grammar and the names. Use ctlseqs for the behavior.
5. POSIX — the termios semantics
IEEE Std 1003.1, "General Terminal Interface" (pubs.opengroup.org/onlinepubs/9699919799/).
The authoritative definition of canonical vs. non-canonical mode, VMIN/VTIME, the special
characters, and — importantly — sessions, process groups, and controlling terminals. When a job
control question is genuinely disputed, this is the answer.
Sections worth bookmarking:
- General Terminal Interface —
termiosin full - Process Groups, Controlling Terminal, Terminal Access Control — the job-control rules, including the orphaned-process-group semantics that nothing else states clearly
- The
tcsetattr,tcsetpgrp,setsidpages
6. The Modern Proposals
Post-2015 protocol work, mostly driven by kitty, Ghostty, contour, foot, and WezTerm. These are becoming standard by adoption, which is how everything in this domain has always worked.
| Proposal | Where | Solves |
|---|---|---|
| Kitty keyboard protocol | sw.kovidgoyal.net/kitty/keyboard-protocol/ | Key release; the Escape ambiguity; unrepresentable combinations |
| Kitty graphics protocol | sw.kovidgoyal.net/kitty/graphics-protocol/ | Images, properly |
Synchronized output (?2026) | contour's SynchronizedOutput doc | Tearing during full-screen redraws |
Grapheme clustering (?2027) | contour / Ghostty docs | Terminal and program disagreeing about width |
| OSC 8 hyperlinks | gist.github.com/egmontkob — the de-facto spec | Clickable links without regex guessing |
| OSC 133 semantic prompts | FinalTerm's original spec; iTerm2 and kitty docs | The terminal knowing where output begins |
XTGETTCAP (DCS + q) | xterm ctlseqs | Programs querying capabilities directly |
Note: These live in project documentation rather than a standards body, and that is not a defect — it is how xterm's extensions became universal too. Adoption is the standardization process here. Check which terminals implement a proposal before depending on it; the ecosystem page has the current shape.
7. Unicode
| Document | Use |
|---|---|
| UAX #11 — East Asian Width | The Wide/Fullwidth/Ambiguous classification behind your width table |
| UAX #29 — Text Segmentation | Grapheme cluster boundaries, for mode 2027 |
| UAX #9 — Bidirectional Algorithm | If you ever attempt RTL, which fights the grid model |
| The Unicode Standard, §3.9 | The "maximal subpart" U+FFFD substitution rule your decoder implements |
unicode-width crate docs | The Rust implementation and its deviations |
The U+FFFD rule in §3.9 is the one people implement wrong, and it is what Lab 9 tests.
8. Reading Real Implementations
Often faster than any specification. Ranked by how pleasant they are to read:
| Codebase | Language | Read it for |
|---|---|---|
vte (Alacritty's parser) | Rust | The cleanest parser implementation in existence. ~1,500 lines. Read this one. |
alacritty_terminal | Rust | The screen model, done well and separately from the app |
termwiz (WezTerm) | Rust | A broader terminal library: parsing, input, surfaces |
portable-pty (WezTerm) | Rust | The Unix/ConPTY abstraction, done right |
| foot | C | A small, fast, extremely readable Wayland terminal |
| kitty | C + Python | Protocol extensions, and the reference for most of them |
| Ghostty | Zig | The libghostty split: core vs. platform apps |
| st (suckless) | C | ~2,500 lines for a whole terminal. Read it in an evening. |
| tmux | C | The multiplexer reference. tty.c and screen-write.c especially. |
| xterm | C | Authoritative, and thirty years of accretion. Reference, do not emulate the style. |
Tip:
stis the single best "read a whole terminal in one sitting" codebase. It is small enough to hold in your head and does everything essential. Read it after Section 2, when you will recognize every function.
9. Papers and Long-Form Writing
| Piece | Why |
|---|---|
| "The TTY demystified" (Linus Åkesson) | The best short explanation of the tty layer ever written. Read it in week 1. |
| Julia Evans' terminal zines and posts | Excellent, concrete, and correct |
| "A history of the TTY" | Where the fossils come from |
| Thomas Dickey's xterm FAQ | Answers the "why does xterm do X" questions definitively |
| Dan Luu, "Terminal latency" | Why input latency varies so much between terminals |
10. What to Read, in Order
If you read nothing else, read these five, in this order:
1. "The TTY demystified" — 30 min, week 1
2. man 3 termios — 45 min, week 1
3. vt100.net/emu/dec_ansi_parser — 1 hour, week 4
4. vte's source (Rust) — 2 hours, week 4
5. XTerm ctlseqs, as a lookup — forever
Everything else is reference material for a specific question.
A Note on Contradictions
You will find sources disagreeing. When they do:
1. What does XTERM do? ← the compatibility target
2. What do kitty/foot/Ghostty do? ← the modern consensus
3. What does ECMA-48 say? ← the formal answer, often ignored
4. What does DEC's manual say? ← the original intent
Implement (1). Note (2) if it differs. Document any deliberate deviation.
And when reality disagrees with all four — which happens — the answer is an experiment:
printf the sequence into five terminals and diff the results. That is what
differential testing is for, and it is the only source that
cannot be out of date.
See also: The Terminal Ecosystem · The Hitchhiker's Guide