Skip to content

Terminal dashboard (colibri-tui)

โ† index

The TUI is Colibriโ€™s live terminal dashboard. It connects to the daemonโ€™s Unix socket, pulls the GlasspaneSnapshot, and renders a color-coded table of supervised panes. It is a display client, not part of the daemon, and not the same thing as colibri-glasspane.

colibri-glasspane is the state machine that decides what state an agent is in from its JSONL events. colibri-tui is the screen that asks the daemon โ€œwhat does the radar look like right now?โ€ and draws it.

ArtifactRoleResident crate
colibri-glasspanePane state machine, event ingestor, snapshot buildercrates/colibri-glasspane
colibri-tuiTerminal dashboard client with rows, colors, keybindingscrates/colibri-glasspane-tui (binary = colibri-tui)

The split matters because the daemon, the MCP bridge, the CLI, and tests all use colibri-glasspane. The TUI is just one consumer. If the TUI is not installed, or crashes, agents keep running.

colibri-tui is a standalone process. It resolves the daemon socket the same way the CLI does (DaemonConfig::from_env().socket_path), then calls client.glasspane_snapshot() every two seconds. The daemon has no awareness of crossterm or ratatui.

This is the same โ€œservice owns state, clients render itโ€ pattern as the MCP bridge and the CLI. It keeps Colibri headless-safe, which is required for an rc.d service that must boot before any operator logs in.

โ†’ crates/colibri-glasspane-tui/src/main.rs (socket resolution, refresh loop)

You can spawn a local test agent (s) and stop the selected pane (x) from the dashboard. That overlaps with commands the colibri CLI can already do, but the experience is different: a CLI command is one-shot; the TUI is a live supervision surface with a selected row and an immediate status bar.

We kept the action keys because the dashboardโ€™s job is to let an operator notice and react โ€” spot a stalled pane and stop it without leaving the terminal.

โ†’ crates/colibri-glasspane-tui/src/main.rs (spawn_agent, kill_selected)

The TUI does not parse agent stdout. It only reads the already-folded GlasspaneSnapshot, so Pi, zot, and local test agents are rendered with the same columns, colors, and state icons. The rendering code concerns itself only with layout and keybindings; all semantic decisions live in colibri-glasspane.

โ†’ crates/colibri-glasspane/src/lib.rs (AgentState, GlasspaneSnapshot)

Naming: the binary is colibri-tui, the crate is colibri-glasspane-tui

Section titled โ€œNaming: the binary is colibri-tui, the crate is colibri-glasspane-tuiโ€

The crate directory is colibri-glasspane-tui because the package implements โ€œa TUI for the glasspane.โ€ The installed binary is named colibri-tui because that is what an operator types. CLAWDIE-STUDIO.md and other docs refer to colibri-tui as shorthand; there is no separate colibri-tui crate.

This duality is currently accepted. If we ever add a second TUI surface (e.g. a colibri-tui-web or colibri-tui-gui), the naming becomes confusing and should be revisited.

KeyAction
q / EscQuit, or close detail pane if open
rRefresh snapshot now
sSpawn a local colibri-test-agent
xStop the selected pane
EnterOpen/close the detail pane for the selected row
Tab / Shift+TabCycle through distinct sessions (incl. โ€œAllโ€)
j / k or โ†“ / โ†‘Navigate the pane table
n / NJump to next / previous attention pane
aToggle the attention filter (only attention)

The dashboardโ€™s primary question is โ€œdoes any pane need me right now?โ€ Attention is the impossible-to-miss signal for that.

โ†’ crates/colibri-glasspane-tui/src/main.rs (needs_attention)

fn needs_attention(pane: &Pane) -> bool {
pane.state == AgentState::Error
|| pane.state == AgentState::Blocked
|| pane.stalled
}

Error + Blocked + Stalled. Blocked is included because the glasspane state machine explicitly marks Blocked = โ€œoperator attention neededโ€ (it is the state for queue_update / pending steering / approval). This single free function is shared by the attention bar, the jump keys (n/N), and the filter (a) โ€” one definition to change.

DEFAULT_STALL_AFTER = 4 * 60 * 60 (4 hours). Stalled is a rare but critical signal, not a frequent one. The attention bar mostly shows Errors and Blocked panes; Stalled is the โ€œsomething is deeply wrongโ€ escalation.

When any pane needs_attention(), the header slot is replaced by a red-bordered attention bar (same 3-line vertical footprint); otherwise the normal header renders. This makes attention impossible to miss without consuming extra space.

โ•”โ• โš  ATTENTION โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘ 3 panes need attention (1 error ยท 1 blocked ยท 1 stalled) โ•‘
โ•‘ scraper-19: Error ยท worker-7: Blocked ยท db-3: Stalled โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  • The counter line derives from snapshot.count() + stalled_count() โ€” no extra API calls.
  • The pane-list line shows pane IDs + state label, truncated to terminal width; if more fit than room allows, it ends with ยท (N more โ€” press a).
  • The bar stays visible even when the attention filter (a) is active, so the operator always sees the total count at a glance.
Row stateNormalSelected
Attentionbg(DarkRed) + fg(White)bg(DarkGray) + fg(LightRed) + bold
Normal(plain)bg(DarkGray)

Attention rows are impossible to miss; the inversion on selection confirms which one the cursor is on without losing the attention signal.

attention_only is a separate field from session_filter. In filtered_panes() the two chain: session filter AND attention filter. Tab cycles sessions within the attention-only view; turning off the attention filter returns to the session-scoped view.

Use the TUI when:

  • You want a live, auto-refreshing view of all panes.
  • You are picking a pane to inspect or stop visually.
  • You are on an SSH session with only a terminal.

Use the colibri CLI when:

  • You are scripting or piping output (colibri snapshot | jq).
  • You need a command not bound to a key (e.g. claim-task, set-cost-mode).
  • You want a one-shot answer without entering an alternate screen.
  • glasspane โ€” the pane state machine the TUI renders
  • operator-cli โ€” the colibri CLI that shares the same socket client