When MAX_CONCURRENT=1 and a cycle is in progress, the trigger server
returns 429. This is expected behavior, not an error — the previous
curl -f treated it as failure (exit code 22).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests the extractFlagValue generic function and the full CLI flag
extraction pipeline (--prompt/-p and --prompt-file). Existing tests
in index-parsing.test.ts and index-edge-cases.test.ts use simplified
re-implementations; these tests cover the exact behavior including
error messages, process.exit on missing values, startsWith("-") guard,
sequential two-pass extraction, and edge cases with flag-like values.
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>
- `spawn agents` now shows the key users need to type (e.g., `claude`)
alongside the display name and cloud count
- `spawn clouds` now shows the key (e.g., `sprite`) alongside the display
name and description
- Both commands show a usage hint at the bottom
- Error when both --prompt and --prompt-file are provided (was silently
overwriting)
- Remove duplicate agent validation in handleDefaultCommand (was loading
manifest twice without spinner, showing different error format)
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>
- Add 15-minute hard deadline with escalation at 10/12/15 min marks
- Limit each agent to ONE PR (prevents runaway micro-refactors)
- Add periodic issue re-scan every 5 minutes + mandatory final sweep
- Update shutdown checklist to verify per-issue comment coverage
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Terminals without UTF-8 support display garbled characters (e.g., "â"
instead of bullets). Replace all Unicode symbols (bullets, em dashes,
arrows, check marks, box drawing) with ASCII equivalents.
Fixes#99
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Extract duplicated prompt flag parsing into extractFlagValue helper
The --prompt and --prompt-file argument extraction in main() shared identical
patterns for flag detection, value validation, and args splicing. Extracted
into a reusable extractFlagValue() function that handles all three concerns.
Agent: complexity-hunter
* refactor: Consolidate multiple python3 JSON reads into single calls
OVH, Kamatera, and UpCloud each spawned separate python3 processes to
read different fields from the same JSON config file. Consolidate into
a single python3 call per file, printing all fields at once and reading
them with bash read. Also fixes OVH using string interpolation for the
file path instead of the safer sys.argv[1] pattern.
Agent: complexity-hunter
* refactor: Extract flyctl auth and token validation from ensure_fly_token
Split the 75-line ensure_fly_token into focused helpers:
- _try_flyctl_auth: encapsulates flyctl CLI token retrieval
- _validate_fly_token: encapsulates API validation with error reporting
The main function is now a clear sequential flow of token source attempts.
Agent: complexity-hunter
* refactor: Deduplicate retry backoff logic in kamatera_api
The two error branches (network error and HTTP 429/503) had identical
interval update and attempt increment code. Restructure with early
return for success, then unified backoff at the end of the loop.
Agent: complexity-hunter
* refactor: Remove unnecessary async IIFE wrapper in validateAndGetAgent
The function wrapped its body in `return (async () => { ... })()` when
it can simply be declared as `async function` directly.
Agent: complexity-hunter
---------
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
- Fix triple-quote injection in SSH keys (Scaleway, UpCloud), userdata
(BinaryLane), init scripts (Civo, Kamatera), and GraphQL queries
(RunPod) by passing data via stdin/json_escape instead of inline
string interpolation
- Add input validation for all cloud provider env vars (region, type,
plan, etc.) using validate_region_name/validate_resource_name to block
shell metacharacters before they reach Python string interpolation
- Validate Modal image name as Python identifier to prevent code injection
- Validate numeric env vars (RAM, GPU count, disk size) across all providers
Affects: 19 cloud provider lib/common.sh files
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>
Three new test files target gaps in existing coverage:
- index-edge-cases: tests startsWith("-") guard for --prompt/-p values, --prompt-file
validation, combined flag extraction order, and agent list truncation logic
- manifest-helpers: tests isValidManifest with unusual data shapes (arrays, strings,
numbers), corrupted cache handling, and countImplemented case sensitivity
- security-encoding: tests unicode homoglyphs, null bytes, CRLF line endings, BOM
markers, and control character handling in identifier/script/prompt validation
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>
- validateImplementation: Show which clouds ARE available when a
combination isn't implemented, instead of a dead-end error
- Interactive mode: Add guidance when no clouds available for agent
- handleError: Add 'spawn help' hint to generic error handler
- handleDefaultCommand: Show agent keys alongside names so users
know what to type (e.g., "claude" not just "Claude Code")
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>
Matrix now shows 14 agents x 21 clouds (264 implemented, 30 missing).
Added OVHcloud and Kamatera cloud columns, Kilo Code agent row.
Agent: team-lead
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kilo Code (15K+ GitHub stars, 98 HN points) is an all-in-one agentic
engineering platform with native OpenRouter support. Adds agent entry,
sprite implementation, and missing matrix entries for all 21 clouds.
Agent: team-lead
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds Kamatera (25+ global datacenters, REST API, hourly billing) as
a new cloud provider. Implements all 13 agent scripts with full
lifecycle: create, wait, destroy, SSH, upload.
Agent: team-lead
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
printf %q escapes spaces and shell metacharacters, turning "claude install"
into "claude\ install" — which bash -c interprets as a single command named
"claude install" (with literal space). This broke all multi-word commands
passed to run_sprite, including pipes, redirects, and && chains.
Since all callers pass trusted, hardcoded command strings (not user input),
the command string should be passed directly to bash -c for normal shell
parsing.
Fixes#88
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sprite/claude.sh script was using 'claude install' which requires
claude to already be on PATH. Changed to use the curl installer which
downloads and installs the binary from scratch.
Fixes#88
Agent: issue-responder
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show clear error when --prompt/-p or --prompt-file is used without a
value (previously silently ignored)
- Fix --prompt-file splice index bug when used after --prompt
- Replace echo -e with printf in fly/lib/common.sh for macOS bash 3.x
compatibility
- Fix incorrect env var name in README (DIGITALOCEAN_TOKEN -> DO_API_TOKEN)
- Add missing agent entries (gptme, OpenCode, Plandex) to 11 cloud READMEs
- Add all 13 agents to Civo README (previously only had 3)
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>
Add generic_cloud_api_custom_auth() to shared/common.sh for cloud
providers that use non-Bearer auth headers. Replace ~120 lines of
duplicated retry logic in upcloud_api() and scaleway_api() with
calls to the new shared function.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change trigger-server MAX_CONCURRENT default from 3 to 1 to prevent
overlapping cycles that duplicate GitHub issue comments
- Add SIGTERM/SIGINT handling to trigger-server so running scripts finish
gracefully on service restart instead of being killed mid-flight
- Add cleanup trap to refactor.sh for worktree/tempfile cleanup on exit
- Add pre-cycle cleanup of stale worktrees, merged branches, and
abandoned PRs from previously interrupted cycles
- Add mandatory Lifecycle Management section to team lead prompt requiring
shutdown_request to all teammates before exiting
- Add dedup checks to community-coordinator: check existing comments
before posting to prevent duplicate acknowledgments/resolutions
- Pass issue number in workflow trigger reason for better logging
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Latitude.sh as the 19th cloud provider in the spawn matrix.
Latitude.sh offers bare metal servers and VMs via REST API with
hourly billing, global locations, and plans starting at $0.07/hr.
New files:
- latitude/lib/common.sh: Provider functions (API wrapper, server
creation/deletion, SSH key management, wait-for-ready)
- latitude/{agent}.sh: All 13 agent deployment scripts
- latitude/README.md: Usage docs with env vars and pricing
Updated:
- manifest.json: Added latitude cloud + 13 matrix entries
- README.md: Updated matrix table (19 clouds, 247 combinations)
Agent: cloud-scout
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hand-rolled ensure_vultr_token() and ensure_linode_token() with
calls to ensure_api_token_with_provider(), matching the pattern already
used by Hetzner, DigitalOcean, Lambda, E2B, and Scaleway.
Extracts test_vultr_token() and test_linode_token() validation functions
to preserve provider-specific error messages and remediation guidance.
Removes ~70 lines of duplicated env-check/config-file/prompt/save logic.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Adds 30 new test cases covering previously untested functions in commands.ts
- Tests for getStatusDescription, renderMatrix helpers, validation logic
- Tests for error handling functions and download fallback logic
- Tests for agent/cloud validation and implementation checking
- Tests for calculateColumnWidth variations with different parameters
- Tests for isLocalSpawnCheckout file detection logic
This improves test coverage for core command logic that wasn't previously tested,
focusing on pure functions and logic that can be tested without full module mocking.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
When sprite version output doesn't match the expected format, the message
now omits the version rather than displaying "unknown". Also broadened the
version regex to match versions without 'v' prefix.
Fixes#79
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
The redirect `> /dev/null 2>&1` was being escaped by `run_sprite`'s
`printf %q`, causing the command to be interpreted incorrectly:
/usr/bin/bash: line 1: claude install > /dev/null 2>&1: No such file or directory
Removing the redirect allows users to see installation progress and
simplifies the command. Installation success is already verified by
the subsequent check on line 33.
Fixes#80
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Same bug as improve.sh — was cd'ing into the skills directory
instead of the repo root.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
improve.sh was setting REPO_ROOT to its own directory, causing
manifest.json lookups and git commands to fail silently.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added 35 tests covering helper functions in commands.ts
- Tests cover error handling, string validation, column width calculation
- Tests verify renderMatrixRow color selection logic
- Tests validate isLocalSpawnCheckout and report functions
- All 35 new tests pass
- Focus on pure functions and functions with minimal side effects
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Split the 66-line generic_cloud_api function into focused helpers to reduce
complexity and eliminate duplication:
- _parse_api_response: Extracts HTTP code and response body (10 lines)
- _make_api_request: Builds curl args and executes request (27 lines)
- _handle_api_transient_error: Centralizes retry logic for all error types (24 lines)
Main function reduced from 66 to 41 lines (38% reduction). Behavior unchanged:
still retries on network errors and transient HTTP codes (429, 503), with
exponential backoff. All test assertions pass.
This extraction pattern makes it clearer how retry logic flows and easier to
modify error handling in the future without duplicating patterns.
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Post a short, natural thank-you for flagging the issue before
diving into categorization and investigation.
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skip the generic "thanks for reporting" boilerplate and go straight
to categorizing and investigating the issue.
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SECURITY FIXES:
- Add validate_oauth_port() to prevent command injection via port parameter
- Ensures port is numeric and in range 1024-65535
- Prevents JavaScript injection in OAuth server code
- Add CSRF state parameter to OAuth flow
- Generate random 128-bit state token per session
- Validate state parameter in callback to prevent OAuth code interception
- Display error page if state validation fails
IMPACT:
- Prevents CRITICAL command injection vulnerability (CVE-worthy)
- Prevents HIGH OAuth code stealing attacks via CSRF
TESTING:
- All 101 tests pass (bun test)
- Syntax validated (bash -n)
- No regressions introduced
Agent: security-auditor
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhance UX across CLI and cloud providers with actionable error messages:
1. Modal sandbox creation failures now provide:
- Detailed error output from Python SDK
- Common causes (auth expired, quota issues, network)
- Step-by-step troubleshooting (re-auth, check quota, status page)
2. Modal CLI installation failures now explain:
- Missing pip/pip3 (with installation commands)
- Permission issues (suggest --user flag)
- Manual installation steps
3. Sprite connectivity failures now include:
- Commands to check sprite status and logs
- Steps to recreate sprite
- Support contact information
4. Sprite CLI installation now:
- Catches installation failures with helpful error messages
- Verifies installation succeeded before proceeding
- Provides manual installation instructions
5. CLI script download failures improved:
- Distinguish between 404 (doesn't exist) and other errors
- Provide specific next steps for each scenario
- Suggest checking matrix for implementation status
All error messages follow the pattern:
- What went wrong
- Why it might have happened (common causes)
- What to do next (actionable steps)
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add `_update_retry_interval()` helper in shared/common.sh to eliminate
repeated backoff interval calculation and cap logic (was copied 10+ times
across cloud provider API wrappers)
- Refactor generic_cloud_api() to use new helper, reducing from 83 to 70 lines
- Refactor scaleway_api() to use new helper, reducing from 66 to 53 lines
- Refactor upcloud_api() to use new helper, reducing from 65 to 52 lines
This reduces cyclomatic complexity by eliminating nested if statements for
interval updates and consolidates the retry backoff logic in one place,
making future maintenance easier and reducing bugs from copy-paste errors.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
- Modified ensure_sprite_installed() to check if sprite is already installed
- When sprite is found, log version and skip installation
- Prevents unnecessary reinstalls when sprite CLI is already present
Fixes#63
Agent: community-coordinator
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Stale remote branches were showing up because git fetch doesn't prune
deleted remote refs by default. Add --prune to every git fetch call in
improve.sh (main entry, run_team_cycle, run_single_cycle,
cleanup_between_cycles) and refactor.sh.
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document the mandatory git conventions for all agent team scripts:
always pull main before creating worktrees, use worktrees for parallel
branch work, include Agent: trailers in commits, and clean up worktrees
at end of cycle.
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add branch-cleaner role that cleans stale remote branches (>4 hours):
merges open PRs if mergeable, closes/deletes if stale
- Require Agent: trailer in all commit messages for traceability
- Switch git workflow from checkout -b to worktrees so parallel agents
don't clobber each other's uncommitted changes
- Always git fetch origin main before creating worktrees to ensure
branches start from latest main
- Add worktree setup/teardown to run_team_cycle and cleanup_between_cycles
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add branch-cleaner agent (Haiku) that cleans stale remote branches:
merges open PRs if mergeable, closes/deletes if stale >4 hours
- Require Agent: trailer in all commit messages so we can trace which
agent authored each change
- Switch from git checkout to git worktrees for parallel branch work,
preventing agents from clobbering each other's uncommitted changes
- Update Issue Fix Workflow to use worktree pattern
- Update Workflow with branch cleanup passes and worktree setup/teardown
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ux: Improve error messages and user guidance across CLI and shell scripts
Enhanced error messages to be more actionable and user-friendly:
CLI improvements (commands.ts):
- Made validateNonEmptyString clearer: "is required but was not provided"
- Reordered troubleshooting steps to check matrix first (most common issue)
- Simplified 404 error message: "doesn't exist yet" vs "may not be implemented"
- Changed "Troubleshooting steps" to just "Troubleshooting" (less formal)
Shared library improvements (shared/common.sh):
- OAuth cancellation now explains why API key is needed and where to get it
- safe_read non-TTY error explains what non-interactive mode is with example
- get_resource_name error shows exact env var syntax needed
- Agent verification failures now list specific possible causes
- All improvements add context and next steps rather than just stating the problem
Hetzner library improvements (hetzner/lib/common.sh):
- Replaced technical "Remediation" with friendly "How to fix"
- Changed log_warn to log_error for error conditions (consistent severity)
- Added spacing for better readability of multi-line errors
- Made server creation errors more specific about account issues
All changes focus on helping users understand WHAT went wrong and HOW to fix it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: Replace issue-triager with community-coordinator agent
Replace the issue-triager agent in the refactor team with a
community-coordinator that actively engages with GitHub issues:
acknowledges reports, posts interim updates, delegates to relevant
teammates, and posts final resolutions — so reporters feel heard.
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 Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes#59
The instanceof operator can fail in bundled/minified code or when
errors cross execution realm boundaries, causing the error:
"instanceof called on an object with an invalid prototype property"
This commit replaces all instanceof Error checks with duck typing
(checking for object with 'message' property) which is more reliable
across different execution contexts.
Changes:
- index.ts: Updated handleError() and prompt file error handling
- commands.ts: Updated getErrorMessage() helper
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Updated overview to reflect current architecture (public sprite URL
with TRIGGER_SECRET bearer auth, not start service API)
- Added Step 5 for setting sprite URL auth to public
- Updated workflow template to use SPRITE_URL + TRIGGER_SECRET secrets
- Updated secret naming convention to match deployed services
- Added Step 10 for CLI-based end-to-end testing
- Added "Current Deployed Services" reference table
- Fixed all stale references and code samples
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>