Three issues broke the OAuth callback server on macOS: 1. echo -e doesn't work in bash 3.x — \r\n appears as literal text in the HTTP response, browser gets malformed headers. Fix: pre-write response with printf to a file before the subshell. 2. local variables inside ( ... ) & subshell — undefined behavior in bash 3.x since subshells aren't function scope. Fix: use plain variables in subshells. 3. ((elapsed++)) when elapsed=0 evaluates to falsy — set -e kills the script on the first iteration of the timeout loop. Fix: use elapsed=$((elapsed + 1)) instead. Also simplified nc_listen detection to only check for BusyBox (the -p flag check could misfire on macOS nc). Applied to all 10 lib/common.sh files. Co-authored-by: Sprite <noreply@sprite.dev> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.3 KiB
Spawn
Spawn is a matrix of agents x clouds. Every script provisions a cloud server, installs an agent, injects OpenRouter credentials, and drops the user into an interactive session.
The Matrix
manifest.json is the source of truth. It tracks:
- agents — coding agents / AI tools (Claude Code, OpenClaw, NanoClaw, ...)
- clouds — cloud providers to run them on (Sprite, Hetzner, ...)
- matrix — which
cloud/agentcombinations are"implemented"vs"missing"
How to Improve Spawn
When run via ./improve.sh, your job is to pick ONE of these tasks and execute it:
1. Fill a missing matrix entry
Look at manifest.json → matrix for any "missing" entry. To implement it:
- Find the cloud's
lib/common.sh— it has all the provider-specific primitives (create server, run command, upload file, interactive session) - Find the agent's existing script on another cloud — it shows the install steps, config files, env vars, and launch command
- Combine them: use the cloud's primitives to execute the agent's setup steps
- The script goes at
{cloud}/{agent}.sh
Pattern for every script:
1. Source {cloud}/lib/common.sh (local or remote fallback)
2. Authenticate with cloud provider
3. Provision server/VM
4. Wait for readiness
5. Install the agent
6. Get OpenRouter API key (env var or OAuth)
7. Inject env vars into shell config
8. Write agent-specific config files
9. Launch interactive session
OpenRouter injection is mandatory. Every agent script MUST:
- Set
OPENROUTER_API_KEYin the shell environment - Set provider-specific env vars (e.g.,
ANTHROPIC_BASE_URL=https://openrouter.ai/api) - These come from the agent's
envfield inmanifest.json
2. Add a new agent
Research coding agents, AI CLI tools, or AI-powered dev tools. To add one:
- Add an entry to
manifest.json→agentswith: name, description, url, install command, launch command, and env vars needed for OpenRouter - Add
"missing"entries to the matrix for every existing cloud - Implement the script for at least one cloud
- Update
README.md
Where to find new agents:
- GitHub trending in AI/coding categories
- OpenRouter's ecosystem
- HuggingFace agent frameworks
- CLI tools that accept
ANTHROPIC_API_KEYorOPENAI_API_KEY(these work with OpenRouter via base URL override)
3. Add a new cloud provider
Research cloud providers with API-based provisioning. To add one:
- Create
{cloud}/lib/common.shwith the provider's primitives:- Auth/token management (env var → config file → prompt)
- Server creation (API call or CLI)
- SSH/exec connectivity
- File upload
- Interactive session
- Server destruction
- Add an entry to
manifest.json→clouds - Add
"missing"entries to the matrix for every existing agent - Implement at least one agent script
- Update
README.md
Good candidate clouds have:
- REST API or simple CLI for provisioning
- SSH access to the created server
- Cloud-init or similar userdata support
- Pay-per-hour pricing (so users can destroy after use)
4. Extend tests
test/run.sh contains the test harness. When adding a new cloud or agent:
- Add mock functions for the cloud's CLI/API calls
- Add per-script assertions matching the agent's setup steps
- Run
bash test/run.shto verify
File Structure Convention
spawn/
cli/
spawn.sh # Main CLI binary (interactive picker, matrix viewer, launcher)
install.sh # One-liner installer (downloads spawn.sh to ~/.local/bin)
{cloud}/
lib/common.sh # Cloud-specific shared functions
{agent}.sh # One script per agent
manifest.json # The matrix (source of truth)
improve.sh # Run this to trigger one improvement cycle
test/run.sh # Test harness
README.md # User-facing docs
CLI (cli/)
The spawn CLI is a pure-bash binary that provides a unified entry point for the matrix.
cli/spawn.sh— Main binary. Fetches manifest.json from GitHub (cached for 1hr at~/.cache/spawn/), parses it withjqorpython3fallback, and provides: interactive picker (spawn), direct launch (spawn <agent> <cloud>), agent info (spawn <agent>), matrix table (spawn list), and self-update (spawn update). Installed to~/.local/bin/spawn.cli/install.sh— One-liner installer. Downloadsspawn.shto~/.local/bin/spawn, sets executable bit, and prints PATH instructions if needed. Override install dir withSPAWN_INSTALL_DIRenv var.
Script Conventions
#!/bin/bash+set -e- Source
lib/common.shwith local-first, remote-fallback pattern - Use
OPENROUTER_API_KEYenv var to skip OAuth when set - All env vars documented in README.md under the relevant section
- Remote fallback URL:
https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/{path} - Scripts must be runnable via:
bash <(curl -fsSL https://openrouter.ai/lab/spawn/{cloud}/{agent}.sh)
After Each Change
- Update
manifest.jsonmatrix status to"implemented" - Update
README.mdwith usage instructions - Run
bash -n {file}to syntax-check your scripts - Commit with a descriptive message
Agent Team Roles
When running as part of an agent team (./improve.sh), teammates are assigned specific roles:
Gap Filler
You're assigned a specific {cloud}/{agent} entry to implement. Steps:
- Read
{cloud}/lib/common.sh— understand the cloud's primitives - Read an existing
{agent}.shon another cloud — understand the install steps - Write
{cloud}/{agent}.shcombining the two - Update
manifest.jsonmatrix entry to"implemented" - Add usage entry to
README.mdunder the cloud's section bash -nsyntax check- Commit your changes only (don't touch other teammates' files)
Agent Scout
Research and add ONE new AI coding agent. Requirements:
- Must be installable via a single command (
npm install -g,pip install,curl | bash, etc.) - Must accept API keys via environment variables (
OPENAI_API_KEY,OPENROUTER_API_KEY,ANTHROPIC_API_KEY, etc.) - OpenRouter compatibility: either native
OPENROUTER_API_KEYsupport, orOPENAI_BASE_URL=https://openrouter.ai/api/v1override - Add to
manifest.json→agentswith full metadata includingenvfield - Add
"missing"entries in the matrix for ALL existing clouds - Implement on at least 2 clouds to prove the pattern
- Update
README.md
Cloud Scout
Research and add ONE new cloud provider. Requirements:
- REST API or CLI for provisioning VMs/instances
- SSH access to created servers
- Cloud-init, userdata, or startup-script support
- Pay-per-hour pricing
- Create
{cloud}/lib/common.shwith ALL primitives (see existing clouds for the pattern) - Add to
manifest.json→clouds - Add
"missing"entries for ALL existing agents - Implement at least 2 agents to prove the lib works
- Update
README.md
Coordination Rules
- Never edit the same file as another teammate — coordinate via the shared task list
- manifest.json conflicts: only ONE teammate should update manifest.json at a time. If you're a Gap Filler, update just your entry. If you're a Scout, add your block and your matrix entries.
- README.md: append your section, don't rewrite others' sections
- Commit early: commit your work as soon as it's done so other teammates can see it
- Self-claim: when you finish your assigned task, check the task list for the next unblocked item