A fast terminal multiplexer in Go: tiling panes, tabs and workspaces that keep running after you close the window. Detach, reattach, scroll back and search. A lighter tmux with sane defaults.
See the codeSplit your terminal. Keep it running when you leave.
A terminal multiplexer with tiling panes, tabs and workspaces, written in Go.
Website · Install · Keys · Configuration · How it works
slat tiles one terminal into panes, tabs and workspaces. Your shells live in a
small background process, so closing the window — or losing the SSH
connection — doesn't end anything. Run slat again and it's all there,
output included.
d disconnects; running slat from any terminal reattachesclear, vim or htop in one pane never touch another, and nothing is lost when you split, close or switchslat ls, run, capture and wait --for idle let anything outside the terminal work a session and know when a pane needs a human (details)slat, not ignored| Platform | How |
|---|---|
| Debian / Ubuntu | signed apt repository |
| Arch Linux | package from the latest release |
| Fedora / RHEL | one dnf command |
| macOS, anything with Go | go install |
| Try it without installing | Docker |
Every package comes for both amd64 and arm64.
Add the repository once; after that, apt upgrade keeps slat up to date.
# 1. Trust the repository's signing key
curl -fsSL https://noturbob.github.io/slat/apt/slat.gpg \
| sudo tee /usr/share/keyrings/slat.gpg > /dev/null
# 2. Add the repository
repo=https://noturbob.github.io/slat/apt
echo "deb [signed-by=/usr/share/keyrings/slat.gpg] $repo stable main" \
| sudo tee /etc/apt/sources.list.d/slat.list
# 3. Install
sudo apt update
sudo apt install slat
.deb insteadThe repository key's fingerprint is:
9040 A503 5BDC A04A 55C3 719A D1A8 1309 D2F2 0668
To install one release without adding the repository:
curl -LO https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.deb
sudo apt install ./slat_linux_amd64.deb
curl -LO https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.pkg.tar.zst
sudo pacman -U slat_linux_amd64.pkg.tar.zst
An AUR package (yay -S slat) is on the way.
Download slat_windows_amd64.zip from the
latest release, unzip it and
put slat.exe on your PATH. Windows 10 1809 or later is required (that's when
ConPTY arrived). Panes run cmd.exe by default; for something else:
# %USERPROFILE%\.config\slat\config.toml
shell = "powershell.exe"
Windows Terminal is recommended — the old conhost window can't render everything slat draws.
sudo dnf install \
https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.rpm
Works on Linux and macOS:
go install github.com/noturbob/slat/cmd/slat@latest
Prebuilt binaries for Linux and macOS are on the releases page.
To build from a checkout:
make build # ./bin/slat
make install # into $(go env GOPATH)/bin
docker run -it --rm ghcr.io/noturbob/slat
The shells run inside the container, not on your machine, and the container stops when you detach, so this is for trying slat out. Install it natively for real use. (The image is published from the next release onwards.)
slat
The first run starts the background daemon; later runs attach to it. Press Ctrl+S then ? inside slat to see every key.
Press the prefix (default Ctrl+S), then one key. Everything else goes straight to your shell — including Ctrl+C. Press the prefix twice to send it to the shell. Prefix then ? shows every key inside slat.
| Key | Action |
|---|---|
v / h | Split left / right, top / bottom |
o / O | Next / previous pane |
arrows, or k j H L | Pane above / below / left / right |
s | Swap with the next pane |
m | Move mode: h j k l walk the pane around, q leaves |
< > K J | Move the pane left / right / up / down |
+ / - | Grow / shrink the pane |
= | Equalize all sizes |
z | Zoom the pane to full size (toggle) |
x | Close the pane |
[ or PageUp | Scroll mode (see below) |
| Key | Action |
|---|---|
c | New tab |
n / p | Next / previous tab |
1–9 | Go to tab N |
, | Rename the tab |
X | Close the tab and all its panes |
| Key | Action |
|---|---|
W | New workspace |
w / P | Next / previous workspace |
$ | Rename the workspace |
| Key | Action |
|---|---|
d | Detach — the session keeps running |
q | Quit — ends every shell |
? | Show all keys |
Prefix then [ (or PageUp) shows the active pane's earlier output. The view
stays put while new output arrives. Your mouse wheel scrolls too, in terminals
that send arrow keys for it.
| Key | Action |
|---|---|
k j, arrows | Up / down a line |
Ctrl-U Ctrl-D, u d | Up / down half a page |
Ctrl-B Ctrl-F, PageUp PageDown, b f space | Up / down a page |
g G, Home End | Oldest output / live screen |
/ ? | Search up / down (a query with no capitals ignores case) |
n N | Next match in the same / opposite direction |
q, Esc | Leave scroll mode |
Each pane keeps 2000 lines by default (scrollback in the config). Full-screen
programs like vim and less use their own screen and add nothing to it, and
clear wipes it, as in most terminals.
In a rename prompt: Enter saves, Esc or Ctrl+C cancels, Ctrl+U clears.
The session ends by itself when its last shell exits. Closing the last tab of a workspace removes just that workspace.
Every command below talks to a running session over its socket, so scripts — and AI coding agents — can drive slat without a terminal attached. Nothing is sent anywhere: slat has no network code.
$ slat ls
*1 idle 1:shell bash ~/src/slat
2 working 1:build go ~/src/slat
$ slat pane new --cmd 'go test ./...' # new pane, your focus stays put
$ slat wait 3 --for idle --timeout 5m # block until it finishes
$ slat capture 3 --lines 20 # read what it printed
| Command | What it does |
|---|---|
slat ls | every pane, with what each one is doing |
slat status [PANE] | one pane's status |
slat pane new [--split v|h] [--cwd D] [--cmd C] [--target P] [--focus] | split a pane |
slat pane close PANE | close a pane |
slat send PANE TEXT [--enter] [--key KEY] | type into a pane |
slat run PANE COMMAND... | send a command and press Enter |
slat capture PANE [--lines N] [--history] | read a pane's text |
slat wait PANE --for idle|input|exit|text=REGEX [--timeout 60s] | block until something happens |
PANE is an id from slat ls, or active (the default). --json on any
command prints one object with a schema field. Exit codes: 0 ok,
1 error, 2 timed out, 3 that pane is gone.
A pane's status is one of four, which is what makes wait useful:
[y/N], a password
prompt), so an agent waiting for a build wakes up instead of hanging. Shell
builtins count: read -p "Overwrite? [y/N] " is detected even though the
shell itself is the foreground process, because the line doesn't end the way
a prompt does.When a pane starts waiting for input, its tab is marked 2:shell ? in the
status bar, and slat can run a command so you don't have to watch:
[agent]
on_input = "notify-send \"slat: pane %p needs input\" %c"
%p is the pane id, %t its tab, %s the status and %c the pane's last
line. Values are shell-quoted for you, so a prompt containing a quote stays
text. The hook runs detached; its output goes to the daemon log, never to your
screen.
Tune the detection under [agent] in the config; see
docs/design/agent-cli.md for the full design.
slat reads ~/.config/slat/config.toml (or $XDG_CONFIG_HOME/slat/config.toml).
Every setting is optional:
prefix = "C-a" # Ctrl + a letter, or C-\ C-] C-^ C-_
shell = "/bin/zsh" # default: $SHELL
status_bar = true
scrollback = 5000 # lines kept per pane; 0 turns it off
animations = true # false turns every animation off
[agent] # how `slat status` reads a pane (see above)
settle = "750ms" # quiet for this long after output = idle
input_after = "10s" # quiet for this long on a prompt = waiting for input
[theme]
name = "gruvbox" # default, gruvbox, nord, rose-pine, mono
accent = "#fabd2f" # override any single colour
[borders]
style = "rounded" # sharp, rounded, heavy, double, dashed, none
# vertical = "┃" # …or set any glyph yourself
[animation]
split = "90ms" # a new pane appearing; 0 turns it off
move = "120ms" # two panes trading places
easing = "out-cubic" # linear, out-quad, out-cubic, out-back
reveal = "curtain" # curtain or none
glyph = "░"
[status]
left = " {workspace} │ {tabs}"
right = "{badge} pane {pane}/{panes} {time} "
tab = " {index}:{name}{alert} "
alert = " ●"
[keybinds]
split-vertical = "|"
split-horizontal = "-"
resize-shrink = "_" # "-" was given away above
zoom = "" # "" unbinds a command
[theme] colours are bg, fg, dim, accent, border, tab_bg,
tab_fg, tab_active_bg and tab_active_fg, written as a colour name, a
palette index (0-255) or #rrggbb. Only what slat draws is themed — pane
contents keep whatever colours the programs in them use.[status] takes left, right, tab and alert. The sides accept
{workspace} {workspace_index} {workspace_count} {workspaces} {tabs}
{tab} {tabs_count} {pane} {panes} {badge} {time} {seconds}
{date}; tab accepts {index} {name} {alert}. Everything else is
literal text, so a Nerd Font glyph goes straight in — and each placeholder is
drawn in the colour that suits it, so there's no colour markup to write.slat, never quietly drawn.docs/rices/ — copy one and edit it,
or send yours in.slat.config.example.toml lists every command with its default.
terminal ── slat (client) ──unix socket──▶ slat daemon
raw keys ─────────────────────────────▶ ├─ workspaces / tabs / layout tree
◀── only the changed cells ───────────── ├─ per-pane terminal emulator
└─ shells on PTYs
slat re-executes itself as a background daemon that owns
every shell. Its socket lives in $XDG_RUNTIME_DIR (or the temp dir) and is
only accessible to you. Attaching from a second terminal takes over from the
first, like tmux attach -d. The daemon's own errors go to the .log file
next to its socket.internal/vt), which keeps that pane's screen. It handles the xterm features
shells and full-screen programs use: colors (16, 256 and 24-bit), wide
characters and emoji, scroll regions, the alternate screen, line drawing and
cursor queries.cmd/slat/ entry point: starts or attaches to the daemon
internal/
daemon/ socket server, attach / detach, session lifetime
client/ raw mode, alternate screen, stdin/stdout ⇄ daemon
proto/ length-prefixed frames from client to daemon
app/ the session: input → actions, frame composition
vt/ terminal emulator for each pane
ui/ frame, diffing renderer, status bar, help, borders
session/ workspaces, tabs, focus, removing dead panes
layout/ binary-tree tiling
pane/ a shell on a PTY with its emulator
input/ prefix key and command table
config/ TOML loading and validation
docs/ the website (GitHub Pages)
packaging/aur/ the AUR package
packaging/apt/ builds the signed apt repository
Releases are built by GoReleaser when a v* tag is pushed:
binaries, .deb, .rpm and Arch packages for Linux and macOS on amd64 and arm64.
The release then republishes the website and the apt repository to GitHub Pages
(pages.yml), signed with the APT_GPG_PRIVATE_KEY secret.
make test runs go vet and the tests with the race detector. The tests in
internal/app drive real shells through splits, closes, overlays and
workspace changes and check what a terminal would display.
slat status says idle or working, never
which program is running, and slat ls shows the directory a pane started
in rather than where its shell has since moved.slat is free and always will be. If it saves you time, you can buy me a coffee on Ko-fi.
MIT
32 commits
Go
71.4%
TypeScript
21.2%
CSS
3.3%
Roff
2.1%
A fast terminal multiplexer in Go: tiling panes, tabs and workspaces that keep running after you close the window. Detach, reattach, scroll back and search. A lighter tmux with sane defaults.
See the codeSplit your terminal. Keep it running when you leave.
A terminal multiplexer with tiling panes, tabs and workspaces, written in Go.
Website · Install · Keys · Configuration · How it works
slat tiles one terminal into panes, tabs and workspaces. Your shells live in a
small background process, so closing the window — or losing the SSH
connection — doesn't end anything. Run slat again and it's all there,
output included.
d disconnects; running slat from any terminal reattachesclear, vim or htop in one pane never touch another, and nothing is lost when you split, close or switchslat ls, run, capture and wait --for idle let anything outside the terminal work a session and know when a pane needs a human (details)slat, not ignored| Platform | How |
|---|---|
| Debian / Ubuntu | signed apt repository |
| Arch Linux | package from the latest release |
| Fedora / RHEL | one dnf command |
| macOS, anything with Go | go install |
| Try it without installing | Docker |
Every package comes for both amd64 and arm64.
Add the repository once; after that, apt upgrade keeps slat up to date.
# 1. Trust the repository's signing key
curl -fsSL https://noturbob.github.io/slat/apt/slat.gpg \
| sudo tee /usr/share/keyrings/slat.gpg > /dev/null
# 2. Add the repository
repo=https://noturbob.github.io/slat/apt
echo "deb [signed-by=/usr/share/keyrings/slat.gpg] $repo stable main" \
| sudo tee /etc/apt/sources.list.d/slat.list
# 3. Install
sudo apt update
sudo apt install slat
.deb insteadThe repository key's fingerprint is:
9040 A503 5BDC A04A 55C3 719A D1A8 1309 D2F2 0668
To install one release without adding the repository:
curl -LO https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.deb
sudo apt install ./slat_linux_amd64.deb
curl -LO https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.pkg.tar.zst
sudo pacman -U slat_linux_amd64.pkg.tar.zst
An AUR package (yay -S slat) is on the way.
Download slat_windows_amd64.zip from the
latest release, unzip it and
put slat.exe on your PATH. Windows 10 1809 or later is required (that's when
ConPTY arrived). Panes run cmd.exe by default; for something else:
# %USERPROFILE%\.config\slat\config.toml
shell = "powershell.exe"
Windows Terminal is recommended — the old conhost window can't render everything slat draws.
sudo dnf install \
https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.rpm
Works on Linux and macOS:
go install github.com/noturbob/slat/cmd/slat@latest
Prebuilt binaries for Linux and macOS are on the releases page.
To build from a checkout:
make build # ./bin/slat
make install # into $(go env GOPATH)/bin
docker run -it --rm ghcr.io/noturbob/slat
The shells run inside the container, not on your machine, and the container stops when you detach, so this is for trying slat out. Install it natively for real use. (The image is published from the next release onwards.)
slat
The first run starts the background daemon; later runs attach to it. Press Ctrl+S then ? inside slat to see every key.
Press the prefix (default Ctrl+S), then one key. Everything else goes straight to your shell — including Ctrl+C. Press the prefix twice to send it to the shell. Prefix then ? shows every key inside slat.
| Key | Action |
|---|---|
v / h | Split left / right, top / bottom |
o / O | Next / previous pane |
arrows, or k j H L | Pane above / below / left / right |
s | Swap with the next pane |
m | Move mode: h j k l walk the pane around, q leaves |
< > K J | Move the pane left / right / up / down |
+ / - | Grow / shrink the pane |
= | Equalize all sizes |
z | Zoom the pane to full size (toggle) |
x | Close the pane |
[ or PageUp | Scroll mode (see below) |
| Key | Action |
|---|---|
c | New tab |
n / p | Next / previous tab |
1–9 | Go to tab N |
, | Rename the tab |
X | Close the tab and all its panes |
| Key | Action |
|---|---|
W | New workspace |
w / P | Next / previous workspace |
$ | Rename the workspace |
| Key | Action |
|---|---|
d | Detach — the session keeps running |
q | Quit — ends every shell |
? | Show all keys |
Prefix then [ (or PageUp) shows the active pane's earlier output. The view
stays put while new output arrives. Your mouse wheel scrolls too, in terminals
that send arrow keys for it.
| Key | Action |
|---|---|
k j, arrows | Up / down a line |
Ctrl-U Ctrl-D, u d | Up / down half a page |
Ctrl-B Ctrl-F, PageUp PageDown, b f space | Up / down a page |
g G, Home End | Oldest output / live screen |
/ ? | Search up / down (a query with no capitals ignores case) |
n N | Next match in the same / opposite direction |
q, Esc | Leave scroll mode |
Each pane keeps 2000 lines by default (scrollback in the config). Full-screen
programs like vim and less use their own screen and add nothing to it, and
clear wipes it, as in most terminals.
In a rename prompt: Enter saves, Esc or Ctrl+C cancels, Ctrl+U clears.
The session ends by itself when its last shell exits. Closing the last tab of a workspace removes just that workspace.
Every command below talks to a running session over its socket, so scripts — and AI coding agents — can drive slat without a terminal attached. Nothing is sent anywhere: slat has no network code.
$ slat ls
*1 idle 1:shell bash ~/src/slat
2 working 1:build go ~/src/slat
$ slat pane new --cmd 'go test ./...' # new pane, your focus stays put
$ slat wait 3 --for idle --timeout 5m # block until it finishes
$ slat capture 3 --lines 20 # read what it printed
| Command | What it does |
|---|---|
slat ls | every pane, with what each one is doing |
slat status [PANE] | one pane's status |
slat pane new [--split v|h] [--cwd D] [--cmd C] [--target P] [--focus] | split a pane |
slat pane close PANE | close a pane |
slat send PANE TEXT [--enter] [--key KEY] | type into a pane |
slat run PANE COMMAND... | send a command and press Enter |
slat capture PANE [--lines N] [--history] | read a pane's text |
slat wait PANE --for idle|input|exit|text=REGEX [--timeout 60s] | block until something happens |
PANE is an id from slat ls, or active (the default). --json on any
command prints one object with a schema field. Exit codes: 0 ok,
1 error, 2 timed out, 3 that pane is gone.
A pane's status is one of four, which is what makes wait useful:
[y/N], a password
prompt), so an agent waiting for a build wakes up instead of hanging. Shell
builtins count: read -p "Overwrite? [y/N] " is detected even though the
shell itself is the foreground process, because the line doesn't end the way
a prompt does.When a pane starts waiting for input, its tab is marked 2:shell ? in the
status bar, and slat can run a command so you don't have to watch:
[agent]
on_input = "notify-send \"slat: pane %p needs input\" %c"
%p is the pane id, %t its tab, %s the status and %c the pane's last
line. Values are shell-quoted for you, so a prompt containing a quote stays
text. The hook runs detached; its output goes to the daemon log, never to your
screen.
Tune the detection under [agent] in the config; see
docs/design/agent-cli.md for the full design.
slat reads ~/.config/slat/config.toml (or $XDG_CONFIG_HOME/slat/config.toml).
Every setting is optional:
prefix = "C-a" # Ctrl + a letter, or C-\ C-] C-^ C-_
shell = "/bin/zsh" # default: $SHELL
status_bar = true
scrollback = 5000 # lines kept per pane; 0 turns it off
animations = true # false turns every animation off
[agent] # how `slat status` reads a pane (see above)
settle = "750ms" # quiet for this long after output = idle
input_after = "10s" # quiet for this long on a prompt = waiting for input
[theme]
name = "gruvbox" # default, gruvbox, nord, rose-pine, mono
accent = "#fabd2f" # override any single colour
[borders]
style = "rounded" # sharp, rounded, heavy, double, dashed, none
# vertical = "┃" # …or set any glyph yourself
[animation]
split = "90ms" # a new pane appearing; 0 turns it off
move = "120ms" # two panes trading places
easing = "out-cubic" # linear, out-quad, out-cubic, out-back
reveal = "curtain" # curtain or none
glyph = "░"
[status]
left = " {workspace} │ {tabs}"
right = "{badge} pane {pane}/{panes} {time} "
tab = " {index}:{name}{alert} "
alert = " ●"
[keybinds]
split-vertical = "|"
split-horizontal = "-"
resize-shrink = "_" # "-" was given away above
zoom = "" # "" unbinds a command
[theme] colours are bg, fg, dim, accent, border, tab_bg,
tab_fg, tab_active_bg and tab_active_fg, written as a colour name, a
palette index (0-255) or #rrggbb. Only what slat draws is themed — pane
contents keep whatever colours the programs in them use.[status] takes left, right, tab and alert. The sides accept
{workspace} {workspace_index} {workspace_count} {workspaces} {tabs}
{tab} {tabs_count} {pane} {panes} {badge} {time} {seconds}
{date}; tab accepts {index} {name} {alert}. Everything else is
literal text, so a Nerd Font glyph goes straight in — and each placeholder is
drawn in the colour that suits it, so there's no colour markup to write.slat, never quietly drawn.docs/rices/ — copy one and edit it,
or send yours in.slat.config.example.toml lists every command with its default.
terminal ── slat (client) ──unix socket──▶ slat daemon
raw keys ─────────────────────────────▶ ├─ workspaces / tabs / layout tree
◀── only the changed cells ───────────── ├─ per-pane terminal emulator
└─ shells on PTYs
slat re-executes itself as a background daemon that owns
every shell. Its socket lives in $XDG_RUNTIME_DIR (or the temp dir) and is
only accessible to you. Attaching from a second terminal takes over from the
first, like tmux attach -d. The daemon's own errors go to the .log file
next to its socket.internal/vt), which keeps that pane's screen. It handles the xterm features
shells and full-screen programs use: colors (16, 256 and 24-bit), wide
characters and emoji, scroll regions, the alternate screen, line drawing and
cursor queries.cmd/slat/ entry point: starts or attaches to the daemon
internal/
daemon/ socket server, attach / detach, session lifetime
client/ raw mode, alternate screen, stdin/stdout ⇄ daemon
proto/ length-prefixed frames from client to daemon
app/ the session: input → actions, frame composition
vt/ terminal emulator for each pane
ui/ frame, diffing renderer, status bar, help, borders
session/ workspaces, tabs, focus, removing dead panes
layout/ binary-tree tiling
pane/ a shell on a PTY with its emulator
input/ prefix key and command table
config/ TOML loading and validation
docs/ the website (GitHub Pages)
packaging/aur/ the AUR package
packaging/apt/ builds the signed apt repository
Releases are built by GoReleaser when a v* tag is pushed:
binaries, .deb, .rpm and Arch packages for Linux and macOS on amd64 and arm64.
The release then republishes the website and the apt repository to GitHub Pages
(pages.yml), signed with the APT_GPG_PRIVATE_KEY secret.
make test runs go vet and the tests with the race detector. The tests in
internal/app drive real shells through splits, closes, overlays and
workspace changes and check what a terminal would display.
slat status says idle or working, never
which program is running, and slat ls shows the directory a pane started
in rather than where its shell has since moved.slat is free and always will be. If it saves you time, you can buy me a coffee on Ko-fi.
MIT
32 commits
Go
71.4%
TypeScript
21.2%
CSS
3.3%
Roff
2.1%