TUI Dashboard
Starting the TUI
Section titled “Starting the TUI”mix annihilationThe TUI enters raw terminal mode using ANSI escape codes and Erlang’s :io module. It uses the alternate screen buffer and restores the terminal on exit.
Architecture
Section titled “Architecture”The TUI is built from scratch — no TUI framework:
Terminal— Raw mode management, ANSI escape code primitives, screen buffer rendering, terminal dimension queriesInput— Pure function parser: transforms raw byte streams into structured key events (:char,:key,:ctrl,:fn, arrows, etc.)Layout— Flexible panel layout system with row/column calculationsMode— Behaviour for TUI modes (init, handle_key, handle_events, render, shortcuts)ModeManager— Mode switching, state preservation, key dispatch, notification badgesEventBridge— Subscribes to system event topics, maps events to affected TUI panels, batches re-renders at 30fps (33ms intervals)
Rendering Pipeline
Section titled “Rendering Pipeline”- System events arrive via
Annihilation.Event EventBridgemaps events to affected panels (e.g.,"agent:streaming"->[:overview, :focus])- Dirty panels are batched and a render timer fires every 33ms
ModeManagerdelegates rendering to the current mode- Mode returns a list of terminal cells:
{row, col, text, attrs_map} Terminal.render/1converts cells to ANSI escape code iodata- Single
IO.write/1call for flicker-free output
Six modes, switchable via Tab (cycle) or number keys 1-6 (direct jump):
1. Overview Mode
Section titled “1. Overview Mode”Split-panel view showing all psychonauts and their activity.
- Left panel: Psychonaut list with status indicators (phase, turn count)
- Right panel: Real-time activity log from all psychonauts
- Bottom: Live streaming preview of the selected psychonaut
Select a psychonaut with Up/Down, press Enter to switch to Focus mode.
2. Focus Mode
Section titled “2. Focus Mode”Full conversation view for a single psychonaut:
- Complete message history (user, assistant, tool calls, tool results)
- Live streaming output with delta updates
- Agent stats: turn count, model, phase, bead ID
- Scrollable with
Up/Down,PageUp/PageDown
3. Tether Mode
Section titled “3. Tether Mode”Pending questions and drifts from psychonauts:
- Question list: Priority indicators (critical/high/normal/low), agent ID, age
- Question detail: Full text + context
- Answer input: Type response, press
Enterto send beacon - Drifted questions: Status badge showing what the psychonaut assumed
- Drift actions: Ground (confirm), Reject (with reason), Note (comment)
4. Grounding Mode
Section titled “4. Grounding Mode”Review generated code and pipeline mutations before they’re applied:
- Grounding queue: Type indicators (NEW AGENT, NEW TOOL, PIPELINE)
- Source code view: Full source with line numbers
- Security scan results: CommandGuard classification of any shell commands
- Actions: Approve (
A), Edit (E), Reject (R) - Pipeline mutations: Shows proposed stages and matching rules
5. Beads Mode
Section titled “5. Beads Mode”Bead management view:
- Bead list with status, priority, type, and labels
- Dependency visualization
- Comment thread view
- Create/update beads
6. Shell Mode
Section titled “6. Shell Mode”Embedded command runner:
- Command input with history
- Output display with scrolling
- Commands run through
CommandGuardclassification - Results visible to other modes for cross-referencing
Keybindings
Section titled “Keybindings”Global Keys
Section titled “Global Keys”| Key | Action |
|---|---|
Tab | Cycle to next mode |
1-6 | Jump to specific mode (when not in text input) |
Ctrl+C / Ctrl+Q | Quit |
Ctrl+L | Force re-render |
Mode-Specific Keys
Section titled “Mode-Specific Keys”| Key | Mode | Action |
|---|---|---|
Up/Down | All | Navigate lists |
Enter | Overview | Focus on selected psychonaut |
Enter | Tether | Submit answer to question |
Esc | Focus | Return to Overview |
A | Grounding | Approve (ground) |
E | Grounding | Edit before approving |
R | Grounding | Reject |
PageUp/PageDown | Focus | Scroll conversation |
Event Bridge
Section titled “Event Bridge”EventBridge maintains a mapping of event topics to affected TUI panels:
# Topic -> affected panels"agent:started" -> [:overview, :focus]"agent:streaming" -> [:overview, :focus]"agent:done" -> [:overview, :focus]"burst:started" -> [:overview, :status_bar]"burst:completed" -> [:overview, :status_bar]"tether:reaching" -> [:tether, :status_bar]"tether:drifts" -> [:tether, :grounding]"keeper:bead_created" -> [:beads]"system" -> [:overview, :status_bar]Notification Badges
Section titled “Notification Badges”When events arrive for a mode that is not currently active, the EventBridge increments a notification counter. The status bar shows badge counts next to mode names:
[1:Overview] [2:Focus] [3:Tether(2)] [4:Grounding(1)] [5:Beads] [6:Shell]Switching to a mode clears its notification count.
Render Batching
Section titled “Render Batching”Events are buffered and rendered at most every 33ms (30fps). This prevents flicker from rapid event bursts during active streaming. The buffer is capped at 100 events.
Status Bar
Section titled “Status Bar”The bottom row displays:
- Current mode name (highlighted)
- All mode tabs with notification badges
- Contextual keyboard shortcuts for the current mode
- System status (burst phase, active agent count)
Mode Behaviour
Section titled “Mode Behaviour”Custom modes implement Annihilation.TUI.Mode:
@callback init(term_size()) :: state()@callback init(term_size(), term()) :: state() # Optional, for data from mode switch@callback handle_key(key_event(), state()) :: {:ok, state()} | {:switch_mode, atom(), term()}@callback handle_events([map()], state()) :: state()@callback render(state()) :: [Terminal.cell()]@callback input_active?(state()) :: boolean() # Block number-key mode switching@callback shortcuts() :: [{String.t(), String.t()}] # Status bar help textHelper functions in the Mode module: truncate/2, word_wrap/2, pad_right/2, relative_time/1.