# Rysh – an AI harness where Claude and Codex agents work as a team (Go)

> Source: <https://github.com/rysh-ai/rysh-cli-code>
> Published: 2026-08-17 22:51:16+00:00

The [Rysh](https://github.com/rysh-ai/rysh-cli-parent) 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](https://github.com/rysh-ai/rysh-cli-shared).

**Building or contributing? Start at
** — it carries the
Makefile, the Go workspace, and CI, and wires this module to a local checkout of
the shared one.

`rysh-cli-parent`

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](#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 |
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 |

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](/rysh-ai/rysh-cli-code/blob/main/LICENSE) and
[NOTICE](/rysh-ai/rysh-cli-code/blob/main/NOTICE) beside the source you are reading.

**The open-source build, from source:**

```
go install github.com/rysh-ai/rysh-cli-code/cmd/rysh@latest
```

The 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 | sh
```

Installs `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.yml`

names that archive`cli-only`

on purpose, so the artifact says what it is.- It
**cannot start a session.** Rysh's PTY layer has no ConPTY implementation, so`platform.PTYSupported`

is`false`

on 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   # rysh
```

Native 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          # -> ./rysh
```

From 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 modules
```

Go 1.25.3 or newer either way.

```
export ANTHROPIC_API_KEY=sk-ant-...
rysh onboard --provider anthropic --key-env ANTHROPIC_API_KEY
rysh doctor
```

`onboard`

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](https://github.com/rysh-ai/rysh-cli-parent#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 down
```

A 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](#video-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's
```

A 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](/rysh-ai/rysh-cli-code/blob/main/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](/rysh-ai/rysh-cli-code/blob/main/SECURITY.md) has the private channels.
