Skip to content

foxfollow/remote-launcher

Repository files navigation

remote-launcher

ShellCheck Claude Code os-macOS License

Launch Claude Code on your Mac while transparently executing every Bash command on a remote Linux host via SSH. Anthropic credentials never touch the remote host.

Why

The default Claude Code workflow for "operate on a remote box" is to install Claude Code on that box and SSH into it. That puts your OAuth token on a machine you may not fully control. remote-launcher keeps Claude (and your token) on the Mac, and ships only individual shell commands across SSH. Files created during a session live on the remote host where they're actually needed.

Architecture

  ┌────────────────────────┐         ┌─────────────────────────┐
  │ Mac                    │         │ Remote VM               │
  │                        │         │                         │
  │ ┌────────────────────┐ │         │                         │
  │ │ Claude Code        │ │         │                         │
  │ │ ─ Read/Edit/Write ─┼─┼── Mac   │                         │
  │ │ ─ Bash tool ───────┼─┼─SSH────►│ /bin/bash → executes    │
  │ └────────────────────┘ │         │     here, files here    │
  │   ▲                    │         │                         │
  │   │ OAuth from keychain│         │                         │
  │   │ stays here         │         │                         │
  └───┴────────────────────┘         └─────────────────────────┘
  • Bash tool → VM via CLAUDE_CODE_SHELL env var (officially supported by Claude Code 2.0.65+).
  • Read/Edit/Write tools → Mac. A system-prompt addendum tells the model to use Bash heredoc for VM-side files.
  • Token isolation. CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 strips Anthropic credentials from the bash subprocess environment before SSH runs.

Requirements

  • macOS (Apple Silicon recommended for the test harness; the launcher itself runs anywhere with bash + ssh)
  • Claude Code 2.0.65 or later
  • SSH key auth to your target host (no passwords, no agent forwarding by default)
  • For tests: apple/container (macOS 26+) and jq

Install

git clone https://github.com/foxfollow/remote-launcher.git ~/code/remote-launcher
cd ~/code/remote-launcher
./install.sh

install.sh is non-destructive: it creates symlinks in ~/.local/bin/ and registers the skill in ~/.claude/skills/remote-launcher/.

Make sure ~/.local/bin is in your PATH.

Use

remote-launcher myvm                                  # bare interactive
remote-launcher myvm --task ~/projects/demo/TASK.md   # pre-load a task
remote-launcher myvm --confirm-bash                   # require approval for every Bash call
remote-launcher myvm -pfp                             # auto-accept changed host fingerprint (after VM snapshot/rebuild)
remote-launcher winhost --shell powershell            # force PowerShell on the remote (default: auto-detect)
remote-launcher myvm -- --model claude-opus-4-7       # forward args to claude

Remote shell flavor. By default the launcher probes the host and picks between POSIX (/bin/sh) and PowerShell (pwsh or powershell). When it detects PowerShell, it loads a PowerShell-flavored system prompt so the model writes Get-Content / Set-Content / Select-String instead of cat / grep / sed, and runs commands via -EncodedCommand so quoting stays sane. Override with --shell posix|powershell if auto-detect picks wrong.

Bash auto-approve. By default the launcher passes --allowedTools 'Bash(*)' to Claude so every Bash call runs without an approval prompt. The Bash tool here means "go through SSH to the VM" — the VM is physically isolated from the Mac, so the prompts add friction without protection. Read/Edit/Write keep prompting because they hit the Mac filesystem. Pass --confirm-bash to restore prompts for Bash too (useful when the VM holds something you care about).

A walkthrough of the simplest case (single agent installs nginx and verifies) is in examples/single-agent.md.

Multi-host (one agent, multiple VMs)

Give a single Claude session access to two or three VMs at once and let it coordinate between them. Useful when you have, say, a web VM and a DB VM and want one agent to set up the app on one and the schema on the other.

remote-launcher webvm --host dbvm                     # default=webvm, also dbvm
remote-launcher webvm --host dbvm --host cachevm      # three hosts

Inside Claude, route a Bash call by prefixing it with @<host>:

@webvm  systemctl status nginx
@dbvm   psql -c '\dt'
hostname                # no prefix → goes to the default host (webvm)

The launcher injects a multi-host block into the system prompt listing the roster and rules. Each host has its own working directory, ControlMaster socket, and shell-mode cache — cd /tmp on webvm does not affect dbvm. Filesystems are independent: to move a file between hosts, the agent uses scp (host-to-host) or pulls to the Mac and pushes back.

A worked example is in examples/multi-host.md.

Roadmap

  • --shared-workdir <path> — auto-sync a Mac directory to all hosts so Read/Edit/Write on the Mac propagates to every VM.
  • @copy hostA:/path hostB:/path helper for inter-host file transfer.
  • ProxyJump / bastion examples.

Multi-agent

Multiple Claude sessions, each in its own terminal, all targeting the same VM:

# Terminal 1 — init agent (sequential)
remote-launcher myvm --task ~/projects/demo/MASTER.md
# inside Claude: "You are Agent 0."

# Terminals 2 and 3 — workers (parallel)
remote-launcher myvm --task ~/projects/demo/MASTER.md   # × 2
# inside each: "You are Agent 1." / 2

# Terminal 4 — reviewer (sequential)
remote-launcher myvm --task ~/projects/demo/MASTER.md
# "You are Agent 3."

# Pull artifacts back
scp -r myvm:~/multi-demo ~/Downloads/

A complete worked example with a shared MASTER.md is in examples/multi-agent.md.

Security model

See docs/security-model.md. Short version:

Concern How it's handled
Anthropic OAuth on VM macOS keychain only; CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 strips Anthropic env from subprocess env
Credentials in env passed via SSH OpenSSH does not forward env unless SendEnv is set; we don't set it
SSH agent / key chaining Agent forwarding off by default (no -A)
Credentials accidentally written to disk on VM Files originate from bash heredocs on the VM; Mac-side never writes secret files
Connection theft after disconnect ControlPersist=15m; the socket is in $TMPDIR of your Mac user only

The full security model is verified by the test suite — see tests/.

Diagnostics

remote-launcher-doctor                # files / PATH check only
remote-launcher-doctor myvm           # also live SSH + wrapper round-trip

Tests

cd tests
./run-tests.sh

The harness uses Apple's container to spin up an Ubuntu micro-VM with sshd, generates a fresh ed25519 keypair just for the test, and exercises the launcher against it. See tests/README.md.

Limitations

  • Interactive TUIs (vim, htop) on the VM may render poorly — the wrapper does not allocate a pty.
  • Each shell call is a fresh remote shell; environment and aliases do not persist between calls. Working directory does (tracked via state file).
  • No file sync. By design — files live on the VM. To pull artifacts: scp -r myvm:path ~/local.

License

MIT. See LICENSE.

Security disclosures

See SECURITY.md.

About

Run Claude Code on your Mac while every Bash command executes on a remote Linux host over SSH — Anthropic credentials never leave the Mac.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages