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 —
.htmlanddist/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:
- Attach at AppMint:
POST /dev-env/attach-domain/<projectName>with the domain name. AppMint validates plan eligibility and stores the alias. - Sync to SpinForge: either redeploy (which forwards the alias list) or call
POST /api/deploy/spinforge/<orgId>/<projectName>/sync-aliasesfor 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
spinforgeCLI. Don'tspinforge 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.tomlordeploy.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:
| Framework | Build command | Output |
|---|---|---|
vanilla-html | none | workspace root |
vite-react | npm install && npm run build | dist/ |
next | npm install && npm run build | Next standalone build |
astro | npm install && npm run build | dist/ |
vue, svelte-kit | npm install && npm run build | framework'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
- Deploy to SpinForge — the deploy flow from Vibe Studio.
- Domains — attach a custom domain.
- session-manager — the service that orchestrates the deploy.