Documentation

Deploy to SpinForge

Ship the workspace to a public URL with one click.

Deploying from Vibe Studio packages the workspace, hands it to session-manager, which forwards it to SpinForge with the partner key. The result is a live site at https://<orgId>-<projectName>.spinforge.dev (plus any custom domains attached to the dev env).

How it works under the hood

Vibe Studio  ── POST /api/deploy/spinforge/<orgId>/<projectName> ──▶  session-manager
                                                                          │
                                                            spawns deploy job (background)
                                                                          │
                                                                          ▼
                                                              ┌──────────────────────┐
                                                              │ init → build →       │
                                                              │ create-site →        │
                                                              │ package → upload →   │
                                                              │ done                 │
                                                              └──────────────────────┘
                                                                          │
                                                                          ▼
                                                              SpinForge partner API
                                                              with sfpk_… key
                                                                          │
                                                                          ▼
                                                              Live site at
                                                              <orgId>-<projectName>.spinforge.dev

session-manager owns the partner key (sfpk_…) — Vibe Studio never sees it. The browser's only role is to start the job and stream progress.

Trigger a deploy

Two paths.

From the studio

Click LaunchDeploy to SpinForge. The studio:

  1. Reads attached custom domains from GET /dev-env/<projectName> on AppMint.
  2. POSTs /api/deploy/spinforge/<orgId>/<projectName> on session-manager with the builder's JWT and the alias list.
  3. Subscribes to /api/deploy/job/<jobId>/stream (SSE).
  4. Renders each step's message as it arrives.

This is the path you'll use 99% of the time.

From a script or the agent

# Pull attached custom domains
ALIASES=$(curl -s "$APPMINT_API_URL/dev-env/$APPMINT_PROJECT_NAME" \
  -H "Authorization: Bearer $APPMINT_TOKEN" \
  -H "orgid: $APPMINT_ORG_ID" \
  | jq -c '.data.domains // []')

# Start the deploy
curl -X POST "$SESSION_MANAGER_URL/api/deploy/spinforge/$APPMINT_ORG_ID/$APPMINT_PROJECT_NAME" \
  -H "Authorization: Bearer $APPMINT_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"customerId\":\"$APPMINT_USER_EMAIL\",\"aliases\":$ALIASES}"

Response:

{ "success": true, "jobId": "job_...", "job": { "status": "running", ... } }

Then poll or stream:

# Poll
curl "$SESSION_MANAGER_URL/api/deploy/job/<jobId>"

# Stream (SSE)
curl -N "$SESSION_MANAGER_URL/api/deploy/job/<jobId>/stream"

The deploy steps

session-manager runs the job through six steps. Each one emits an event the studio shows:

StepWhat happens
initValidate the workspace. Read .vibe/project.json, verify orgId / projectName / owner.
buildIf framework requires a build, run npm install && npm run build (or framework-specific equivalent). Skip for vanilla-html.
create-siteCall SpinForge's partner auth (/_partners/auth) with the partner key + builder's JWT. Mint a sfc_… per-customer session. Create or update the SpinForge site record.
packageZip the workspace's build output. Skip node_modules/, .git/ (unless includeGit), and other ignore-listed paths.
uploadStream the zip to SpinForge. SpinForge extracts, configures DNS, issues TLS, serves the site.
doneFinal event. Includes the live URL and any custom domain aliases.

If a step fails, the job emits an error event with the server's actual message. Don't paper over errors — the agent's instructions explicitly say to surface server errors verbatim, not invent recoveries.

Live URL format

https://<orgId>-<projectName>.spinforge.dev

Two things to know:

  • The subdomain is fixed. You can't pick a different one — orgId and projectName are immutable per workspace.
  • Subdomain DNS takes ~30 seconds for fresh sites. Hitting the URL immediately after done may 404 briefly.

Environment variables

For deployed apps that need server-side env vars (Next.js, etc.), set them at the SpinForge level. The agent or builder configures via SpinForge's partner API (proxied through session-manager). Don't bake secrets into the build output.

For build-time vars (VITE_*, NEXT_PUBLIC_*), include them in .env.production in the workspace before deploy. They're zipped into the package and the build step picks them up.

Don't commit secrets

Production env files in the workspace get zipped and uploaded. If you're using git, .gitignore doesn't help — the zip step ignores .git/ but not other dotfiles by default. Use SpinForge's runtime env config for anything sensitive.

Re-deploys and rollback

Every deploy is a fresh package. To re-deploy after edits, just hit Launch again. The previous deploy's job record is kept (see GET /api/deploy/jobs/<orgId>/<projectName>).

For rollback, check out the previous git commit in the workspace and re-deploy. There's no SpinForge-side "previous version" concept — the live site is always whatever the last deploy uploaded.

Sync custom domains without a deploy

If you attached a new custom domain in AppMint and don't want to redeploy:

curl -X POST "$SESSION_MANAGER_URL/api/deploy/spinforge/$APPMINT_ORG_ID/$APPMINT_PROJECT_NAME/sync-aliases" \
  -H "Authorization: Bearer $APPMINT_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"customerId\":\"$APPMINT_USER_EMAIL\",\"aliases\":$ALIASES}"

This re-runs SpinForge's /_partners/auth with the desired alias list and updates the site's domain bindings without rebuilding or re-uploading.

Deleting a deploy

curl -X DELETE "$SESSION_MANAGER_URL/api/deploy/spinforge/$APPMINT_ORG_ID/$APPMINT_PROJECT_NAME?customerId=$APPMINT_USER_EMAIL" \
  -H "Authorization: Bearer $APPMINT_TOKEN"

This removes the SpinForge site record. The workspace on disk is untouched.

Things that don't exist

The agent's instructions are emphatic about this — none of these are real:

  • spinforge CLI binary. There's no spinforge deploy, spinforge login, spinforge whoami.
  • A SpinForge dashboard upload flow for end users.
  • A filesystem drop path like ~/.spinforge/deployments/.
  • deploy.yaml / spinforge.toml config files.
  • Browser auth flow for SpinForge users.

If a tutorial or AI suggestion mentions any of these, it's wrong. The deploy is API-driven, full stop.

Related