Run commands on remote hosts & containers without quoting hell.
argv travels as a JSON array to execve on the target — never through a shell.
English · 中文
rsb lets LLM agents (Claude Code, Codex, Cursor, …) operate remote servers
the same way they operate the local machine. It kills the two problems that
make ssh host "cmd" unusable for agents:
- Quoting hell. A command string passes through local shell → remote
shell → (optional) container shell, and escaping compounds at each layer.
No LLM can reliably produce
ssh prod "docker exec api sh -c 'echo \"$X\"'"across three shells. - State loss. Every
ssh host "cmd"is a fresh login shell.cd /appfollowed byssh host "ls"lands back in~. Agents can't express "keep working in this directory."
rsb's fix: commands are a []string argv, sent as a length-delimited
JSON frame to a small agent process on the remote host, which execves it
directly. No shell ever parses it — so there's no escaping layer to get wrong.
A persistent daemon + sessions make cd and env stick across commands.
Inspired by Warp's SSH extension (companion process on the remote, structured protocol, one server many sessions) — but rsb targets agent-native remote execution, not terminal UI.
# This command contains double quotes, single quotes, and a $ variable.
# Over ssh it would be a quoting nightmare. Over rsb it just works —
# argv is an array, so every character arrives at the target verbatim.
rsb exec prod --argv '["echo","he said \"hi\" and '"'"'yo'"'"', $HOME stays literal"]'
# => he said "hi" and 'yo', $HOME stays literalSame command for a container — --container keeps argv intact into the
container's process, still no shell:
rsb exec prod --container api --argv '["env"]'# 1. Build (or grab a prebuilt binary from releases)
go build -o bin/rsb ./cmd/rsb
go build -o bin/rsb-agent ./cmd/rsb-agent
go build -o bin/rsb-daemon ./cmd/rsb-daemon
# 2. One-time: symlink the current platform's binaries into bin/
rsb install-local
# 3. Verify your setup
rsb doctor # self-check: home, binaries, daemon, docker
rsb doctor prod --container=api # also probe a remote host + real container test
# 4. Install the agent on a remote host (probes OS/arch, scp's matching binary, sha256-verifies)
rsb ensure prod
# 5. Run commands
rsb exec prod --argv '["kubectl","logs","deploy/api","--tail=50"]'
rsb exec prod --session work --argv '["cd","/opt/app"]'
rsb exec prod --session work --argv '["ls"]' # still in /opt/appyour agent / shell
│ rsb exec (or rsb repl)
▼
local daemon ──unix socket──► rsb-daemon ──ssh──► rsb-agent (remote, persistent)
(1 conn per host, ├─ execve(argv) ← no shell
connection reuse) ├─ session table ← cwd/env persist
└─ docker adapter ← argv into container
- Zero new ports. The daemon talks over a unix socket; the remote agent is
a child process of
sshd, communicating over the existing SSH channel's stdin/stdout. If you cansshto a host, rsb works — no firewall changes. - argv to execve. The protocol carries
[]string, not a command string. The agent resolvesargv[0]viaPATHand callsexecve. Quotes,$, spaces, backticks — none of them are "special", because nothing parses them. - Persistent daemon + sessions. One SSH connection per host is kept open
and reused. Sessions serialize commands in the same session (so
cdis meaningful) while different sessions run concurrently.
| Status | |
|---|---|
| argv array → execve (no shell, zero quoting) | ✅ |
| Persistent daemon + connection reuse | ✅ |
Sessions: cd / cwd / env persist across commands |
✅ |
| Streaming stdin (pipes, interactive) | ✅ |
Docker container execution (--container) |
✅ |
| Multi-request concurrency + cancel | ✅ |
Interactive REPL (rsb repl) |
✅ |
ensure with atomic install + sha256 verification |
✅ |
doctor self-check with real container smoke test |
✅ |
| Remote agent version + hash visibility | ✅ |
| Cross-platform prebuilt binaries (linux/macOS × amd64/arm64) | ✅ |
Kubernetes (kubectl exec) adapter |
🔜 |
| Compose service-name resolution | 🔜 |
| Tool | What it solves | What it leaves |
|---|---|---|
ssh host "cmd" / ansible / fabric |
wrapping ssh | still a command string — quoting hell intact |
| paramiko / asyncssh | SSH library | exec_command(string) — shell parsing problem remains |
| tmux Control Mode (Warp legacy) | connection reuse | terminal-UI oriented, not an agent exec API |
| Warp SSH extension | structured protocol + reuse | closed-source, terminal-user oriented |
| VS Code Remote-SSH | structured protocol | IDE-specific, not an agent API |
| rsb | argv to execve + daemon + sessions + containers | — |
rsb sits in an empty niche: an agent-native remote execution runtime that's open, single-binary, and treats argv as a first-class citizen end to end.
git clone https://github.com/<owner>/rsb.git
cd rsb
./scripts/build.sh # builds 3 binaries for 3 platforms into skill/bin/Grab the archive for your platform from Releases. Each
archive contains rsb, rsb-agent, rsb-daemon for one platform. Drop them
in a directory and run rsb install-local.
The skill/ directory is a self-contained, agent-installable package:
SKILL.md teaches the agent when and how to use rsb; bin/ holds prebuilt
binaries for all platforms. Copy skill/ into your agent's skills directory
(e.g. ~/.codex/skills/rsb/).
rsb exec <host> --argv '<json>' [options]
--argv '<json>' (required) JSON string array, e.g. '["ls","-la"]'
--cwd DIR working directory on the target
--env K=V environment variable (repeatable); values are NOT expanded
--timeout MS kill the command after N milliseconds
--session NAME share cwd/env across commands; "cd" persists per session
--container NAME run inside a Docker container (argv reaches it verbatim)
--stdin pipe local stdin to the remote command
--local run on this machine (no SSH)
rsb repl <host> [--session NAME] interactive multi-command session
rsb ensure <host> [--force] install/upgrade the remote agent (sha256-verified)
rsb agent-version <host> show the agent version on a host
rsb doctor [host] [--container=NAME] self-check (real container smoke test if --container)
rsb install-local symlink current-platform binaries into bin/
rsb daemon status|stop manage the local daemon (usually automatic)
rsb version
run `rsb <command> --help` for detailed per-command help.
Exit code: rsb exec's exit code equals the remote command's exit code.
By default rsb enters containers via docker exec (works for unprivileged
users with docker-group access). For root/privileged hosts, set
RSB_CONTAINER_MODE=nsenter to use nsenter directly (faster, skips the
docker daemon round-trip).
If --container fails with nsenter: Permission denied, your remote agent is
likely a stale (pre-0.5.0) version that defaulted to nsenter. Fix it:
rsb ensure <host> --force # upgrade + verify
rsb agent-version <host> # confirm it matchesFallback that always works (still argv, still no shell):
rsb exec prod --argv '["docker","exec","api","ls","/app"]'agent code (Python/JS/shell)
│ argv = ["echo", 'has "double" and $HOME'] ← you write a list
│ json.dumps(argv) ← JSON escaping is deterministic
▼
JSON wire: ["echo","has \"double\" and $HOME"]
│ rsb carries it as a length-delimited frame
▼
remote execve(["echo", 'has "double" and $HOME']) ← restored exactly, no shell
▼
echo receives: has "double" and $HOME ← correct
Contrast with traditional SSH, where the same intent must survive N shell parsers, each with its own escaping rules, and the agent must mentally simulate the result of every layer. rsb removes the parsers entirely.
cmd/
rsb/ client CLI (exec, repl, ensure, doctor, …)
rsb-agent/ remote daemon (multi-request, sessions, execve, docker)
rsb-daemon/ local daemon (connection pool, frame routing)
internal/
protocol/ length-delimited JSON framing + message types
daemon/ host connection pool + client bridge
client/ daemon connect / autostart / streaming stdin / repl
docker/ container adapter (docker exec default, nsenter opt-in)
paths/ install-home discovery (RSB_HOME > executable > cwd)
skill/ self-contained agent-installable package
docs/ changelog + pain-point records
scripts/ cross-compile script (3 platforms)
- Kubernetes adapter (
--container→kubectl exec) - Compose service-name resolution (
--container api→project-api-1) -
rsb scp(file transfer over the same connection) - Per-host allowlist / audit hook for destructive commands
MIT