In one line: a proposal to move TUI borders from "glyphs that occupy a whole cell" to "an attribute drawn on the cell's edges, handled like a background color." Ratatui maintainer Josh McKinney (joshka) published a blog post and a draft spec with a Ghostty patch on 2026-11-13, and HN (402 points / 182 comments), Lobsters, and Ghostty Discussion #14324 are now arguing over whether it's good design or yet another extension turning terminals into browsers.
Why this, why now
- On 2026-11-13 joshka published "Terminal borders that don't cost a cell." He implemented a terminal protocol for drawing lines on cell edges as a Ghostty patch (about 1,650 lines, a fair chunk of it tests), added Ratatui demos (tiling panes, a btop-style monitor), and asked terminal and TUI authors for feedback.
- HN: 402 points / 182 comments. Lobsters: 57 points / 52 comments. The support side says throwing away rows and columns for one-pixel lines is wasteful; the opposition says this pushes terminals too close to GUIs or browsers, and that existing SGR attributes, DEC ruled lines, or image protocols are enough.
- In Ghostty Discussion #14324, lhecker from the Windows Terminal side and j4james (deeply versed in VT compatibility) joined in, and it became a debate about escape-sequence design itself: build a new DCS protocol, or make a small extension to existing SGR? Within days there were experimental forks for kitty (errnoh) and WezTerm + tmux (dpc).
- The backdrop is that TUIs are being built in large numbers again, coding agents among them. joshka mentions having worked on the Codex TUI and also says GUIs are the vastly superior interface — so this isn't TUI cheerleading, it's "if you're going to build a TUI, how do you reduce its constraints?"
The problem
Every one of these follows from borders being text (joshka's framing):
- Space: on a 16" laptop with a readable font, the terminal is roughly 200×50. Columns are mostly fine; rows aren't. A couple of levels of nested panels can spend 6–8 of those 50 rows on nothing but lines.
- No line between two occupied cells: you can't underline a text field right under its text or outline a button without adding padding.
- Rounded-corner color artifacts: a corner glyph like
╭ has one background color, so when the panel's background differs from what's around it you get a little square of the wrong color in each corner. Line weight and position are whatever the font decides.
- Copy/paste junk: select text inside a box and you get the
│ too.
- Breakage in CJK setups (from an HN comment): box drawing U+2500–257F and the block elements are East Asian Ambiguous in UAX #11, so in a terminal configured to render ambiguous characters as double width, every line glyph takes two cells and the whole frame lands in the wrong place.
What's needed is both: drawing a line must not change the layout, and on existing terminals and multiplexers (tmux, etc.) the app must be able to fall back safely to ordinary box-drawing characters.
How it works
1. Borders are a cell attribute, applied by a "pen" just like background color
- Each cell can carry up to 12 segments: the two halves of each of its four edges (8) plus four arms from the center (
H_LEFT / H_RIGHT / V_TOP / V_BOTTOM). Edges are split in halves so borders line up with quadrant block characters like ▘▗ (e.g. ▘ is outlined by TOP_LEFT|LEFT_TOP|H_LEFT|V_TOP = mask 1345).
- Each segment independently has width, color, placement, and layer. Width is in 1/256 of the cell width (1–64, at least one device pixel), measured against cell width for both orientations so horizontal and vertical lines look equally thick on tall cells. Placement
0 = inside the cell, 1 = centered on the cell edge. Layer 0 = below text, 1 = above text.
- Colors are
RRGGBB, palette pN, or default foreground fg. Palette colors resolve at draw time, so they follow theme changes. Border colors never depend on the cell's SGR colors.
- The core mechanism is the pen: a border set held in the cursor's rendition state (alongside SGR attributes). One rule — "every cell the terminal writes or blanks takes a copy of the pen as its border set" — determines behavior for printing, ECH/EL/ED, insert/delete, and scrolling. The trick is that it reuses the terminal's existing background-color-erase path.