Protects against 'unbound variable' errors even if set -u is
re-enabled or inherited. Every [[ -n "$UPPER_VAR" ]] pattern now
uses [[ -n "${UPPER_VAR:-}" ]] to safely default to empty.
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The autonomous refactoring added `set -euo pipefail` but the scripts
check optional env vars with `[[ -n "$VAR" ]]` which is a fatal error
under nounset when the var isn't set (e.g. SPRITE_NAME, OPENROUTER_API_KEY).
Fix: downgrade to `set -eo pipefail` across all 42 affected files.
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When scripts run via `bash <(curl ...)`, BASH_SOURCE resolves to
/dev/fd/N, making the relative path `../../shared/common.sh` fail.
Fix: add remote fallback — try local file first, fall back to
fetching shared/common.sh from GitHub via eval+curl.
Applied to all 5 refactored lib/common.sh files (sprite, hetzner,
digitalocean, vultr, linode).
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
macOS ships bash 3.x which doesn't support nested process substitution.
When scripts are run via `bash <(curl ...)`, the inner `source <(curl ...)`
for loading common.sh fails silently, causing "command not found" errors.
Fix: replace `source <(curl -fsSL URL)` with `eval "$(curl -fsSL URL)"`
across all 100 agent scripts. eval+curl works on bash 3.x and newer.
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cline is an open-source AI coding agent for the terminal.
Works with OpenRouter via OPENAI_BASE_URL override.
- Implemented on all 7 clouds
- Matrix now 10 agents x 7 clouds = 70/70 implemented
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AWS's AI coding assistant, works with OpenRouter via OPENAI_BASE_URL override.
Installed via official installer script, launched with `q chat`.
- Implemented on all 7 clouds
- Matrix now 9 agents x 7 clouds = 63/63 implemented
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Google's open-source coding agent, works with OpenRouter via
OPENAI_BASE_URL override and GEMINI_API_KEY env var.
- Implemented on all 6 clouds: sprite, hetzner, digitalocean, vultr, linode, aws-lightsail
- Matrix now 8 agents x 6 clouds = 48/48 implemented
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Open Interpreter provides a natural language interface for computer control.
Works with OpenRouter via OPENAI_BASE_URL=https://openrouter.ai/api/v1.
- Implemented on all 5 clouds: sprite, hetzner, digitalocean, vultr, linode
- Matrix now 7 agents x 5 clouds = 35/35 implemented
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Goose is Block's open-source model-agnostic AI coding agent.
Supports OpenRouter via GOOSE_PROVIDER=openrouter env var.
- sprite/goose.sh, hetzner/goose.sh, digitalocean/goose.sh
- Matrix now 5 agents x 3 clouds = 15/15 implemented
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aider is the most popular open-source AI pair programming CLI.
Natively supports OpenRouter via OPENROUTER_API_KEY env var
and --model openrouter/... flag.
- sprite/aider.sh, hetzner/aider.sh, digitalocean/aider.sh
- Matrix now 4 agents x 3 clouds = 12/12 implemented
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add styled success page with CSS-animated checkmark, fade-in messaging,
and auto-close after 3 seconds with fallback text if browser blocks it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add nc_listen helper that detects busybox nc and uses -p flag accordingly
- Add termux-open-url support to open_browser
- Deduplicate inline browser opener in try_oauth_flow to use open_browser
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add NanoClaw spawn script
NanoClaw is a lightweight WhatsApp-based Claude AI assistant that runs
agents in isolated containers. This script sets up a sprite with
nanoclaw pre-configured: clones the repo, installs dependencies,
configures the API key, and launches in dev mode for WhatsApp QR auth.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix verify_sprite_connectivity exiting script early after single failed check
Retry connectivity up to 6 attempts (30s) instead of trying once and
silently continuing, which caused the next sprite exec to fail under set -e.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add test harness for spawn scripts
Mocks the sprite CLI and runs each script end-to-end verifying:
- common.sh sources correctly and all functions resolve
- Log functions write to stderr (not stdout)
- Env var flow (SPRITE_NAME, OPENROUTER_API_KEY)
- Sprite commands called in correct order
- Temp files created and cleaned up
- Each script reaches its final interactive launch
Usage: bash test/run.sh
42 tests, all passing.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Retry connectivity up to 6 attempts (30s) instead of trying once and
silently continuing, which caused the next sprite exec to fail under set -e.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- safe_read(): Test /dev/tty is functional before using it (exists
but fails in containers/VMs)
- Log functions: Write to stderr so they don't pollute stdout in
command substitutions like $(get_sprite_name)
- ensure_sprite_exists(): Fix grep regex (use -E for ERE)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
BASH_SOURCE[0] is /proc/self/fd/N with process substitution, not
"-" or "bash". Instead of guessing execution context, just check
if the local lib/common.sh file actually exists.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The scripts were failing when run via curl | bash because they tried
to read from /dev/tty which doesn't exist in piped contexts.
## Changes
- Added safe_read() helper function that gracefully handles TTY absence
- Updated get_sprite_name() to support SPRITE_NAME env variable
- Updated all read commands to use safe_read()
- Added clear error messages for non-interactive usage
- Updated README with non-interactive mode documentation
## Usage
Interactive:
curl URL | bash
Non-interactive:
SPRITE_NAME=dev-mk1 curl URL | bash
SPRITE_NAME=dev-mk1 OPENROUTER_API_KEY=sk-xxx curl URL | bash
## Fixes
- /dev/tty: No such device or address error
- Scripts now work in CI/CD and automated contexts
- OAuth fallback still works via OPENROUTER_API_KEY env var
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- OAuth authentication flow with OpenRouter to mint API keys
- Automatic sprite creation and environment configuration
- Claude Code setup with bypassed onboarding and dark theme
- OpenClaw setup with gateway and TUI launch
- Shell environment setup (bun PATH, zsh switch)