{"id":48918394,"url":"https://github.com/buildingopen/moto","last_synced_at":"2026-04-17T04:01:03.505Z","repository":{"id":351913261,"uuid":"1213042320","full_name":"buildingopen/moto","owner":"buildingopen","description":"🛵 One command to run 20+ Claude Code / Codex / opencode agents on a remote Linux server from your Mac. tmux sessions, authenticated Chrome, residential proxy, reboot-proof. Hetzner-tested.","archived":false,"fork":false,"pushed_at":"2026-04-17T03:27:41.000Z","size":62,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-17T03:39:19.402Z","etag":null,"topics":["agent-farm","agents","ai-agents","chrome-automation","claude-code","codex","dev-server","devops","docker","hetzner","homelab","iterm","opencode","remote-development","residential-proxy","reverse-tunnel","self-hosted","sshfs","tmux","vps"],"latest_commit_sha":null,"homepage":"https://github.com/buildingopen/moto#readme","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/buildingopen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-17T01:43:38.000Z","updated_at":"2026-04-17T03:27:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/buildingopen/moto","commit_stats":null,"previous_names":["buildingopen/moto"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/buildingopen/moto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buildingopen%2Fmoto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buildingopen%2Fmoto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buildingopen%2Fmoto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buildingopen%2Fmoto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buildingopen","download_url":"https://codeload.github.com/buildingopen/moto/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buildingopen%2Fmoto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31914458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"online","status_checked_at":"2026-04-17T02:00:06.879Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-farm","agents","ai-agents","chrome-automation","claude-code","codex","dev-server","devops","docker","hetzner","homelab","iterm","opencode","remote-development","residential-proxy","reverse-tunnel","self-hosted","sshfs","tmux","vps"],"created_at":"2026-04-17T04:00:48.094Z","updated_at":"2026-04-17T04:01:03.497Z","avatar_url":"https://github.com/buildingopen.png","language":"Shell","readme":"# moto 🛵\n\n\u003e Your Mac is the remote control. A Linux box is the garage. **One command brings every agent window back.**\n\n\u003e **Status: v0.1 — experimental.** This is extracted from a setup that runs 20+ concurrent Claude sessions on a Hetzner AX41 24/7. The code and docs are solid, but it has not yet been end-to-end installed on a clean box from this repo. Expect small paper cuts. Issues + PRs very welcome.\n\n`moto` is an opinionated, reproducible setup for running an army of AI coding agents (Claude Code, Codex, opencode) on a big Linux box, controlled from your Mac, with:\n\n- 🪟 **One iTerm window, many tabs** — every agent session as a tab, restored with one command after a reboot, laptop close, or Mac sleep\n- 🔐 **Full-access Mac tunnel** — the server can read/write your Mac's `~/.claude` live over SSHFS (reverse tunnel), so your local config is the source of truth\n- 🍎 **`moto`** — one command from the Mac: `moto up` reopens everything, `moto new` spawns a new session, `moto kill` cleans up\n- ♻️ **Reboot / OOM survival** — `tmux` is OOM-immune, containers auto-restart, SSHFS re-mounts every 30s, stale processes are reaped nightly\n- 🌐 **Residential-IP egress** — drop-in proxy container, all agent traffic rewritten through your provider of choice\n- 🧰 **Code-execution sandboxes** — pre-wired containers for rendering, Node dev servers, and a logged-in headless Chrome with CDP exposed on the Docker bridge\n- 🧹 **Auto-cleanup** — orphan `next dev` / `tsx watch` / Chrome / old `node_modules` are garbage-collected so the box doesn't rot\n\nBuilt by [@federicodeponte](https://github.com/federicodeponte) to run 20+ concurrent Claude sessions on a Hetzner AX41 without ever babysitting the box.\n\n---\n\n## Who is this for?\n\n- **You run Claude Code (or Codex, or opencode) all day** and your laptop's fan is tired.\n- **You already have a VPS / dedicated box** (Hetzner, OVH, Latitude, Fly machine, your own homelab) and want to stop SSH-ing in and re-creating tmux windows by hand.\n- **You want agents that survive**: Mac sleep, laptop closed, server OOM, server reboot — `moto up` restores the same 20 tabs in one iTerm window every time.\n- **You need agents that look logged-in**: shared Chrome with CDP on the Docker bridge, so agents attach to an already-authenticated browser instead of logging into Google / GitHub / LinkedIn per session.\n- **You don't want to maintain scattered dotfiles**: the whole setup is one repo, one `install.sh mac`, one `install.sh server-remote`.\n\nNot for you if: you only run agents locally, you're on Windows, or you're looking for a hosted SaaS.\n\n---\n\n## 60-second quickstart\n\n```bash\ngit clone https://github.com/buildingopen/moto.git\ncd moto\ncp .env.example .env\n$EDITOR .env              # fill in AX41_HOST, MAC_USER, etc.\n\n./install.sh mac          # on your Mac\n./install.sh server       # via SSH on your Linux box\n```\n\nThen from the Mac:\n\n```bash\nmoto up                   # reopen every tmux session in ONE iTerm window\nmoto new myproj/feature   # spawn a fresh Claude session\nmoto ls                   # list active sessions\nmoto kill myproj/feature  # kill one\n```\n\n---\n\n## Architecture\n\n```\n┌────────────────────────────── YOUR MAC ──────────────────────────────┐\n│                                                                      │\n│   iTerm (one window, N tabs)        ~/.claude  (source of truth)     │\n│        │                                 ▲                           │\n│        │ tmux -CC (ControlCC)            │ sshfs reverse mount       │\n│        │ over SSH ControlMaster          │                           │\n│        ▼                                 │                           │\n│   moto CLI  ──── ssh ax41 ────► ax41:22  │   ◄── ssh -R 2222 ─┐      │\n│                                          │        Mac sshd     │      │\n└──────────────────────────────────────────┼─────────────────────┼──────┘\n                                           │                     │\n┌──────────────────────── YOUR LINUX BOX ──┼─────────────────────┼──────┐\n│                                          ▼                     │      │\n│   /mnt/mac-claude  (FUSE view of Mac ~/.claude)                 │      │\n│                                                                 │      │\n│   tmux-server.service (MemoryLow=16G, OOMScoreAdjust=-900)      │      │\n│     ├─ tmux session  myproj/feature  → claude                   │      │\n│     ├─ tmux session  other/main      → codex                    │      │\n│     └─ ... (each a tab in your Mac iTerm)                       │      │\n│                                                                 │      │\n│   authenticated-chrome.service     → Xvfb :98 + Chrome :9222 ◄──┤      │\n│   chrome-bridge-keeper.service     → CDP keepalive              │      │\n│   cdp-docker-proxy.service         → 172.17.0.1:9222 for agents │      │\n│                                                                 │      │\n│   mac-mount-check.timer   → every 30s: remount if stale ────────┘      │\n│   moto-cleanup.timer      → every 10min: reap orphans                  │\n│   node-modules-gc.timer   → nightly: rm old node_modules               │\n│                                                                        │\n│   docker compose: ┌──────────────────────────────────────────┐         │\n│                   │ proxy  (residential IP egress, all-in)   │         │\n│                   │ runtime-api  (node execution sandbox)    │         │\n│                   │ dev-sandbox  (sshd + node, port 2223)    │         │\n│                   │ cloudflared  (outbound public tunnels)   │         │\n│                   └──────────────────────────────────────────┘         │\n└────────────────────────────────────────────────────────────────────────┘\n```\n\nSee [`docs/architecture.md`](docs/architecture.md) for the full diagram.\n\n---\n\n## What `moto` does differently\n\n| Problem | Typical solution | `moto` |\n|---|---|---|\n| Laptop sleeps, agents die | Run on laptop, restart | Agents live in `tmux` on server, Mac just attaches |\n| Server OOM kills your session | `oom_score_adj` guesses | `tmux-server.service` reserves 16 GB + `OOMScoreAdjust=-900`; `earlyoom` picks someone else |\n| Claude config drifts between machines | `rsync` / Dropbox / git | SSHFS reverse mount — the Mac *is* the filesystem |\n| Re-opening 20 windows is tedious | Shell for-loop | `moto up` — kills iTerm, creates one window, opens every session as a tab, retries stubborn ones 5× |\n| Agents get rate-limited by IP | Random VPN | Dedicated proxy container; only outbound agent traffic is rewritten |\n| Agents need to use logged-in services | New login per session | Shared `authenticated-chrome` with CDP — agents attach, don't log in |\n| Reboot nukes everything | `docker-compose up` by hand | All services are systemd-managed with `Restart=on-failure`, containers are `--restart unless-stopped` |\n\n---\n\n## Requirements\n\n**Mac**: macOS 13+, iTerm2, Homebrew, `ssh` (ControlMaster), OpenSSH server (for reverse tunnel).\n\n**Server**: Debian 12 / Ubuntu 22.04+, root or sudo, ≥16 GB RAM recommended, public IPv4. Tested on Hetzner AX41.\n\n**Agent CLIs (install separately on the server after `./install.sh server`)** — `moto` wraps these, it doesn't bundle them:\n\n```bash\n# Claude Code\nnpm i -g @anthropic-ai/claude-code \u0026\u0026 claude /login\n\n# Codex (OpenAI)\nnpm i -g @openai/codex\n\n# opencode (optional)\nnpm i -g opencode\n```\n\n`moto new foo/bar` needs `claude` in `PATH`. `moto newx` needs `codex`. `moto newo` needs `opencode`. Only install what you'll actually use.\n\n---\n\n## Commands\n\n```\nmoto up              # restore all sessions in one iTerm window (idempotent)\nmoto new NAME        # create session NAME (format: project/task)\nmoto attach NAME     # attach existing session as a new iTerm tab\nmoto ls              # list server sessions\nmoto kill NAME       # kill a session\nmoto status          # server health: tmux count, mount status, chrome, containers\nmoto img PATH        # scp an image to the server and print its remote path\nmoto logs            # tail moto-cleanup + mac-mount-check logs\nmoto down            # detach all clients (leaves sessions running)\nmoto doctor          # diagnose the setup\n```\n\nLegacy aliases (`ax`, `axo`, `axn`, `axk`, `axl`, `axwin`, `aximg`, `axd`, `axq`) are preserved — see [`mac/shell/20-sessions.zsh`](mac/shell/20-sessions.zsh).\n\n---\n\n## Documentation\n\n- [Architecture](docs/architecture.md) — how the pieces fit\n- [Bootstrap a fresh server](docs/bootstrap.md) — zero-to-moto on a new box\n- [Browser login](docs/browser-login.md) — how to log `authenticated-chrome` into Google/GitHub/LinkedIn\n- [Residential proxy setup](docs/proxy.md) — Bright Data, Smartproxy, or generic SOCKS5\n- [Reboot recovery](docs/reboot-recovery.md) — what happens when the box comes back up\n- [Claude config sync (why SSHFS)](docs/claude-sync.md) — why not rsync/git\n\n---\n\n## Known gaps (v0.1)\n\n- **Cold install validated in a throwaway container** (`debian:12` on the author's Hetzner AX41 — 50/50 checks pass, see [`server/test/`](server/test/)). Not yet validated on a bare-metal box from zero, but every piece the installer touches on a new box — apt, Chrome, Docker CE, systemd unit syntax, script layout — is exercised by that test.\n- **Residential proxy sidecar end-to-end tested** with `server/test/proxy-smoke.sh`: URL parser handles http/https/socks5 with and without auth, direct egress works when `PROXY_URL` is empty, and chained traffic is proved to flow through the upstream (parent tinyproxy's own logs show the forwarded request). Tinyproxy under the hood — we tried 3proxy first, parent directive was silently ignored across three versions.\n- **Agent CLIs not bundled**: `claude` / `codex` / `opencode` are npm installs — see [Requirements](#requirements).\n- **`chrome-bridge-keeper`** ships as a simple bash CDP-ping loop. The author's real setup uses a ~300-line Python variant that also auto-patches the Claude Code browser extension; too specific to include here. Add `# MOTO_KEEP_LOCAL` to your own script and `server/install.sh` will preserve it.\n- **x86_64 only** for now — Chrome, Docker images, and the Hetzner target are all amd64. ARM support is untested.\n- **IPv6**: reverse tunnel and SSHFS work over IPv4; IPv6 is not explicitly tested.\n- **No automated e2e test** for the reverse-tunnel → SSHFS → `moto up` path. `moto doctor` covers static health.\n\nIf you hit something, please open an issue — most gaps are 10-minute fixes once surfaced.\n\n## Contributing\n\nPRs welcome. Before submitting:\n\n```bash\nshellcheck -S warning server/bin/* mac/bin/moto server/test/*.sh server/docker/proxy/entrypoint.sh\n(cd server/docker \u0026\u0026 docker compose config) \u003e/dev/null\nHOST=your.host ./server/test/run-container-test.sh   # full isolated install test\nHOST=your.host ./server/test/proxy-smoke.sh          # proxy sidecar end-to-end\n```\n\nSee [`server/test/README.md`](server/test/README.md) for what the tests cover.\n\n---\n\n## Related projects\n\n`moto` pairs well with other [BuildingOpen](https://github.com/buildingopen) tools for Claude Code operators:\n\n| Project | What it does |\n|---------|--------------|\n| **[claude-setup](https://github.com/buildingopen/claude-setup)** | The Claude Code config (`~/.claude`) that moto syncs to the server — 60+ skills, 12 safety hooks, CLAUDE.md templates |\n| **[openqueen](https://github.com/buildingopen/openqueen)** | Autonomous agent orchestrator — spawn Claude / Codex workers on moto from WhatsApp or Telegram |\n| **[bouncer](https://github.com/buildingopen/bouncer)** | Gemini-powered quality gate that audits Claude's output before it can stop |\n| **[session-recall](https://github.com/buildingopen/session-recall)** | Recover Claude Code context after automatic compaction |\n| **[browse](https://github.com/buildingopen/browse)** | Browser automation CLI — the agents running inside moto use this against the shared Chrome CDP |\n| **[openbrowser](https://github.com/buildingopen/openbrowser)** | MCP server that gives agents authenticated browser access |\n| **[blast-radius](https://github.com/buildingopen/blast-radius)** | Find every file affected by a change — one bash script |\n\n## License\n\nMIT © Federico de Ponte. See [LICENSE](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuildingopen%2Fmoto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbuildingopen%2Fmoto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuildingopen%2Fmoto/lists"}