Appearance
How Terminals Work
The architecture behind every terminal session
Before escape sequences and feature matrices, there's a stack of systems that make terminals work: control characters from the 1960s, a kernel driver that transforms input, a pseudo-terminal that connects your shell to your emulator, and a detection mechanism that tells applications what the terminal can do.
The Stack
Every terminal session involves the same layers, whether you're running ls in a basic prompt or building a full TUI application. Understanding these layers explains why things work the way they do — and why some things don't work at all.
Control Characters
C0 control codes and ASCII — the 33 bytes that aren't text
The non-printable bytes (0x00–0x1F, 0x7F) that predate escape sequences. Backspace, Tab, Line Feed, Carriage Return, Bell — and ESC, the character that started everything.
TTY Architecture
PTY, kernel TTY discipline, shell, terminal emulator
The pseudo-terminal pair, the kernel line discipline that sits between your shell and your terminal, and why SSH and tmux add extra layers.
stty & Line Discipline
Raw mode, canonical mode, echo, signals
The kernel's TTY line discipline transforms your input before the shell sees it. stty controls that transformation — and TUI apps bypass it entirely with raw mode.
Terminal Detection
$TERM, $COLORTERM, DA1, DECRPM, runtime probing
How applications discover what the terminal supports — from unreliable environment variables to runtime escape sequence queries. Why static databases fall short.
How These Layers Connect
When you press a key in a terminal, it flows through every layer before anything appears on screen:
- The terminal emulator (Ghostty, Kitty, iTerm2) captures the keypress and writes the corresponding byte(s) to the PTY master
- The kernel TTY line discipline may transform the input — echoing it back, generating signals (Ctrl+C → SIGINT), or buffering until Enter in canonical mode
- The byte arrives at your shell (bash, zsh, fish) or application (vim, htop) via stdin
- The application writes its response (text, escape sequences) to stdout
- The line discipline passes the output through to the PTY
- The terminal emulator parses the bytes, interprets escape sequences, and renders the result
Understanding this pipeline explains why Ctrl+C kills processes even when the application isn't listening for it (the kernel handles it), why stty raw changes everything (it disables the line discipline), and why $TERM is unreliable (it's just a string — the terminal doesn't enforce it).