rz
Universal messaging for AI agents — cmux, zellij, NATS, or any terminal.
One binary that works in cmux, zellij, or any plain terminal via PTY wrapping. Spawn agents, send messages, bridge across machines with NATS — rz send peer "hello" works the same way everywhere.
Auto-detects your environment: cmux (CMUX_SURFACE_ID), zellij (ZELLIJ), or use rz agent for any terminal.
Fork of rz by @HodlOg. Zellij support based on meepo/rz.
Install
From source (macOS requires codesign):
Crates
| Crate | Description |
|---|---|
rz-agent |
CLI — cmux + zellij + file + http + NATS |
rz-agent-protocol |
@@RZ: wire format library (use in your own agents) |
rz-hub |
Zellij WASM plugin for in-process routing (build separately) |
Quick start
Inside a multiplexer (cmux / zellij)
# Spawn agents (auto-detects your multiplexer)
# Observe and interact
Any terminal (no multiplexer needed)
# Start a NATS server
# Run an agent with PTY wrapping — works in any terminal
rz agent creates a pseudo-terminal, wraps the command, and subscribes to NATS. Incoming messages are injected directly into the child's input as @@RZ: lines. No cmux or zellij required.
┌──────────────┐ ┌──────────┐ ┌──────────────────────┐
│ rz send │──pub──│ NATS │──sub──│ rz agent --name X │
│ worker "msg" │ │ agent.X │ │ ├─ NATS subscriber │
└──────────────┘ └──────────┘ │ ├─ writes @@RZ: to │
│ │ PTY master fd │
│ └─ child sees it │
│ as typed input │
└──────────────────────┘
Cross-machine / cross-multiplexer (NATS)
Agents in cmux and zellij can talk to each other via NATS:
# Start a NATS server with JetStream (messages survive restarts)
# Set the hub URL (add to your shell profile)
# cmux terminal: spawn an agent — NATS listeners auto-start
# zellij terminal: send to the cmux agent — routes through NATS
When RZ_HUB is set, rz run automatically starts background NATS listeners for both the new agent and the lead. No manual rz listen needed.
Universal agents (file mailbox, HTTP)
# Register agents with different transports
# Send — rz picks the right transport automatically
# Receive from file mailbox
Backends
rz auto-detects the environment:
| Backend | Detection | Pane IDs | Best for |
|---|---|---|---|
| cmux | CMUX_SURFACE_ID env |
UUIDs (B237E171-...) |
Claude Code desktop app |
| zellij | ZELLIJ env |
Numeric (terminal_3) |
Zellij terminal users |
| PTY agent | rz agent --name X |
Agent name | Any terminal, remote servers, CI |
Both backends support the same commands. Backend-specific features:
| Feature | cmux | zellij |
|---|---|---|
| Browser control | rz browser open/screenshot/eval |
— |
| Pane colors | — | rz color <pane> --bg #003366 |
| Pane rename | — | rz rename <pane> "name" |
| WASM hub plugin | — | rz-hub (optional, enables timers + name routing) |
Transports
| Transport | Delivery method | Best for |
|---|---|---|
cmux |
Paste into terminal via cmux socket | cmux agents |
zellij |
Paste into pane via zellij CLI | zellij agents |
file |
Write JSON to ~/.rz/mailboxes/<name>/inbox/ |
Universal fallback |
http |
POST @@RZ: envelope to URL |
Network agents, APIs |
nats |
Publish to NATS subject agent.<name> |
Cross-machine, cross-multiplexer |
Message routing
rz send coder "implement auth"
|
+-- resolve "coder" -> names.json -> surface titles -> registry -> NATS
|
+-- cmux? -> paste @@RZ: envelope into cmux surface
+-- zellij? -> paste into zellij pane
+-- file? -> write to ~/.rz/mailboxes/coder/inbox/
+-- http? -> POST to registered URL
+-- nats? -> publish to agent.coder (via RZ_HUB)
Protocol
Every message is a single line: @@RZ:<json>
Message kinds
| Kind | Body | Purpose |
|---|---|---|
chat |
{text} |
General communication |
ping / pong |
— | Liveness check |
error |
{message} |
Error report |
timer |
{label} |
Self-scheduled wakeup |
Commands
Agent lifecycle
| Command | Description |
|---|---|
rz run <cmd> --name X -p "task" |
Spawn agent in multiplexer pane |
rz agent --name X -- <cmd> |
Run agent with PTY wrapping (no multiplexer needed) |
rz list / rz ps |
List all agents — shows (me) next to your own |
rz close <target> / rz kill |
Close a pane/surface |
rz ping <target> |
Check liveness, measure RTT |
Messaging
| Command | Description |
|---|---|
rz send <target> "msg" |
Send @@RZ: message (auto-routes) |
rz send --ref <id> <target> "msg" |
Reply to specific message (threading) |
rz send --wait 30 <target> "msg" |
Send and block for reply |
rz ask <target> "msg" |
Shorthand for send + wait |
rz broadcast "msg" |
Send to all agents |
Discovery
| Command | Description |
|---|---|
rz id |
Print this pane/surface ID |
rz register --name X --transport T |
Register agent in universal registry |
rz deregister X |
Remove agent from registry |
rz status |
Pane counts and message stats |
File mailbox
| Command | Description |
|---|---|
rz recv <name> |
Read and consume all pending messages |
rz recv <name> --one |
Pop oldest message |
rz recv <name> --count |
Count pending messages |
NATS
| Command | Description |
|---|---|
rz listen <name> --deliver <method> |
Subscribe to NATS subject, deliver locally |
rz timer 30 "label" |
Self-deliver Timer message after N seconds |
Delivery methods: stdout, file, cmux:<surface_id>, zellij:<pane_id>
Observation
| Command | Description |
|---|---|
rz log <target> |
Show @@RZ: protocol messages |
rz dump <target> |
Full terminal scrollback |
rz gather <id1> <id2> |
Collect last message from each agent |
Workspace
| Command | Description |
|---|---|
rz init |
Create shared workspace (/tmp/rz-<session>/) |
rz dir |
Print workspace path |
Browser (cmux only)
| Command | Description |
|---|---|
rz browser open <url> |
Open browser split |
rz browser screenshot <id> |
Take screenshot |
rz browser eval <id> "js" |
Run JavaScript |
rz browser click <id> "sel" |
Click element |
Zellij-specific
| Command | Description |
|---|---|
rz color <pane> --bg #HEX |
Set pane border color |
rz rename <pane> "name" |
Set pane title |
rz watch <pane> |
Stream pane output in real-time |
Project structure
rz/
├── crates/
│ ├── rz-protocol/ # @@RZ: wire format (transport-agnostic)
│ │ └── lib.rs # Envelope, MessageKind, encode/decode
│ ├── rz-cli/
│ │ ├── main.rs # CLI commands + auto-detect backend
│ │ ├── backend.rs # Backend trait + CmuxBackend + ZellijBackend
│ │ ├── cmux.rs # cmux socket client
│ │ ├── zellij.rs # zellij CLI wrapper
│ │ ├── pty.rs # PTY agent wrapper (no multiplexer)
│ │ ├── nats_hub.rs # NATS transport (JetStream + core)
│ │ ├── registry.rs # Agent discovery (~/.rz/registry.json)
│ │ ├── mailbox.rs # File-based message store
│ │ ├── transport.rs # Pluggable delivery abstraction
│ │ ├── bootstrap.rs # Agent bootstrap message
│ │ ├── log.rs # @@RZ: message extraction
│ │ └── status.rs # Session status
│ └── rz-hub/ # Zellij WASM plugin (optional)
│ ├── main.rs # Plugin lifecycle
│ ├── registry.rs # Agent registry + name index
│ └── router.rs # Pipe dispatch + message routing
└── Makefile # build + codesign + install + publish
Credits
Forked from rz (crates.io/crates/rz-cli) by @HodlOg. Zellij support based on work by @meepo. The @@RZ: protocol, bootstrap design, and core messaging architecture are from the original project.
License
MIT OR Apache-2.0