* feat(digitalocean): guided readiness checklist before deploy Runs evaluateDigitalOceanReadiness after cloud auth and before region/size selection so users fix billing/SSH/OpenRouter blockers early, with a checklist UI that rechecks after each fix. Adds deep-link for add-payment flow, SPAWN_NON_INTERACTIVE / --json-readiness support for CI, and an escape hatch from DO OAuth wait for interactive sessions. Other clouds unchanged. Ported from digitalocean/spawn#2 (Scott Miller @scott). Bumps CLI to 1.1.0. Refactors the new preflight TTY-gating test to drive process.std*.isTTY directly with descriptor save/restore and clears stale ~/.config/spawn/digitalocean.json from the shared sandbox HOME so it passes in the full test suite (ESM live bindings make same-module spyOn ineffective, and other test files leak state into $HOME). Co-Authored-By: Scott Miller <scottmiller@digitalocean.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): update-check mock versions for 1.1.0 version bump Mock "newer" versions (1.0.99) were no longer newer than the current 1.1.0 version, causing all update-check tests to fail. Bumped mock versions to 99.0.0 for general tests, 1.1.99 for patch, 1.2.0 for minor, keeping 2.0.0 for major. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(readiness): expand coverage + remove aspirational coverage threshold - Add evaluateDigitalOceanReadiness tests: auth failure, all-pass, email/payment/droplet/ssh/openrouter blockers, multi-blocker ordering, saved key fallback, edge cases (limit=0, count API failure) - Expand checklistLineStatus tests: all 6 blocker codes, pending-when- do_auth-blocked, all-blockers-active scenario - Add READINESS_CHECKLIST_ROWS validation tests - Expand sortBlockers tests: empty input, dedup, canonical order, single - Remove coverageThreshold from bunfig.toml — main was already at 82.99% functions vs 90% threshold (never enforced on push, only on PRs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude <claude@anthropic.com> Co-authored-by: Scott Miller <scottmiller@digitalocean.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Ahmed Abushagur <ahmed@abushagur.com> |
||
|---|---|---|
| .claude | ||
| .githooks | ||
| .github | ||
| .husky | ||
| assets | ||
| fixtures | ||
| lint | ||
| packages | ||
| packer | ||
| sh | ||
| skills | ||
| .gitignore | ||
| .shellcheckrc | ||
| biome.json | ||
| bun.lock | ||
| bunfig.toml | ||
| CLAUDE.md | ||
| commitlint.config.ts | ||
| LICENSE | ||
| manifest.json | ||
| package.json | ||
| README.md | ||
Spawn
Launch any AI agent on any cloud with a single command. Coding agents, research agents, self-hosted AI tools — Spawn deploys them all. All models powered by OpenRouter. (ALPHA software, use at your own risk!)
9 agents. 7 clouds. 63 working combinations. Zero config.
Install
macOS / Linux — and Windows users inside a WSL2 terminal (Ubuntu, Debian, etc.):
curl -fsSL https://openrouter.ai/labs/spawn/cli/install.sh | bash
Windows PowerShell (outside WSL):
irm https://openrouter.ai/labs/spawn/cli/install.ps1 | iex
Usage
spawn # Interactive picker
spawn <agent> <cloud> # Launch directly
spawn matrix # Show the full agent x cloud matrix
Examples
spawn # Interactive picker
spawn claude sprite # Claude Code on Sprite
spawn codex hetzner # Codex CLI on Hetzner
spawn claude sprite --prompt "Fix bugs" # Non-interactive with prompt
spawn codex sprite -p "Add tests" # Short form
spawn claude # Show clouds available for Claude
spawn delete # Delete a running server
spawn delete -c hetzner # Delete a server on Hetzner
Commands
| Command | Description |
|---|---|
spawn |
Interactive agent + cloud picker |
spawn <agent> <cloud> |
Launch agent on cloud directly |
spawn <agent> <cloud> --dry-run |
Preview without provisioning |
spawn <agent> <cloud> --zone <zone> |
Set zone/region for the cloud |
spawn <agent> <cloud> --size <type> |
Set instance size/type for the cloud |
spawn <agent> <cloud> --prompt "text" |
Non-interactive with prompt (or -p) |
spawn <agent> <cloud> --prompt-file <file> |
Prompt from file (or -f) |
spawn <agent> <cloud> --headless |
Provision and exit (no interactive session) |
spawn <agent> <cloud> --output json |
Headless mode with structured JSON on stdout |
spawn <agent> <cloud> --model <id> |
Set the model ID (overrides agent default) |
spawn <agent> <cloud> --config <file> |
Load options from a JSON config file |
spawn <agent> <cloud> --steps <list> |
Comma-separated setup steps to enable |
spawn <agent> <cloud> --custom |
Show interactive size/region pickers |
spawn <agent> |
Show available clouds for an agent |
spawn <cloud> |
Show available agents for a cloud |
spawn matrix |
Full agent x cloud matrix |
spawn list |
Browse and rerun previous spawns |
spawn list <filter> |
Filter history by agent or cloud name |
spawn list -a <agent> |
Filter history by agent |
spawn list -c <cloud> |
Filter history by cloud |
spawn list --flat |
Show flat list (disable tree view) |
spawn list --json |
Output history as JSON |
spawn list --clear |
Clear all spawn history |
spawn tree |
Show recursive spawn tree (parent/child relationships) |
spawn tree --json |
Output spawn tree as JSON |
spawn history export |
Dump history as JSON to stdout (used by parent VMs) |
spawn fix |
Re-run agent setup on an existing VM (re-inject credentials, reinstall) |
spawn fix <spawn-id> |
Fix a specific spawn by name or ID |
spawn link <ip> |
Register an existing VM by IP |
spawn link <ip> --agent <agent> |
Specify the agent running on the VM |
spawn link <ip> --cloud <cloud> |
Specify the cloud provider |
spawn last |
Instantly rerun the most recent spawn |
spawn agents |
List all agents with descriptions |
spawn clouds |
List all cloud providers |
spawn feedback "message" |
Send feedback to the Spawn team |
spawn uninstall |
Uninstall spawn CLI and optionally remove data |
spawn update |
Check for CLI updates |
spawn delete |
Interactively select and destroy a cloud server |
spawn delete -a <agent> |
Filter servers to delete by agent |
spawn delete -c <cloud> |
Filter servers to delete by cloud |
spawn delete --name <name> --yes |
Headless delete by name (no prompts) |
spawn status |
Show live state of cloud servers |
spawn status -a <agent> |
Filter status by agent |
spawn status -c <cloud> |
Filter status by cloud |
spawn status --prune |
Remove gone servers from history |
spawn help |
Show help message |
spawn version |
Show version |
Config File
The --config flag loads options from a JSON file. CLI flags override config values.
{
"model": "openai/gpt-5.3-codex",
"steps": ["github", "browser", "telegram"],
"name": "my-dev-box",
"setup": {
"telegram_bot_token": "123456:ABC-DEF...",
"github_token": "ghp_xxxx"
}
}
spawn codex gcp --config setup.json --headless --output json
Setup Steps
Control which optional setup steps run with --steps:
spawn openclaw gcp --steps github,browser # Only GitHub + Chrome
spawn claude gcp --steps "" # Skip all optional steps
Available steps vary by agent:
| Step | Agents | Description |
|---|---|---|
github |
All | GitHub CLI + git identity |
reuse-api-key |
All | Reuse saved OpenRouter key |
browser |
openclaw | Chrome browser (~400 MB) |
telegram |
openclaw | Telegram bot (set TELEGRAM_BOT_TOKEN for non-interactive) |
whatsapp |
openclaw | WhatsApp linking (interactive QR scan, skipped in headless) |
Fast Mode
Use --fast for significantly faster deploys. Enables all speed optimizations:
spawn claude hetzner --fast
What --fast does:
- Parallel boot: server creation runs concurrently with API key prompt and account checks
- Tarballs: installs agents from pre-built tarballs instead of live install
- Skip cloud-init: for lightweight agents (Claude, OpenCode, Hermes), skips the package install wait since the base OS already has what's needed
- Snapshots: uses pre-built cloud images when available (Hetzner, DigitalOcean)
Beta Features
Individual optimizations can be enabled separately with --beta <feature>. The flag is repeatable:
spawn claude gcp --beta tarball --beta parallel
| Feature | Description |
|---|---|
tarball |
Use pre-built tarball for agent install (faster, skips live install) |
images |
Use pre-built cloud images/snapshots (faster boot) |
parallel |
Parallelize server boot with setup prompts |
recursive |
Install spawn CLI on VM so it can spawn child VMs |
sandbox |
Run local agents in a Docker container (sandboxed) |
--fast enables tarball, images, and parallel (not recursive or sandbox).
Recursive Spawn
Use --beta recursive to let spawned VMs create their own child VMs:
spawn claude hetzner --beta recursive
What this does:
- Installs spawn CLI on the remote VM
- Delegates credentials (cloud + OpenRouter) so child VMs can authenticate
- Injects parent tracking (
SPAWN_PARENT_ID,SPAWN_DEPTH) into the VM environment - Passes
--beta recursiveto children so they can also spawn recursively
View the spawn tree:
spawn tree
# spawn-abc Claude Code / Hetzner 2m ago
# ├─ spawn-def Codex CLI / Hetzner 1m ago
# └─ spawn-ghi OpenClaw / Hetzner 30s ago
# └─ spawn-jkl Claude Code / Hetzner 10s ago
Tear down an entire tree:
spawn delete --cascade <id> # Delete a VM and all its children
Sandboxed Local
Use --beta sandbox to run local agents inside a Docker container instead of directly on your machine:
spawn claude local --beta sandbox
What this does:
- Pulls the agent's Docker image from
ghcr.io/openrouterteam/spawn-<agent> - Runs the agent in a container with filesystem, network, and process isolation
- Auto-installs Docker if not present (OrbStack on macOS, docker.io on Linux)
- Cleans up the container automatically when the session ends
In the interactive picker, --beta sandbox adds a "Local Machine (Sandboxed)" option alongside the regular "Local Machine":
spawn --beta sandbox # Interactive picker shows both local options
spawn openclaw local --beta sandbox # Direct launch, sandboxed
Without the CLI
Every combination works as a one-liner — no install required:
bash <(curl -fsSL https://openrouter.ai/labs/spawn/{cloud}/{agent}.sh)
Non-Interactive Mode
Skip prompts by providing environment variables:
# OpenRouter API key (required for all agents)
export OPENROUTER_API_KEY=sk-or-v1-xxxxx
# Cloud-specific credentials (varies by provider)
# Note: Sprite uses `sprite login` for authentication
export HCLOUD_TOKEN=... # For Hetzner
export DIGITALOCEAN_ACCESS_TOKEN=... # For DigitalOcean
# Run non-interactively
spawn claude hetzner
You can also use inline environment variables:
OPENROUTER_API_KEY=sk-or-v1-xxxxx spawn claude sprite
Get your OpenRouter API key at: https://openrouter.ai/settings/keys
For cloud-specific auth, see each cloud's README in this repository.
Troubleshooting
Installation issues
If spawn fails to install, try these steps:
-
Check bun version: spawn requires bun >= 1.2.0
bun --version bun upgrade # if needed -
Manual installation: If auto-install fails, install bun first
curl -fsSL https://bun.sh/install | bash source ~/.bashrc # or ~/.zshrc for zsh curl -fsSL https://openrouter.ai/labs/spawn/cli/install.sh | bash -
PATH issues: If
spawncommand not found after install# Add to your shell config (~/.bashrc or ~/.zshrc) export PATH="$HOME/.local/bin:$PATH"
Windows (PowerShell)
-
Use the PowerShell installer — not the bash one:
irm https://openrouter.ai/labs/spawn/cli/install.ps1 | iexThe
.ps1extension is required. The defaultinstall.shis bash and won't work in PowerShell. -
Set credentials via environment variables before launching:
$env:OPENROUTER_API_KEY = "sk-or-v1-xxxxx" $env:DIGITALOCEAN_ACCESS_TOKEN = "dop_v1_xxxxx" # For DigitalOcean $env:HCLOUD_TOKEN = "xxxxx" # For Hetzner spawn openclaw digitalocean -
Local build failures during auto-update are normal on Windows — the CLI falls back to a pre-built binary automatically. You may see a brief build error followed by a successful update.
-
EISDIR or EEXIST errors on config files: If you see errors about
digitalocean.jsonbeing a directory, delete it:Remove-Item -Recurse -Force "$HOME\.config\spawn\digitalocean.json" -ErrorAction SilentlyContinue spawn openclaw digitalocean
Headless JSON mode — agent exits immediately
When using --headless --output json with Claude Code, you must also pass --prompt (or -p). Without it, Claude exits with Input must be provided through stdin or --prompt and the JSON output will show "status":"error":
# WRONG — Claude exits immediately
spawn claude gcp --headless --output json
# RIGHT — provide a prompt
spawn claude gcp --headless --output json --prompt "Fix all linter errors"
Note: auto-update messages may appear before the JSON on older CLI versions. Run spawn update to get the fix.
Agent launch failures
If an agent fails to install or launch on a cloud:
-
Check credentials: Ensure cloud provider credentials are set
# Example for Hetzner export HCLOUD_TOKEN=your-token-here spawn claude hetzner -
Try a different cloud: Some clouds may have temporary issues
spawn <agent> # Interactive picker to choose another cloud -
Use --dry-run: Preview what spawn will do before provisioning
spawn claude hetzner --dry-run -
Check cloud status: Visit your cloud provider's status page
- Many failures are transient (network timeouts, package mirror issues)
- Retrying often succeeds
Getting help
- View command history:
spawn listshows all previous launches - Rerun last session:
spawn lastorspawn rerun - Check version:
spawn versionshows CLI version and cache status - Update spawn:
spawn updatechecks for the latest version - Report bugs: Open an issue at https://github.com/OpenRouterTeam/spawn/issues
Matrix
| Local Machine | Hetzner Cloud | AWS Lightsail | DigitalOcean | GCP Compute Engine | Daytona | Sprite | |
|---|---|---|---|---|---|---|---|
| Claude Code | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| OpenClaw | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Codex CLI | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| OpenCode | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Kilo Code | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Hermes Agent | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Junie | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Cursor CLI | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Pi | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
How it works
Each cell in the matrix is a self-contained bash script that:
- Provisions a server on the cloud provider
- Installs the agent
- Injects your OpenRouter API key so every agent uses the same billing
- Drops you into an interactive session
Scripts work standalone (bash <(curl ...)) or through the CLI.
Development
git clone https://github.com/OpenRouterTeam/spawn.git
cd spawn
git config core.hooksPath .githooks
Structure
sh/{cloud}/{agent}.sh # Agent deployment script (thin bash → bun wrapper)
packages/cli/ # TypeScript CLI — all provisioning logic (bun)
manifest.json # Source of truth for the matrix
Adding a new cloud
- Add cloud-specific TypeScript module in
packages/cli/src/{cloud}/ - Add to
manifest.json - Implement agent scripts
- See CLAUDE.md for full contributor guide
Adding a new agent
- Add to
manifest.json - Implement on 1+ cloud by adapting an existing agent script
- Must support OpenRouter via env var injection
Contributing
The easiest way to contribute is by testing and reporting issues. You don't need to write code.
Test a cloud provider
Pick any agent + cloud combination from the matrix and try it out:
spawn claude hetzner # or any combination
If something breaks, hangs, or behaves unexpectedly, open an issue using the bug report template. Include:
- The exact command you ran
- The cloud provider and agent
- What happened vs. what you expected
- Any error output
Request a cloud or agent
Want to see a specific cloud provider or agent supported? Use the dedicated templates:
Requests with real-world use cases get prioritized.
Report auth or credential issues
Cloud provider APIs change frequently. If you hit authentication failures, expired tokens, or permission errors on a provider that previously worked, please report it — these are high-priority fixes.
Code contributions
See CLAUDE.md for the full contributor guide covering shell script rules, testing, and the shared library pattern.