--- name: tui-validate description: Validates Terminal User Interface (TUI) output using freeze for screenshot capture and LLM-as-judge for semantic validation. Supports both visual (PNG/SVG) and text-based validation modes. type: anthropic-skill version: "1.0" metadata: internal: true --- # TUI Validate ## Overview This skill validates Terminal User Interface (TUI) applications by capturing their output and using LLM-as-judge for semantic validation. It leverages [freeze](https://github.com/charmbracelet/freeze) from Charmbracelet for high-fidelity terminal screenshots and provides structured validation criteria. **Philosophy**: Rather than brittle string matching, this skill uses semantic understanding to validate that TUI output "looks right" - checking layout, content presence, and visual hierarchy without breaking on minor formatting changes. ## When to Use - Validating TUI rendering after changes - Checking that UI components display correctly - Visual regression testing for terminal applications - Verifying TUI state after specific interactions - Creating documentation screenshots with validation ## Prerequisites **Required:** - `freeze` CLI tool installed (`brew install charmbracelet/tap/freeze`) - `tmux` for interactive TUI capture (optional, for live applications) **Verification:** ```bash # Check freeze is installed freeze --version # Check tmux is installed (for interactive capture) tmux -V ``` ## Parameters - **target** (required): What to validate. One of: - `file:` - ANSI output file to validate - `command:` - Command to execute and capture - `tmux:` - Live tmux session to capture - `buffer:` - Raw text/ANSI to validate - **criteria** (required): Validation criteria. Can be: - A predefined criteria name (see Built-in Criteria) - A custom criteria string describing what to check - **output_format** (optional, default: "svg"): Screenshot format - `svg` - Vector format, best for documentation - `png` - Raster format, best for visual diff - `text` - Text-only extraction, fastest - **save_screenshot** (optional, default: false): Whether to save the screenshot - If true, saves to `{target_name}.{format}` in current directory - **judge_mode** (optional, default: "semantic"): Validation approach - `semantic` - LLM judges based on meaning and layout - `strict` - Also checks exact content presence - `visual` - Requires PNG, checks visual appearance ## Built-in Criteria ### `ralph-header` Validates Ralph TUI header component: - Iteration counter in `[iter N]` or `[iter N/M]` format - Elapsed time in `MM:SS` format - Hat indicator with emoji and name - Mode indicator (`▶ auto` or `⏸ paused`) - Optional scroll mode indicator `[SCROLL]` - Optional idle countdown `idle: Ns` ### `ralph-footer` Validates Ralph TUI footer component: - Activity indicator (`◉ active`, `◯ idle`, or `■ done`) - Last event topic display - Search mode display when active ### `ralph-full` Validates complete Ralph TUI layout: - Header section at top (3 lines) - Terminal content area (variable height) - Footer section at bottom (3 lines) - Proper visual hierarchy and borders ### `tui-basic` Generic TUI validation: - Has visible content (not blank) - No rendering artifacts or broken characters - Proper terminal dimensions ## Execution Flow ### 1. Capture Phase Capture TUI output based on target type: **For file targets:** ```bash freeze {file_path} -o /tmp/tui-capture.{format} ``` **For command targets:** ```bash freeze --execute "{command}" -o /tmp/tui-capture.{format} ``` **For tmux targets:** ```bash tmux capture-pane -pet {session} | freeze -o /tmp/tui-capture.{format} ``` **For buffer targets:** ```bash echo "{buffer}" | freeze -o /tmp/tui-capture.{format} ``` **Constraints:** - You MUST verify freeze is installed before attempting capture - You MUST handle capture failures gracefully and report the error - You MUST use appropriate freeze flags for the output format - You SHOULD use `--theme base16` for consistent rendering - You SHOULD set reasonable dimensions with `--width` and `--height` ### 2. Extraction Phase Extract content for LLM analysis: **For text/semantic validation:** - If format is `text`, use the captured text directly - If format is `svg` or `png`, also capture text version for content analysis **For visual validation:** - Requires PNG format - Will analyze the image directly using vision capabilities **Constraints:** - You MUST extract both visual and text representations when judge_mode is `visual` - You MUST preserve ANSI escape sequences for color validation when relevant ### 3. Validation Phase Apply LLM-as-judge with the appropriate criteria: **Semantic Validation Prompt Template:** ``` Analyze this terminal UI output and determine if it meets the following criteria: CRITERIA: {criteria_description} TERMINAL OUTPUT: {captured_text} Evaluate each criterion and provide: 1. PASS or FAIL for each requirement 2. Brief explanation for any failures 3. Overall verdict: PASS or FAIL Be lenient on exact formatting but strict on: - Required content presence - Logical layout and hierarchy - No rendering errors or artifacts ``` **Visual Validation Prompt Template (with image):** ``` Examine this terminal screenshot and validate: CRITERIA: {criteria_description} Check for: 1. Visual hierarchy and layout 2. Color coding correctness 3. No rendering artifacts or broken characters 4. Proper alignment and spacing Verdict: PASS or FAIL with explanation ``` **Constraints:** - You MUST return a clear PASS or FAIL verdict - You MUST provide specific feedback on failures - You MUST be lenient on whitespace/formatting differences - You MUST be strict on content presence and semantic correctness - You SHOULD note any warnings even on PASS results ### 4. Reporting Phase Report validation results: **On PASS:** ``` ✅ TUI Validation PASSED Criteria: {criteria_name} Target: {target} Mode: {judge_mode} All requirements satisfied. {optional_notes} ``` **On FAIL:** ``` ❌ TUI Validation FAILED Criteria: {criteria_name} Target: {target} Mode: {judge_mode} Issues found: - {issue_1} - {issue_2} Screenshot saved: {path_if_saved} ``` **Constraints:** - You MUST always provide a clear verdict - You MUST list specific issues on failure - You MUST offer the screenshot path if saved - You SHOULD suggest fixes for common issues ## Examples ### Example 1: Validate Ralph Header from File **Input:** ``` /tui-validate file:test_output.txt criteria:ralph-header ``` **Process:** 1. Read `test_output.txt` containing ANSI output 2. Capture with freeze: `freeze test_output.txt -o /tmp/capture.svg` 3. Extract text content 4. Apply `ralph-header` criteria via LLM judge 5. Report PASS/FAIL with details ### Example 2: Validate Live TUI in tmux **Input:** ``` /tui-validate tmux:ralph-session criteria:ralph-full save_screenshot:true ``` **Process:** 1. Capture tmux pane: `tmux capture-pane -pet ralph-session | freeze -o ralph-session.svg` 2. Also capture text: `tmux capture-pane -pet ralph-session > /tmp/text.txt` 3. Apply `ralph-full` criteria checking header, content, and footer 4. Save screenshot to `ralph-session.svg` 5. Report validation result ### Example 3: Custom Criteria Validation **Input:** ``` /tui-validate command:"cargo run --example tui_demo" criteria:"Shows a bordered box with 'Hello World' text centered inside" output_format:png judge_mode:visual ``` **Process:** 1. Execute command and capture: `freeze --execute "cargo run --example tui_demo" -o /tmp/capture.png` 2. Use vision model to analyze PNG 3. Check for bordered box and centered text 4. Report visual validation result ### Example 4: Quick Text Validation **Input:** ``` /tui-validate buffer:"[iter 3/10] 04:32 | 🔨 Builder | ▶ auto" criteria:ralph-header output_format:text ``` **Process:** 1. Analyze text directly (no freeze needed for text mode with buffer) 2. Check for iteration format, elapsed time, hat, and mode indicator 3. Report validation result ## Criteria Definitions ### ralph-header (Full Definition) ```yaml name: ralph-header description: Ralph TUI header component validation requirements: - name: iteration_counter description: Shows iteration in [iter N] or [iter N/M] format required: true pattern: '\[iter \d+(/\d+)?\]' - name: elapsed_time description: Shows elapsed time in MM:SS format required: true pattern: '\d{2}:\d{2}' - name: hat_indicator description: Shows current hat with emoji prefix required: true examples: ["🔨 Builder", "📋 Planner", "🎯 Executor"] - name: mode_indicator description: Shows loop mode status required: true values: ["▶ auto", "⏸ paused"] - name: scroll_indicator description: Shows [SCROLL] when in scroll mode required: false pattern: '\[SCROLL\]' - name: idle_countdown description: Shows idle timeout when present required: false pattern: 'idle: \d+s' ``` ### ralph-footer (Full Definition) ```yaml name: ralph-footer description: Ralph TUI footer component validation requirements: - name: activity_indicator description: Shows current activity state required: true values: ["◉ active", "◯ idle", "■ done"] - name: event_topic description: Shows last event topic required: false examples: ["task.start", "build.done", "loop.terminate"] - name: search_display description: Shows search query and match count when searching required: false pattern: 'Search: .+ \d+/\d+' ``` ### ralph-full (Full Definition) ```yaml name: ralph-full description: Complete Ralph TUI layout validation requirements: - name: header_section description: Header at top with iteration, time, hat, and mode required: true references: ralph-header - name: content_section description: Main terminal content area required: true checks: - Has visible content or is ready for content - Properly bounded between header and footer - name: footer_section description: Footer at bottom with activity status required: true references: ralph-footer - name: visual_hierarchy description: Clear visual separation between sections required: true checks: - Borders or spacing between sections - Consistent width across sections ``` ## Troubleshooting ### freeze not found ```bash # macOS brew install charmbracelet/tap/freeze # Linux (via Go) go install github.com/charmbracelet/freeze@latest # Verify installation freeze --version ``` ### tmux capture fails - Ensure the tmux session exists: `tmux list-sessions` - Verify pane number: `tmux list-panes -t {session}` - Try capturing specific pane: `tmux capture-pane -pet {session}:{pane}` ### Rendering artifacts in capture - Try different terminal emulator settings in freeze - Use `--theme` flag for consistent colors - Ensure terminal dimensions match TUI expectations ### LLM judge too strict/lenient - Adjust criteria to be more specific - Use `strict` mode for exact matching requirements - Use `semantic` mode for layout/presence checking ## Integration with Tests This skill can be integrated into test suites: ```rust // In tests/tui_validation.rs #[test] #[ignore] // Run with: cargo test -- --ignored fn validate_header_rendering() { // 1. Render header to buffer let output = render_header_to_string(&test_state); // 2. Save to temp file std::fs::write("/tmp/header_test.txt", &output).unwrap(); // 3. Run tui-validate skill (via CLI or programmatic) // /tui-validate file:/tmp/header_test.txt criteria:ralph-header // 4. Assert validation passed } ``` ## Best Practices 1. **Use semantic validation for layout checks** - Don't break on minor formatting 2. **Use strict validation for content requirements** - Ensure critical info is present 3. **Save screenshots on failure** - Aids debugging 4. **Test with various terminal sizes** - TUIs should be responsive 5. **Combine with unit tests** - Use this for integration/visual validation, unit tests for logic