- Agent info (spawn <agent>) now shows "X of Y" cloud count and groups
clouds by type (api, cli, sandbox) for easier scanning
- Cloud info (spawn <cloud>) now shows "X of Y" agent count, auth method,
and lists missing agents when there are 5 or fewer
- Cloud listing (spawn clouds) groups providers by type with X/Y ratio
counts instead of singular/plural text
- Remove unused TYPE_COLUMN_WIDTH constant
- Bump CLI version to 0.2.26
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validates ALL implemented scripts against CLAUDE.md shell script rules,
covering shebang, set -eo pipefail, lib/common.sh sourcing, macOS bash
3.x compatibility (no echo -e, no source <(), no set -u), and remote
fallback patterns. Unlike manifest-integrity.test.ts which samples 20
scripts, this checks every implemented script exhaustively.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Hostinger: HOSTINGER_OS_TEMPLATE was interpolated into Python code
without validation, allowing Python code injection via env var.
Added validate_resource_name check.
Contabo: CONTABO_PRODUCT_ID, CONTABO_REGION, CONTABO_IMAGE_ID were
interpolated into Python strings without validation. CONTABO_PERIOD
was interpolated as bare Python (not even quoted), allowing arbitrary
code execution. Added validate_resource_name, validate_region_name,
and integer validation checks.
Agent: security-auditor
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover the previously untested branch in validateAgent (lines 150-158) and
validateCloud (lines 186-194) where findClosestMatch against display names
is used when key-based suggestion fails. Also tests findClosestMatch with
display name arrays and end-to-end through cmdRun/cmdAgentInfo/cmdCloudInfo.
22 new tests, all pass.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show agent/cloud URLs in info pages (spawn <agent>, spawn <cloud>)
- Add setup instructions link to cloud info pages
- Suggest available clouds when --prompt is used without a cloud arg
- Fix help text alignment for spawn list
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The log file is cumulative — result events from previous cycles persist.
The watchdog was grepping the entire file, so every new cycle immediately
matched an old result event and killed itself after 13 seconds.
Now records log file size at cycle start (LOG_START_SIZE) and only
searches content written since then via `tail -c +OFFSET | grep`.
Applied to both refactor.sh and discovery.sh.
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ports the same three improvements from refactor.sh (#340, #355):
1. Capture claude's actual PID via subshell wrapper (not tee's)
2. Detect stream-json "result" event and exit in 30s instead of 10min
3. kill_claude() kills the full process tree (TERM→5s→KILL)
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Automated improvements
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: Kill claude process tree reliably via captured PID
The watchdog was killing tee (last in the pipe), not claude. Killing
tee doesn't propagate — claude and its agent subprocesses stay alive
as zombies, blocking the trigger server slot.
Now captures claude's actual PID via a subshell wrapper and kills the
full tree: SIGTERM children → SIGTERM claude → 5s grace → SIGKILL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Hostinger VPS hosting as a new cloud provider with REST API
provisioning and cloud-init support. Budget VPS starting at $4.95/mo
with hourly billing.
Implementation:
- hostinger/lib/common.sh: Full API wrapper with auth, provisioning,
SSH management, and cleanup functions
- hostinger/claude.sh: Claude Code on Hostinger VPS
- hostinger/aider.sh: Aider on Hostinger VPS
- hostinger/openclaw.sh: OpenClaw on Hostinger VPS
- hostinger/README.md: Complete usage documentation
Added to manifest.json:
- New cloud entry with API details and defaults
- 15 matrix entries (hostinger/claude through hostinger/continue)
- 3 implemented, 12 marked as "missing"
Agent: cloud-scout-2
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Contabo is a budget European VPS provider with affordable CPU instances
starting at $4.95/month. Ideal for AI agents using remote API inference.
Key features:
- Budget-friendly pricing ($4.95-$59/mo)
- Full REST API with OAuth2 authentication
- Cloud-init/user_data support for provisioning
- Full root access via SSH
- European data centers (GDPR-friendly)
- Unlimited traffic included
Implementation:
- contabo/lib/common.sh: OAuth2 token flow, instance provisioning, SSH access
- contabo/claude.sh: Claude Code deployment (implemented)
- contabo/aider.sh: Aider deployment (implemented)
- contabo/openclaw.sh: OpenClaw deployment (implemented)
- manifest.json: Added Contabo cloud + 15 matrix entries (3 implemented)
- contabo/README.md: Complete usage guide with API setup
Authentication uses OAuth2 password grant requiring 4 credentials from
https://my.contabo.com/api/details: Client ID, Client Secret, API User,
API Password.
Agent: cloud-scout-1
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Implements exoscale/continue matrix entry using Exoscale cloud primitives
and Continue installation pattern from existing implementations.
Agent: gap-filler-exoscale-4
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements exoscale/kilocode matrix entry using Exoscale cloud primitives
and Kilo Code installation pattern from existing implementations.
Agent: gap-filler-exoscale-4
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements exoscale/plandex matrix entry using Exoscale cloud primitives
and Plandex installation pattern from existing implementations.
Agent: gap-filler-exoscale-4
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
After `claude -p` emits the stream-json "result" event, the session is
complete but the process hangs waiting for agent subprocesses. The
watchdog was waiting 10 min of silence before killing — wasting time.
Now the watchdog greps for `"type":"result"` in the log every 10s.
Once detected: 30s grace for cleanup, then kill. Also treats
SESSION_ENDED as success for checkpoint creation.
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Exoscale as a new cloud provider to Spawn with:
- European cloud with per-second billing across 7 zones
- CLI-based provisioning via exo tool (auto-installed)
- SSH access with ubuntu user
- Implements claude, aider, and goose agents
Technical details:
- exoscale/lib/common.sh: Provider primitives using exo CLI
- Auto-installs exo CLI from GitHub releases (v1.90.1)
- Supports EXOSCALE_API_KEY + EXOSCALE_API_SECRET auth
- Default zone: ch-gva-2 (Geneva), configurable to 6 other zones
- Uses standard.small instance type by default
- Cloud-init support for agent setup
- Full OpenRouter integration for all agents
Matrix: Added 15 missing entries, implemented 3 (claude, aider, goose)
Agent: cloud-scout
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds Continue CLI integration on Civo cloud platform using:
- Bun install for @continuedev/cli
- OpenRouter API key injection via OAuth
- Config file at ~/.continue/config.json with OpenRouter provider
- Interactive TUI launch via 'cn' command
Agent: gap-filler-civo-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Implements daytona/continue.sh script following the standard pattern:
- Sources daytona/lib/common.sh for cloud-specific primitives
- Installs Continue CLI via npm
- Injects OPENROUTER_API_KEY into shell environment
- Creates ~/.continue/config.json with OpenRouter provider
- Launches Continue TUI via interactive session
Updates manifest.json matrix entry to "implemented".
Agent: gap-filler-daytona-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Continue CLI agent deployment script for OVHcloud. Uses OVH's Public
Cloud API for provisioning, installs Continue CLI via npm, and configures
OpenRouter integration with ~/.continue/config.json.
Agent: gap-filler-ovh-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Implements binarylane/continue.sh to run Continue CLI on BinaryLane servers.
- Uses BinaryLane REST API to provision Ubuntu 24.04 server
- Installs Node.js via NVM and Continue CLI (@continuedev/cli)
- Configures OpenRouter integration in ~/.continue/config.json
- Launches interactive TUI mode (cn command)
Agent: gap-filler-binarylane-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Adds Continue CLI support on Fly.io by combining Fly.io's Machines API
primitives with Continue's setup steps. Includes OpenRouter config injection
via ~/.continue/config.json.
Agent: gap-filler-fly-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Continue agent script for Scaleway cloud provider.
Uses scaleway/lib/common.sh primitives for provisioning and SSH connectivity.
Installs Continue CLI via npm, creates OpenRouter config at ~/.continue/config.json,
and launches interactive TUI mode via cn command.
Agent: gap-filler-scaleway-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Implements Continue.dev CLI agent on UpCloud cloud platform:
- Uses UpCloud REST API to provision server
- Installs Continue CLI via npm
- Injects OpenRouter API key into environment
- Creates ~/.continue/config.json with OpenRouter provider
- Launches Continue in TUI mode
Agent: gap-filler-upcloud-continue
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Spinner completion messages now show "done" state instead of repeating
the in-progress message (e.g., "Loading manifest" instead of "Loading manifest...")
- Script failures show actionable troubleshooting (missing credentials,
rate limits, dependencies) instead of generic "Script exited with code N"
- Ctrl+C (exit code 130) exits silently instead of showing an error
- Fuzzy matching for unknown agents/clouds now also searches display names,
so "Hetzner" suggests "hetzner" even when the key doesn't fuzzy-match
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: `claude -p` (print mode) terminates the session when the
model produces a text response with no tool call. The team lead would
spawn 6 agents, output "I'll wait for messages", and the session would
end — orphaning all agents.
Fix: the prompt now explains the technical constraint (must always
include a tool call) and prescribes an active polling loop using
TaskList + `sleep 30` + gh pr list to stay alive while waiting for
teammate messages, instead of passively waiting.
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the naive `claude | tee` pipe with a background process +
watchdog loop that monitors log file growth every 10 seconds.
If no output is produced for 10 minutes (IDLE_TIMEOUT=600s), the
watchdog kills the hung process. This catches stuck API calls,
network hangs, and the team lead silently exiting while teammates
are orphaned — much faster than waiting for the 75min RUN_TIMEOUT_MS.
Team cycle: 10min idle timeout, 60min hard wall-clock timeout
Single cycle: 10min idle timeout, 35min hard wall-clock timeout
The next cron trigger starts a fresh cycle automatically.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename "Missing" column to "Not available on" to avoid confusion
- Change "all clouds" to "-- all clouds supported" for full coverage agents
- Only show +/- grid legend in grid view (not compact view)
- Fix help text alignment for "spawn list" command
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>