Deploy anywhere in one command
Deployment is where MVPs stall. Not because it is hard, exactly, but because it is a pile of provider-specific trivia: login flows, SPA rewrite rules, environment variables that need the final URL before the final URL exists. geenius-mvp folds all of it into one command.
pnpm deploy my-idea # cloudflare by default
pnpm deploy my-idea --to vercel # or netlify | surge | heroku | github-pages
pnpm deploy my-idea --dry-run # see the plan without touching anything
pnpm deploy --providers # login status for all 6 providers
Six providers, zero setup reading
Cloudflare Pages is the default; Vercel, Netlify, Surge, Heroku, and GitHub Pages are a flag away. If you are not logged in to the chosen provider, the script detects it and launches the login flow for you instead of failing with an authentication error you have to decode. pnpm deploy --providers shows the login status of all six at once, which is also how an agent decides which target is viable before committing to one.
The backend deploys first, idempotently
For Convex apps, the backend goes out before the frontend. The script reuses the Convex project recorded in the app's .env.local — it never duplicates a cloud project, and it preserves BETTER_AUTH_SECRET across deploys. This guard exists because the failure mode is nasty: running the wrong configure command on an app that already has a deployment silently mints a second cloud project, and now half your data lives somewhere your app no longer looks. The deploy script refuses to make that mistake, and AGENTS.md tells agents not to bypass it.
SITE_URL, solved in the right order
Auth needs to know the app's public URL, but you do not know the URL until the frontend has landed. The deploy script sequences this correctly: backend first, then the frontend upload, then SITE_URL is synced to the real deployed URL. Hosted sign-in works on the first deploy, not the second.
Per-host SPA fallbacks
A React SPA needs every deep link to serve index.html, and each host spells that differently — a redirects file here, a rewrite config there, a 404 trick on GitHub Pages. The deploy script writes the correct fallback for whichever provider you chose, so /records/xyz refreshes cleanly everywhere. Static-stack sites skip all of this: they deploy as plain files, which is the point of the static stack.
Remembered, repeatable, parseable
Your provider choice is remembered in apps/your-slug/.deploy.json, so the next pnpm deploy my-idea goes to the same place without the flag. Failures print the failing provider step inline. And with --json, the final line is the same @geenius-mvp:result marker the scaffolder uses — carrying the live URL, so an agent can deploy, parse one line, and open the site to verify.
Idempotent where it matters: run it twice, get the same app in the same place.
One command, six targets, and the provider trivia lives in tools/deploy.mjs where it belongs — not in your head, and not in your agent's context window.