@sprigr/cli
v0.3.0
Published
Sprigr Team CLI: create, deploy, and manage websites (custom domains, env vars, rollbacks) on Sprigr Tenant Hosting from your terminal.
Maintainers
Readme
@sprigr/cli
Sprigr Team CLI — deploy static sites and Next.js apps to Sprigr Tenant Hosting from your terminal.
Install
npm install -g @sprigr/cli
# or run without installing
npx @sprigr/cli --helpRequires Node.js 20+.
Quick start
# 1. Log in (device flow; or export SPRIGR_API_KEY=sk_... from the portal)
sprigr login
# 2. Create a website; a starter page goes live immediately
sprigr site create --name "My Docs"
# → created site_abc123 (my-docs)
# → live at https://<workspace>-my-docs.sites.sprigr.com
# 3. Deploy your own files over it
sprigr deploy site_abc123 --dir ./public
# 4. Or deploy a Next.js app (built with @opennextjs/cloudflare)
sprigr deploy site_abc123 --dir ./.open-next --framework next
# 5. Point a custom domain at it
sprigr domain add site_abc123 www.example.com # prints the DNS records to publish
sprigr domain verify site_abc123 www.example.comCommands
sprigr site <create|list|status|deployments|rollback|preview|logs|delete>
Website lifecycle. site create provisions the site and auto-deploys a
starter page, so the printed URL is live before your first deploy.
site status shows the site row, live URL, active deployment id, and
recent builds in one shot. site rollback <siteId> <deploymentId> flips
the live pointer back to a previous deployment (pick the id from
site deployments). site preview mints a 15-minute authenticated URL
for private sites. site delete <siteId> --yes soft-deletes with a
30-day grace before the permanent purge.
| Flag (site create) | Description | Default |
| --- | --- | --- |
| --name <name> | Display name | required |
| --slug <slug> | URL slug | derived from name |
| --description <text> | Dashboard description | - |
| --type <siteType> | website, landing, docs | website |
| --visibility <public\|private> | Private sites need a grant or preview token to view | public |
| --agent <agentId> | Link an agent: the starter page gets a chat widget wired to it | - |
sprigr domain <add|list|verify|remove>
Custom hostnames, backed by Cloudflare for SaaS. domain add <siteId>
<hostname> registers the hostname and prints the DNS records to publish:
the ownership TXT and the ssl-cert TXT records first (the certificate
pre-issues with zero traffic impact), the CNAME cutover last. Then poll
domain verify <siteId> <hostname> until it reports active; it exits
0 when active and 3 while still verifying, so scripts can poll on the
exit code. verify and remove accept the hostname or the dom_... id.
sprigr env <set|list|unset>
Per-site environment variables / secrets, encrypted at rest. Values are
write-only: no read path returns them (env list shows metadata and a
value hash). Setting an existing key rotates it, and runtime keys
hot-swap into the live worker without a redeploy when possible.
sprigr env set site_abc123 API_KEY=sk_live_x DATABASE_URL=postgres://...
sprigr env set site_abc123 NEXT_PUBLIC_FLAG=on --plain --build-time
sprigr env unset site_abc123 API_KEY| Flag (env set) | Description | Default |
| --- | --- | --- |
| --env <name> | production, staging, preview | production |
| --plain | Not a secret (value column visible in the portal) | secret |
| --build-time | Also inject during builds (NEXT_PUBLIC_* inlining) | off |
| --no-runtime | Build-only (npm tokens etc.) | runtime on |
sprigr deploy <siteId> --dir <dir>
Bundle a directory and deploy it as a new build for the given website.
| Flag | Description | Default |
| --- | --- | --- |
| --dir <path> | Directory to bundle | required |
| --framework <static\|next\|astro\|remix> | Framework hint | static |
| --endpoint <url> | API endpoint override | https://api.team.sprigr.com |
| --api-key <key> | API key (overrides env) | from SPRIGR_API_KEY |
The CLI streams progress and prints the build id. Use sprigr builds get to follow status, or watch the portal's Builds panel.
sprigr builds list <siteId>
List recent builds for a site.
| Flag | Description | Default |
| --- | --- | --- |
| --limit <N> | Number of rows | 20 |
sprigr builds get <siteId> <buildId>
Fetch a single build's status, including logs once available.
sprigr app dev --dir <dir>
Local development harness for marketplace apps. Runs an HTTP server that emulates the two platform pieces an app's backend touches, so the OAuth callback and tool handlers can be exercised end to end before the first publish:
- OAuth bouncer —
GET /<slug>/oauth/callback?code&statedecodes the state and dispatches{ code, state, redirectUri, environment, installId }to your<slug>_oauth_callbacktool, with the same success/failure rendering as the shared bouncer. Registerhttp://localhost:<port>/<slug>/oauth/callbackas the redirect URI on your provider's dev OAuth app (most providers allow localhost), and point your/oauth/startat it via the scaffold's<PROVIDER>_REDIRECT_URIoverride. - Tool dispatch —
POST /__sprigr/tool/<name>with a JSON body invokes the handler with the platform's{ ok: true, result }envelope; undeclared tools returnno_handler. - Per-install D1 — a local SQLite file (
.sprigr/dev/<installId>.sqlite, needs Node >= 22.5) with your manifest migrations applied through the same filename+sha256 ledger the platform keeps. Add.sprigr/to your.gitignore.
Handlers are re-bundled per request (esbuild, resolved from your app's
node_modules), so edits apply without a restart. Secrets declared in
manifest.secrets[] load from --secrets-file, then
.sprigr/dev/secrets.json, then the environment. env.SPRIGR (platform
callbacks) has no local twin and throws with a pointer to staging.
| Flag | Description | Default |
| --- | --- | --- |
| --dir <path> | App directory (with sprigr-app.json) | required |
| --port <n> | Listen port | 8666 |
| --install-id <id> | Local install id (one DB file per id) | inst_local_dev |
| --secrets-file <path> | JSON object of secret key → value | .sprigr/dev/secrets.json |
| --manifest <path> | Manifest override | <dir>/sprigr-app.json |
Two dev-only helpers close the loop the harness can't produce itself (it serves your handlers, not your Next.js routes):
GET /dev/state?csrf=<csrf>mints a wire-correct OAuth state blob for driving a callback by hand.POST /dev/sqlwith{"sql": "...", "params": [...]}runs a statement against the local per-install D1 — e.g. seed theoauth_csrfrow your/oauth/startroute would normally write, then mint a matching state and drive the callback's success path.
Note the response envelope on tool dispatch is the platform's: your
handler's own return value (often itself { ok, ... }) appears under
result, so callback-style handlers read as {"ok":true,"result":{"ok":...}}.
sprigr app bouncer-status <slug>
Self-serve check that your app slug is live on the publisher-shared OAuth
bouncer (no more emailing platform support). Reports whether the slug is
registered, enabled, and whether the current version's manifest declares
the <slug>_oauth_callback tool the bouncer dispatches to, plus the exact
callback URL to register with your provider. Exit code 0 only when all
three hold, so CI can gate on it.
| Flag | Description | Default |
| --- | --- | --- |
| --bouncer <url> | Bouncer origin override | derived from the active endpoint |
Without --bouncer, the bouncer origin derives from the active API
endpoint (from --endpoint, SPRIGR_ENDPOINT, or your login's saved
endpoint): the staging endpoint maps to the staging bouncer, prod to the
prod bouncer. The output header names the bouncer it queried. Any other
endpoint (local gateway, tunnel) requires an explicit --bouncer.
Environment variables
| Variable | Purpose |
| --- | --- |
| SPRIGR_API_KEY | Authentication. Create one in the portal. |
| SPRIGR_ENDPOINT | API endpoint. Accepts a full URL, or the shortcuts staging / prod. |
How deploys work
- The CLI tarballs your
--dir(gzip). - It POSTs to the Sprigr Team provisioning worker, which enqueues a build job.
- The build farm container picks it up, runs the framework adapter (no-op for
static,@opennextjs/cloudflare buildfornext), and streams output back. - On success the bundle is uploaded to Workers for Platforms for SSR sites or to R2 + website-serve for static, then the site's production deployment pointer flips atomically.
Static sites are billed by request count; SSR sites are billed by request count + container-seconds during the build. Plan limits (max sites, retention, custom domains) are enforced at deploy time.
Roadmap
sprigr builds get <siteId> <buildId> --followfor live log tailing.
Links
- Sprigr — https://sprigr.com
- Issues — https://github.com/sprigr/sprigr-team/issues
License
MIT
