Skip to content

Repository files navigation

Katu

CI License: MIT GitHub

A minimalist terminal multiplexer with first-class AI context.

Katu replaces cryptic multiplexer flags with semantic verbs: start, join, list, stop. Sessions survive disconnects. Each session exposes its own AI context file through KATU_AI_CONTEXT, so your AI assistant switches context when you switch sessions — without Katu ever talking to an AI API itself.

Two katu windows with a vertical and horizontal split, and the katu status bar showing window tabs, clock, battery, and session name

Status: early development. Sessions, attach/detach, pane splits, windows, capture, AI context injection, AI agent management, session persistence (katu resurrect), and copy mode work. See PRD.md for the product vision and docs/manual.md for the complete command, keybinding, and configuration reference.

Why "Katu"

Katu is Tupi-Guarani for "good," "proper," or "well made" — the standard a tool has to meet before it earns a place in a terminal you live in all day. Katu started as a personal itch: tmux does everything, but I wanted something smaller, built around the two things I actually do — juggle panes and run AI agents — with nothing else demanding to be configured first. It's built for that use, but nothing about it is private; anyone who wants a minimalist multiplexer with agent-awareness built in from the start is welcome to it.

Quick start

The very first katu you ever run writes a default katu.toml, prints three lines confirming it, and drops you straight into a main session — no setup wizard. Every run after that is just this:

katu                     # attach to the last session, or create "main"
katu start api           # create and attach to session "api"
katu join api            # attach to an existing session
katu list                # show all sessions
katu split               # split the current pane side by side
katu split --horizontal  # split the current pane top/bottom
katu window new          # open a new window (tab)
katu stop api            # kill one session
katu stop --all          # kill the server and every session
katu reload              # apply katu.toml changes without restarting anything
katu resurrect           # recreate sessions saved at the last clean shutdown
katu completions fish > ~/.config/fish/completions/katu.fish  # or bash/zsh/elvish/powershell

Detach with ctrl+space then d. The shell keeps running in the background.

Keybindings

Defaults are my preference keybinding Alt chords, with a ctrl+space prefix for the rest:

Keys Action
alt \ Split pane side by side
alt - Split pane stacked
alt h/j/k/l Focus the pane in that direction
alt H/J/K/L Move the nearest divider left/down/up/right
alt z Zoom: toggle the pane to full window
alt q Close the pane (kills its shell)
alt Q Close the window and all its panes
alt n New window
alt 19 Jump to window by tab number
alt y Copy mode: browse history, select, and yank (see below)
alt < / alt > Scroll the pane in front up / down. In a popup, alt k / alt j (vim) scroll it too
alt p Toggle the scratch-shell popup
alt a Toggle the AI popup
alt u Agent picker popup (fzf, jumps on enter)
alt r Toggle the HTTP request tool popup (see Testing APIs)
alt s Session switcher popup: pick a session, or type a new name to create one
prefix d Detach (session keeps running)
prefix n / p Next / previous window
prefix o Focus next pane
prefix = / - Grow / shrink the pane inside its split
prefix 19 Jump to window by tab number

Every action is rebindable (see Configuration): values take the form alt + <key> or prefix + <key>. Case matters for Alt (alt + H is Alt+Shift+h); alt + [, alt + ], and alt + O are reserved by terminal escape sequences.

A pane closes when its shell exits; the sibling pane takes over the space.

Switching sessions

alt s opens a session switcher — a bordered popup the client draws itself (no external picker, no dependency) — without ever detaching to your shell: type to filter, arrows or ctrl+p/ctrl+k (up) and ctrl+n/ctrl+j (down) to move, Enter to act on whatever's highlighted, Esc to cancel and stay exactly where you were. The session you're switching from always shows a filled , even though it's technically already detached by the time the popup draws. "Create a new session" only ever appears as its own explicit row below any matches — typing an existing session's name never risks silently duplicating it, and creating one always shows exactly what will happen before you press Enter. This is also how katu start <name>/katu join <name> behave when you're already inside a session — attaching directly isn't possible from a nested shell (there's no OS-level channel from a process inside a pane to the client bridging your terminal), so the error message points you at alt s instead.

The session switcher popup listing main (current), web, and api with window counts and idle times

Persistence

katu stop --all (or a server restart via SIGTERM) writes every running session's windows and splits — with each pane's working directory — to ~/.katu/sessions.json before it exits. Run katu resurrect afterward (it starts the server if needed) to recreate them: same windows, same splits, same directories, fresh shells — agent windows come back running the AI command again rather than a plain shell, and resume the actual conversation if [ai] resume_flag is set. Sessions already running under a saved name are left alone, so running it again is always safe.

This is v1 and deliberately minimal: no scrollback, no popup state, no zoom, and no autosave — only a clean shutdown saves anything, so a crash isn't covered. AI context needs no special handling: context files are already keyed by session name alone, so a resurrected session reconnects to its existing KATU_AI_CONTEXT file automatically.

Testing APIs

katu http (or alt r inside a session) opens a small request tool in the brand palette: cycle the method, type a URL, add headers, edit the body in $EDITOR, and send. Status, timing, size, and a pretty-printed JSON body (server field order preserved) come back in a scrollable viewer that treats a 500 as a result to inspect, not an error.

The katu HTTP request tool popup with labelled method, url, and body fields and a keybinding footer

{{base_url}}-style variables resolve at send time against switchable environments (e), defined globally in ~/.katu/http/environments.toml or per project in a committable .katu/http.toml. The UI and every file on disk keep the raw templates — tokens live only in your environment files. Every send lands in a filterable history (h), and S saves the request to a hand-editable TOML collection (c to browse).

As a popup, hiding it with alt r keeps the drafted request alive — the same trick as the AI popup; katu http --window gives it a full window instead. See docs/manual.md for every key and file format.

Status line

Four themes ship with Katu:

  • katu (default) — Katu's own palette: Jenipapo (#1A1C19) background and Palha (#E5DFD3) text for a calm, high-contrast bar over long sessions; Urucum (#C85A3C) marks the active window and the session block, the same restraint a tiling WM gives an active border; Mata (#4A6B53) and Ocre (#D9A05B) carry inactive tabs, separators, and the clock/battery — support colors that never compete with the accent. Window tabs with a per-process Nerd Font icon and the pane's directory on the left; date, clock, battery, and session name on the right, refreshed every second. Needs a Nerd Font and a truecolor terminal.
  • shugyo — an IBM Carbon dark bar, otherwise laid out the same as katu.
  • craftzdog — a pixel-faithful clone of the classic Solarized-dark tmux statusline: session:window.pane and username in flat color blocks on the left, window tabs in the middle (the active tab gets a two-tone cream/yellow block), hostname on the right. No icons, no separators — plain truecolor only, no font requirements.
  • minimal — a plain reverse-video bar that works on any terminal.
The four status-line themes compared: katu, shugyo, craftzdog, and minimal, each showing the same two windows

By default the bar appears only when you have more than one window (status_bar = "auto").

Copy mode

alt y opens copy mode: a cursor over the pane's history (1000 lines) that you can move, select from, and yank to your system clipboard — no mouse required. The [copy n] badge shows the scrollback offset; it becomes [copy n selecting] once you've marked a selection.

Copy mode with a multi-line selection highlighted and the [copy 0 selecting] badge in the top-right corner
Keys Action
/ k, / j Move the cursor up/down a line, paging the view as needed
/ h, / l Move the cursor left/right a column
PgUp / PgDn Page up / down
g / G Jump to the oldest / newest line
v Mark the selection anchor here (press again to cancel it)
y Yank the selection to your system clipboard (via OSC 52) and exit
q, Esc Exit copy mode

Copying uses OSC 52, the same terminal-native clipboard escape tmux and others use — it needs a terminal that supports it (ghostty, wezterm, kitty, alacritty, and foot all do), but needs nothing else: no xclip/wl-copy, no dependency, and it works exactly the same over SSH.

A selection can span more than one screen — extend it by paging with k/j/PgUp/PgDn — but only as far as the far end (the anchor) stays representable on the current screen; once extending further would push it off-screen, that direction just stops. Selecting across many screens in one continuous move isn't supported in this first pass.

AI context

Every session gets a private context file:

$ katu join api
$ echo "$KATU_AI_CONTEXT"
/home/you/.katu/ai-contexts/api.json

External AI CLIs read and write that file; switching sessions switches the file. To hand your assistant the current terminal output:

katu capture | claude "explain this database lock error"

AI agents

Katu manages parallel AI agents natively (inspired by tmux-claude-session-manager):

katu ai              # toggle a floating AI popup inside a session, or start
                     # a dedicated ai-<dir> session for the current directory
katu agents          # list agents inside katu: status, name, age, location
katu agents --pick   # fzf picker; enter jumps to the agent's pane

alt a toggles the AI popup: a floating pane over your work, tmux display-popup style. Hiding it keeps the agent running. alt u opens the agent picker in a popup, and alt p gives you a scratch-shell popup. The status line marks any window hosting an agent with a robot icon colored by state — yellow when the agent is waiting for your input, red while busy, green when idle — so a glance at the bar tells you which agent needs attention. Agent discovery uses claude agents --json (Claude Code ≥ 2.1.139); the command is configurable via [ai] command.

Claude Code renders its transcript inline and doesn't track the mouse, so its history lands in the pane's terminal scrollback. In the AI popup, alt k / alt j (or alt < / alt >) page back through that output — vim-style, no mouse needed. A mouse-tracking full-screen app (less, htop) gets wheel events from the same keys instead, so it scrolls its own viewport.

The AI popup floating over an editor, showing an agent waiting for input
The agent picker listing three agents (waiting, busy, idle) with a live output preview of the highlighted one
A floating scratch-shell popup hovering over a full-screen editor session

When an agent transitions to waiting for you, katu also sends an OSC 9 terminal notification ([ai] notify, on by default) — so you don't have to keep glancing at the bar to know an agent anywhere in the session needs attention. Needs a terminal that supports OSC 9 (iTerm2, wezterm, kitty, and foot do); unsupported terminals just ignore it.

katu resurrect (see Persistence) restores an agent window as an agent again, not a plain shell. Set [ai] resume_flag (e.g. "--continue" for Claude Code) to also resume the actual conversation for that pane's restored directory — off by default, since an unrecognized flag could stop an arbitrary configured [ai] command from starting at all.

Configuration

Optional TOML file at ~/.config/katu/katu.toml:

[ui]
theme = "katu"           # katu (default) | shugyo | craftzdog (tmux-style) | minimal
status_bar = "auto"      # auto | visible | hidden

[ai]
context_directory = "~/.katu/ai-contexts/"
command = "claude"             # launched by `katu ai` and prefix + a
notify = true                  # OSC 9 notification when an agent starts waiting on you
resume_flag = ""                # e.g. "--continue" to resume agent panes on `katu resurrect`

[bindings]
prefix = "ctrl+space"
detach = "prefix + d"
split_vertical = "alt + \\"    # side by side
split_horizontal = "alt + -"   # stacked
window_new = "alt + n"
window_next = "prefix + n"
window_prev = "prefix + p"
window_close = "alt + Q"
pane_focus_left = "alt + h"
pane_focus_down = "alt + j"
pane_focus_up = "alt + k"
pane_focus_right = "alt + l"
pane_focus_next = "prefix + o"
pane_resize_left = "alt + H"
pane_resize_down = "alt + J"
pane_resize_up = "alt + K"
pane_resize_right = "alt + L"
pane_zoom = "alt + z"
pane_close = "alt + q"
pane_grow = "prefix + ="
pane_shrink = "prefix + -"
scrollback = "alt + y"
popup = "alt + p"
agent_popup = "alt + a"
agent_picker = "alt + u"
session_switcher = "alt + s"
scroll_up = "alt + <"
scroll_down = "alt + >"

$KATU_CONFIG overrides the config file path. Run katu reload to apply edits to a running server without restarting any session — status theme, visibility, and the AI command update immediately; a malformed file is rejected with an error instead of touching anything.

Architecture

Katu is one binary with two roles:

  • Server — a background daemon that owns the PTYs, keeps sessions alive across disconnects, and exits when the last session ends. It starts automatically on first use. Each session runs as an actor task holding a vt100 grid per pane, so reattaching repaints the exact screen and panes compose into one view.
  • Client — a stateless process that connects over a Unix socket (mode 600) and bridges your terminal to a session.

Everything Katu writes (~/.katu, context files, the socket) is restricted to your user.

Development

The repo ships a Nix flake with the full toolchain:

direnv allow    # or: nix develop
cargo build
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings

The workspace has two crates:

  • crates/katu-core — config, IPC protocol, shared types
  • crates/katu — the CLI, client, and server

Roadmap

  • v0.4 — mouse support
  • Later — remote session sharing, cloud sync (PRD §6)

License

MIT

About

A minimalist terminal multiplexer with first-class AI context

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages