scaffold-saas
scaffold-saas
You are running inside the scaffoldo repo. The user wants a new SaaS project bootstrapped. This skill conducts the interview and delegates the filesystem work to the scaffoldo npm CLI.
Single source of truth
The canonical question schema lives in src/core/interview.ts in the scaffoldo repo. A human-readable mirror is in questions.md. Both files must stay in sync — if you change one, change the other.
Phase 1 — Interview
Use AskUserQuestion to walk the question list. Group up to 4 questions per call to keep the experience tight. Required fields, in order:
projectName— display name (free text)projectSlug— kebab-case slug for the directory and packagetargetDir— absolute path; default to~/Desktop/<slug>oneLinePitch— one sentence, used as the landing herotargetAudience— who is this forcoreProblem— the problem being solvedcoreSolution— how the product solves itmonetization—subscription/one-time/freemium/usage-baseddomainEntities— 1–5 PascalCase nouns, comma-separated; each becomes a Prisma model + a CRUD route stuboptionalModules— multi-select frompinecone,upstash,resend(default: all on)
Validation rules (mirror src/core/interview.ts):
projectSlugmust match/^[a-z][a-z0-9-]*[a-z0-9]$/domainEntitiesitems must match/^[A-Z][A-Za-z0-9]*$/, between 1 and 5targetDirmust be an absolute path
If a user answer fails validation, ask again with a corrective hint. Do not silently fix it.
Phase 2 — Delegate to the CLI
Build an answers object that matches the Answers interface, write it to a tempfile, then invoke the CLI.
ANSWERS_FILE="$(mktemp -t scaffoldo-answers-XXXXXX.json)"
cat > "$ANSWERS_FILE" <<'JSON'
{
"projectName": "...",
"projectSlug": "...",
"targetDir": "/absolute/path",
"oneLinePitch": "...",
"targetAudience": "...",
"coreProblem": "...",
"coreSolution": "...",
"monetization": "subscription",
"domainEntities": ["Lead", "Pipeline"],
"optionalModules": ["pinecone", "upstash", "resend"]
}
JSON
npx scaffoldo@latest init --answers-file "$ANSWERS_FILE"
Run that as a single Bash invocation. The CLI prints a Next steps block on success.
During development of scaffoldo itself, scaffoldo@latest may not yet be on npm. Fall back to running the local build:
node /absolute/path/to/scaffoldo/dist/cli.js init --answers-file "$ANSWERS_FILE"
Detect dev mode by checking whether the current working directory is the scaffoldo repo (package.json has "name": "scaffoldo"). If so, prefer pnpm --silent build && node ./dist/cli.js init ….
Phase 3 — Surface the post-scaffold checklist
After the CLI returns, read these files from the target dir and surface their content to the user inline (do not just point at paths — paste the relevant sections):
<targetDir>/docs/setup.md— per-service signup walkthrough<targetDir>/docs/checklist.md— the 15-feature launch checklist tailored to this project<targetDir>/.env.example— list every key that needs a real value beforepnpm dev
End with a concrete "what to do next" block:
cd <targetDir> && pnpm install- Walk through
docs/setup.mdin order: GitHub → Vercel → Supabase → Clerk → Stripe → (optional services). - Paste keys into
.env.local(copied from.env.example). pnpm db:pushonceDATABASE_URLis set.pnpm dev.
Hard constraints
- Never ask the user for, read, or write real API keys. Only
.env.example(placeholder values) is touched. - Never run
git commit,git push,pnpm install, orpnpm buildwithout an explicit user OK — the user's global rules forbid this. - English only in all generated content (overrides the user's global "comments in Russian" preference for scaffoldo and its outputs).
- If the target directory already exists and is non-empty, abort and ask the user to pick a different path. Do not pass
--force.