Skip to main content

TUI Architecture Documentation

Overview​

The Radium TUI (Terminal User Interface) is a unified prompt-based interface built with ratatui that provides an interactive CLI experience for working with AI agents, orchestration, and MCP integrations. This document describes the architecture, component structure, and design patterns used throughout the TUI implementation.

Architecture Diagram​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ main.rs β”‚
β”‚ - Terminal initialization (crossterm) β”‚
β”‚ - Event loop (keyboard input polling) β”‚
β”‚ - Render loop (ratatui frame drawing) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ App β”‚
β”‚ - Main application state β”‚
β”‚ - Keyboard event handling β”‚
β”‚ - Command execution β”‚
β”‚ - Orchestration service integration β”‚
β”‚ - MCP integration β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PromptData β”‚ β”‚ SetupWizard β”‚
β”‚ - Input buffer β”‚ β”‚ - State machine β”‚
β”‚ - Output buffer β”‚ β”‚ - Provider selection β”‚
β”‚ - Conversation history β”‚ β”‚ - API key input β”‚
β”‚ - Command suggestions β”‚ β”‚ - Credential storage β”‚
β”‚ - Command palette β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Views Layer β”‚
β”‚ - prompt.rs - Main unified prompt interface β”‚
β”‚ - header.rs - Header with session info β”‚
β”‚ - splash.rs - Startup splash screen β”‚
β”‚ - loading.rs - Loading indicators β”‚
β”‚ - markdown.rs - Markdown rendering β”‚
β”‚ - sessions.rs - Session list view β”‚
β”‚ - model_selector.rs - Model selection UI β”‚
β”‚ - split.rs - Split view for complex workflows β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Components Layer β”‚
β”‚ - output_window.rs - Output display with scrolling β”‚
β”‚ - agent_timeline.rs - Agent execution timeline β”‚
β”‚ - telemetry_bar.rs - Token/metrics display β”‚
β”‚ - checkpoint_modal.rs - Checkpoint management UI β”‚
β”‚ - log_viewer.rs - Log viewing component β”‚
β”‚ - loop_indicator.rs - Loop execution indicator β”‚
β”‚ - status_footer.rs - Status footer β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ State Layer β”‚
β”‚ - workflow_state.rs - Workflow execution tracking β”‚
β”‚ - agent_state.rs - Individual agent state β”‚
β”‚ - telemetry_state.rs - Token/metrics tracking β”‚
β”‚ - checkpoint_state.rs - Checkpoint management β”‚
β”‚ - OutputBuffer - Bounded output buffer β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Core Components​

1. Application Entry Point (main.rs)​

The entry point initializes the terminal, sets up logging, and runs the main event loop.

Key Responsibilities:

  • Terminal setup (raw mode, alternate screen)
  • Splash screen rendering
  • Event polling and routing to App
  • Frame rendering coordination

Event Flow:

Terminal Event β†’ crossterm β†’ main.rs β†’ App::handle_key() β†’ State Update β†’ Render

2. Application Core (app.rs)​

The App struct is the central coordinator for all TUI functionality.

State Management:

  • PromptData - Unified prompt interface state
  • SetupWizard - Optional setup wizard state
  • WorkspaceStatus - Workspace initialization state
  • OrchestrationService - AI orchestration integration
  • McpIntegration - MCP tool integration

Key Methods:

  • handle_key() - Routes keyboard events to appropriate handlers
  • execute_command() - Executes slash commands (/help, /chat, etc.)
  • handle_orchestrated_input() - Routes natural language to orchestration
  • send_chat_message() - Sends messages to AI agents

Event Routing:

Keyboard Event β†’ App::handle_key()
β”œβ”€ Setup wizard active? β†’ SetupWizard::handle_key()
β”œβ”€ Command palette active? β†’ Update palette suggestions
β”œβ”€ Slash command? β†’ execute_command()
└─ Regular input β†’ handle_orchestrated_input() or send_chat_message()

3. Unified Prompt Interface (views/prompt.rs)​

The PromptData struct and render_prompt() function provide a unified interface that adapts to different display contexts.

Display Contexts:

  • Chat - Active chat session with an agent
  • AgentList - List of available agents
  • SessionList - List of chat sessions
  • Dashboard - System dashboard
  • Help - Help information
  • ModelSelector - Model selection interface

Key Features:

  • Command autocomplete with suggestions
  • Command palette (Ctrl+P) with fuzzy search
  • Scrollback buffer for conversation history
  • Markdown rendering for agent responses

4. Setup Wizard (setup.rs)​

State machine-based wizard for first-time user setup.

States:

  1. Welcome - Initial welcome screen
  2. ProviderSelection - Select AI providers (Gemini, OpenAI)
  3. ApiKeyInput - Enter API key for selected provider
  4. Validating - Validating API key (future)
  5. Complete - Setup complete

State Transitions:

Welcome β†’ ProviderSelection β†’ ApiKeyInput β†’ Complete
↑ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ (Esc to go back)

5. State Management (state/)​

Modular state management for workflow execution and agent tracking.

Workflow State (workflow_state.rs)​

Tracks overall workflow execution:

  • Workflow status (Idle, Running, Paused, Completed, Failed, Cancelled)
  • Step progression
  • Agent registration and state
  • Output buffer management
  • Telemetry tracking

Agent State (agent_state.rs)​

Tracks individual agent execution:

  • Agent status and sub-agent states
  • Execution timeline
  • Output per agent

Telemetry State (telemetry_state.rs)​

Tracks token usage and metrics:

  • Input/output token counts
  • Cost estimation
  • Request timing

Checkpoint State (checkpoint_state.rs)​

Manages workflow checkpoints:

  • Checkpoint creation and restoration
  • Checkpoint metadata

Output Buffer (state/mod.rs)​

Bounded buffer for output lines:

  • Fixed capacity (default 1000 lines)
  • Automatic oldest-line removal
  • Scroll position management
  • Viewport culling support

6. View Components (views/)​

View modules handle rendering of different UI contexts.

Prompt View (prompt.rs)​

  • Main unified interface rendering
  • Context-aware content display
  • Command palette overlay
  • Markdown rendering integration

Header View (header.rs)​

  • Session information display
  • Status indicators
  • Branding

Markdown View (markdown.rs)​

  • Converts markdown text to ratatui Line objects
  • Supports bold, italic, code, lists
  • Handles code blocks

Model Selector (model_selector.rs)​

  • Model selection interface
  • Provider grouping
  • Default model indication

Sessions View (sessions.rs)​

  • Session list display
  • Session metadata (message count, last active)

Split View (split.rs)​

  • Side-by-side content display
  • Useful for complex workflows

7. UI Components (components/)​

Reusable UI components for specific functionality.

Output Window (output_window.rs)​

  • Displays OutputBuffer content
  • Scroll indicators
  • Status line with scroll position
  • Split view support

Agent Timeline (agent_timeline.rs)​

  • Visual timeline of agent execution
  • Status indicators per agent
  • Sub-agent hierarchy

Telemetry Bar (telemetry_bar.rs)​

  • Token usage display
  • Cost estimation
  • Request metrics

Checkpoint Modal (checkpoint_modal.rs)​

  • Checkpoint creation UI
  • Checkpoint restoration interface

Log Viewer (log_viewer.rs)​

  • Structured log display
  • Log level filtering

Loop Indicator (loop_indicator.rs)​

  • Visual indicator for loop execution
  • Iteration count
  • Bottom status bar
  • Contextual information

Event Flow​

Keyboard Input Flow​

1. crossterm polls for events (main.rs)
2. Event received β†’ App::handle_key()
3. Route based on current state:
- Setup wizard active? β†’ SetupWizard::handle_key()
- Command palette active? β†’ Update palette
- Slash command? β†’ Command::parse() β†’ execute_command()
- Regular input? β†’ handle_orchestrated_input() or send_chat_message()
4. State updated in App/PromptData
5. Next frame render β†’ views render updated state

Command Execution Flow​

1. User types "/chat agent-1"
2. Command::parse() creates Command struct
3. App::execute_command() matches command name
4. Command handler executes:
- Loads agent configuration
- Creates/retrieves session
- Updates DisplayContext to Chat
- Updates PromptData with agent info
5. Next render shows chat interface

Orchestration Flow​

1. User types natural language (no "/")
2. App::handle_orchestrated_input() called
3. OrchestrationService processes input
4. Service determines actions/agents needed
5. Execution happens asynchronously
6. Results streamed to conversation buffer
7. UI updates with streaming output

Integration Points​

radium_core Integration​

Authentication:

  • CredentialStore - API key storage and retrieval
  • ProviderType - AI provider enumeration

Workspace:

  • Workspace - Workspace initialization and management

Agents:

  • Agent discovery from ./agents/ or ~/.radium/agents/
  • Agent configuration loading

MCP:

  • McpIntegration - MCP server connection and tool execution
  • SlashCommandRegistry - MCP-provided slash commands

Orchestration Service Integration​

Initialization:

  • OrchestrationService created with workspace config
  • Service handles natural language input
  • Routes to appropriate agents/tools

Event Handling:

  • Completion events streamed to UI
  • Progress updates via telemetry
  • Error handling and recovery

Design Patterns​

1. State Machine Pattern​

Used in SetupWizard for managing setup flow:

  • Clear state transitions
  • State-specific behavior
  • Error recovery

2. Component-Based UI​

Views and components are modular:

  • Reusable components
  • Clear separation of concerns
  • Easy to test and maintain

3. Event-Driven Architecture​

Async/await for AI interactions:

  • Non-blocking UI updates
  • Streaming responses
  • Concurrent operations

4. Unified Interface Pattern​

Single PromptData struct adapts to multiple contexts:

  • Reduces code duplication
  • Consistent user experience
  • Easy to add new contexts

Configuration​

Theme System (theme.rs)​

The RadiumTheme struct provides consistent colors:

  • Primary/secondary brand colors
  • Status colors (success, warning, error, info)
  • Text and background colors
  • Border colors

Currently hardcoded, but designed for future config file support.

Workspace Configuration​

Workspace initialized from:

  • Current directory (if .radium/ exists)
  • ~/.radium/ (fallback)

Testing Strategy​

Unit Tests​

State modules have comprehensive unit tests:

  • workflow_state.rs - Workflow lifecycle tests
  • state/mod.rs - OutputBuffer tests

Integration Tests​

Located in apps/tui/tests/:

  • integration_test.rs - Basic integration tests
  • orchestration_commands_test.rs - Orchestration command tests

Test Fixtures​

Common test scenarios:

  • Mock credential store
  • Mock workspace
  • Mock AI responses

Performance Considerations​

Current Limitations​

  1. Output Buffer: Limited to 1000 lines (good)
  2. Conversation History: Grows unbounded (needs optimization)
  3. Rendering: Full re-render on every frame (needs viewport culling)
  4. Markdown: Parsed on every render (could be cached)

Optimization Opportunities​

  1. Viewport Culling: Only render visible lines
  2. Conversation Limits: Archive old messages to disk
  3. Markdown Caching: Cache parsed markdown
  4. Incremental Rendering: Only re-render changed areas

Future Enhancements​

  1. Theme Customization: Config file support for themes
  2. Keyboard Shortcuts Help: In-app shortcut reference
  3. Performance Optimization: Viewport culling and conversation limits
  4. Plugin System: Extensible command system
  5. Multi-language Support: i18n for internationalization

File Structure​

apps/tui/src/
β”œβ”€β”€ main.rs # Entry point, event loop
β”œβ”€β”€ app.rs # Main application logic
β”œβ”€β”€ lib.rs # Library exports
β”œβ”€β”€ commands.rs # Command parsing
β”œβ”€β”€ setup.rs # Setup wizard
β”œβ”€β”€ theme.rs # Theme system
β”œβ”€β”€ icons.rs # Status icons
β”œβ”€β”€ errors.rs # Error handling
β”œβ”€β”€ workspace.rs # Workspace initialization
β”œβ”€β”€ session_manager.rs # Session management
β”œβ”€β”€ chat_executor.rs # Chat execution
β”œβ”€β”€ navigation.rs # Navigation helpers
β”œβ”€β”€ views/ # View layer
β”‚ β”œβ”€β”€ prompt.rs # Main prompt interface
β”‚ β”œβ”€β”€ header.rs # Header view
β”‚ β”œβ”€β”€ splash.rs # Splash screen
β”‚ β”œβ”€β”€ loading.rs # Loading indicators
β”‚ β”œβ”€β”€ markdown.rs # Markdown rendering
β”‚ β”œβ”€β”€ sessions.rs # Session list
β”‚ β”œβ”€β”€ model_selector.rs # Model selection
β”‚ └── split.rs # Split view
β”œβ”€β”€ components/ # Reusable components
β”‚ β”œβ”€β”€ output_window.rs
β”‚ β”œβ”€β”€ agent_timeline.rs
β”‚ β”œβ”€β”€ telemetry_bar.rs
β”‚ β”œβ”€β”€ checkpoint_modal.rs
β”‚ β”œβ”€β”€ log_viewer.rs
β”‚ β”œβ”€β”€ loop_indicator.rs
β”‚ └── status_footer.rs
└── state/ # State management
β”œβ”€β”€ workflow_state.rs
β”œβ”€β”€ agent_state.rs
β”œβ”€β”€ telemetry_state.rs
β”œβ”€β”€ checkpoint_state.rs
└── mod.rs

API Reference​

App​

pub struct App {
pub should_quit: bool,
pub prompt_data: PromptData,
pub current_agent: Option<String>,
pub current_session: Option<String>,
pub setup_complete: bool,
pub available_commands: Vec<(&'static str, &'static str)>,
pub setup_wizard: Option<SetupWizard>,
pub workspace_status: Option<WorkspaceStatus>,
pub orchestration_service: Option<Arc<OrchestrationService>>,
pub orchestration_enabled: bool,
pub mcp_integration: Option<Arc<Mutex<McpIntegration>>>,
pub mcp_slash_registry: SlashCommandRegistry,
}

impl App {
pub fn new() -> Self;
pub async fn handle_key(&mut self, key: KeyCode, modifiers: KeyModifiers) -> Result<()>;
pub async fn execute_command(&mut self, cmd: Command) -> Result<()>;
pub async fn handle_orchestrated_input(&mut self, input: String) -> Result<()>;
pub async fn send_chat_message(&mut self, message: String) -> Result<()>;
}

PromptData​

pub struct PromptData {
pub context: DisplayContext,
pub input: String,
pub output: Vec<String>,
pub conversation: Vec<String>,
pub agents: Vec<(String, String)>,
pub sessions: Vec<(String, usize)>,
pub selected_index: usize,
pub command_suggestions: Vec<String>,
pub selected_suggestion_index: usize,
pub scrollback_offset: usize,
pub command_palette_active: bool,
pub command_palette_query: String,
}

impl PromptData {
pub fn new() -> Self;
pub fn push_char(&mut self, c: char);
pub fn pop_char(&mut self);
pub fn clear_input(&mut self);
pub fn add_output(&mut self, line: String);
pub fn clear_output(&mut self);
}

SetupWizard​

pub enum SetupState {
Welcome,
ProviderSelection { selected_providers: Vec<ProviderType>, cursor: usize },
ApiKeyInput { provider: ProviderType, input: String },
Validating { provider: ProviderType },
Complete,
}

pub struct SetupWizard {
pub state: SetupState,
pub error_message: Option<String>,
}

impl SetupWizard {
pub fn new() -> Self;
pub fn new_skip_welcome() -> Self;
pub fn is_needed() -> bool;
pub async fn handle_key(&mut self, key: KeyCode, modifiers: KeyModifiers) -> Result<bool>;
pub fn display_lines(&self) -> Vec<String>;
pub fn title(&self) -> String;
}

WorkflowUIState​

pub enum WorkflowStatus {
Idle,
Running,
Paused,
Completed,
Failed,
Cancelled,
}

pub struct WorkflowUIState {
pub workflow_id: String,
pub workflow_name: String,
pub status: WorkflowStatus,
pub start_time: Option<Instant>,
pub end_time: Option<Instant>,
pub current_step: usize,
pub total_steps: usize,
pub agents: HashMap<String, AgentState>,
pub output_buffer: OutputBuffer,
pub telemetry: TelemetryState,
pub checkpoint: CheckpointState,
pub error_message: Option<String>,
}

impl WorkflowUIState {
pub fn new(workflow_id: String, workflow_name: String, total_steps: usize) -> Self;
pub fn start(&mut self);
pub fn pause(&mut self);
pub fn resume(&mut self);
pub fn complete(&mut self);
pub fn fail(&mut self, error: String);
pub fn cancel(&mut self);
pub fn next_step(&mut self);
pub fn register_agent(&mut self, agent_id: String, agent_name: String);
pub fn progress_percentage(&self) -> u8;
}

Conclusion​

The TUI architecture follows a clear separation of concerns with modular components, state management, and view layers. The unified prompt interface provides a consistent user experience while supporting multiple display contexts. The event-driven, async architecture ensures responsive UI updates during AI interactions.

For questions or contributions, refer to the main project documentation and development guidelines.