ratto
Ratatui-powered terminal primitives for shell dashboards. The binary is rat.
ratto is a small CLI in the spirit of gum,
built for one job gum doesn't cover: scripts that act as live dashboards —
watching long-running jobs, rendering progress, and repainting flicker-free.
It keeps gum's scripting ergonomics (results on stdout, UI on the terminal,
meaningful exit codes) and adds the terminal-control plumbing you'd otherwise
hand-roll in every watcher script.
Ratto is Italian for rat — a nod to ratatui, which does the rendering under the hood (this project is not affiliated with ratatui).
# The pitch, in one line: a flicker-free dashboard loop with zero escape codes.
Install
Works in any shell; examples here are plain bash, and examples/
has full scripts in bash, zsh, fish, and PowerShell. Synchronized-output repainting
uses terminal mode 2026 (Ghostty, Kitty, Alacritty, WezTerm, iTerm2, Windows
Terminal, …). Terminals without it just ignore the escapes — everything still
works. Check yours with rat doctor.
The dashboard toolkit
rat watch — run a command on an interval, repaint in place
Cursor hiding, synchronized frames, redraw-only-on-change, height capping,
and terminal restore on exit/ctrl-c are all built in. ANSI colors from the
child pass through untouched. Piped output degrades to plain text, so
rat watch ... | tee log stays readable.
While watching: q quits, and v (or Enter) opens the full untruncated
frame in your pager — resolved bat-style from RAT_PAGER, then PAGER,
then less (with -R ensured so colors survive; quit the pager and the
watch resumes). On Windows, when less isn't installed the stock
more.com steps in. When output is taller than the screen, the truncation
line says so: … 12 more lines · v views all · q quits.
rat frame — flicker-free repaint for script-owned loops
When you want your own loop, pipe each frame's content through rat frame:
while ; do
{
} |
done
Unchanged frames write nothing; changed frames repaint in place; a terminal
resize forces a clean repaint. rat frame begin / rat frame end emit raw
synchronized-output escapes for full manual control.
rat bar — progress bars without the arithmetic
# release recovery ██████████████████████████████░░ 1242/1288 96.4% running
Batch mode reads label<TAB>value<TAB>total[<TAB>state] rows and aligns one
label column automatically:
|
# build ████████████████░░░░ 8/10 80.0% tests
# deploy ████░░░░░░░░░░░░░░░░ 2/10 20.0% waiting
Color by completion band instead of picking colors in the caller, or animate an unknown total:
Presets: --preset blocks|shade|ascii|line|dots.
rat spark — sparklines
|
rat duration / rat date — time, portably
Same flags on macOS and Linux — no more date -j -u -f '%Y-%m-%dT%H:%M:%SZ'.
rat style / rat log — styled text
Colors survive command substitution — capability is detected from the
terminal, never from stdout, so banner=$(rat style --bold hi) keeps its
escapes even though stdout is a pipe. (This is the opposite of
grep --color=auto, on purpose: capturing styled text is the whole point.)
Under the default --color auto, output goes plain only when:
- there is no terminal at all —
/dev/ttycannot be opened and stderr is not a tty (cron, CI runners, fully detached processes); NO_COLORis set (wins over everything, includingCLICOLOR_FORCE);CLICOLOR=0is set (unlessCLICOLOR_FORCEoverrides it);CIis set — CI logs are treated as not-a-terminal;TERMisdumb, unset, or names no color support.
--color always and --color never beat the environment entirely: an
explicit flag outranks ambient variables, so always colors at full
TERM depth even under NO_COLOR or in CI, and never always strips.
To strip ANSI coming from other programs, pipe through a bare
rat style: input escapes are removed by default and an empty style adds
nothing back.
Interactive prompts
The gum staples, rendering to /dev/tty so stdout stays clean:
fruit=
names= # space selects, enter confirms
&& name=
pw=
branch=
Exit codes everywhere: 0 success, 1 no selection / negative / error,
2 usage error, 124 timeout (--timeout 30s), 130 ctrl-c, and
rat spin forwards the child's code.
A complete dashboard
#!/usr/bin/env bash
Runnable versions of this — plus the interactive prompts chained together —
live in examples/ for bash, zsh, fish, and PowerShell.
Differences from gum
rat is not gum-complete, on purpose. It is gum's scripting primitives plus
the dashboard toolkit above.
- Not ported:
table,join,format,write,file,pager— none of them earn their keep in a dashboard script. - Added:
bar,spark,watch,frame,doctor,duration,date. - Named colors are accepted (
--foreground red); gum silently drops them. - UI goes to
/dev/ttywith an stderr fallback, so prompts survive2>/dev/null; gum writes UI to stderr only. rat filterquits on one Esc press; gum needs two.rat spinuses pipes, not a PTY; children that only colorize on a tty getCLICOLOR_FORCE=1instead.--color alwaystrustsTERMeven when piped, so forced color keeps its full depth in scripts and CI.- Box-model styling (
--border,--margin, padding, alignment) is not implemented.
Windows
ratto builds and runs on Windows (PowerShell, Windows Terminal, conhost,
or ssh'd into from any terminal). The UI stream uses CONOUT$ where unix
uses /dev/tty; watch --shell runs through %COMSPEC% /C; synchronized
output works in Windows Terminal and is harmlessly ignored by legacy
conhost. Two notes:
- The
vkey inwatchprefersless.exeon PATH (Git for Windows, scoop, and winget all provide one) and falls back to the stockmore.com, with the console held in UTF-8 while the pager runs so glyphs render correctly; setRAT_PAGERto override. rat frame's default state file is keyed per terminal session; when running several dashboards in one console session, pass--state.
Exit codes
| Situation | Code |
|---|---|
| Success | 0 |
Esc / nothing selected / confirm no / error |
1 |
| Usage error | 2 |
spin child exited N |
N |
--timeout expired |
124 |
| Ctrl-C | 130 |