Every command, one page.
sproobo is a single binary that drives the exact same audited, role-gated API the dashboard uses: one org per API key, plan-first writes, and no privileged AI-only path. This page is the full reference: install, sign in, the plan-first model, every command and flag grouped by area, exit codes, and a CI recipe.
Install
One command, any OS/architecture it detects:
curl -fsSL https://cp.sproobo.com/cli/install.sh | shIt resolves the latest version, downloads the right binary, and verifies its sha256 against published checksums before installing. See Scripts & one-liners for the sudo-free SPROOBO_INSTALL_DIR option and the rest of the installer behavior.
Staying up to date
sproobo upgrade updates the CLI in place: it resolves the latest published version, downloads the right binary for your OS/architecture, verifies its sha256 against published checksums, and atomically replaces the running binary — the same integrity check the installer runs.
sproobo upgrade sproobo upgrade --check
- --check: report whether a newer version is available, then exit; install nothing.
- --json: machine-readable result — {"current":"…","latest":"…","upgraded":<bool>} — for scripts.
If sproobo lives on a path the current user can't write to, the upgrade stops before touching anything and tells you to re-run it with sudo sproobo upgrade; it never escalates on its own. Like every command it honors SPROOBO_ENDPOINT / --endpoint, so a self-hosted control plane serves its own builds.
Automatic notifications. After a command finishes, the CLI checks at most once every 24 hours (the result is cached to disk) whether a newer version has been published and, if so, prints a one-line hint to stderr — after your command's own output, never mixed into it:
A new version of sproobo is available: 0.2.0 → 0.3.0 Run `sproobo upgrade` to update.
The check skips itself automatically whenever it would be noise: under --json, when CI is set, when stderr isn't a terminal (scripts, cron, pipes), and for local or unreleased builds. To turn it off everywhere, set SPROOBO_NO_UPDATE_CHECK=1; sproobo upgrade itself still works regardless — it's explicit intent.
Sign in
Three equivalent forms, pick the one that fits where you're running:
sproobo login sproobo login --paste sproobo login --token sk_…
- sproobo login: browser-based login. It opens a browser and a human must approve the request there.
- --paste: prompts for a key instead of opening a browser.
- --token <sk_…>: fully non-interactive; no browser, no prompt.
CI / headless: set SPROOBO_TOKEN in the job environment to an sk_ API key minted in the dashboard under Team → API Keys (see Team, orgs & billing for scoped keys and roles), no sproobo login needed. The env var beats the stored profile.
Self-hosted / non-default control plane: set SPROOBO_ENDPOINT (or pass --endpoint) to the control-plane base URL. Default: https://cp.sproobo.com.
Credentials live in the CLI's own config: ~/.config/sproobo/config.json on Linux, ~/Library/Application Support/sproobo/config.json on macOS. Never copy tokens anywhere else.
Verify what the current key resolves to at any time: sproobo whoami shows the org and role.
The plan-first model
Writes are plan-first: without -y a write prints a PLAN and changes nothing. In an interactive terminal the CLI shows that plan and prompts Apply? [y/N]; -y/--approve skips the prompt and applies. These flags apply to every command:
| Flag | Meaning |
|---|---|
| -y, --approve | Apply writes (skip the plan-only dry run). |
| --correlation-id <id> | Stable idempotency key for writes (auto-generated when omitted; reuse it to make retries replay instead of re-apply). |
| --endpoint <url> | MCP endpoint base URL (overrides config/env; default https://cp.sproobo.com). |
| --json | Output raw JSON. |
| --profile <name> | Config profile to use. |
Every write carries a correlation ID whether you set one or not: it's the idempotency key the control plane uses to tell “retry the same write” from “apply it again.” To retry a write safely (a flaky CI job, a dropped connection), reuse the printed id via --correlation-id and the server replays instead of re-applying. Add --json to any command when you're parsing output instead of reading it.
The CLI ships and updates independently of this page. If this reference and sproobo <command> --help ever disagree, trust --help.
Identity
| Command | Description |
|---|---|
| sproobo login | Browser-based login (opens a browser; a human must approve). --paste prompts for a key instead; --token <sk_…> is fully non-interactive. |
| sproobo whoami | Show the org and role the current API key resolves to. |
Inventory
Read-only lists, the source of the ids every other command takes:
| Command | Description |
|---|---|
| sproobo servers | List servers. |
| sproobo apps | List apps. |
| sproobo apps get <appId> | One app in detail. |
| sproobo services | List backing services. |
| sproobo backups | List backup tasks. |
| sproobo deployments [--app <appId>] | List deployments, optionally scoped to one app. |
| sproobo status <server|service|app> <id> | Fused health diagnosis of one resource. |
Deploys
| Command | Description |
|---|---|
| sproobo deploy <appId> [-y] [--detach] | Blue-green deploy; streams progress until the health gate decides. Exit 0 iff the new release went live healthy; exit 1 otherwise: the previous release is still serving (rolled back automatically if the switch had already happened). --detach returns right after enqueueing. |
| sproobo rollback <appId> [--to <releaseId>] [-y] | Roll back. --to targets a specific release (ids come from sproobo deployments); without it, the last healthy release is picked automatically. |
See Apps & deploys for the blue-green mechanics behind both commands.
Apps
| Command | Description |
|---|---|
| sproobo apps create <name> --server <serverId> --repo <git-url> --domain <apex> [--branch <b>] [--port <n>] [--dockerfile <path>] [--health-path <path>] [--detach] [-y] | Create an app (apex+www ingress + TLS cert) and watch its first deploy. Port defaults to 3000; branch defaults to the repo default. |
| sproobo apps set-tag <appId> [tag] [-y] | Set (or, with no tag, clear) the app's internal tag/label. |
| sproobo apps set-auto-deploy <appId> <on|off> [-y] | Turn auto-deploy-on-push on or off for the app. |
| sproobo apps set-domains <appId> --domain <host> [--domain <host>...] --tls-mode <mode> [--wildcard-domain <id>] [--alias <host>[,<www-host>]]... [--clear-aliases] [-y] | Set the app's ingress domains, TLS mode, and alias domains in one atomic write. |
- --dockerfile <path>: build a Dockerfile that lives in a subdir of a monorepo (built from the repo root, e.g. apps/web/Dockerfile). Without it, a repo with no root Dockerfile falls back to Railpack auto-detection on the repo root.
- --health-path <path>: health-gate probe path (default /healthz). Pass / for a static-image app (e.g. a Caddy-served static export) that has no /healthz endpoint.
- --tls-mode <mode>: required on set-domains, one of default, dns01, external, wildcard (see Networking & TLS). It's checked locally, so a typo fails before the round trip. --wildcard-domain <id> is required with, and only with, --tls-mode=wildcard.
- --alias <host>[,<www-host>]: repeatable, and each occurrence is one alias group, either a single host (--alias old.com) or an apex and its www packed into one comma-separated value (--alias old.com,www.old.com). Passing it replaces the app's entire alias set; there's no partial add or remove of a single alias.
- Alias handling has three states, and picking the wrong one deletes rows: pass neither flag and existing aliases are left untouched (the default, and the right one for a plain domain or TLS change), --alias replaces the set with exactly what you list, and --clear-aliases removes every alias. The two flags are mutually exclusive and rejected together before any network call.
A domain, TLS, or alias edit takes effect on the app's next deploy, so follow it with sproobo deploy <appId>. Skip that and the app sits half-applied, where real visitors can hit ERR_TOO_MANY_REDIRECTS. An app that belongs to a multi-server group is pinned to external TLS, and the command refuses any other mode until the app leaves the group.
Creating a static site itself is dashboard-only today: there's no dedicated CLI flag for it; once created, an app created either way deploys and rolls back through the same commands above.
Groups
One built image across up to four of your servers behind your own load balancer, cutting over on all of them together or on none. See Multi-server groups for the barrier, the leader and the join requirements.
| Command | Description |
|---|---|
| sproobo groups | List app groups: id, name and member count. |
| sproobo groups create <name> [--repo <url>] [--branch <b>] [-y] | Create an empty group and print its id, which add-app needs next. Deploys nothing and moves no traffic. |
| sproobo groups add-app <groupId> <appId> [--role leader|member] [-y] | Add an app (cap 4). It must already run external TLS with no bound service and no durable mounts. Turns the app's own auto-deploy off and keeps it off while it stays a member. Server default for --role: leader for the first app in an empty group, member after that. |
| sproobo groups remove-app <appId> [-y] | Detach one app; the group stands. The app keeps its ingress, certificate, release history and running container. May promote a new leader, which changes the repo the group builds from. Auto-deploy stays off. |
| sproobo groups set-source <groupId> [--repo <url>] [--branch <b>] [-y] | Set the repo and branch pushes are matched against — a push matcher, not a build input: the image is built from the leader app's repo, so set this to the leader's. An omitted flag leaves that field alone; an empty value clears it (--repo "" unsets, --branch "" returns to main). Clearing the repo turns the group's auto-deploy off. |
| sproobo groups deploy <groupId> [-y] | Build the leader once, stage that image on every member, then move production traffic on all of them together. Returns a groupDeploymentId immediately — poll groups status. There is no --watch. |
| sproobo groups status <groupDeploymentId> | Barrier state plus every member's per-node status. Keeps working for past deployments even after the group itself is deleted. |
| sproobo groups delete <groupId> [-y] | Delete the group, releasing its members — each keeps its domain, certificate, release history and running container. No traffic moves, no server is contacted. Refused while a deploy is in flight (temporary), and while the last deploy is degraded and unacknowledged (not temporary — acknowledge first). |
Two group capabilities are deliberately not CLI commands. Acknowledging a degraded group is the MCP tool force_release_app_group — there is no sproobo groups force-release. And arming a group's auto-deploy is dashboard-only: an API key must not be able to make every push deploy unattended across a whole fleet.
Secrets
Values are write-only: the CLI never reads one back, only names. See Secrets & env for the envelope-encryption model underneath.
| Command | Description |
|---|---|
| sproobo secrets ls <appId> | List secret NAMES (never values). |
| sproobo secrets set <appId> KEY[=value] [--value <v>|@file] [-y] | Set one secret; value via KEY=value, --value, --value @file, or stdin. |
| sproobo secrets import <appId> [file|-] [-y] | Bulk-set from a .env file or stdin, as one atomic write. |
| sproobo secrets rm <appId> KEY [-y] | Delete a secret. Destructive: confirm with the human before approving it. |
Secret changes take effect on the app's next deploy.
Logs
| Command | Description |
|---|---|
| sproobo logs --deployment <deploymentId> | A deployment's log. |
| sproobo logs --server <serverId> --container <name> [-f] [--tail <n>] | Container logs; -f streams, --tail sets the initial window (default 200). |
Servers
| Command | Description |
|---|---|
| sproobo enroll <name> [-y] | Register a server and print the bootstrap one-liner the human runs as root on the box. Denied for scoped keys: it needs an unscoped admin key. |
See Servers & enrollment for the enrollment lifecycle the printed one-liner drives.
Misc
| Command | Description |
|---|---|
| sproobo mcp | Run an MCP stdio bridge to the org (for MCP-native clients). |
| sproobo mcp config | Print the MCP client-config JSON snippet. |
| sproobo completion <shell> | Shell autocompletion script. |
| sproobo upgrade [--check] | Self-update to the latest published version (verifies sha256, atomic in-place swap). --check only reports whether one is available. |
| sproobo --version | CLI version. |
A tool that speaks MCP natively can use sproobo mcp directly instead of shelling out to individual commands: same API, same permissions, same audit trail. See AI & CLI for connectors and the coding- agent skill.
Exit codes
| Exit code | Meaning |
|---|---|
| 0 | The new release went live and passed its health gate. |
| 1 | Build failure or health-gate failure: the previous release is still serving (rolled back automatically if the traffic switch had already happened; a pre-switch failure never took the old release offline). |
That's sproobo deploy <appId> -y as-is: a gating CI step, no extra polling needed. --detach returns right after enqueueing, so its exit code then reflects only the enqueue, not the deploy's outcome.
CI recipe
Sproobo auto-deploys on push when an app's GitHub repo is connected (see Apps & deploys), so most projects need no CI wiring at all. Reach for the CLI in CI when you want explicit control: deploy only after tests pass, deploy from a CI system Sproobo isn't connected to, or scripted rollbacks.
Mint an API key in the dashboard (Team → API Keys) and store it as a CI secret. Set SPROOBO_TOKEN in the job environment, no sproobo login needed. MEMBER role suffices for deploys and secrets.
deploy:
runs-on: ubuntu-latest
steps:
- name: Install sproobo
run: curl -fsSL https://cp.sproobo.com/cli/install.sh | sh
- name: Deploy
run: sproobo deploy ${{ vars.SPROOBO_APP_ID }} -y
env:
SPROOBO_TOKEN: ${{ secrets.SPROOBO_TOKEN }}Writes are idempotent per correlation ID; the CLI generates one per write and already retries transient network errors itself. To make a whole re-run of the job replay instead of re-apply, pass a stable key, e.g. --correlation-id "deploy-$GITHUB_SHA".
Add --json to any command for machine-readable output.
Troubleshooting
- command not found: sproobo. Install it (see Scripts & one-liners), then re-check.
- UNAUTHENTICATED / 401. The key is missing, revoked, or mistyped. Interactive: sproobo login (opens a browser; a human must approve). Headless: check SPROOBO_TOKEN. sproobo whoami verifies what the current key resolves to.
- Permission / scope denied. Org roles run VIEWER < MEMBER < ADMIN < OWNER. Reads work at VIEWER (except live container logs, which need MEMBER); writes (deploy, secrets set/import/rm, apps create) need MEMBER or higher. sproobo enroll is denied for scoped keys entirely. It needs an unscoped admin key.
- A plan printed but nothing changed. That's plan-first working as designed: without -y writes are a dry run. Re-run the same command with -y to apply it.
- Deploy exited 1. The previous release is still serving. Diagnose with sproobo deployments --app <appId> to find the failed deployment's id, then sproobo logs --deployment <depId> for its build and runtime output, and sproobo status app <appId> for current fused health.
- logs shows nothing. Container logs need both --server and --container; deployment logs need --deployment. Mixing the flags up returns nothing useful.
- Self-hosted / non-default control plane. Set SPROOBO_ENDPOINT (or pass --endpoint) to the control-plane base URL. Default: https://cp.sproobo.com.
Next
- See every installer's exact flags and behavior on Scripts & one-liners.
- Roles, scoped API keys, and who can mint one: Team, orgs & billing.
- The blue-green deploy and rollback mechanics behind deploy/rollback: Apps & deploys.
- Connectors, the coding-agent skill, and the MCP bridge: AI & CLI.