Skip to content
antony4859Public

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

relay

Continue an agent session — with your repo's exact working state — on another machine.

relay carries two things to a remote box over SSH and continues there:

  1. Git repo working state — HEAD + commits the remote lacks (via bundle, so unpushed branches work) + tracked changes + untracked files + deletions. Reconstructed so git status on the box matches yours.
  2. Agent conversation — a Claude Code or Codex session (transcript + subagents + memory + todos / rollout + auth), resumed in place inside herdr.

It is project-agnostic — it knows nothing about any specific repo. Anything a repo needs after sync (install deps, start a stack) goes in an optional committed hook the repo provides.

Install

git clone https://github.com/antony4859/relay.git
ln -s "$PWD/relay/relay" ~/.local/bin/relay   # or add the clone to PATH

Quickstart

relay vm create devbox            # spin a GCE box (no Tailscale key needed — uses public IP)
cd ~/some/repo
relay devbox codex <session-id>   # carries THIS repo + your conversation, resumes on the box
relay devbox attach               # hop on and take over
relay vm destroy devbox           # done — zero billing

That's it. Run relay <box> <cmd> from inside any repo. Other commands:

relay init <name> <user@host>     # register a box you can already SSH to (instead of vm create)
relay <box> claude <session-id>   # same as codex, for a Claude session
relay <box> doctor                # one-command health check
relay <box> pull <session-id>     # bring a session transcript back home
relay <box> sync                  # just push repo working-state (no session move)
relay vm stop|start <box>         # pause/resume (stop pauses compute billing)
relay hosts [--live] · relay use <name> · relay rename <old> <new>

Targeting: relay <name> <cmd> hits the named remote; relay <cmd> hits the default (* in relay hosts); or --host <name> / RELAY_HOST_NAME.

Tailscale is optional. With a key (~/.config/relay/tailscale-authkey or RELAY_TS_AUTHKEY) the VM joins your tailnet (private); without one, relay uses the VM's public IP. Codex auth copies automatically; Claude needs a one-time login on the box (relay <box> attach → claude, or set CLAUDE_CODE_OAUTH_TOKEN).

With no session id, relay claude picks your most-recent session for the repo — for interactive "continue what I'm doing here, over there." (Pass an explicit id if the latest isn't the one you mean.)

Orchestrate the box's agent (no attach)

A move is a role change: the box now owns the work, and this side becomes its orchestrator. Instead of attaching interactively, watch, verify, and steer the remote agent over the same SSH channel (relay drives herdr's agent API on the box):

relay <box> status [agent]         # working | idle | blocked
relay <box> tail   [agent] [-n N]  # print the agent's recent output
relay <box> watch  [agent]         # block until it goes idle/blocked (prints each transition)
relay <box> say    [--to A] <text> # send it a message / answer a prompt / brief a fresh agent

agent defaults to the last one relay launched on the box (recorded in ~/.relay/last-agent), so you can omit it. watch is the orchestration primitive — run it in the background and it emits a line on every status change, exiting when the agent needs you (idle = finished a turn, blocked = hit a prompt). The loop is: watch → tail (verify) → say (steer/unblock) → watch.

say types the text into the agent's prompt and submits it (herdr's raw agent send only types without pressing Enter, so say follows with an Enter keystroke). A moved session (relay claude/codex) is auto-nudged to continue on launch so the work resumes on the box without you sending the first message (--no-kickoff / --kickoff "<msg>" to control it); a fresh agent (relay up) starts idle with no task, so say it the work first.

Per-repo hooks (optional, committed in the repo)

relay stays generic; a repo opts in to its own setup:

  • .agent-remote/sync — newline list of extra gitignored paths to ship (e.g. .env files). Normal tracked + untracked files always sync; this is for the gitignored ones a repo genuinely needs on the box.
  • .agent-remote/setup.sh — run on the box (in the repo) after each sync: install deps, start a stack, whatever. No hook → relay just places code + resumes.

Example (<your-repo>/.agent-remote/):

# .agent-remote/sync
.env.dev.keys
.env.dev.local
# .agent-remote/setup.sh
#!/usr/bin/env bash
# install deps + start the local stack
...

Configuration

Everything personal lives under ~/.config/relay/, outside the repo:

  • config — optional personal defaults, sourced by relay on startup (see config.example):
    RELAY_GCE_ZONE="${RELAY_GCE_ZONE:-europe-north2-a}"
    RELAY_GCE_MACHINE_TYPE="${RELAY_GCE_MACHINE_TYPE:-e2-standard-4}"
    The VAR="${VAR:-…}" form keeps env vars set by the caller winning over the file.
  • hosts/<name> — one file per registered remote (written by relay init / vm create).
  • default — name of the default remote.
  • tailscale-authkey — optional Tailscale auth key for new VMs.

GCE VMs

relay vm create <name> needs gcloud authed (gcloud auth login) with a project set. A Tailscale auth key is optional — with one the VM joins your tailnet; without one relay uses the VM's public IP.

It creates an Ubuntu VM (zone/machine-type from ~/.config/relay/config, --zone/--machine-type, or the defaults us-central1-a/e2-standard-4), runs bootstrap-linux.sh (git/node/uv/docker + claude/codex/herdr + optional tailnet join), and registers it as a relay host. relay vm stop|start|destroy <name> manage its lifecycle (stop pauses compute billing; the disk persists).

How a box is reachable

relay connects with plain SSH — over your tailnet when the box is on it, otherwise via the box's public IP. It deliberately does not use Tailscale SSH (which can demand interactive browser re-auth that non-interactive relay can't satisfy); the box runs regular sshd with the key relay authorizes at create time.

Auth on the box

  • Claude: no Keychain on Linux — log in once (claude) or set CLAUDE_CODE_OAUTH_TOKEN (from claude setup-token) in ~/.zshenv.
  • Codex: relay codex copies your auth.json over automatically if the box has none.

Notes

  • One-way by design: after a move, the box owns that session — don't keep resuming the local copy or the transcripts diverge. Switch to the orchestrator role (watch/tail/say) instead; relay pull brings it home.
  • Transfers auto-retry on a dropped connection (RELAY_RETRIES, default 3).
  • relay never pushes to GitHub; commits move via git bundle.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages