蜘蛛 — spider in Japanese.
Kumo is a terminal multiplexer that weaves your AI agents together into a
single web 🕸️. Every pane is a live terminal, every AI CLI you run
(opencode, claude, codex, …) is a thread in that web, and the sidebar
keeps you aware of what each agent is doing at a glance — because a spider
always knows what's happening in its web. ✨
Built in Rust 🦀 with a single TUI frontend on ratatui, real terminal emulation from libghostty-vt (Ghostty's headless terminal core), and portable-pty for PTY management. 🧵
And it's featherweight 🪶: while you work, kumo itself idles at ~0.7% CPU and ~6 MB of memory — the real cost is whatever you run inside its panes, not the multiplexer.
- 🖥️ Real terminal emulation — each pane is a genuine VT/xterm emulator (vendored Ghostty). Shells, TUIs, and full-screen apps behave exactly like in a native terminal: cursor, colors, scrollback, the works. 🎨
- 🧩 Split panes & sessions — binary split tree (vertical/horizontal), mouse-drag resizing, zoom 🔍, multiple independent sessions, tab cycling.
- 🤖 AI CLI panes — spawn a dedicated pane running your AI CLI with one
keystroke, or just run
opencode/claude/codex… in any shell pane: kumo auto-detects the agent process and weaves it into the sidebar. 🕸️ - 🟢🟠⚪ Agent status at a glance — the sidebar shows each agent's workspace and CLI name with a status dot: green = working, orange = blocked (waiting for approval), gray = idle. Detected from the live terminal buffer (not the viewport), so it stays accurate even while you scroll. Lifecycle detection is per-agent — see Agents. ⚡
- 🔔 Agent notifications — when an agent blocks (waiting for approval)
or finishes, kumo raises a transient toast in every attached viewer
(click to jump to the pane) and plays a distinct chime per event. Blocked
agents float to the top of the AGENTS list (with a filled
◉dot and· blockedhint) and their pane glows orange, even without focus. Tune the corner with[notifications] position, mute with[notifications] sound = false. 🔔 - 📋 Native text selection — drag to select in any pane, even inside apps that own the mouse (opencode's TUI, vim, less). Clicks still reach the app, and the highlight hugs the text like a normal terminal. ✂️
- 🐣 Plain-tty identity — panes present as a plain
xterm-256color(no mouse capabilities advertised), so apps don't hijack the mouse and selection always works. 🧤 - 📂 Workspace-aware — kumo opens in the directory you launch it from; every new pane/session starts there. 🗂️
CLI (recommended) — the kumo binary (daemon + TUI + control CLI in one),
via the cargo-dist installer generated by the release pipeline:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/marcrdgz/kumo/releases/latest/download/kumo-installer.sh | shDesktop app — installed separately from its Kumo-<arch>.dmg on the
release page (macOS). The app manages the whole install: if the kumo CLI is
missing or outdated it offers to install/update it, and it can self-update from
a newer .dmg — all from inside its interface.
Nightly — rolling build of main (macOS ARM + Linux x86_64; the full
target matrix can be built on demand via a manual workflow dispatch):
kumo update --nightlyFrom source (development):
cargo install --path app/kumo --locked
# or: make installThe desktop app is the "smart" interface for updates: on launch it checks both
the kumo CLI and the desktop app against the latest release, installs the CLI
automatically when it's missing, and shows a one-click banner when either is
outdated.
The TUI keeps its own kumo update for the CLI:
kumo update # update to the latest stable release
kumo update --nightly # update to the latest nightly build
kumo update --check # report availability (exit 0 = up to date, 1 = update)At startup kumo checks (at most once per day for stable, every 6 h for
nightly) for a newer release and, if one exists, shows a banner at the
top-right with a red ✕ to dismiss it. Disable the check with
update-check = false in the config or by setting KUMO_NO_UPDATE=1.
Kumo reads a single config file at ~/.config/kumo/config.toml. The old
flat key = value file at ~/.config/kumo/config (and the legacy ~/.kumo)
still reads as a fallback, but config.toml wins when both exist. The
directory follows the XDG layout, so the config lives in ~/.config/kumo/,
runtime state in ~/.local/state/kumo/, and the detach server's IPC socket in
$XDG_RUNTIME_DIR/kumo.
# ~/.config/kumo/config.toml
[keymap]
leader = "ctrl+b"
# Leader bindings are remappable: override a stock key or add a new one.
[keymap.bindings]
s = "split-vertical" # now leader+s splits vertically
x = "close-pane"
ai-cmd = "claude --model sonnet"
shell = "/bin/zsh"
update-check = trueSupported keys:
| Key | Description | Default |
|---|---|---|
keymap.leader |
Leader chord that enters leader mode (ctrl+b, ctrl+space, f12, …). A top-level leader also reads as a deprecated alias. |
ctrl+b |
keymap.bindings |
Overrides/additions to the leader bindings: chord = "action-id" (e.g. s = "split-vertical"). Invalid chords/actions are ignored with a warning. |
stock keymap |
ai-cmd |
AI CLI to run in the AI pane (program + args, space-separated). ai_cmd also works for back-compat. |
opencode |
shell |
Login shell used to spawn panes. | $SHELL → /bin/zsh |
update-check |
Whether the startup update check runs (also KUMO_NO_UPDATE=1). |
true |
notifications.position |
Where agent toasts anchor: top-right, top-left, bottom-right, bottom-left, center; off/never silences toasts (also KUMO_NO_NOTIFY=1). |
top-right |
notifications.blocked / notifications.finished |
Toast when an agent blocks / finishes (idle, done are aliases of finished). |
true |
notifications.sound |
Whether blocked/finished agent transitions play an audible chime (alert-sound also works; also KUMO_NO_SOUND=1). A top-level agent-sound reads as a deprecated alias. |
true |
Overrides for the config/state locations (not keys) follow the usual
conventions: KUMO_CONFIG_DIR, KUMO_STATE_DIR, XDG_CONFIG_HOME,
XDG_STATE_HOME.
Kumo auto-detects supported AI CLIs running inside a pane and lists them in the
sidebar. Lifecycle rules are bundled for every agent below and may be replaced
or extended from ~/.config/kumo/agent-detection/*.toml.
opencode— permission dialogs, question prompt, prompt-footer signalsclaude— approval forms, permission prompts, OSC-title spinnercodex·gemini·qwen·aider·cody·swe·coco
Rules are deliberately conservative: when no explicit live marker matches,
the pane remains unknown instead of being guessed idle or blocked.
Run kumo agent explain PANE to inspect the evidence behind a state. Run
kumo agent skill to print the bundled orchestration skill, or install it with
kumo agent skill --output PATH.
- 🦀 Rust toolchain (
cargo) — to build from source - ⚡ Zig on
PATH—build.rscompiles the vendoredlibghostty-vtlibrary at build time - 🐙 GitHub CLI (
gh, authenticated) — only for maintainers publishing releases via the cargo-dist pipeline; not required to use or update kumo
All leader bindings are configurable — override a stock key or add a new one in
[keymap.bindings] with "chord" = "action-id" (see Configuration).
The action-id column below is exactly what goes on the right-hand side.
| Key | Action id ([keymap.bindings]) |
Action |
|---|---|---|
Ctrl+B |
leader |
Leader key (configurable via leader; points to the command palette in the status bar) |
v |
split-vertical |
Split the focused pane vertically 🪓 |
- |
split-horizontal |
Split the focused pane horizontally 🪓 |
a |
split-ai |
Spawn an AI CLI pane (vertical split) 🤖 |
z |
zoom |
Zoom the focused pane 🔍 |
h |
focus-left |
Move focus left 🎯 |
j |
focus-down |
Move focus down 🎯 |
k |
focus-up |
Move focus up 🎯 |
l |
focus-right |
Move focus right 🎯 |
H |
resize-left |
Resize the focused pane left 📐 |
J |
resize-down |
Resize the focused pane down 📐 |
K |
resize-up |
Resize the focused pane up 📐 |
L |
resize-right |
Resize the focused pane right 📐 |
Tab |
cycle-pane |
Cycle focus between panes ↹ |
s |
swap-panes |
Swap the focused pane with its sibling 🔀 |
o |
rotate-layout |
Rotate the pane layout 🔄 |
q |
show-pane-numbers |
Show pane numbers — press a number to jump 🔢 |
c |
new-session |
Create a new session (name it in the popup; enter ok, esc cancel) 🆕 |
x |
close-pane |
Close the focused pane ❌ |
n / p |
next-session / prev-session |
Cycle to the next / previous session ⏭️ |
1–9 |
jump-session-1 … jump-session-9 |
Jump to the session at that sidebar position 🎯 |
b |
toggle-sidebar |
Toggle the sidebar 📌 |
d |
detach |
Detach (daemon keeps running) 🚪 |
? |
show-keybinds |
Searchable command palette — filter by action, key, or group and run with Enter 🔎 |
Esc |
— | Exit leader mode ↩️ |
The leader key and the leader bindings are configurable via
[keymap]inconfig.toml(see above).Escand the leader chord are not remappable actions; mouse gestures are deliberately not remappable — they are positional hit-testing, not key sequences.
🖱️ Mouse
- 🖐️ Drag selects text (copied on release) — works even in apps with mouse reporting.
- 👆 Click is forwarded to the app when it owns the mouse.
- 🎚️ Scroll is forwarded to reporting apps; otherwise it scrolls the pane's scrollback.
↔️ Drag a splitter to resize.- 🧭 MENU button (right of the mode chip in the status bar) opens a small
dropdown with
config(coming soon),keybinds(the same command palette asleader+?), andexit.
Kumo is on a path to become fully customizable — TOML config, data-driven
keybinding remapping (including the LEADER+? command palette), follow-workspace
(your cwd follows the focused pane, PID-based), themes & status-bar widgets, and
a thin plugin system. See ROADMAP.md for the details.
Until then, kumo stays opinionated: it picks good defaults for you so it just works, and you can follow the roadmap above as the knobs land. 🔧
kumo # 🏠 attach to the daemon (starts it if needed)
kumo attach # 🧷 attach to the running daemon
kumo new ~/proyecto # 🆕 start a fresh session in the daemon
kumo ~/proyecto # 🗂️ same as `kumo new ~/proyecto` (back-compat)
kumo daemon ~/proyecto # 🐞 run the headless daemon in the foreground
kumo ls # 📋 list the daemon's sessions (* = active)
kumo kill # 🛑 stop the daemon (kills its panes)
kumo --version # ℹ️ prints the version and channel (stable / nightly / dev)During development: cargo run -p kumo or make run. 🧑💻
leader+d (or MENU → detach) detaches this terminal; the daemon keeps
running in the background, owning your panes, their processes, and their agents.
Re-attach from any terminal with kumo or kumo attach, and everything is
exactly where you left it.
- The daemon auto-stops when the last session closes — no lingering process.
kumo newalways starts a fresh session; it never attaches to an existing one.- The socket is owner-only and the daemon refuses connections from other users.
Cargo.toml 📄 virtual workspace (kumo-protocol, kumo-core, kumo, kumo-desktop)
app/kumo/ 🕸️ the single `kumo` binary — daemon + TUI + control CLI + update
src/main.rs dispatcher: `kumo daemon` | TUI | `kumo session|pane|agent` | `kumo update`
src/daemon/ the headless daemon: PTYs, terminal emulators, layout tree, agents
build.rs 🏗️ compiles the vendored libghostty-vt (Zig)
src/daemon/app.rs sessions/panes, layout tree, PTYs, agents
src/daemon/pane.rs 🪟 Pane = PTY + libghostty-vt terminal (agent status, dirty render)
src/daemon/vt.rs 🔌 FFI bindings to libghostty-vt (emulator + native selection)
src/daemon/pty.rs 🔧 portable-pty wrapper
src/daemon/agents/ 🔍 per-agent lifecycle detection (opencode.rs, claude.rs)
src/cli/ the client — TUI (all chrome), control CLI, update
src/cli/client_view.rs geometry, input, mouse, and all chrome rendering
app/desktop/ 🖥️ native GPUI desktop client (draws its own chrome; distributed
as a `.dmg` on macOS, manages kumo CLI + app updates)
crates/kumo-core/ 📦 shared logic — config, layout, themes, updates, worktrees
crates/kumo-protocol/ 🔌 the pure wire protocol (Command/DaemonEvent)
vendor/libghostty-vt/ 📚 vendored Ghostty terminal emulator (Zig + C headers)
🕸️ A spider always knows what's happening in its web.