spawn/CLAUDE.md
L 6ac59e6bb3
Fix OAuth server for macOS bash 3.x (#24)
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>
2026-02-07 14:21:47 -08:00

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/agent combinations 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.jsonmatrix 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_KEY in the shell environment
  • Set provider-specific env vars (e.g., ANTHROPIC_BASE_URL=https://openrouter.ai/api)
  • These come from the agent's env field in manifest.json

2. Add a new agent

Research coding agents, AI CLI tools, or AI-powered dev tools. To add one:

  1. Add an entry to manifest.jsonagents with: name, description, url, install command, launch command, and env vars needed for OpenRouter
  2. Add "missing" entries to the matrix for every existing cloud
  3. Implement the script for at least one cloud
  4. 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_KEY or OPENAI_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:

  1. Create {cloud}/lib/common.sh with 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
  2. Add an entry to manifest.jsonclouds
  3. Add "missing" entries to the matrix for every existing agent
  4. Implement at least one agent script
  5. 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.sh to 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 with jq or python3 fallback, 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. Downloads spawn.sh to ~/.local/bin/spawn, sets executable bit, and prints PATH instructions if needed. Override install dir with SPAWN_INSTALL_DIR env var.

Script Conventions

  • #!/bin/bash + set -e
  • Source lib/common.sh with local-first, remote-fallback pattern
  • Use OPENROUTER_API_KEY env 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

  1. Update manifest.json matrix status to "implemented"
  2. Update README.md with usage instructions
  3. Run bash -n {file} to syntax-check your scripts
  4. 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:

  1. Read {cloud}/lib/common.sh — understand the cloud's primitives
  2. Read an existing {agent}.sh on another cloud — understand the install steps
  3. Write {cloud}/{agent}.sh combining the two
  4. Update manifest.json matrix entry to "implemented"
  5. Add usage entry to README.md under the cloud's section
  6. bash -n syntax check
  7. 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_KEY support, or OPENAI_BASE_URL=https://openrouter.ai/api/v1 override
  • Add to manifest.jsonagents with full metadata including env field
  • 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.sh with ALL primitives (see existing clouds for the pattern)
  • Add to manifest.jsonclouds
  • 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