Companion Offload
Offload the current Claude Code session to a remote Companion sandbox so it can continue running autonomously in the cloud.
When to use
- The user says "offload this task" or "run this in the cloud"
- A long-running task needs to continue without tying up the local machine
- The user wants to hand off work to their Companion sandbox
Prerequisites
- The
companionCLI must be installed and the user must be logged in (companion login) - An active sandbox must exist and be running (
companion lsto check) rsyncmust be available locally
Instructions
Step 1: Verify companion CLI is available and user is logged in
companion whoami
If this fails, tell the user to run companion login first.
Step 2: Check that a sandbox is running
companion ls
If no sandbox exists or it's not running, tell the user to create one with companion create <handle>.
Step 3: Inject SSH key into the sandbox
Use --inject-only to set up SSH access without connecting:
companion ssh --inject-only
This outputs the SSH key path and the manual SSH command. Parse the output to extract:
- The key path (e.g.
~/.companion/ssh/id_ed25519_<handle>) - The sandbox handle
Step 4: Build the SSH/rsync connection parameters
The Companion SSH gateway uses a ProxyCommand. Construct the connection parameters:
HANDLE="<sandbox-handle-from-step-2>"
KEY_PATH="$HOME/.companion/ssh/id_ed25519_$HANDLE"
SSH_GATEWAY="${COMPANION_SSH_GATEWAY:-ssh.os.companion.ai}"
SSH_PORT="2222"
PROXY_CMD="sh -c '( printf \"COMPANION:${HANDLE}\n\"; cat ) | nc ${SSH_GATEWAY} ${SSH_PORT}'"
SSH_OPTS="-i $KEY_PATH -o StrictHostKeyChecking=accept-new -o LogLevel=ERROR -o ProxyCommand=$PROXY_CMD"
Step 5: Determine the remote workspace path
ssh $SSH_OPTS node@$HANDLE '[ -d /home/node/.openclaw/workspace ] && echo "/home/node/.openclaw/workspace" || ([ -d /home/node/.pi/workspace ] && echo "/home/node/.pi/workspace" || echo "NONE")'
If NONE, use /home/node/.openclaw/workspace and create it:
ssh $SSH_OPTS node@$HANDLE 'mkdir -p /home/node/.openclaw/workspace'
Store the result as REMOTE_WORKSPACE.
Step 6: Install Claude Code on the sandbox if missing
ssh $SSH_OPTS node@$HANDLE 'command -v claude >/dev/null 2>&1 && echo "installed" || echo "missing"'
If missing:
ssh $SSH_OPTS node@$HANDLE 'curl -fsSL https://claude.ai/install.sh | sh 2>/dev/null || npm install -g @anthropic-ai/claude-code'
Step 7: Sync the repository to the sandbox
Use rsync over the SSH ProxyCommand to transfer the current project:
rsync -avz --progress \
--exclude='node_modules' \
--exclude='.git/objects' \
--exclude='__pycache__' \
--exclude='.venv' \
--exclude='venv' \
--exclude='.next' \
--exclude='dist' \
--exclude='build' \
-e "ssh $SSH_OPTS" \
"$(pwd)/" "node@$HANDLE:$REMOTE_WORKSPACE/"
Step 8: Sync the Claude session and config
Transfer the project-level .claude/ directory (session history, project memory) if it exists:
rsync -avz --progress \
-e "ssh $SSH_OPTS" \
"$(pwd)/.claude/" "node@$HANDLE:$REMOTE_WORKSPACE/.claude/"
Also sync the global ~/.claude/ directory (global settings, global memory, credentials, CLAUDE.md):
rsync -avz --progress \
-e "ssh $SSH_OPTS" \
"$HOME/.claude/" "node@$HANDLE:/home/node/.claude/"
Both are needed: the project-level .claude/ has session history for --continue, and the global ~/.claude/ has settings, global memory, and the user's global CLAUDE.md instructions.
Step 9: Transfer environment variables
Capture relevant env vars (especially ANTHROPIC_API_KEY) and send them to the sandbox:
env | grep -v '^_=' | grep -v '^SHELL=' | grep -v '^TERM_' | grep -v '^SSH_' | \
grep -v '^DISPLAY=' | grep -v '^HOME=' | grep -v '^USER=' | grep -v '^LOGNAME=' | \
grep -v '^PATH=' | grep -v '^PWD=' | grep -v '^OLDPWD=' | grep -v '^SHLVL=' \
> /tmp/companion_env_export.txt
rsync -avz -e "ssh $SSH_OPTS" /tmp/companion_env_export.txt "node@$HANDLE:$REMOTE_WORKSPACE/.companion_env"
rm -f /tmp/companion_env_export.txt
Step 10: Launch Claude Code on the sandbox
If the user provided a specific task/prompt to offload:
ssh -t $SSH_OPTS node@$HANDLE "cd $REMOTE_WORKSPACE && set -a && source .companion_env 2>/dev/null; set +a && claude --dangerously-skip-permissions --prompt '${TASK_PROMPT}'"
Otherwise, continue the session:
ssh -t $SSH_OPTS node@$HANDLE "cd $REMOTE_WORKSPACE && set -a && source .companion_env 2>/dev/null; set +a && claude --dangerously-skip-permissions --continue"
Step 11: Confirm to the user
After launching, tell the user:
- The session is now running on their Companion sandbox
- They can reconnect with:
companion sshthencd $REMOTE_WORKSPACE && claude --continue - To sync results back locally:
rsync -avz -e "ssh $SSH_OPTS" node@$HANDLE:$REMOTE_WORKSPACE/ ./
Important notes
- Always exclude
node_modules,.git/objects, and other large directories from rsync - The
--dangerously-skip-permissionsflag is required so the remote session runs autonomously - If the sandbox already has
ANTHROPIC_API_KEYset, the offloaded session will use it. Otherwise ensure Step 9 transfers it. - Session history in
.claude/gives the remote Claude full context of the local conversation - The SSH gateway at
ssh.os.companion.ai:2222routes connections via theCOMPANION:<handle>prefix
Error handling
- If
companion whoamifails: user needs tocompanion login - If
companion lsshows no sandbox: user needs tocompanion create <handle> - If SSH key injection fails: sandbox may not be running
- If rsync fails: check disk space on sandbox
- If Claude is not installable: ensure Node.js >= 18 is on the sandbox