taui - TUI Framework
pkg/taui is Tau's standalone terminal UI framework. It provides a widget-based rendering engine for building inline terminal interfaces - no alternate screen, no full-screen mode. All rendering goes directly into the terminal scrollback.
Design
taui renders widgets as a tree structure, where each widget implements the Element interface. The TUI engine drives the render loop: it collects widget output, formats it into ANSI escape sequences, and writes directly to stdout.
Key Principles
- Inline rendering: Output scrolls naturally into the terminal scrollback. No alternate screen, curses, or full-screen takeover.
- Widget tree: The UI is a tree of widgets (
TUI→Box→Text/LineInput/Completions/...). - Reactive via closure: State changes call
engine.RequestRender()to schedule the next frame. No reactive state framework - rendering pulls state from widget closures on each frame. - Kitty protocol: Uses the Kitty terminal protocol for advanced features (synchronous rendering, hyperlinks, progress indicators).
Package Layout
pkg/taui/
├── tui.go # TUI engine - render loop, event handling, lifecycle
├── renderer.go # ANSI rendering pipeline
├── box.go # Vertical/horizontal layout container
├── text.go # Styled text spans with color, bold, italic
├── lineinput.go # Single-line text input with history
├── completions.go # Drop-down autocomplete menu
├── paragraph.go # Word-wrapped text blocks
├── toolrow.go # Tool call status row with icons
├── loader.go # Animated spinner
├── terminal.go # Terminal initialization, raw mode, signal handling
├── stdin_buffer.go # Buffered stdin reading
├── fuzzy.go # Fuzzy string matching for completions
├── utils.go # Shared utilities
├── termkit/
│ ├── color.go # Color system (16 + 256 + true color)
│ ├── cursor.go # Cursor movement and visibility
│ ├── hyperlink.go # OSC 8 hyperlinks
│ ├── progress.go # Progress indicators
│ ├── spinner.go # Spinner frames
│ └── toollifecycle.go # Tool lifecycle theme (colors, icons)TUI Engine
type TUI struct {
// ...
}
func New(opts ...TUIOption) *TUI
func (t *TUI) Run(root Element) error
func (t *TUI) RequestRender()
func (t *TUI) Quit()Lifecycle
New()- Initializes the terminal (raw mode, Kitty protocol detection), starts the render loop.Run(root)- Enters the main loop: reads stdin events, dispatches to the focused widget, renders the widget tree.RequestRender()- Schedules a re-render for the next frame (debounced, non-blocking).Quit()- Stops the render loop, restores terminal state.
Render Loop
Each frame:
- Process any pending stdin events.
- Call
root.Render(width, height)to collect widget output. - Format output with ANSI escape sequences.
- Write to stdout (inline - no screen clearing).
Element Interface
type Element interface {
Render(width, height int) RenderResult
SetFocus(focused bool)
IsFocused() bool
}RenderResult
type RenderResult struct {
Lines []Line
PreferredHeight int
MinHeight int
}Widgets
Box
Layout container. Stacks children vertically or horizontally:
func Box(opts ...BoxOption) Element
func VBox(children ...Element) Element // vertical stack
func HBox(children ...Element) Element // horizontal stackOptions: WithBorder, WithPadding, WithGap, WithFlex.
Text
Styled text spans:
func Text(content string, opts ...TextOption) ElementOptions: WithColor, WithBold, WithItalic, WithUnderline, WithBackground.
Paragraph
Word-wrapped text blocks that reflow on width changes:
func Paragraph(content string, opts ...ParagraphOption) ElementLineInput
Single-line text input with history navigation:
func LineInput(value string, onChange func(string), opts ...LineInputOption) ElementOptions: WithPlaceholder, WithHistory, WithMultiline.
Completions
Drop-down autocomplete menu with fuzzy filtering:
func Completions(source CompletionSet, opts ...CompletionOption) ElementCompletionSet provides completions for the current input. Results are fuzzy-filtered against the token under the cursor.
ToolRow
Tool call status display:
func ToolRow(name, args string, status ToolStatus, opts ...ToolRowOption) ElementStatuses: ToolRunning (spinner), ToolOK (check), ToolError (X).
Loader
Animated spinner with optional message:
func Loader(message string, frames []string) ElementKeyValue, List, Table, Divider, Stack, StatusRow
Added for plugin-rendered panels (see the Plugin SDK's Panels and Views), these follow the package's actual builder-based constructor style rather than the functional-options sketch above:
func NewKeyValue(entries []KeyValueEntry) *KeyValue // aligned "key: value" lines
func NewList(items []string, ordered bool) *List // bulleted/numbered, word-wrapped
func NewTable(headers []string, rows [][]string) *Table // column-aligned, shrinks to fit width
func NewDivider(label string) *Divider // horizontal rule, optional centered label
func NewStack(direction StackDirection, gap int) *Stack // vertical (Container) or horizontal (zipped columns) layout
func NewStatusRow(label, detail string, state StatusRowState) *StatusRow // ToolRow's spinner/✓/✗ language, generalizedStack embeds Container; StackVertical simply delegates to Container.Render (which only concatenates lines top-to-bottom - there is no other horizontal-layout primitive in the package), while StackHorizontal renders each child independently and zips their lines side by side with Gap spaces between columns. StatusRow adds a fourth, non-animated Neutral state to ToolRow's running/success/failed model, for status that isn't an in-progress lifecycle.
Color System
pkg/taui/termkit/color.go provides a layered color system:
- 16-color (ANSI basic) - guaranteed compatibility.
- 256-color - extended palette.
- True color (24-bit RGB) - full color when terminal supports it.
Colors auto-degrade to the best available mode for the terminal.
Kitty Protocol
taui uses the Kitty terminal protocol for:
- Synchronous rendering (
CSI ? 2026 h) - prevents screen tearing on render. - Hyperlinks (OSC 8) - clickable links in terminal output.
- Progress indicators (OSC 9) - taskbar/dock progress on supported terminals.
Tool Lifecycle Theme
pkg/taui/termkit/toollifecycle.go defines the visual theme for tool execution:
- Running tools: amber/yellow with spinner
- Successful tools: green with checkmark
- Failed tools: red with X mark
These are consumed by ToolRow in the TUI's tool display.
Standalone Usage
taui is a standalone package with zero tau-internal imports. It can be used by any Go project:
import "github.com/samcharles93/tau/pkg/taui"
func main() {
t := taui.New()
root := taui.VBox(
taui.Text("Hello, World!", taui.WithColor(taui.ColorGreen)),
taui.Paragraph("This is a taui application."),
)
t.Run(root)
}The framework handles terminal initialization, raw mode, signal handling, and cleanup automatically.