Decision #8

TUI Alternative

Why Bubbletea + Lip Gloss as the headless fallback to the pixel office

The Question

Not everyone wants a game-like desktop app. Server environments, SSH sessions, and CI need text-based visibility with the same coordination awareness. The orchestrator must be observable without a display server, a GPU, or a native window manager. The question is which TUI framework — if any — earns a place alongside the pixel office as a first-class interface.

Options Considered

Bubbletea + Lip Gloss (Go)
Elm architecture, same language as orchestrator
Chosen
Pros
  • No IPC bridge — shares the Go runtime directly
  • Elm architecture guarantees render/state parity
  • Lip Gloss enables styled, responsive layouts in the terminal
  • Bubbletea's message loop mirrors the orchestrator's event model
Cons
  • Less visually expressive than a pixel renderer
  • Limited animation — no sprite movement
Ratatui (Rust)
Immediate-mode TUI framework
Rejected
Pros
  • Extremely fast rendering with fine-grained control
  • Rich widget library out of the box
Cons
  • Rust is a different language — requires an IPC bridge to the Go orchestrator
  • Adds a second runtime and a serialization layer
  • State drift risk across the process boundary
Textual (Python)
CSS-like styling for terminal UIs
Rejected
Pros
  • Rapid prototyping — CSS-like layout feels familiar
  • Rich theming and component model
Cons
  • Requires Python runtime — third language in the stack
  • IPC bridge unavoidable; adds serialization overhead
  • No compelling advantage over Bubbletea given the Go context
No TUI — API Only
Expose gRPC / REST for external consumers
Rejected
Pros
  • Minimal maintenance surface — no rendering code
  • Integrates with any tooling that speaks gRPC or REST
Cons
  • Poor DX for operators in SSH sessions or CI pipelines
  • No visual story — leaves the headless context without first-class support
  • Debugging becomes raw log-reading

Interface Comparison

Pixel Office Desktop
P
planner
running
C
coder
working
R
reviewer
idle
T
tester
error
Running
Working
Idle
Error

Agent sprites at desks with animated state transitions, spatial awareness, and desk-to-desk handoff visuals.

Same gRPC state stream
Bubbletea TUI Headless
agenKic-orKistrator — agents
AGENT STATUS TASK UPTIME
planner ● running plan-042 00:03:12
coder ◑ working feat/auth 00:07:55
reviewer ○ idle 00:12:01
tester ✗ error suite-7 00:01:08

15:42:03 INFO planner dispatched task plan-042
15:42:11 INFO coder accepted feat/auth
15:43:22 WARN tester: suite-7 timeout exceeded

Tabular agent list, status indicators, scrolling log, and task queue — readable over SSH with no display server.

Same gRPC state stream

The Decision

Bubbletea shares the Go runtime with the orchestrator, eliminating any IPC bridge. Its Elm architecture — a single model, a pure update function, and a view function — maps cleanly onto the orchestrator's own event model. State mutations that happen inside the orchestrator produce messages that flow directly into the Bubbletea update loop; the TUI view is always a deterministic function of the current model, which makes render/state parity a structural guarantee rather than a discipline.

Lip Gloss handles layout and styling without a DOM: adaptive columns, colour themes, and borders work across terminal capabilities from 256-colour to basic ANSI. The result is a UI that degrades gracefully rather than failing silently in constrained environments.

Why It Works

No IPC bridge
Both the orchestrator and the TUI live in the same binary. State updates are function calls, not socket messages — zero serialization overhead and no version mismatch surface.
Render / state parity
Elm's unidirectional data flow means the view can never race against the model. What you see in the TUI is exactly the state the orchestrator holds at that tick.
🖥
Server-native DX
Operators in SSH sessions and CI pipelines get the same awareness as a local desktop user — agent status, task queue, and log tail — without installing a display server or forwarding X11.
🎨
Styled layouts with Lip Gloss
Lip Gloss provides composable, adaptive layout primitives. Status columns, colour-coded state indicators, and box borders render correctly from xterm-256color down to basic terminals.

Perspective

"The TUI is not a lesser version — it's the right tool for its context. Server operators, SSH sessions, and CI pipelines deserve first-class visibility too."

Trade-offs Accepted

Area Concern Impact
Spatial awareness The TUI cannot match the spatial metaphor of the pixel office. Agent-to-agent handoffs are logged events, not visible movements across a floor plan. Medium
Two UIs to maintain A shared gRPC state stream reduces coupling, but changes to agent state shape must be reflected in both the pixel office and the TUI view functions. Medium
Elm boilerplate Every new piece of state requires a message type, a case in the update switch, and a view fragment. The pattern is mechanical but verbose for large models. Low
Terminal capability variance Lip Gloss adapts to terminal capability, but some environments (minimal Docker images, legacy CI runners) may render box-drawing characters as garbage. Low