Skip to main content
plugin

rhost — GitHub Copilot plugin: what it does, how to install

Executes shell commands on SSH-reachable Linux hosts directly from GitHub Copilot. Preserves standard stdin, output streams, and exit codes.

Install into GitHub Copilot · Command from the source All methods and platforms ↓
copilot plugin install rhost@awesome-copilot
Open on GitHub

What rhost does

The plugin bridges your local agent to remote Linux servers using local OpenSSH configurations. Commands run as if they were local. Stdin feeds into the remote process, output streams return immediately, and rhost exits with the remote program's status code. OpenSSH handles host keys, alias resolution, and ProxyJump jumps.

Direct execution requires bash, setsid, ps, and a base64 decoder on the target machine. Interactive sessions depend on tmux and flock. Text and file helpers require remote Python 3.5 or newer. The standalone installer script needs local Python 3.11+.

You can probe host tools with rhost doctor <host> --json. Missing remote dependencies cause immediate REMOTE_DEPENDENCY_MISSING errors before any file edit begins.

What it helps with

  • run test suites and builds on remote GPU workstations
  • inspect remote Linux servers without leaving GitHub Copilot
  • pipe local data directly into remote commands via stdin
  • validate remote tools with doctor probes before mutating files

Example prompts for the agent

  • Run cargo test on host gpu inside ~/work/project using rhost
  • Check remote host edge capabilities with rhost doctor
  • Execute nvidia-smi on the gpu workstation via rhost

How to install rhost

Command from the source

copilot plugin install rhost@awesome-copilot

Step by step, with commands for each platform: Claude Code plugins: marketplaces, installing, and building your own

Questions about rhost

How to install rhost in GitHub Copilot?

Run copilot plugin install rhost@awesome-copilot. You must also have the rhost executable installed on your local machine.

What does rhost do?

It lets GitHub Copilot dispatch shell commands to remote Linux machines over SSH. Commands behave like local child processes without running background daemons on the host.

What dependencies are needed on the remote host?

Basic commands require bash, setsid, ps, and base64. Filesystem modifications need Python 3.5+, while session management requires tmux and flock.

Source text

SKILL.md · MIT
# rhost

**Remote execution for coding agents, built on OpenSSH.**

*The agent stays local. The work doesn't have to.*

A coding agent already knows how to use a shell. rhost carries that command
model to any SSH-reachable Linux machine without installing an agent, running a
daemon, or introducing another authentication system.

```bash
rhost exec gpu --cwd '~/work/project' --command 'cargo test --locked'
```

Foreground commands behave like commands: stdin goes in, stdout and stderr come
back, and rhost exits with the remote command's status. OpenSSH still resolves
the target, authenticates it, checks its host key, follows ProxyJump, and reuses
connections.

```text
local coding agent
  |-- rhost edge --> remote Linux host
  `-- rhost gpu  --> GPU workstation
```

Direct execution needs remote `bash`, `setsid`, `ps`, and a base64 decoder.
Optional operations need more: sessions use `tmux` and `flock`, remote filesystem
helpers require Python 3.5 or newer with the needed filesystem features, and
resumable or checksum-aware transfers use rsync. Run `rhost doctor <host>
--json` to see which commands resolve; helper readiness is checked on the
target when a file operation runs.

## Install

The release installer requires local Python 3.11+ and supports macOS and Linux
on amd64 and arm64. It verifies
the downloaded binary against the published SHA-256 file before atomically
replacing an existing installation.

```bash
curl -fsSL https://raw.githubusercontent.com/starfield17/rhost/main/scripts/install.sh | bash
```

On macOS, the installer first looks for a writable standalone `rhost` already
selected by `PATH`. Otherwise it uses a writable Homebrew `bin` directory on
`PATH` when one has no existing `rhost`. On Linux, or when neither macOS location
is suitable, it uses `~/.local/bin`. Set `RHOST_INSTALL_DIR` to choose a directory
explicitly, or `RHOST_VERSION` to pin a published release. After installation,
the script checks which `rhost` your `PATH` selects and prints a correction if
another copy still takes precedence. An open shell may need `rehash` (zsh) or
`hash -r` (bash) afterwards.
The default version lookup uses GitHub's stable-release redirect. If the lookup
fails, set `RHOST_VERSION` to a known release to skip it.

To build from source with Rust 1.85 or newer:

```bash
git clone https://github.com/starfield17/rhost.git
cd rhost
make build-release
install -m 755 target/release/rhost ~/.local/bin/rhost
```

`make build-release` is the shipping build: locked dependencies, `--release`,
and the commit and UTC build date stamped in so `rhost version --json` names
what the binary was built from. `make build` is the faster debug build for
development; it stamps the same provenance but is not the release candidate.

## First use

Use a target that already works with OpenSSH. Probe it once to see which
operations its installed tools support, then run an ordinary command:

```bash
rhost doctor gpu --json
rhost exec gpu --command 'uname -a'
```

For `doctor`, `ok:true` means the probe completed. Inspect
`data.capabilities` and `data.state_dir_writable` before relying on an
optional operation. On failure, branch on `error.code` and use the
[recovery guide](skills/rhost/references/RECOVERY.md) before retrying a
mutation.
`data.capabilities.python3` means the command was found, not that the remote
filesystem helper can run; an unusable interpreter produces
`REMOTE_DEPENDENCY_MISSING` before a file edit.

Use any target that already works with `ssh`: an OpenSSH config alias,
`user@example-host`, or a bare hostname.

```bash
# Inspect an edge host.
rhost exec edge --command 'uname -a && systemctl --failed'

# Check a GPU worker.
rhost exec gpu --command 'nvidia-smi'

# Run the same command an agent would run locally.
rhost exec gpu --cwd '~/work/project' --command 'pytest -q'

# Forward stdin and preserve normal pipeline behavior.
printf 'hello\n' | rhost exec edge --command 'cat'
rhost exec gpu --command 'cat results.txt' | sort
```

The `--command` value is one complete remote shell program. Pipelines,
redirects, variables, and compound syntax inside it run in a fresh remote login
bash. Shell syntax outside it remains local. `-c` is the short form; for a
larger local script use `--command-file ./script.sh`, which leaves stdin free for
the remote program.

Human mode streams output and has no default deadline or output cap. Add
`--timeout 30s` when the command has a meaningful bound. Use `--json` when the
caller needs one versioned result rather than terminal output. With JSON,
`--stream` mirrors live command output to stderr while stdout remains exactly
one final envelope. Add `--fresh` when diagnosis needs an independent SSH
connection.

## Why not just SSH?

For a human, `ssh gpu ...` is often enough. For an agent, the edges decide
whether it can classify a result and retry safely:

- stdin, stdout, stderr, and the remote exit status keep ordinary process
  behavior;
- a remote command failure is distinct from usage, transport, and local output
  failures;
- a timeout says whether cleanup was confirmed instead of pretending an
  uncertain mutation is safe to repeat;
- sessions and tunnels survive the rhost invocation that created them;
- OpenSSH remains authoritative for configuration, authentication, host keys,
  ProxyJump, and connection reuse;
- replacing remote text can require the hash returned by the preceding read.

rhost stays below the agent protocol layer. It is not an SSH client or a
resident control plane. It is a remote process boundary that a coding agent can
invoke like any other command-line program.

## When foreground execution is not enough

Direct execution is the default. Reach for a specialized operation only when
the work needs an additional guarantee.

| Requirement | Operation |
|---|---|
| A shell, REPL, or debugger must keep state | `rhost session` |
| Bytes must cross local and remote filesystems | `rhost fs` |
| A text edit needs an atomic hash precondition | `rhost fs read/write/patch` |
| A port forward must survive its creator | `rhost tunnel` |
| SSH or remote dependency diagnosis | `rhost doctor` |

For work that only needs to outlive one blocking tool call, let the coding agent
run an ordinary `rhost exec` process in its own background facility. The rhost
process remains the foreground owner, so output and exit status keep their
normal meaning.

Work that must survive the coding agent itself belongs to a scheduler already
installed on the remote host. Invoke that scheduler explicitly, for example:

```bash
rhost exec gpu --cwd '~/work/project' \
  --command 'systemd-run --user --unit=training --collect python train.py --config configs/train.yaml'
```

rhost does not select or install a scheduler. Use the host's own systemd, Slurm,
Kubernetes, tmux, or other established runtime when its lifecycle guarantees
are required. A persistent rhost session is for terminal state, not a generic
scheduler.

File operations and sessions remain explicit:

```bash
rhost fs read gpu '~/work/project/src/main.rs' --json
rhost fs write gpu '~/work/project/src/main.rs' --from ./main.rs --if-hash <sha256>

rhost session create gpu --name debug --cwd '~/work/project' --json
rhost session exec gpu debug --command 'python3 -m pdb app.py' --json
```

Creating a file needs no hash. Replacing or patching one requires the SHA-256
from the last `fs read`. Sync and mirror delete only with explicit `--delete`.
Remote search stays an ordinary command:

```bash
rhost exec gpu --cwd '~/work/project' --command 'rg TODO src'
```

`session attach` is deliberately refused with `USAGE_ERROR`: schema v2 has no
honest way to represent terminal attachment in a single result envelope.

## What rhost does not own

rhost does not manage SSH keys, keep a host database, install a remote agent,
run a daemon, or define a deployment language.

OpenSSH owns connections and authentication. Remote tmux owns persistent
terminals. Remote schedulers own scheduled work. The filesystem owns files.
rhost owns the contract between those components and the caller.

## Structured results

Every agent-visible behavior has a `--json` path. JSON mode writes exactly one
schema-v2 document to stdout, never mixes progress or command output into it,
and provides stable `error.code` values.

For execution results, inspect:

- `data.execution.status`: `completed`, `unknown`, or `not_started`;
- `data.execution.exit_code`: present only when remote completion is known;
- `data.output.stdout.content` and `data.output.stderr.content`, together with
  their byte counts and truncation flags;
- `data.cleanup.status`: `not_attempted`, `confirmed_stopped`, or `unconfirmed`.

| Process status | Meaning |
|---|---|
| 0-254 | Remote command status when completion is known |
| 124 | rhost execution deadline |
| 130 / 143 | rhost handled SIGINT / SIGTERM |
| 255 | Adapter, transport, usage, or local delivery failure |

A remote program can return the same numeric values. In ambiguous cases inspect
`ok`, `data.execution`, and `error.code` rather than branching on English text.
Missing completion evidence is reported conservatively as
`REMOTE_EXECUTION_UNKNOWN`; confirmed process-group cleanup does not by itself
make a side effect safe to replay.

## Use as an agent skill

The repository includes a concise skill that teaches an agent when an ordinary
command is enough and when sessions, file operations, or tunnels provide a
needed guarantee:

```bash
npx skills add starfield17/rhost --skill rhost
```

The canonical skill is also listed on
[skills.sh](https://skills.sh/starfield17/rhost/rhost). Codex users can ask the
built-in skill installer to install this GitHub directory; the new skill is
available on the next turn:

```text
$skill-installer install the rhost skill from
https://github.com/starfield17/rhost/tree/main/skills/rhost
```

The root `plugin.json` is the portable Agent Plugin entry point, while
`.codex-plugin/plugin.json` exposes the same skill to Codex plugin discovery.
Both package the skill and require the `rhost` CLI to be installed separately.

## Design and verification

The CLI process owns no durable remote work. Killing and restarting it does not
erase state it promised to preserve.

- [Architecture and ownership](docs/ARCHITECTURE.md)
- [Agent skill](skills/rhost/SKILL.md)
- [CLI reference and file input examples](skills/rhost/references/CLI.md)
- [JSON envelope schema](schemas/result-v2.schema.json)
- [Contributor rules](AGENTS.md)
- [Maintenance policy](docs/MAINTENANCE.md)

```bash
make test-smoke
make check

RHOST_TEST_HOST=<user>@<host> RHOST_BIN=./target/debug/rhost make test-live
RHOST_TEST_HOST=<user>@<host> RHOST_BIN=./target/debug/rhost make test-live-session
RHOST_TEST_HOST=<user>@<host> RHOST_BIN=./target/debug/rhost make test-live-all
```

`test-smoke` is the complete local Rust black-box suite and cannot contact a
real host. `test-live-all` is the serial, Rust-native real-SSH suite and the
documented manual pre-release verification; the release workflow does not run it
because no CI-reachable host is provisioned. The historical Go implementation
and its harness live in the read-only `rhost-go-old` repository.

Live suites always take their target and binary from `RHOST_TEST_HOST` and
`RHOST_BIN`; the repository has no machine-specific default. The v1 schema
is archived with the Go implementation. Current command availability is defined by `rhost
--help`, and ongoing compatibility and release policy is defined in
[`docs/MAINTENANCE.md`](docs/MAINTENANCE.md).

© starfield17 · MIT · starfield17/rhost

Similar plugins

All plugins for Agent setup: memory, context, orchestration →

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor