The original mrxvt was a tabbed terminal emulator written in C, popular in the mid-2000s for being lighter than gnome-terminal and more featureful than xterm. Its killer feature was input broadcasting: type in one tab, send the keystrokes to all of them simultaneously. Perfect for managing clusters of servers.
It was also unmaintained by 2008, had no UTF-8 support worth speaking of, and crashed on malformed escape sequences.
rs-mrxvt is a from-scratch Rust rewrite that keeps the mrxvt soul — tabs, broadcasting, lightweight, power-user-oriented — and modernizes everything else. It runs on any Linux distro, picks the best available rendering backend automatically, and ships with the creature comforts you'd expect from a 2020s terminal: a command palette, true-color themes, hot-reloading Lua config, inline images, and clickable hyperlinks.
Design goals
- Distro-agnostic. No assumptions about package managers, init systems, or display servers. One
sysprep.shdetects your distro and installs the right deps. The default TUI backend works on anything that can runratatui— even over SSH with no display. - Backend auto-detect. The renderer picks the best available option at startup:
wgpu(Vulkan) →wgpu(GL) →softbuffer(CPU raster, the modern VESA mode) → TUI (always works). - Memory-safe core. The original mrxvt was plagued by buffer overflows. Rust's borrow checker eliminates that class of bug by construction.
- Feature-flagged. Build only what you need.
--features luaadds dynamic config;--features imagesadds Sixel + iTerm2 image protocol;--features gpuadds the wgpu + softbuffer renderers. The default build has zero system graphics dependencies.
The killer feature, reborn
Input broadcasting works exactly as you remember it, plus a modern twist. Three modes:
- Active — input goes to the focused tab only (default).
- All — input goes to every open tab. The status bar turns red and shows
● BROADCAST:All. Toggle with Ctrl+Shift+I. - Group — input goes only to tabs tagged with a specific name. Tag tabs with
-g <name>on the CLI or via the command palette. Useful for "broadcast to all my web servers but not the database tab".
The classic flag is preserved: rs-mrxvt -n 5 -j -g web opens 5 tabs tagged "web" with broadcast on. Type apt update && apt upgrade -y once, watch it run on all five.
Keybindings (modern + classic)
Both schools of muscle memory are honored:
| Shortcut | Action | Style |
|---|---|---|
| Alt+N | New bash tab | Modern |
| Alt+Z | New zsh tab | Modern |
| Alt+Shift+X | Close focused tab | Modern |
| Alt+1 … Alt+0 | Go to tab 1..10 | Classic mrxvt |
| Alt+← / Alt+→ | Shuffle prev/next tab | Modern |
| Ctrl+Shift+T | New tab | Classic mrxvt |
| Ctrl+Shift+W | Close tab | Classic mrxvt |
| Ctrl+Shift+I | Toggle broadcast | Classic mrxvt |
| Ctrl+Shift+P | Command palette | Modern (Warp/VS Code style) |
All bindings are rebindable in config.toml or config.lua.
The command palette
Press Ctrl+Shift+P and a fuzzy-search overlay appears over the terminal. Every command — new tab, close tab, toggle broadcast, reset terminal, switch theme — is searchable by name. No more memorizing obscure chords.
This is the Warp / VS Code influence. The classic mrxvt had hidden shortcuts; rs-mrxvt surfaces them all in a discoverable UI.
Configuration: TOML today, Lua tomorrow (today)
Two config formats, picked automatically by file extension:
TOML — for static config
[terminal]
cols = 120
rows = 40
shell = "/bin/bash"
[ui]
theme = "tokyo-night"
[profiles.default]
command = ["bash"]
[profiles.zsh]
command = ["zsh"]
[profiles.web-1]
command = ["ssh", "user@web-01.example.com"]
tag = "web"
[transparency]
enabled = true
tint = "#004080"
opacity = 0.85
Lua — for dynamic config
Requires --features lua. The same config, but with logic:
local hour = tonumber(os.date("%H"))
local theme = "mrxvt"
if hour >= 20 or hour < 6 then
theme = "tokyo-night"
end
local is_ssh = os.getenv("SSH_CLIENT") ~= nil
local shell = is_ssh and "/bin/sh" or "/bin/bash"
return {
ui = { theme = theme },
terminal = { cols = 120, rows = 40, shell = shell },
profiles = {
default = { command = { shell } },
zsh = { command = { "zsh" } },
},
}
Config files hot-reload on save — no restart needed. The polling watcher survives bad configs (logs a warning, keeps the last good config).
Themes
Six built-in true-color themes:
| Theme | Vibe |
|---|---|
mrxvt | Classic green-on-black (default) |
tokyo-night | Dark blue, popularized by VS Code |
gruvbox | Warm retro palette |
dracula | Dark purple |
solarized-dark | Solarized Dark |
solarized-light | Solarized Light |
Custom themes can be defined inline in TOML — all 16 ANSI colors plus bg/fg/cursor.
Image protocol support
With --features images, rs-mrxvt understands both major inline-image protocols:
- iTerm2 inline images (
ESC ] 1337 ; File = ...) — PNG, JPEG, GIF, WebP, BMP. Compatible withranger,neofetch,chafa,viu. - Sixel (
DCS q ... ST) — the old DEC format, still used bymltermandxterm -ti vt340. The parser is pure Rust.
Images are stored in a thread-safe ImageStore keyed by ID; the renderer composites them at the appropriate cell coordinates.
Hyperlinks
OSC 8 (ESC ] 8 ; ... ST) lets programs mark ranges of cells as clickable hyperlinks. ls --hyperlink=auto, modern gcc diagnostics, and various TUI file managers use this. rs-mrxvt has a streaming scanner that extracts these from the PTY byte stream and a cell-indexed store for fast hit-testing.
Mouse support
Three mouse reporting modes — X10, X11 normal, SGR-1006 — are all implemented. When the child program enables reporting, mouse events are encoded and forwarded. When it hasn't, mouse events drive local text selection (click-drag to select, release to copy).
Performance
Each tab runs its own reader thread with a bounded channel, so one tab's heavy output never blocks the UI thread. The wgpu backend renders the full terminal grid with an instanced quad pipeline (one draw call per frame) and a lazily-uploaded glyph atlas.
Distro support
The sysprep.sh script auto-detects your distro and installs the right packages:
| Distro family | Package manager |
|---|---|
| Arch, Manjaro, EndeavourOS, Garuda, Artix | pacman |
| Debian, Ubuntu, Pop!_OS, Mint, Elementary, Kali, Raspbian | apt |
| Fedora, RHEL, Rocky, Alma, CentOS, Amazon Linux | dnf |
| openSUSE, SUSE Linux Enterprise | zypper |
| Void | xbps-install |
| Alpine | apk |
| NixOS | prints a shell.nix recipe |
| SourceMage | cast |
| Gentoo, Funtoo | emerge |
One command from a fresh checkout to a system-installed binary:
sudo ./install.sh --sysprep
The architecture in one paragraph
The app owns a TerminalManager (vec of TerminalTabs, each with a PTY + an alacritty_terminal::Term + a reader thread), an InputRouter (translates key chords to Commands or raw bytes), a PaletteState (command palette), and a SessionState (mouse, selection, hyperlinks, images). The renderer is a trait — TuiRenderer (ratatui + crossterm) is the default; WgpuRenderer (Vulkan/GL) and SoftRenderer (CPU raster via tiny-skia) are opt-in. Auto-detect probes in priority order: wgpu → soft → tui. Every backend translates its native events into AppEvent at the renderer boundary, so the app loop is fully backend-agnostic.
Try it
# Clone the repo, then:
./scripts/sysprep.sh # install build deps for your distro
./scripts/build.sh # cargo build --release --features lua,images,gpu
./target/release/rs-mrxvt # run it
# Or in one shot:
sudo ./install.sh --sysprep
For the full feature list and config schema, see the README. For a 60-second tour, see the Quick Start.