noturbob/slat

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.

Go

1

32 commits

updated Sep 21, 2026

See the code
cli
command-line
detach
developer-tools
go
golang
linux
multiplexer
productivity
pty
screen
session-manager
shell
terminal
terminal-emulator
terminal-multiplexer
tiling
tmux
tmux-alternative
tui

See what people are saying (1)

SourceMessageScoreDate

Slat, a terminal multiplexer I've been writing in Go for about a year. What's missing for you? (r/commandline)

Hi all. I started writing slat about a year ago, mostly because I wanted to understand how **Tmux** actually works rather than because the world needed another multiplexer. It grew into something I now use daily, and I'd like some honest opinions before I keep going. **What it does today**: tiling…

1

Sep 21, 2026

README

slat logo

slat

Split your terminal. Keep it running when you leave.

A terminal multiplexer with tiling panes, tabs and workspaces, written in Go.

Go License: MIT Platform Ko-fi

Website · Install · Keys · Configuration · How it works

slat splitting a terminal into panes, running htop and go test side by side, scrolling back and searching the output, then detaching and reattaching with everything still running


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.

  • Panes — split left/right or top/bottom, move between them by direction, swap, resize, zoom
  • Tabs and workspaces — group tabs into named workspaces, rename them in place
  • Detach and reattachd disconnects; running slat from any terminal reattaches
  • Scroll mode — page back through each pane's output and search it, vim-style
  • Every pane keeps its own screenclear, vim or htop in one pane never touch another, and nothing is lost when you split, close or switch
  • Fast — only changed cells are sent to your terminal; half a million lines of output render in about a third of a second
  • New panes open where you are — a split starts in the directory of the pane you split from (Linux)
  • Drivable from scripts and AI agentsslat ls, run, capture and wait --for idle let anything outside the terminal work a session and know when a pane needs a human (details)
  • Move panes around — walk a pane through the layout like a tiling window manager; the swap slides instead of jumping
  • Themes — five built-in palettes, or set any colour yourself
  • One checked config file — mistakes are reported when you run slat, not ignored

Install

PlatformHow
Debian / Ubuntusigned apt repository
Arch Linuxpackage from the latest release
Fedora / RHELone dnf command
macOS, anything with Gogo install
Try it without installingDocker

Every package comes for both amd64 and arm64.

Debian / Ubuntu

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
Key fingerprint, or install a single .deb instead

The 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

Arch Linux

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.

Windows

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.

Fedora / RHEL

sudo dnf install \
  https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.rpm

With Go

Works on Linux and macOS:

go install github.com/noturbob/slat/cmd/slat@latest
Other ways: prebuilt binaries, or build from source

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

Try it in Docker

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.)

First run

slat

The first run starts the background daemon; later runs attach to it. Press Ctrl+S then ? inside slat to see every key.

Keys

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.

Panes

KeyAction
v / hSplit left / right, top / bottom
o / ONext / previous pane
arrows, or k j H LPane above / below / left / right
sSwap with the next pane
mMove mode: h j k l walk the pane around, q leaves
< > K JMove the pane left / right / up / down
+ / -Grow / shrink the pane
=Equalize all sizes
zZoom the pane to full size (toggle)
xClose the pane
[ or PageUpScroll mode (see below)

Tabs

KeyAction
cNew tab
n / pNext / previous tab
19Go to tab N
,Rename the tab
XClose the tab and all its panes

Workspaces

KeyAction
WNew workspace
w / PNext / previous workspace
$Rename the workspace

Session

KeyAction
dDetach — the session keeps running
qQuit — ends every shell
?Show all keys

Scroll mode

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.

KeyAction
k j, arrowsUp / down a line
Ctrl-U Ctrl-D, u dUp / down half a page
Ctrl-B Ctrl-F, PageUp PageDown, b f spaceUp / down a page
g G, Home EndOldest output / live screen
/ ?Search up / down (a query with no capitals ignores case)
n NNext match in the same / opposite direction
q, EscLeave 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.

Scripting and agents

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
CommandWhat it does
slat lsevery 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 PANEclose 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:

  • idle — the pane's own shell has the terminal: the command finished.
  • working — a program is running.
  • input — something has gone quiet on a question ([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.
  • exited — the pane's program is gone.

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.

Configuration

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.
  • A mistake anywhere — an unknown colour, a glyph two columns wide, a placeholder that doesn't exist, an easing curve that doesn't either — is reported when you run slat, never quietly drawn.
  • Fonts belong to your terminal, not to slat. slat draws characters; which font paints them is Kitty's, Alacritty's or WezTerm's business. Point that at a Nerd Font and its glyphs work here like any other character.
  • Ready-made setups live in docs/rices/ — copy one and edit it, or send yours in.
  • Keybinds you don't set keep their defaults.
  • Giving a default key to another command takes it away from the default command, so bindings never silently collide.
  • An unknown setting, an unknown command name, a key that isn't a single character, or two commands on one key is an error, shown when you run slat.

config.example.toml lists every command with its default.

How it works

 terminal ── slat (client) ──unix socket──▶ slat daemon
   raw keys ─────────────────────────────▶   ├─ workspaces / tabs / layout tree
   ◀── only the changed cells ─────────────  ├─ per-pane terminal emulator
                                             └─ shells on PTYs
  • Daemon. The first 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.
  • Emulation. Each pane's output is fed into slat's own terminal emulator (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.
  • Rendering. On every change slat composes a frame from the panes, borders, status bar and overlays, compares it with what your terminal already shows, and sends only the difference. Since frames are built from state rather than patched step by step, a split, close, resize or reattach can't leave stale or missing text behind.
  • Input modes. The active pane's cursor-key mode and bracketed paste are mirrored onto your terminal, so arrow keys in vim and multi-line pastes into your shell behave as they do outside slat.

Source layout

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.

Limitations

  • Scroll mode can't select and copy text yet.
  • Mouse events aren't passed to programs in panes.
  • On Windows, ConPTY has no foreground process group, so a pane's status comes from output timing alone: 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.

Requirements

  • Go 1.23+ to build
  • Linux, macOS, or Windows 10 1809 and later

Support

slat is free and always will be. If it saves you time, you can buy me a coffee on Ko-fi.

License

MIT

Contributors

noturbob

32 commits

noturbob/slat

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.

Go

1

32 commits

updated Sep 21, 2026

See the code
cli
command-line
detach
developer-tools
go
golang
linux
multiplexer
productivity
pty
screen
session-manager
shell
terminal
terminal-emulator
terminal-multiplexer
tiling
tmux
tmux-alternative
tui

See what people are saying (1)

SourceMessageScoreDate

Slat, a terminal multiplexer I've been writing in Go for about a year. What's missing for you? (r/commandline)

Hi all. I started writing slat about a year ago, mostly because I wanted to understand how **Tmux** actually works rather than because the world needed another multiplexer. It grew into something I now use daily, and I'd like some honest opinions before I keep going. **What it does today**: tiling…

1

Sep 21, 2026

README

slat logo

slat

Split your terminal. Keep it running when you leave.

A terminal multiplexer with tiling panes, tabs and workspaces, written in Go.

Go License: MIT Platform Ko-fi

Website · Install · Keys · Configuration · How it works

slat splitting a terminal into panes, running htop and go test side by side, scrolling back and searching the output, then detaching and reattaching with everything still running


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.

  • Panes — split left/right or top/bottom, move between them by direction, swap, resize, zoom
  • Tabs and workspaces — group tabs into named workspaces, rename them in place
  • Detach and reattachd disconnects; running slat from any terminal reattaches
  • Scroll mode — page back through each pane's output and search it, vim-style
  • Every pane keeps its own screenclear, vim or htop in one pane never touch another, and nothing is lost when you split, close or switch
  • Fast — only changed cells are sent to your terminal; half a million lines of output render in about a third of a second
  • New panes open where you are — a split starts in the directory of the pane you split from (Linux)
  • Drivable from scripts and AI agentsslat ls, run, capture and wait --for idle let anything outside the terminal work a session and know when a pane needs a human (details)
  • Move panes around — walk a pane through the layout like a tiling window manager; the swap slides instead of jumping
  • Themes — five built-in palettes, or set any colour yourself
  • One checked config file — mistakes are reported when you run slat, not ignored

Install

PlatformHow
Debian / Ubuntusigned apt repository
Arch Linuxpackage from the latest release
Fedora / RHELone dnf command
macOS, anything with Gogo install
Try it without installingDocker

Every package comes for both amd64 and arm64.

Debian / Ubuntu

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
Key fingerprint, or install a single .deb instead

The 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

Arch Linux

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.

Windows

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.

Fedora / RHEL

sudo dnf install \
  https://github.com/noturbob/slat/releases/latest/download/slat_linux_amd64.rpm

With Go

Works on Linux and macOS:

go install github.com/noturbob/slat/cmd/slat@latest
Other ways: prebuilt binaries, or build from source

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

Try it in Docker

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.)

First run

slat

The first run starts the background daemon; later runs attach to it. Press Ctrl+S then ? inside slat to see every key.

Keys

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.

Panes

KeyAction
v / hSplit left / right, top / bottom
o / ONext / previous pane
arrows, or k j H LPane above / below / left / right
sSwap with the next pane
mMove mode: h j k l walk the pane around, q leaves
< > K JMove the pane left / right / up / down
+ / -Grow / shrink the pane
=Equalize all sizes
zZoom the pane to full size (toggle)
xClose the pane
[ or PageUpScroll mode (see below)

Tabs

KeyAction
cNew tab
n / pNext / previous tab
19Go to tab N
,Rename the tab
XClose the tab and all its panes

Workspaces

KeyAction
WNew workspace
w / PNext / previous workspace
$Rename the workspace

Session

KeyAction
dDetach — the session keeps running
qQuit — ends every shell
?Show all keys

Scroll mode

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.

KeyAction
k j, arrowsUp / down a line
Ctrl-U Ctrl-D, u dUp / down half a page
Ctrl-B Ctrl-F, PageUp PageDown, b f spaceUp / down a page
g G, Home EndOldest output / live screen
/ ?Search up / down (a query with no capitals ignores case)
n NNext match in the same / opposite direction
q, EscLeave 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.

Scripting and agents

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
CommandWhat it does
slat lsevery 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 PANEclose 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:

  • idle — the pane's own shell has the terminal: the command finished.
  • working — a program is running.
  • input — something has gone quiet on a question ([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.
  • exited — the pane's program is gone.

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.

Configuration

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.
  • A mistake anywhere — an unknown colour, a glyph two columns wide, a placeholder that doesn't exist, an easing curve that doesn't either — is reported when you run slat, never quietly drawn.
  • Fonts belong to your terminal, not to slat. slat draws characters; which font paints them is Kitty's, Alacritty's or WezTerm's business. Point that at a Nerd Font and its glyphs work here like any other character.
  • Ready-made setups live in docs/rices/ — copy one and edit it, or send yours in.
  • Keybinds you don't set keep their defaults.
  • Giving a default key to another command takes it away from the default command, so bindings never silently collide.
  • An unknown setting, an unknown command name, a key that isn't a single character, or two commands on one key is an error, shown when you run slat.

config.example.toml lists every command with its default.

How it works

 terminal ── slat (client) ──unix socket──▶ slat daemon
   raw keys ─────────────────────────────▶   ├─ workspaces / tabs / layout tree
   ◀── only the changed cells ─────────────  ├─ per-pane terminal emulator
                                             └─ shells on PTYs
  • Daemon. The first 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.
  • Emulation. Each pane's output is fed into slat's own terminal emulator (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.
  • Rendering. On every change slat composes a frame from the panes, borders, status bar and overlays, compares it with what your terminal already shows, and sends only the difference. Since frames are built from state rather than patched step by step, a split, close, resize or reattach can't leave stale or missing text behind.
  • Input modes. The active pane's cursor-key mode and bracketed paste are mirrored onto your terminal, so arrow keys in vim and multi-line pastes into your shell behave as they do outside slat.

Source layout

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.

Limitations

  • Scroll mode can't select and copy text yet.
  • Mouse events aren't passed to programs in panes.
  • On Windows, ConPTY has no foreground process group, so a pane's status comes from output timing alone: 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.

Requirements

  • Go 1.23+ to build
  • Linux, macOS, or Windows 10 1809 and later

Support

slat is free and always will be. If it saves you time, you can buy me a coffee on Ko-fi.

License

MIT

Contributors

noturbob

32 commits

Languages

Go

71.4%

TypeScript

21.2%

CSS

3.3%

Roff

2.1%