spawn/cli/README.md
Sprite 9772fb5c02 docs: add CLI architecture and usage documentation
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 00:49:09 +00:00

11 KiB
Raw Blame History

Spawn CLI

The spawn CLI is a command-line tool for launching AI coding agents on cloud providers, pre-configured with OpenRouter.

Overview

The spawn CLI provides a unified interface to:

  • Launch any supported AI agent (Claude Code, Aider, etc.) on any supported cloud provider
  • Interactively browse available agents and clouds
  • View the agent × cloud compatibility matrix
  • Self-update to the latest version

Architecture

Three-Tier Installation Strategy

The CLI uses a progressive fallback installation strategy to maximize compatibility:

┌─────────────────────────────────────────────────────────┐
│ Method 1: Bun (Preferred)                               │
│ - Fastest execution (native TypeScript runtime)         │
│ - Full TypeScript support with minimal overhead         │
│ - Falls back to compiled binary if global install fails │
└─────────────────────────────────────────────────────────┘
                         ↓ (if bun not found)
┌─────────────────────────────────────────────────────────┐
│ Method 2: npm                                           │
│ - Standard Node.js package manager                      │
│ - Transpiles TypeScript to JavaScript at install time   │
│ - Requires Node.js runtime                              │
└─────────────────────────────────────────────────────────┘
                         ↓ (if npm not found)
┌─────────────────────────────────────────────────────────┐
│ Method 3: Bash Fallback                                 │
│ - Pure bash implementation (spawn.sh)                   │
│ - Zero runtime dependencies except curl + jq/python3    │
│ - Functional subset of TypeScript CLI                   │
└─────────────────────────────────────────────────────────┘

Why this pattern?

  • Universal compatibility: Works on any system with bash and curl
  • Optimal performance: Uses the fastest available runtime (bun > node > bash)
  • Zero friction: No prerequisite installation required for basic usage
  • Graceful degradation: Each tier provides full functionality with varying performance characteristics

Directory Structure

cli/
├── src/
│   ├── index.ts        # Entry point (routes commands to handlers)
│   ├── commands.ts     # All command implementations
│   ├── manifest.ts     # Manifest fetching and caching logic
│   └── version.ts      # Version constant
├── install.sh          # Multi-tier installer script
├── spawn.sh            # Bash fallback CLI (full implementation)
├── package.json        # npm package metadata
└── tsconfig.json       # TypeScript configuration

TypeScript Implementation

The TypeScript CLI (src/*.ts) provides:

  • Interactive mode: Terminal UI with prompts for selecting agents and clouds
  • Manifest caching: Local cache with TTL to minimize network requests
  • Progress indicators: Spinners and colored output for better UX
  • Error handling: Structured error messages and exit codes

Key dependencies:

  • @clack/prompts — Interactive terminal prompts
  • picocolors — Terminal color support

Bash Fallback Implementation

The bash CLI (spawn.sh) is a standalone script that:

  • Implements the same commands as the TypeScript version
  • Uses jq or python3 for JSON parsing (auto-detects which is available)
  • Provides a numbered menu picker for interactive mode
  • Maintains local manifest cache with TTL
  • Supports all core commands: list, agents, clouds, run, improve, update

Why maintain both implementations?

  • Portability: Bash version works on minimal systems (CI containers, embedded Linux, etc.)
  • Bootstrap: Used by installer when bun/npm aren't available
  • Reference: Demonstrates that the protocol is runtime-agnostic

Installation

Quick Install

curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/cli/install.sh | bash

The installer will:

  1. Check for bun → install via bun install -g if found
  2. Check for npm → install via npm install -g if found
  3. Fallback → download spawn.sh to $HOME/.local/bin if neither found

Environment Variables

  • SPAWN_INSTALL_DIR — Override install directory (default: $HOME/.local/bin for fallback method)

Manual Installation (Development)

cd cli
bun install
bun link

Or build a standalone binary:

bun run compile  # Creates ./spawn executable

Usage

Interactive Mode

spawn

Launches an interactive picker to select an agent and cloud provider.

Direct Launch

spawn <agent> <cloud>

Examples:

spawn claude sprite    # Launch Claude Code on Sprite
spawn aider hetzner    # Launch Aider on Hetzner Cloud

Agent Information

spawn <agent>

Show which cloud providers support the specified agent.

Example:

spawn claude
# Output:
# Claude Code — AI coding agent from Anthropic
#
# Available clouds:
#   Sprite          spawn claude sprite
#   Hetzner Cloud   spawn claude hetzner

List All Combinations

spawn list

Display the full agent × cloud compatibility matrix.

List Agents

spawn agents

Show all available agents with descriptions.

List Cloud Providers

spawn clouds

Show all available cloud providers with descriptions.

Improve Command

spawn improve [--loop]

Clone (or update) the spawn repository and run the improve.sh script, which uses Claude to autonomously add missing matrix entries or new agents/clouds.

Update CLI

spawn update
  • TypeScript version: Displays update instructions (re-run installer)
  • Bash version: Self-updates by downloading the latest spawn.sh

Version

spawn version

Display the current CLI version.

Development

Prerequisites

  • Bun 1.0+ (or Node.js 18+ with npm)
  • TypeScript 5.0+

Running Locally

bun run dev             # Run TypeScript CLI directly
bun run build           # Build to cli.js
bun run compile         # Compile to standalone binary

Testing

# Test TypeScript version
bun run dev list
bun run dev agents
bun run dev claude sprite

# Test bash version
bash spawn.sh list
bash spawn.sh agents
bash spawn.sh claude sprite

Code Organization

src/index.ts

  • Command-line argument parsing
  • Routes to appropriate command handler
  • Minimal logic (just dispatching)

src/commands.ts

  • All command implementations
  • Interactive picker UI
  • Script execution logic
  • Help text

src/manifest.ts

  • Manifest fetching from GitHub
  • Local caching with TTL
  • Offline fallback to stale cache
  • Typed manifest structure

src/version.ts

  • Single source of truth for version number
  • Imported by both TypeScript and bash implementations

Adding a New Command

  1. Add command handler in src/commands.ts:

    export async function cmdMyCommand() {
      const manifest = await loadManifest();
      // ... implementation
    }
    
  2. Add routing in src/index.ts:

    case "mycommand":
      await cmdMyCommand();
      break;
    
  3. Update help text in src/commands.tscmdHelp()

  4. (Optional) Add equivalent implementation to spawn.sh for bash fallback

Design Rationale

Why TypeScript?

  • Type safety: Manifest structure is type-checked at compile time
  • Modern async/await: Clean, readable asynchronous code
  • Rich ecosystem: Access to high-quality CLI libraries (@clack/prompts, etc.)
  • Single codebase: Same code runs on bun, node, or as a compiled binary

Why Bash Fallback?

  • Universality: Bash is available on virtually all Unix-like systems
  • Zero dependencies: Only requires curl and jq/python3 (one of which is usually installed)
  • CI/CD friendly: Works in minimal Docker containers, GitHub Actions, etc.
  • Educational: Demonstrates the protocol can be implemented in any language

Why Bun → npm → Bash Tiering?

  • Performance gradient: Bun is fastest, npm is widely available, bash always works
  • User experience: Bun users get instant execution, others get working tool
  • Distribution: Can be installed via package manager or curl | bash
  • Maintenance: Single TypeScript codebase serves bun and npm, bash is separate but synchronized

Manifest Caching

Both implementations cache the manifest locally to reduce network requests:

  • Cache location: $XDG_CACHE_HOME/spawn/manifest.json (or ~/.cache/spawn/manifest.json)
  • TTL: 1 hour (3600 seconds)
  • Offline fallback: If fetch fails, uses stale cache if available
  • Invalidation: spawn update clears the cache

Script Execution Flow

When you run spawn <agent> <cloud>:

  1. Load manifest: Fetch from GitHub or use cached version
  2. Validate combination: Check that matrix["<cloud>/<agent>"] is "implemented"
  3. Download script: Fetch https://openrouter.ai/lab/spawn/<cloud>/<agent>.sh
    • Fallback to GitHub raw URL if OpenRouter CDN fails
  4. Execute: Pipe script to bash -c with inherited stdio
  5. Interactive handoff: User interacts directly with the spawned agent

Contributing

Before Submitting Changes

  1. Test both TypeScript and bash versions:

    bun run dev --help
    bash spawn.sh --help
    
  2. Ensure version numbers are synchronized:

    • src/version.tsVERSION
    • spawn.shSPAWN_VERSION
    • package.jsonversion
  3. Update this README if you add new commands or change behavior

  4. Run the installer locally to verify the three-tier strategy works:

    # Test with bun
    bash install.sh
    
    # Test without bun (rename temporarily)
    mv $(which bun) $(which bun).bak
    bash install.sh
    mv $(which bun).bak $(which bun)
    

Release Checklist

  1. Bump version in all three locations (see above)
  2. Update CHANGELOG (if exists)
  3. Test installer on clean system
  4. Tag release: git tag -a cli-vX.Y.Z -m "Release vX.Y.Z"
  5. Push tag: git push --tags

License

See repository root for license information.