The Rysh CLI: an agentic terminal
multiplexer written in Go. Tabs, panes, splits, and vim/htop working exactly
as you expect — except every pane is also an agent that can answer prompts and
call tools.
This repository holds the CLI itself. It depends on
rysh-cli-shared.
Building or contributing? Start at
rysh-cli-parent — it carries the
Makefile, the Go workspace, and CI, and wires this module to a local checkout of
the shared one.
Five narrated, subtitled walkthroughs of what rysh actually does, in order — each one assumes the previous. Every player below is live on this page; press play, nothing leaves GitHub. The first four are recorded against the build the install line gives you, so every command in them is one you can type.
1 — Install, and your first tabs, lanes and stacked panes · 1:29
01-first-panes.mp4
|
2 — Stop the session, start it again — the agents are still there · 2:44
02-stop-start.mp4Why a session is a daemon and not a terminal. Claude and Codex are each told a codeword, the session is stopped outright, and after the restart both resume unprompted and answer with the codeword they were told before it. |
3 — Claude and Codex in three stacked panes at once · 2:07
03-claude-codex-parallel.mp4More than one agent, and more than one vendor, side by side: |
4 — A fleet that talks to itself, on a shared board · 2:29
04-fleet-board.mp4
|
5 — Graph engineering — designing the shape of a fleet · 4:00
05-graph-engineering.mp4The deep end: why an agent org chart is a graph, what the edges mean, and what changes when you remove one. Orders travel down as messages, results come up on the board, and two workers with no edge between them give independent verdicts. |
|
Start at 1 even if you have used tmux or Zellij for years — the panes look familiar and the session model underneath them does not, which is video 2.
SecretNAT is on by default. Secrets are substituted with tokens in the request body before it leaves the machine, and a response carrying a live credential in plaintext is reported into the pane. Responses are not rewritten — by design.
The mapping is reversible locally, so ##snat get <token> hands you back the real
value in your own pane, and the model only ever saw the token.
Two binaries exist and they are not interchangeable:
| this repository | the prebuilt distribution | |
|---|---|---|
| binary name | rysh |
ry |
| how you get it | go install, or the installer below |
its own channels, not documented here |
The names differ so that one machine can carry both. Every install command in
this README installs rysh, and a script, alias or doc written for one does
not run against the other — which is the whole reason the names differ. Check
what you have with rysh version or ry version.
This repository is the rysh half: Apache-2.0, with LICENSE and
NOTICE beside the source you are reading.
The open-source build, from source:
go install github.com/rysh-ai/rysh-cli-code/cmd/rysh@latestThe binary lands in $(go env GOPATH)/bin as rysh. Requires Go 1.25.3 or
newer — the floor declared in this module's go.mod.
The open-source build, prebuilt:
curl -fsSL https://packages.rysh.ai/install-rysh.sh | shInstalls rysh from this repository's own releases — the Apache-2.0 binary, not
ry. It resolves the newest release at run time; set RYSH_VERSION to pin one
instead, or RYSH_INSTALL_DIR to choose where it lands.
The prebuilt distribution — installs ry, not rysh. It is the packaged
product and a separate distribution; nothing in it is produced by this repository,
so ry --help describing a command is not evidence about the source here. Use
go install above if you want the build whose source you are reading.
Its install commands are deliberately not reproduced here: this README documents the open-source build. The prebuilt distribution has its own channels and its own documentation.
WSL2 is the supported path. Native Windows compiles and runs, but it cannot open a pane — those are two different claims and both are true:
GOOS=windows GOARCH=amd64 go build ./...succeeds — the windows/amd64 target builds clean from this source. This repository's.goreleaser.ymlnames that archivecli-onlyon purpose, so the artifact says what it is.- It cannot start a session. Rysh's PTY layer has no ConPTY implementation, so
platform.PTYSupportedisfalseon Windows and every session-opening command is refused up front with WSL guidance — rather than starting a session and then failing on your first pane (cmd/rysh/pty_preflight.go). - What it can do is the pane-less command set, including talking to a session
running in WSL from the Windows side:
rysh send,rysh exec,rysh prompt,rysh list-sessions,rysh install,rysh eval,rysh doctor.
For a real session, install WSL2 and use the Linux instructions inside it — the Linux build runs unmodified:
wsl --install# inside WSL
go install github.com/rysh-ai/rysh-cli-code/cmd/rysh@latest # ryshNative panes need ConPTY behind the same seam; it is not implemented yet.
This module alone builds standalone — it carries no replace directive, so the
shared module resolves from its published version:
git clone https://github.com/rysh-ai/rysh-cli-code
cd rysh-cli-code
go build ./cmd/rysh # -> ./ryshFrom the superrepo, which is how to develop against both modules at once — its
go.work wires the shared module to the sibling checkout, so an edit there is
picked up without a release round-trip:
git clone --recursive https://github.com/rysh-ai/rysh-cli-parent
cd rysh-cli-parent
make build # -> bin/rysh
make install # -> ~/.local/bin/rysh (override with PREFIX=)
make test # both modulesGo 1.25.3 or newer either way.
export ANTHROPIC_API_KEY=sk-ant-...
rysh onboard --provider anthropic --key-env ANTHROPIC_API_KEY
rysh doctoronboard validates the key, writes a project-local rysh.config.yaml, and opens
your session. rysh --help lists the full command surface.
Each pane has an input mode and Esc Esc cycles it: shell (a real PTY) →
prompt (goes to the LLM) → rysh (multiplexer commands) → chat
(conversation, no tools). Those four are enabled by default; ##mode list shows
what a pane has and ##mode new <mode> adds the rest.
The parent repo README has the keybindings, sessions, agents and humanoids.
Commands starting with ## are typed into a pane in rysh mode. From outside
the session, rysh exec -- '##<cmd>' runs the same thing and prints its output.
rysh create work # create and attach; add -d to leave it detached
rysh list-sessions # what is running
rysh attach work # come back to it later
rysh detach work # leave it running
rysh stop work # shut the daemon downA session is a daemon plus its panes. It outlives your terminal, so closing the window detaches rather than kills.
A tab holds lanes (columns); a lane holds stacks; a stack holds panes,
Zellij-style — one expanded, the rest collapsed to a title bar showing [N/M].
##new tab a new tab
##new lane a new lane (column) in the active tab
##new pane a pane at the bottom of the active lane
##new grid 4 4 panes stacked in the active lane
##new grid 3x4 3 lanes x 4 panes, in the active tab
##new grid 2x3x4 2 tabs x 3 lanes x 4 panes
##new stack 4 4 more stacked panes in the active stack
Look at what you built, and move things around:
##tab list ##lane list ##pane list
##panegroup layout the lane layout, whole
##move pane up|down|left|right reorder in the stack, or cross to the next lane
##move pane <p> to-lane <lane> put a live pane somewhere else
##tab name build ##lane name left ##pane name builder
A stack with an agent in every pane is video 3 of the tutorials at the top of this page.
Panes can run an interactive Claude or Codex, and rysh remembers which, so a session stop/start resumes the same conversation:
##claude run claude in this pane, resumed automatically
##codex run codex in this pane, same deal
##pane new --claude "start on the parser" a new pane, already working
The agents board is where those panes talk to each other and to you:
##board open open the board pane
##board post <text> post a milestone
##board reply <thread> <text>
An agent inside a pane posts without stealing focus, and reads back:
rysh board post --as "$RYSH_PANE" -- 'parser wiring done'
rysh board tail --limit 20##board agent up starts a board agent — a hidden pane running Claude that
sits in the path, routes messages between agents, and refuses a request it knows
is stale. ##board agent visible draws it without moving your focus;
##board agent invisible puts it away while it keeps running.
A fleet is a named group of panes with a board of its own. Registering one opens no panes — it is the cheap half:
##fleet register epic-07 --board epic-07
##fleet state epic-07 up
##fleet list ##fleet show epic-07
##fleet forget epic-07 drop it; the panes keep running
rysh board tail --fleet epic-07 # that fleet's stream, not the session'sA fleet may be claudes, codexes, or both — the commands are the same either way.
| Path | What |
|---|---|
cmd/rysh |
the main package — entry point and command surface |
internal/tui |
the terminal UI |
internal/actors |
workspace / tab / pane / agent actors, proto.actor over NATS |
internal/vterm |
terminal emulation, including a vt10x fork with scrollback |
internal/provider |
LLM provider adapters |
internal/platform |
host capabilities that change what rysh can do (e.g. PTY support) |
action/ |
the setup-rysh composite GitHub Action |
This repository is a one-way export of a tree developed elsewhere, so a commit pushed straight here is overwritten by the next export rather than kept. That does not make patches pointless — CONTRIBUTING.md explains where one actually lands.
Found a vulnerability? Do not open a public issue, PR or discussion. Rysh runs shell commands and holds provider credentials on a developer's machine, so a public report is an exploit notice. SECURITY.md has the private channels.