
pi.dev is a terminal-based coding agent, similar in spirit to Claude Code but minimal by design: a handful of tools, an editable system prompt, and a theme system with 51 color tokens covering the UI, markdown rendering, syntax highlighting, tool diffs, and thinking-level indicators. \ The theme system assumes a truecolor terminal. Its own documentation is explicit about this: colors are defined as 24-bit RGB hex values, with a fallback to the 256-color xterm palette for older terminals. The list of terminals it mentions is iTerm2, Kitty, WezTerm, Windows Terminal, and VS Code. \ A raw Linux virtual terminal - the console you get on tty1 – tty6 without X or a terminal emulator running on top - is not in that list, and is not supported. There is no framebuffer console fallback anywhere in the theming code. Why the default themes break on a VT. A Linux VT does not interpret truecolor escape sequences. It renders text through the kernel's own console driver, with a fixed palette of 8 (or 16, with the bold/bright attribute) colors. Any RGB value that isn't one of those gets approximated by the console driver itself, inconsistently, or simply ignored. The result with any of pi's stock themes is either wrong colors or unreadable ones - not a crash, just a UI that was never designed for this environment. \ pi.dev does not need to add VT support for this to be fixable. The theme format is just JSON, and nothing stops a theme from restricting itself to values a VT can actually display. The Trick: A theme that only uses the VT's own palette. Instead of picking arbitrary hex values, vt8.json maps every token to the eight basic ANSI colors and their names: { "name": "vt8", "vars": { "black": "#000000", "red": "#ff0000", "green": "#00ff00", "yellow": "#ffff00", "blue": "#0000ff", "magenta": "#ff00ff", "cyan": "#00ffff", "white": "#ffffff", "darkgray": "#808080" }, "colors": { "background": "black", "foreground": "white", "text": "white", "textMuted": "darkgray", "textSubtle": "darkgray", "border": "white", "borderMuted": "darkgray", "borderAccent": "cyan", "accent": "cyan", "success": "green", "warning": "yellow", "error": "red", "info": "cyan", "bashMode": "magenta", "customMessageBg": "black", "customMessageLabel": "cyan", "customMessageText": "white", "dim": "darkgray", "mdCode": "green", "mdCodeBlock": "black", "mdCodeBlockBorder": "darkgray", "mdHeading": "yellow", "mdHr": "darkgray", "mdLink": "cyan", "mdLinkUrl": "blue", "mdListBullet": "green", "mdQuote": "black", "mdQuoteBorder": "darkgray", "muted": "darkgray", "selectedBg": "blue", "syntaxComment": "darkgray", "syntaxFunction": "cyan", "syntaxKeyword": "magenta", "syntaxNumber": "yellow", "syntaxOperator": "white", "syntaxPunctuation": "white", "syntaxString": "green", "syntaxType": "cyan", "syntaxVariable": "white", "thinkingHigh": "magenta", "thinkingLow": "darkgray", "thinkingMedium": "yellow", "thinkingMinimal": "blue", "thinkingOff": "darkgray", "thinkingText": "white", "thinkingXhigh": "red", "toolDiffAdded": "green", "toolDiffContext": "darkgray", "toolDiffRemoved": "red", "toolErrorBg": "black", "toolOutput": "white", "toolPendingBg": "black", "toolSuccessBg": "black", "toolTitle": "cyan", "userMessageBg": "black", "userMessageText": "white" } } The hex values are pure primaries ( #ff0000 , #00ff00 , #0000ff , and so on) plus darkgray at 50% gray. These are not an arbitrary aesthetic choice: they are the same eight colors a VT already knows how to render natively, so when pi's truecolor-to-256-color fallback runs, there is no approximation error to speak of - the requested color and the displayed color coincide. \ Every one of the 51 required tokens has to be filled in; pi has no optional colors, so a partial theme will not load. Wiring it up. Drop vt8.json next to pi's other themes (either the global ~/.pi/agent/themes/ directory or a project-local .pi/themes/ ), then point settings.json at it: { "lastChangelogVersion": "0.80.3", "theme": "vt8" } \ Restart pi (or reload the theme), and it will render using only the primary colors and gray that the VT already understands. What this is and isn't. This is not VT support. pi.dev still assumes a modern terminal for things like cursor positioning and redraw behavior, and none of that changes with a theme file. What changes is a much narrower problem: which colors get requested. By requesting only colors the VT's fixed palette already contains, the mismatch between "what pi asks for" and "what the console can draw" disappears, and the output becomes readable - eight colors and a gray, not the full palette pi was designed around, but perfectly usable for a coding session on a bare console.
View original source — Hacker Noon ↗


