Linux · macOS · Android in Termux

A tiling window manager for the terminal.

i3's container tree and Hyprland's dwindle placement, where every window is a PTY. Sessions, workspaces, a floating layer and a scratchpad, driven by a leader key and a modal WM mode, configured in Lua and themed in TOML.

欄間

ranma, named for the 欄間: the carved transom panel above sliding doors. A lattice framed in wood, with light coming through it.

curl -fsSL https://masshirodev.github.io/ranma/install.sh | sh

Run it again to update. Or apt, dnf, the AUR, Homebrew, Nix, cargo or npm: every channel.

ranma: nvim in a large pane beside a shell running tests and a tail of pacman.log, the bar on top with workspaces, the focused workspace's panes and system modules

The leader is Ctrl+b, the key tmux uses.

Press it and let go, and ranma enters WM mode: the keys you press now go to ranma instead of the program in the pane. Wait half a second and a panel lists what each key does. Esc leaves it.

The leader is a setting, like everything else: ranma.set { leader = "ctrl+a" }. man ranma-keys lists the rest.

1 · first steps
leader t
open a pane next to the focused one
leader ←↓↑→
move focus (Alt+arrows without the leader)
leader q
close the focused pane
leader 1…0
go to workspace 1-10 (Alt+1…0)
leader w
float the pane, or put it back
leader d
detach: ranma keeps running
leader ?
every key, searchable
leader :
run any action by name
leader p
the settings panel

What it does

A daily driver: every milestone of the roadmap is done. Six panels, the way the README groups them.

1 · tiling

Panes place themselves.

Dwindle splits the focused pane along its longer side, like Hyprland. Or group panes into tabs, float one over the tiling, keep a scratchpad, or lay a workspace out as niri's strip of scrolling columns. Window rules and saved layouts on top.

dwindle
tabbed
floating
scratchpad
scrolling
2 · sessions

Close the terminal. Nothing closes.

ranma runs as a server: closing the terminal, or losing SSH, only detaches, and ranma again picks up where you were. Workspaces and sessions with fuzzy switchers. An upgrade moves running servers to the new build without closing anything.

3 · copy mode

Copy from history, over SSH too.

Copy mode is alacritty's vi mode, with history search. What you yank reaches the system clipboard by OSC 52, from a pane on the far side of an SSH connection as well. Files paste into a pane that runs ssh.

4 · images and keys

The kitty protocols, both of them.

Images draw in panes with the kitty graphics protocol. The kitty keyboard protocol works both ways, so a program asking for exact keys gets them. Outside WM mode bytes pass through raw; a paste is trusted to bracketed paste, not guessed.

5 · the bar

waybar's shape, without waybar's config.

Modules in Lua or shell, left, centre and right. Run ranma inside ranma and the nested ones share the outer bar rather than stack their own. Toasts from ranma notify when a build finishes.

The bar from the README screenshot: a ranma label, workspaces 1 nvim, 2 zsh, 3 vps, the focused workspace's panes, and cpu, memory, host and clock modules

From the screenshot's configuration, below.

6 · mobile

A phone can drive it.

While a phone drives the screen, ranma switches to a mobile view built from scriptable pieces. And it runs on the phone itself, in Termux.

plugins

Plain Lua on the same API as init.lua, in Neovim's layout. hako comes with ranma and installs them; leader L, then B, browses the official list. A plugin that fails while loading is dropped whole; a watchdog stops one that hangs.

Configured in Lua, themed in TOML.

The configuration behind the screenshot, as it is in doc/examples/screenshot. Lua for behaviour, TOML for looks. Both are parsed strictly: a name ranma doesn't know is an error that names it.

1 · init.lua
ranma.set { theme = "sumi" } -- themes/sumi.toml, beside this file

-- The left pill: a fixed label. The built-in `session` module would show the
-- session's name, but only once there is more than one session.
ranma.module("label", {
  render = function()
    return { text = "ranma", style = "accent" }
  end,
})
⋯
ranma.module("cpu", { format = "\u{f4bc} %s" }) -- nf-oct-cpu
ranma.module("mem", { format = "\u{f035b} %s" }) -- nf-md-memory
ranma.module("clock", {
  interval = 60,
  render = function()
    return "\u{f43a} " .. os.date("%H:%M") -- nf-oct-clock
  end,
})

ranma.bar {
  left = { "label", "workspaces" },
  center = { "pane_strip" },
  right = { "cpu", "mem", "host", "clock" },
}
2 · themes/sumi.toml
# sumi — ink, washi paper and hinoki wood. The airy variant.
#
#   ink      #141317  ground            washi    #e8e1d3  text
#   hinoki   #d9a55b  focus / accent    ai       #7b93c9  floats, tabs
#   shu      #e0533d  WM mode / urgent  matcha   #9db37a  occupied
#   kasumi   #6e665c  dim               sumi-2   #2a2724  module pills

[colors]
border_active = "#d9a55b" 
border_inactive = "#3a3631" 
border_floating = "#7b93c9" 
bar_bg = "default"
bar_fg = "#e8e1d3" 
bar_dim = "#6e665c" 
bar_accent = "#d9a55b" 
bar_urgent = "#e0533d" 
⋯
[border]
style = "rounded"
floating_style = "double"
title = "top"
title_align = "left"
title_format = " {index} · {title} "

ranma --dump-config prints the default, with every option documented.

ranma --check-config checks yours and its theme.

CONFIG.md, also man 5 ranma

Why not tmux, zellij or tuios?

They are good, and you may want one of them instead. ranma gets where it is mostly by refusing scope, not by out-engineering anyone.

tmux

Use tmux where it is already installed on every machine you touch. ranma keeps its leader, its five preset layouts and the things people style in it, and adds a window manager's tree: dwindle placement, a floating layer, a scratchpad. A tmux shim covers a stated subset for programs that drive tmux; matching tmux feature for feature is a non-goal.

zellij

zellij is a whole workspace with its own interface and WebAssembly plugins. ranma takes its shape from tiling window managers instead: i3's tree, Hyprland's placement, niri's columns. Its plugins are plain Lua on the same API as your init.lua.

tuios

tuios is the model for the feel: a terminal that behaves like a window manager. ranma makes different trade-offs and keeps its scope small:

  • one process, one copy of each grid, queues bounded by bytes
  • a server that owns everything, and a client that holds nothing
  • bytes pass through raw outside WM mode; bracketed paste is trusted, not guessed
what ranma refuses to be
  • Not reboot-proof. A snapshot brings back sessions, layouts and commands as new processes; the old ones are gone.
  • Not remote. No remote hosts, SSH or web servers, no clients keeping copies of the layout in step.
  • No AI in the core. A Lua hook can do that for someone who wants it.
  • Not native Windows. WSL2 is the Windows story. Not the BSDs yet either.
  • Not tmux. What it took from tmux it took in its own terms.

DESIGN.md records every decision and what it rules out.

Linux (x86_64, aarch64), macOS (Apple silicon, Intel) and Android in Termux (aarch64), into ~/.local. Run it again to update; it checks the new binary against your config and moves running servers onto it.

curl -fsSL https://masshirodev.github.io/ranma/install.sh | sh

Or with a package manager

Every channel ships the same release binary, except cargo install and Nix, which build it.

apt · Debian 12+, Ubuntu 22.04+
sudo install -d /etc/apt/keyrings
curl -fsSL https://masshirodev.github.io/ranma/ranma.asc | sudo tee /etc/apt/keyrings/ranma.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/ranma.asc] https://masshirodev.github.io/ranma/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/ranma.list
sudo apt update && sudo apt install ranma
Signed; the key and repository stay on GitHub Pages.
dnf · Fedora, RHEL 9+, openSUSE
sudo curl -fsSL -o /etc/yum.repos.d/ranma.repo https://masshirodev.github.io/ranma/ranma.repo
sudo dnf install ranma
# openSUSE:
sudo zypper addrepo https://masshirodev.github.io/ranma/ranma.repo && sudo zypper install ranma
The last line is openSUSE’s, with zypper.

Then

Start it with ranma, and press Ctrl+b ? for every key. The man pages come with every install: man ranma, man 5 ranma, man ranma-keys.

After a package-manager upgrade

A package manager replaces the binary but doesn't check it or move servers. Shells and scrollback stay: ranma --check-config && ranma upgrade --all

Platforms

Linux with glibc 2.34+ (musl builds from source), WSL2, macOS arm64 and Intel, Termux on aarch64. Not the BSDs or native Windows. Details