When all required credentials (OPENROUTER_API_KEY + cloud auth vars) are
already configured, the Quick start section in `spawn <agent>` and
`spawn <cloud>` now shows a concise "credentials detected -- ready to go"
message with just the launch command, instead of showing export instructions
the user doesn't need.
Previously, the `hasCreds` variable was computed but unused in both
`printCloudQuickStart` and `cmdAgentInfo`. This change puts it to use
to give users a clear signal when they're ready to launch.
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>
Replace unsafe heredoc/echo patterns with inject_env_vars_ssh (Atlantic.Net)
and inject_env_vars_local (CodeSandbox) for API key injection. The previous
patterns embedded OPENROUTER_API_KEY values directly into shell command strings
without escaping, allowing potential command injection if the API key contained
shell metacharacters (quotes, backticks, dollar signs).
Affected scripts (11 total):
- atlanticnet: codex, continue, gemini, gptme, kilocode, opencode
- codesandbox: amazonq, gemini, goose, opencode, plandex
The safe helpers (generate_env_config) properly single-quote all values and
escape embedded single quotes, preventing shell interpretation of special chars.
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>
The file had 5 nearly-identical inline Node.js scripts, each repeating
the same require/init/async-IIFE/try-catch boilerplate. Extract two
shared helpers:
- _csb_sdk_eval: runs arbitrary JS with an authenticated SDK instance
- _csb_run_cmd: connects to a sandbox and runs a command (used by
run_server and interactive_session)
interactive_session was a verbatim copy of run_server — it now delegates
to run_server directly.
Net result: -96 lines, +49 lines (287 → 241 lines total).
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
- local/cline.sh: Add missing SPAWN_PROMPT non-interactive mode support,
replace manual sed -i.bak env var handling with inject_env_vars_local
(eliminates leftover .bak files), add installation verification
- local/plandex.sh: Replace manual shell config handling with
inject_env_vars_local for consistency, fix printf '%q' prompt escaping
that corrupted prompt text with literal backslashes
- local/aider.sh: Fix printf '%q' prompt escaping -- pass SPAWN_PROMPT
directly as quoted argument instead of shell-escaping it
- local/interpreter.sh: Same printf '%q' fix as aider.sh
- 7 local scripts: Standardize "Appending environment variables to
~/.zshrc..." to "Setting up environment variables..." for consistency
with all other cloud providers
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 a centralized `render_api` function that delegates to `generic_cloud_api`,
giving Render the same automatic retry logic (429/503/network errors with
exponential backoff) that all other providers already have.
- `_render_create_service`: raw curl POST -> `render_api POST`
- `_render_wait_for_service`: raw curl GET -> `render_api GET` + `_extract_json_field`
- `cleanup_server`: raw curl DELETE -> `render_api DELETE`
Also improves the wait loop with `INSTANCE_STATUS_POLL_DELAY` support and
better timeout messaging matching the standard provider pattern.
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>
Replace technical "Remediation steps:" with "How to fix:" and
"Remediation: Check <url>" with "Check your dashboard: <url>" across
14 cloud providers for clearer error guidance. Add actionable error
messages to Atlantic.Net create_server and SSH key registration failures.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Cover get_resource_name, get_validated_server_name, get_model_id_interactive,
interactive_pick, _display_and_select, and show_server_name_requirements --
all previously untested functions used by every agent/cloud script.
Tests exercise env-var bypass paths (critical for CI/non-interactive use),
validation rejection of injection attempts, boundary conditions, and menu
rendering output.
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>
Implemented local/amazonq.sh to run Amazon Q CLI directly on the user's local
machine. Uses the standard local provider pattern with OpenRouter API key
injection via OPENAI_API_KEY and OPENAI_BASE_URL environment variables.
Agent: gap-filler
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
The simplified security workflow passes github.event_name directly as
the reason parameter, which includes workflow_dispatch for manual
triggers. The trigger server was rejecting it with a 400 error.
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Simplify security workflow to match discovery/refactor pattern
Move mode-detection logic from the GitHub Actions workflow into
security.sh where it belongs. The workflow now passes github.event_name
directly as the reason parameter (like discovery.yml and refactor.yml),
and security.sh uses `gh issue view` to check labels when reason=issues.
- Remove 25-line if/elif/else reason-mapping block from security.yml
- Remove workflow_dispatch mode input (server-side handles it)
- Add `if:` label guard for issues (safe-to-work + team-building/security)
- Add `labeled` to issue trigger types
- Set cancel-in-progress: false (prevents killing long review_all runs)
- Bump cron to */5
- Handle schedule/workflow_dispatch → review_all in security.sh
- Keep backwards compat for direct team_building/triage reasons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: Add pre-cycle stale branch cleanup to security.sh
Clean up merged and stale security-related branches (team-building/*,
review-pr-*) and leftover worktrees before each cycle starts. Follows
the same pattern as qa-cycle.sh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: Add pre-cycle stale branch cleanup to discovery.sh and refactor.sh
Each agent script now cleans up its own merged branches before starting:
- discovery.sh: add-*, impl-*, gap-filler-* branches
- refactor.sh: fix/*, refactor/*, test/*, ux/* branches
- (security.sh already added in prior commit)
- (qa-cycle.sh already had this)
Replaces the "branch pruning handled by security team" comments with
actual cleanup, following the qa-cycle.sh pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move mode-detection logic from the GitHub Actions workflow into
security.sh where it belongs. The workflow now passes github.event_name
directly as the reason parameter (like discovery.yml and refactor.yml),
and security.sh uses `gh issue view` to check labels when reason=issues.
- Remove 25-line if/elif/else reason-mapping block from security.yml
- Remove workflow_dispatch mode input (server-side handles it)
- Add `if:` label guard for issues (safe-to-work + team-building/security)
- Add `labeled` to issue trigger types
- Set cancel-in-progress: false (prevents killing long review_all runs)
- Bump cron to */5
- Handle schedule/workflow_dispatch → review_all in security.sh
- Keep backwards compat for direct team_building/triage reasons
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two UX improvements:
1. `spawn clouds` now shows a green "ready" indicator next to clouds where
credentials are already configured in the environment, making it immediately
clear which providers the user can use without additional setup.
2. `spawn list` now shows relative timestamps ("5 min ago", "yesterday",
"3d ago") instead of absolute dates, giving immediate temporal context.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace raw API JSON dumps with extracted error messages and actionable
troubleshooting steps for server creation and SSH key registration failures.
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>
Daytona now rejects explicit resource flags (--cpu, --memory, --disk)
when using snapshots. Switch to --class (default: small) which works
with all sandbox configurations. Explicit resource env vars are still
supported but auto-retry with --class on snapshot conflict.
Fixes#800
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>
Replace misleading "Appending environment variables to ~/.zshrc..."
with "Setting up environment variables..." to match all other cloud
providers. The old message incorrectly specified ~/.zshrc which could
confuse bash users.
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>
* feat: Add plandex on Atlantic.Net
Agent: gap-filler
* fix: address review comments for atlanticnet/plandex
- Use inject_env_vars_ssh instead of raw heredoc for env var injection
- Fix source fallback guard to match established pattern
- Add shellcheck source comment
- Fix README ordering (Plandex after OpenClaw)
- Add server details to success message
Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comprehensive test coverage for the CodeSandbox provider (merged in #857)
which previously had zero dedicated tests. Validates:
- Manifest integration (type, auth, exec_method, matrix entries)
- lib/common.sh API surface (13 required functions, no SSH leakage)
- SDK security: all 5 SDK functions pass user data via env vars
- Sandbox ID validation (regex, error handling, called by consumers)
- upload_file() security (path injection protection, base64 encoding)
- Authentication flow (ensure_api_token_with_provider delegation)
- create_server/destroy_server/list_servers SDK patterns
- Agent scripts follow standard provisioning flow (3 scripts)
- macOS bash 3.x compatibility (no echo -e, source <(), set -u)
- Node.js SDK code quality (try/catch, process.exit, process.env)
- No dangerous patterns (no eval, no unquoted expansions, no injection)
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Add HOSTKEY (https://hostkey.com/) as a new cloud provider to the spawn
matrix. HOSTKEY offers affordable VPS hosting starting from €1/month with
hourly billing, making it suitable for running AI agents that use remote
API inference.
Changes:
- Created hostkey/lib/common.sh with HOSTKEY API wrappers
- Implemented hostkey/claude.sh (Claude Code agent)
- Implemented hostkey/openclaw.sh (OpenClaw agent)
- Added HOSTKEY to manifest.json clouds section
- Added matrix entries for all 15 agents (2 implemented, 13 missing)
- Updated test/record.sh with HOSTKEY test infrastructure
- Updated test/mock.sh with HOSTKEY URL handling
- Created hostkey/README.md with usage instructions
Data centers: Amsterdam, Frankfurt, Helsinki, Reykjavik, Istanbul, New York
Agent: cloud-scout
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Combines CodeSandbox SDK primitives with NanoClaw agent setup:
- Creates sandbox using CodeSandbox API
- Installs Node.js dependencies (tsx)
- Clones and builds nanoclaw from GitHub
- Injects OpenRouter API key as ANTHROPIC_API_KEY
- Configures .env file with API credentials
- Launches interactive WhatsApp QR code authentication flow
Updates manifest.json matrix status to "implemented"
Agent: gap-filler
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
- Replace 38-line _scaleway_power_on_and_wait polling loop with generic_wait_for_instance
- Remove _scaleway_extract_ip (IP extraction now handled by generic_wait_for_instance)
- Replace inline Python JSON building in create_server and scaleway_register_ssh_key with json_escape
- Replace inline Python error parsing with extract_api_error_message shared helper
- Replace inline Python field extraction with _extract_json_field shared helper
Net reduction: 58 lines (372 -> 315)
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>
local/cline.sh and local/plandex.sh were writing API keys to shell
config using double-quoted printf format strings. If an API key
contained shell metacharacters (", $, backtick), sourcing the shell
config could execute arbitrary code.
Replace manual printf with inject_env_vars_local which uses the safe
generate_env_config helper (single-quoted values with proper escaping).
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>
local/continue.sh used a double-quoted heredoc to write the API key
directly into ~/.continue/config.json without escaping. If the key
contained double quotes, it could produce invalid JSON or inject
additional config fields. Replace inline heredoc with the shared
setup_continue_config helper which uses json_escape.
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>
Adds comprehensive test coverage for the local cloud provider, which
runs agents directly on the user's machine without cloud provisioning.
Previously had zero dedicated tests despite 14 implemented agent scripts.
Tests cover:
- local/lib/common.sh API surface (no-op destroy, bash -c exec, cp uploads)
- All 14 local agent scripts follow local-specific patterns
- No SSH/SCP patterns leak into local scripts
- OpenRouter API key handling with OAuth fallback
- SPAWN_PROMPT handling for interactive/non-interactive modes
- Installation verification (command -v checks)
- Safety checks (no sudo, no rm -rf system dirs)
- Manifest consistency for local cloud entries
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>
Add Atlantic.Net Cloud as a new cloud provider with REST API support.
Starting at $4-8/mo for budget VPS instances with SSH access.
Implementation:
- Created atlanticnet/lib/common.sh with HMAC-SHA256 API auth
- Implemented 3 agent scripts: claude.sh, aider.sh, openclaw.sh
- Updated manifest.json with cloud entry and 15 matrix entries
- Added test coverage in test/record.sh and test/mock.sh
- Created atlanticnet/README.md with usage docs
API authentication uses timestamp + random GUID signed with private key.
Defaults: G2.2GB plan, ubuntu-24.04_64bit image, USEAST2 location.
Agent: cloud-scout-1
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Kilo Code agent support for local machine cloud provider.
- Install @kilocode/cli via npm if not already installed
- Inject OpenRouter credentials via env vars
- Set KILO_PROVIDER_TYPE=openrouter and KILO_OPEN_ROUTER_API_KEY
- Support SPAWN_PROMPT for non-interactive execution
- Update manifest.json matrix entry to "implemented"
Agent: gap-filler
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
The refactor team's pr-maintainer can now rebase and merge PRs
that the security team has already approved. This closes the gap
where approved PRs sat unmerged because neither team was merging
them.
- pr-maintainer: merge APPROVED+MERGEABLE PRs (rebase first)
- Still NEVER review or approve PRs (security team only)
- Updated separation of concerns section
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>