remote-workspace

Remote workspaces for coding agents, over plain SSH.

What it is

Set up your coding agent on one machine. It can then work on any machine you can SSH into.

The remote side runs one small binary that the agent drives over your existing SSH config. No daemon, no open port, no copying your project around. If ssh myhost works, this works.

coding agent │ ▼ remote-workspace-mcp (on your machine) │ │ JSON Lines over ssh stdin/stdout ▼ remote-workspace-server (on the remote; automatic install on Linux x86_64)

Install

You need two binaries on your own machine. The server is installed on Linux x86_64 remotes for you when you add a workspace.

Linux x86_64

BASE=https://github.com/hesic73/remote-workspace/releases/latest/download

mkdir -p ~/.local/bin
for b in remote-workspace remote-workspace-mcp; do
  curl -fsSL "$BASE/$b-linux-x86_64-musl" -o ~/.local/bin/$b
  chmod +x ~/.local/bin/$b
done

remote-workspace --version

Windows x64 (PowerShell)

$releaseBase = "https://github.com/hesic73/remote-workspace/releases/latest/download"
$installDir = "$env:LOCALAPPDATA\remote-workspace\bin"
New-Item -ItemType Directory -Force $installDir | Out-Null
foreach ($name in @("remote-workspace", "remote-workspace-mcp")) {
    Invoke-WebRequest "$releaseBase/$name-windows-x86_64.exe" -OutFile "$installDir\$name.exe"
}
$env:Path = "$installDir;$env:Path"   # this shell only; add it to your user PATH
remote-workspace --version

Checksums: SHA256SUMS (Linux), SHA256SUMS-windows-x86_64 (Windows).

Build from source

git clone https://github.com/hesic73/remote-workspace
cd remote-workspace
cargo build --release --locked

install -m755 target/release/remote-workspace \
              target/release/remote-workspace-mcp ~/.local/bin/

Platform support

Client / MCPRemote hostServer installation
Linux x86_64 or Windows x64Linux x86_64, POSIX shellAutomatic
Windows x64Windows, PowerShell OpenSSH default shellManual build and --remote-bin

Linux clients cannot use PowerShell endpoints. Other POSIX targets need a server built and installed manually.

Add a workspace

One command probes the host, installs the matching server, runs a real round trip against your directory, and only then records the workspace. The directory must already exist.

remote-workspace workspace add robot \
  --host robot@workstation \
  --root /home/robot/project
Adding workspace 'robot'
  SSH                    connected
  Remote shell           posix
  Remote platform        linux-x86_64
  Workspace root         valid
  Server                 installed 0.6.2
  Protocol               3
  Workspace probe        passed
  Fleet configuration    updated
Workspace 'robot' is ready.

If any step fails, nothing is recorded and the error names the layer that broke. Add as many workspaces as you like, on as many machines as you like.

Windows remote

On the remote Windows host, build a checkout of the same release with cargo build --release --locked -p remote-workspace-server. Place target\release\remote-workspace-server.exe at a persistent path and configure PowerShell as the OpenSSH DefaultShell. From a Windows client:

remote-workspace workspace add windows --host user@windows-host --root C:/projects/app --remote-bin C:/tools/remote-workspace-server.exe --remote-shell powershell

PowerShell endpoints use one short SSH/server process per request, serialized per workspace. Installing and upgrading a Windows server is manual.

Adding is for new workspaces. A name already in the fleet is refused; moving registered hosts onto a newer release is upgrading.

Connect it to your agent

One entry serves your whole fleet, and it can be added before any workspace exists: workspaces added later are picked up on the next call. Restart the host application after registering, since MCP servers are loaded at startup.

Claude Code

claude mcp add --scope user remote-workspace -- remote-workspace-mcp

Claude Desktop

In claude_desktop_config.json. Use an absolute path, because a GUI app does not inherit your shell's PATH.

{
  "mcpServers": {
    "remote-workspace": {
      "command": "/home/you/.local/bin/remote-workspace-mcp"
    }
  }
}

Codex

codex mcp add remote-workspace -- remote-workspace-mcp

Grok Build

grok mcp add --scope user remote-workspace -- remote-workspace-mcp

On Windows, use remote-workspace-mcp.exe or its absolute path.

Check it works

remote-workspace-mcp --check
fleet config /home/you/.remote-workspace/workspaces.toml ok: 2 workspace(s)
robot [robot@workstation:/home/robot/project]: ok
lab   [lab-gpu-1:/data/experiments]: ok

Your agent now has nine tools: list, read, create, edit and delete files, run commands, and transfer single files in either direction. One edit_file call carries up to a hundred replacements: they apply in order, and either all of them land or the file is left untouched. Every tool except list_workspaces takes a required workspace argument, so a call cannot land on the wrong machine by default. Inspecting what happened afterwards is a job for the remote-workspace CLI, not a tool the agent carries.

Making conda work

Every command runs in a fresh process, so conda activate in one call never leaks into the next. Say once what a command's environment should be, in a config file on the remote host:

# ~/.remote-workspace/config.toml on the remote machine
default_profile = "user"

[profiles.user]
shell = ["bash", "-lc"]
setup = """
. "$HOME/miniforge3/etc/profile.d/conda.sh"
conda activate myenv
"""

[profiles.raw]
shell = ["bash", "-c"]
setup = ""

Point the workspace at it when adding, with --config /home/robot/.remote-workspace/config.toml.

Prefer an explicit setup over an interactive shell. bash -lic loads your dotfiles, but without a terminal it prints job-control warnings on every command, and zsh prompt plugins can fail noisily. Sourcing what you need is quieter. Note that zsh reads .zshrc only when interactive, so dropping -i without an explicit setup can change which python runs.

Upgrading

Your own binaries first: the client installs only the server release matching its own version.

BASE=https://github.com/hesic73/remote-workspace/releases/latest/download

for b in remote-workspace remote-workspace-mcp; do
  curl -fsSL "$BASE/$b-linux-x86_64-musl" -o ~/.local/bin/$b
  chmod +x ~/.local/bin/$b
done

remote-workspace workspace upgrade

The second command installs once per SSH identity, transfers nothing when a host is current, never downgrades a newer server, and never edits your fleet file. Restart the host application afterwards, since MCP servers are loaded at startup. If you skip it, the MCP refuses a server on a different protocol with server_too_old or client_too_old instead of failing call by call.

Where things live

Your fleet is ~/.remote-workspace/workspaces.toml on your own machine, written by workspace add and re-read whenever it changes, so a new workspace appears without restarting your agent.

On the remote, the operation log sits in ~/.remote-workspace/state/, outside your project. Nothing appears in git status, and a destructive command inside the workspace cannot take the history with it. The log records what happened; it does not reverse it, so keep anything that must survive a mistake in version control. Paths beginning @scratch/ address a transient area there for the agent's own working files; anything untouched for a week is deleted, so keep what matters in the workspace or pull it down with download_file.

To see which tools your agent actually reaches for, register the MCP with --log-dir ~/.remote-workspace/log and read it back:

remote-workspace stats

tool                calls   errors
run_command          1800       24
edit_file             678       37
read_file             201        5
list_directory          8        0

It is off by default, because a logged request carries the full text of every file your agent writes.

When something breaks

SymptomUsually
connect_failed SSH itself cannot reach the host. Try ssh <host> true. Anything needing a password prompt fails rather than hanging.
probe_failed, state directory is locked Another session is using that workspace; one server serves a root at a time. A server orphaned by a dropped connection releases the lock about fifteen minutes after its last activity (longer if a command is still running). server.jsonl in the state directory records when each server started and stopped.
server_too_old, client_too_old Your binaries and the remote server are on different protocols. See upgrading.
Connected, but the wrong python A profile problem rather than a connection problem. Compare run_command under profile: "raw" with your default.
Edited workspaces.toml by hand, cannot connect Editing it yourself installs nothing and checks nothing. A wrong SSH username quietly produces paths that do not exist. Remove the entry and use workspace add.