Skip to content
AstroPaper
Go back

Terminal, TUI, and Python — A Concept Guide

Edit page

What Is a Terminal? 🖥️

A terminal is historically a dumb hardware device — a screen and keyboard with no application logic. It could only:

All logic lived on the mainframe. The terminal was just a renderer.

1970s physical setup:

┌─────────────┐   serial cable   ┌─────────────┐
│   terminal  │ ←──────────────→ │  mainframe  │
│  (dumb box) │  chars + escape  │  all logic  │
│  keyboard   │      codes       │  lives here │
└─────────────┘                  └─────────────┘

Modern terminal emulators — Windows Terminal, iTerm2, Alacritty — are software that faithfully pretends to be that same dumb hardware box. They stay dumb deliberately to stay compatible with 50 years of terminal software.


The Screen: A Grid of Colored Characters

The terminal screen is a 2D grid of cells. Each cell has:

That’s it. No pixels, no images (natively), no layout engine.

Everything visual in a TUI is an illusion made from characters. Unicode provides block and box-drawing characters specifically for this:

█ ▓ ▒ ░       block fill levels
─ │ ┌ ┐ └ ┘   box drawing
┼ ┬ ┴ ├ ┤     box intersections
▲ ▼ ◆ ●       shapes

A “panel with a border” is literally:

┌─── Title ───┐
│             │
│   content   │
│             │
└─────────────┘

ANSI Escape Codes: Content and Style in One Stream

The terminal receives a single byte stream — a mix of regular characters and special escape sequences starting with \x1b[ (ESC + [).

\x1b[31m        → set text color to red
\x1b[1m         → bold on
\x1b[0m         → reset all styling
\x1b[2J         → clear the entire screen
\x1b[5;10H      → move cursor to row 5, column 10

When rich prints bold red text, it actually sends:

\x1b[1m\x1b[31mHello\x1b[0m

The terminal interprets the escape codes and renders accordingly. TUI libraries wrap all of this — you never write escape codes yourself.


Terminal vs Browser: A Fundamental Difference

The browser and terminal have opposite architectures.

BrowserTerminal over SSH
Layout engineClient (browser)Server (TUI app)
Resize handlingLocal reflow, no serverRound trip to server
Mouse hoverCSS :hover, localSent to server, redrawn
ScrollLocalSent to server
Key pressOften local (JS)Always sent to server
Image displayNativeExtensions only
Touch/audio/videoNativeNot supported

Browser sends structure; client renders it. Terminal sends the already-rendered result; client executes it blindly.

This is why terminal apps over slow SSH feel laggy — even typing a single character requires a full round trip:

keypress → SSH → server → app redraws → SSH → terminal renders

One round trip per keystroke. At 200ms latency, typing becomes painful.


Terminal Is Not Like a Web Page

A web page is sent once and the browser handles resize locally. A terminal app must redraw on every resize:

sequenceDiagram
    participant U as User
    participant T as Terminal Emulator
    participant S as SSH / Server
    participant A as TUI App

    U->>T: resize window
    T->>S: send new cols × rows
    S->>A: SIGWINCH signal
    A->>A: recalculate layout
    A->>S: send new escape codes
    S->>T: deliver escape codes
    T->>U: render new layout

The terminal grid is sized in character cells, not pixels. When the user resizes the window, the row × column count changes and the server redraws.


Mouse Support: Bolted On Later

The original VT100 (1978) had no mouse. Mouse support was added in the VT200 series in the 1980s as an optional extension.

The TUI app must first opt in by sending escape codes:

\x1b[?1000h    enable mouse click reporting
\x1b[?1006h    enable extended coordinates

After that, clicks are reported back as escape codes:

\x1b[<0;10;5M    left click at col 10, row 5
\x1b[<0;10;5m    mouse release at col 10, row 5

Mouse support is inconsistent across terminal emulators because it was never part of the original design. TUI frameworks abstract this away.


Full-Screen vs Inline TUI

Not every TUI app takes over the whole terminal.

ModeDescriptionExample
Full-screenClears and owns the entire terminalvim, htop, textual apps
InlinePrints styled output in the normal flowrich output, ls --color

For a chat agent, full-screen is better — you control the whole space, keep the input box fixed at the bottom, and can stream text into the history pane without mixing with shell output.

One tradeoff: when you exit a full-screen app the screen clears, so conversation history is lost unless saved to a file.


TUI Widgets: Same Concepts as HTML

TUI frameworks provide widgets that map to familiar web concepts:

HTML/GUITextual equivalent
divWidget, Container
scrollable divScrollableContainer
p / textStatic
inputInput
textareaTextArea
buttonButton
checkboxCheckbox
tableDataTable
progress barProgressBar
tabsTabbedContent

But at the low level, none of these exist. A button is just:

  1. Characters drawn at a position: [ OK ]
  2. A bounding box the framework tracks
  3. An event fired when the mouse clicks inside it or Enter is pressed on it

Everything is characters + coordinate math.


No Standard Like HTML5 ⚠️

The only de facto standard is ANSI/VT100 escape codes — the low-level communication protocol. Above that level, nothing is standardized:

This is why there are many incompatible TUI libraries and why TUI apps never reached the richness of web apps. The web broke from the past and invented a smart client model. The terminal ecosystem kept the dumb terminal model from 1978.


Python TUI Libraries

LibraryStyleBest for
textualFull-screen, CSS-like layout, asyncModern apps, chat interfaces
richInline, styled outputPretty printing, tables, progress bars
prompt_toolkitInline + full-screen, low-levelREPLs, autocomplete, custom input
urwidFull-screen, low-levelFull control
cursesFull-screen, stdlib built-inNo dependencies
blessedFull-screen, thin curses wrapperSimpler than curses

For an Agent Chat UI

textual is the right choice:

A minimal layout:

class ChatApp(App):
    def compose(self):
        yield ScrollableContainer(id="history")
        yield Input(placeholder="Type a message...")

compose() is like writing HTML. textual handles sizing, positioning, and resize reflow.


Why TUI Is Having a Revival

TUI was the mainstream before GUI (1970s–80s). Windows killed it for desktop apps in the 1990s. But:

Tools like htop, lazygit, k9s, and Claude Code itself show that developers actively prefer terminal-native tools. The terminal never died — it just stopped being mainstream for normal users.


Edit page
Share this post on:

Previous Post
Building TUI Apps with Textual — A Practical Guide
Next Post
Python dataclass Explained