Skip to content

ralph-tui

Terminal UI for real-time Ralph monitoring.

Overview

ralph-tui provides:

  • Real-time iteration display
  • Hat and event status
  • Agent output streaming
  • Interactive controls

Built with ratatui.

Features

Header Display

Shows current orchestration state:

  • Iteration count: [iter 3]
  • Elapsed time: 00:02:15
  • Active hat emoji and name: 🔨 Builder
  • Mode indicator

Content Area

Displays agent output with:

  • Real-time streaming
  • Syntax highlighting
  • Scroll support

Shows activity status:

  • Activity indicator: â—‰ (active), â—¯ (idle), â–  (stopped)
  • Current event topic
  • Search display (if active)

Usage

The TUI is enabled by default with ralph run:

# TUI mode (default)
ralph run

# Disable TUI
ralph run --no-tui

Key Bindings

Key Action
q Quit
↑/↓ Scroll output
PgUp/PgDn Page scroll
Home/End Jump to start/end
/ Search
n Next search result
N Previous search result

Programmatic Use

TUI Application

use ralph_tui::TuiApp;

let app = TuiApp::new();
app.run().await?;

TUI Stream Handler

For integration with adapters:

use ralph_tui::TuiStreamHandler;
use tokio::sync::mpsc;

let (tx, rx) = mpsc::channel(100);
let handler = TuiStreamHandler::new(tx);

// Handler sends UxEvents to TUI

UX Events

Events from the orchestrator to TUI:

use ralph_proto::UxEvent;

enum UxEvent {
    TerminalWrite(String),
    Resize { width: u16, height: u16 },
    FrameCapture(Vec<u8>),
    IterationStart(usize),
    HatSelected(String),
    EventPublished(String),
}

Widgets

Header Widget

use ralph_tui::widgets::Header;

let header = Header::new()
    .iteration(3)
    .elapsed(Duration::from_secs(135))
    .hat("🔨 Builder")
    .mode("hat-based");
use ralph_tui::widgets::Footer;

let footer = Footer::new()
    .activity(Activity::Active)
    .event_topic("build.done")
    .search_query(None);

Content Widget

use ralph_tui::widgets::Content;

let content = Content::new()
    .text(&output)
    .scroll(scroll_position);

Customization

Colors

use ralph_tui::theme::Theme;

let theme = Theme {
    header_bg: Color::Rgb(30, 30, 46),
    header_fg: Color::Rgb(205, 214, 244),
    active_indicator: Color::Green,
    // ...
};

Layout

use ralph_tui::Layout;

let layout = Layout {
    header_height: 3,
    footer_height: 2,
    // content fills remaining space
};

Error Handling

pub enum TuiError {
    IoError(std::io::Error),
    RenderError(String),
    EventError(String),
}

Example: Custom TUI Integration

use ralph_tui::{TuiApp, TuiStreamHandler};
use ralph_adapters::PtyExecutor;
use tokio::sync::mpsc;

#[tokio::main]
async fn main() -> Result<()> {
    // Create channel for TUI updates
    let (tx, rx) = mpsc::channel(100);

    // Create TUI handler for adapter
    let handler = TuiStreamHandler::new(tx);

    // Spawn TUI in separate task
    let tui_handle = tokio::spawn(async move {
        let app = TuiApp::with_receiver(rx);
        app.run().await
    });

    // Execute backend with TUI handler
    let executor = PtyExecutor::new();
    executor.execute(&backend, &prompt, Box::new(handler)).await?;

    // Wait for TUI to finish
    tui_handle.await??;

    Ok(())
}

TUI Validation

For testing TUI rendering, use the /tui-validate skill:

/tui-validate file:output.txt criteria:ralph-header

See Testing & Validation for details.