Documentation

SpinForge

The deploy target for Vibe Studio workspaces — subdomains, custom domains, build pipeline.

SpinForge is where Vibe Studio workspaces become public sites. It's a partner integration: AppMint owns a SpinForge partner key (sfpk_…); session-manager calls SpinForge's partner API on behalf of the builder; SpinForge handles DNS, TLS, CDN, and serves the live site. Builders never log in to SpinForge directly — the entire flow goes through session-manager so the partner key stays server-side.

What it provides

  • Subdomain provisioning — every workspace gets a deploy URL at <orgId>-<projectName>.spinforge.dev. DNS, TLS via Let's Encrypt, all automatic.
  • Custom domain support — point your own domain at SpinForge and it joins the site as an alias.
  • Static and Node sites.html and dist/ outputs serve as static; Next.js standalone, etc., serve as Node runtimes.
  • CDN — global edge cache.
  • Per-site environment variables — set runtime env at the SpinForge level.

How a deploy reaches SpinForge

Vibe Studio
    │  POST /api/deploy/spinforge/<orgId>/<projectName>
    ▼
session-manager
    │
    │  1. Validate workspace, read .vibe/project.json
    │  2. Run framework's build command (skip for vanilla-html)
    │  3. POST /_partners/auth on SpinForge with sfpk_ + builder JWT
    │     → SpinForge mints a per-customer session sfc_…
    │  4. Create or update SpinForge site via partner API
    │  5. Zip the build output, stream to SpinForge upload endpoint
    │  6. SpinForge extracts, configures DNS/TLS, serves
    ▼
SpinForge

session-manager's job is to be the credentialed proxy. The browser sees deploy progress over SSE on /api/deploy/job/<jobId>/stream; the partner key never enters the browser.

Subdomain format

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

Both pieces come from .vibe/project.json and are immutable per workspace. To get a different subdomain, create a different workspace.

DNS for fresh subdomains takes ~30 seconds to resolve globally. The first hit after a deploy may 404 briefly.

Custom domains

Two-step flow:

  1. Attach at AppMint: POST /dev-env/attach-domain/<projectName> with the domain name. AppMint validates plan eligibility and stores the alias.
  2. Sync to SpinForge: either redeploy (which forwards the alias list) or call POST /api/deploy/spinforge/<orgId>/<projectName>/sync-aliases for a no-rebuild update.

After DNS resolves, SpinForge issues a Let's Encrypt cert automatically. Detailed guidance in Domains.

What SpinForge ISN'T

The agent's instructions are explicit about fabrications to avoid:

  • No spinforge CLI. Don't spinforge deploy, spinforge login, etc. None of those exist.
  • No SpinForge dashboard upload. Builders don't log into a SpinForge UI.
  • No filesystem drop path. ~/.spinforge/deployments/ doesn't exist.
  • No spinforge.toml or deploy.yaml. Deploys are API-driven; there's no config file in the workspace.
  • No browser auth flow for SpinForge. session-manager owns the partner key.

If a tutorial or stale piece of content mentions any of these, it's wrong.

Per-customer sessions

The sfc_… token SpinForge mints during /_partners/auth represents the builder as a SpinForge customer. session-manager passes the builder's customerId (their AppMint email) and JWT; SpinForge returns a session token scoped to that customer. The token is short-lived and re-minted on each deploy.

This is what makes per-builder isolation work: even though the partner key is shared, each builder's deploys live under their own customer record on SpinForge.

Build pipeline

session-manager runs the build before packaging:

FrameworkBuild commandOutput
vanilla-htmlnoneworkspace root
vite-reactnpm install && npm run builddist/
nextnpm install && npm run buildNext standalone build
astronpm install && npm run builddist/
vue, svelte-kitnpm install && npm run buildframework's output dir

If framework is null in .vibe/project.json, session-manager treats the workspace as static — it ships the workspace files as-is. Set the field correctly to get the build step.

Environment variables

Two layers:

  • Build-time.env.production, .env.local, etc. in the workspace. Zipped into the package and read by the build command.
  • Runtime — set on the SpinForge site record via the partner API. Used by Node runtimes at request time.

For secrets, prefer runtime env at the SpinForge level. Build-time env files are committed to the package — even if .gitignore excludes them, they may end up in the upload zip unless you also exclude them from the deploy package.

Deleting a deployed site

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 folder on session-manager is untouched — you can still edit, redeploy, or delete the workspace separately.

Status check

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

Returns the SpinForge site's readiness, the live URL, and any custom domain bindings. Useful for CI checks after a deploy.

Limits

  • Free tier: subdomain only, no custom domains, low traffic ceiling.
  • Paid tiers: custom domains (count varies), higher traffic ceilings, optional dedicated edge regions.

The plan check happens at AppMint's /dev-env/attach-domain endpoint — SpinForge enforces traffic ceilings on its side. If you're hitting limits in production, the AppMint billing page is the right starting point.

Related