toolkit/packages/skills/tui-style-guide/SKILL.md
TUI style guide for consistent terminal interface design
npx skillsauth add stevengonsalvez/agents-in-a-box tui-style-guideInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Premium styling patterns for agents-in-a-box TUI components.
// Core accent colors
const CORNFLOWER_BLUE: Color = Color::Rgb(100, 149, 237); // Primary accent, borders, section titles
const GOLD: Color = Color::Rgb(255, 215, 0); // Important CTAs, emphasis, highlights
const SELECTION_GREEN: Color = Color::Rgb(100, 200, 100); // Active selections, success states
const WARNING_ORANGE: Color = Color::Rgb(255, 165, 0); // Warnings, alternate modes
// Background colors
const DARK_BG: Color = Color::Rgb(25, 25, 35); // Main UI background
const INPUT_BG: Color = Color::Rgb(35, 35, 45); // Input field backgrounds
const PANEL_BG: Color = Color::Rgb(30, 30, 40); // Panel/nested container backgrounds
const LIST_HIGHLIGHT_BG: Color = Color::Rgb(40, 40, 60); // List item hover/selection
// Text colors
const SOFT_WHITE: Color = Color::Rgb(220, 220, 230); // Primary text
const MUTED_GRAY: Color = Color::Rgb(120, 120, 140); // Secondary text, hints
const MEDIUM_GRAY: Color = Color::Rgb(180, 180, 180); // Tertiary text
const DARK_GRAY: Color = Color::Rgb(100, 100, 100); // Disabled/faded text
// Accent/status colors
const PROGRESS_CYAN: Color = Color::Rgb(100, 200, 230); // Loading/processing
const LIGHT_BLUE: Color = Color::Rgb(100, 200, 255); // Info highlights
const SUBDUED_BORDER: Color = Color::Rgb(60, 60, 80); // Separator lines, secondary borders
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(CORNFLOWER_BLUE))
.style(Style::default().bg(DARK_BG))
.border_style(Style::default().fg(SELECTION_GREEN))
.border_style(Style::default().fg(SUBDUED_BORDER))
.title(Line::from(vec![
Span::styled(" folder_icon ", Style::default().fg(GOLD)),
Span::styled("Section Title",
Style::default().fg(GOLD).add_modifier(Modifier::BOLD))
]))
.title(Line::from(vec![
Span::styled(" Section ", Style::default().fg(SOFT_WHITE)),
Span::styled(
format!("({})", count),
Style::default().fg(CORNFLOWER_BLUE).add_modifier(Modifier::BOLD)
)
]))
// Prefix
Span::styled(" > ", Style::default().fg(SELECTION_GREEN))
// Text
Span::styled(&item_text,
Style::default()
.fg(SELECTION_GREEN)
.add_modifier(Modifier::BOLD))
// Prefix (spacing to align with selected)
Span::raw(" ")
// Text
Span::styled(&item_text, Style::default().fg(SOFT_WHITE))
.highlight_style(Style::default().bg(LIST_HIGHLIGHT_BG))
.highlight_symbol("> ")
| Status | Icon | Color | |--------|------|-------| | Running | Green circle | Green | | Stopped | Red circle | Red | | Idle | Yellow circle | Yellow | | Error | X mark | Red | | Success | Checkmark | Green | | Warning | Warning sign | Orange | | Info | Info sign | Cyan | | Loading | Refresh | Cyan |
Span::styled(
format!("[{}]", status_symbol),
Style::default()
.fg(status_color)
.add_modifier(Modifier::BOLD)
)
fn get_file_icon(filename: &str) -> &'static str {
match filename {
f if f.ends_with(".rs") => "rust",
f if f.ends_with(".py") => "python",
f if f.ends_with(".js") || f.ends_with(".jsx") => "js",
f if f.ends_with(".ts") || f.ends_with(".tsx") => "ts",
f if f.ends_with(".md") => "markdown",
f if f.ends_with(".json") => "json",
f if f.ends_with(".toml") || f.ends_with(".yaml") || f.ends_with(".yml") => "config",
f if f.ends_with(".sh") || f.ends_with(".bash") => "shell",
f if f.ends_with(".html") => "html",
f if f.ends_with(".css") || f.ends_with(".scss") => "css",
f if f.ends_with(".go") => "go",
f if f.ends_with(".java") => "java",
_ => "file",
}
}
// Folder icons
const FOLDER_ICON: &str = "folder";
const FOLDER_OPEN_ICON: &str = "folder-open";
// Expand/collapse indicators
const EXPANDED: &str = "v";
const COLLAPSED: &str = ">";
const LEAF: &str = ">";
// Tree lines
const TREE_BRANCH: &str = "|-";
const TREE_LAST: &str = "`-";
const TREE_VERTICAL: &str = "|";
Line::from(vec![
Span::styled("Up/Down", Style::default().fg(GOLD).add_modifier(Modifier::BOLD)),
Span::styled(" Navigate", Style::default().fg(MUTED_GRAY)),
Span::styled(" | ", Style::default().fg(SUBDUED_BORDER)),
Span::styled("Enter", Style::default().fg(GOLD).add_modifier(Modifier::BOLD)),
Span::styled(" Select", Style::default().fg(MUTED_GRAY)),
])
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(SELECTION_GREEN))
.style(Style::default().bg(INPUT_BG))
// Cursor character
Span::styled("_", Style::default().fg(SELECTION_GREEN))
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(SELECTION_GREEN))
.style(Style::default().bg(Color::Rgb(35, 45, 35))) // Green tint
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Rgb(70, 70, 90)))
.style(Style::default().bg(PANEL_BG))
const GIT_ADDED: Color = Color::Green;
const GIT_MODIFIED: Color = Color::Yellow;
const GIT_DELETED: Color = Color::Red;
const GIT_RENAMED: Color = Color::Blue;
const GIT_UNTRACKED: Color = Color::Magenta;
// Line prefixes
const DIFF_ADDITION: Color = Color::Green; // Lines starting with +
const DIFF_DELETION: Color = Color::Red; // Lines starting with -
const DIFF_HUNK: Color = Color::Cyan; // @@ lines
const DIFF_FILE_HEADER: Color = Color::Yellow; // +++ and --- lines
const DIFF_CONTEXT: Color = Color::White; // Unchanged lines
const MD_HEADING1: Style = Style::default()
.fg(Color::Cyan)
.add_modifier(Modifier::BOLD | Modifier::UNDERLINED);
const MD_HEADING2: Style = Style::default()
.fg(Color::Cyan)
.add_modifier(Modifier::BOLD);
const MD_HEADING3: Style = Style::default()
.fg(Color::Blue)
.add_modifier(Modifier::BOLD);
const MD_CODE_BLOCK: Style = Style::default()
.fg(Color::Green)
.bg(Color::Rgb(30, 30, 30));
const MD_CODE_HEADER: Style = Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::BOLD);
const MD_LINK: Style = Style::default()
.fg(Color::Blue)
.add_modifier(Modifier::UNDERLINED);
const MD_BLOCKQUOTE: Style = Style::default()
.fg(Color::Gray)
.add_modifier(Modifier::ITALIC);
Constraint::Length(N) for headers/footersConstraint::Min(0)use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, BorderType, List, ListItem, ListState, Paragraph, Tabs, Wrap},
Frame,
};
Usage: Reference this guide when styling new TUI components to maintain visual consistency across the application.
documentation
Report reflect drain spend over a time window — tokens split by cached (cache_read), uncached writes (cache_creation), and io (input+output), with a $ estimate, grouped by day / outcome / model / transcript. Reads the drainer's cost log and surfaces outlier runs and cache-reuse health (the 41.5M-token failure mode = low cache reuse + high cache writes). Use to answer "what is reflection costing me" for the last day / week.
development
Show fleet status — every claude session running on the host, merged across ainb + claude-peers broker + background jobs. Use when you need to enumerate sessions before composing an action, see which sessions have a peer registered (broker-routable) vs tmux-only, check the `summary` of each session, or pipe the list into jq for filtering. Default output: text table. Pass --format json for LLM consumption.
testing
Ordered multi-step prompts to fleet targets, ack-gated between steps via JSONL assistant-turn-end detection. Use for cycles like disconnect→reconnect→verify, or any flow where step N+1 requires step N to have completed first. The skill BLOCKS until each target's transcript shows the next assistant turn finishing OR per-step timeout fires (default 300s).
development
Center control panel — enumerate every claude session that is blocked waiting on something: a user answer (AskUserQuestion fired), an API error retry, an idle assistant turn-end with no follow-up, or an explicit WAITING: marker. Returns rich JSON with signal kind + context per session. Use this when you've stepped away from the fleet and want one place to see everything that wants your attention and answer it.