| name | setup |
| description | > Use when this capability is needed. |
/setup — Project Onboarding
Progressive setup for new projects using this starter kit.
Starts with infrastructure, then hands off to gStack for product planning.
When to use
Run /setup when cloning this starter kit for a new project.
Instructions
You are helping a solo developer set up a new project from the mvp-kit starter kit.
The setup is split into two phases:
- Phase A (this skill): Get the project RUNNABLE — infra, deps, dev server.
- Phase B (gStack): Plan the product and build features via
/office-hours.
Phase A should be fast — get to a working npm run dev ASAP.
Phase B is where the real product decisions happen.
Before Phase A: check the stack profile. If .mvp-kit/stack.json does not
exist, run /tech-stack-consult first. Without a profile, /setup assumes
nestjs-only (NestJS + BullMQ, no Rust). See Step 0.5 below.
CRITICAL — DO NOT regenerate boilerplate code. COPY + REPLACE only.
The starter kit ships with EVERYTHING pre-built and tested, including pinned
dependency versions. /setup should NOT write any file from scratch.
The ONLY things /setup does:
- Copy
.template files → real files (package.json.template → package.json)
- Replace
__PROJECT_NAME__ placeholder with actual project name
- Install Shadcn components (npm-installed, not in boilerplate)
- Fix Sonner next-themes import (Shadcn bug)
- Run prisma migrate
Pre-built files that MUST NOT be regenerated (saves ~5000 tokens each run):
- API: main.ts, app.module.ts, prisma.service.ts, base-crud.service/controller,
health module, interceptors, filters, DTOs
- Frontend: main.tsx, providers.tsx, router.tsx, layout.tsx, home.tsx,
api-client.ts, form-utils.ts, query-keys.ts, utils.ts, globals.css,
use-paginated-query.ts, use-api-mutation.ts, use-debounce.ts, test utils
- Config: vite.config.ts, tailwind.config.ts, postcss.config.js, components.json,
tsconfig.json (root, frontend, api, shared), vitest.config.ts,
jest.config.ts, jest.e2e.config.ts, nest-cli.json,
biome.json, lefthook.yml, docker-compose.yml, .env.example
- Shared: types/job-envelope.ts, constants/job-types.ts
If /setup rewrites ANY of these, it's wasting tokens and risking regressions.
Phase A: Get Runnable
Follow these steps IN ORDER. Ask one section at a time. Wait for user confirmation before proceeding.
Step 0: Trust But Verify + Install gStack
Before writing any code, help the user verify the repo and install required tools.
Security scan — "don't trust, verify":
Tell the user:
"Before we start, let's verify this repo is safe. Run a quick security scan:"
npx @anthropic-ai/claude-code-security-scanner . 2>/dev/null || echo "Scanner not available — manual review recommended"
grep -r "eval(" --include="*.ts" --include="*.js" . | head -20
grep -r "exec(" --include="*.ts" --include="*.js" . | head -20
grep -rn "password\|secret\|token\|api_key" .env* 2>/dev/null
If the security scanner is not available, suggest manual review:
"No automated scanner found. You can review the repo yourself:
- Check
scripts/ for anything unexpected
- Check
.claude/ for suspicious hooks or skills
- Check
package.json for unknown dependencies
- Run
git log --oneline -20 to see recent commit history
When you're satisfied, confirm and we'll continue."
Wait for user confirmation before proceeding.
Install gStack globally:
First, check if gStack is already installed globally:
ls ~/.claude/skills/gstack/SKILL.md 2>/dev/null && echo "FOUND" || echo "NOT_FOUND"
If FOUND — skip installation, tell the user:
"gStack is already installed globally. Skipping installation."
If NOT_FOUND — install globally:
mkdir -p ~/.claude/skills
cd ~/.claude/skills && git clone https://github.com/garrytan/gstack.git && cd gstack && ./setup
Tell the user:
"gStack is now installed globally at ~/.claude/skills/gstack/. It will be available across all your projects — not just this one. This gives you product planning (/office-hours), code review (/review), QA (/qa), and deployment (/ship) skills."
If the install fails, suggest:
"gStack install failed. Try manually:
mkdir -p ~/.claude/skills
cd ~/.claude/skills && git clone https://github.com/garrytan/gstack.git && cd gstack && ./setup
Or check https://github.com/garrytan/gstack for instructions."
Step 0.5: Stack Profile
Check whether the user has run /tech-stack-consult:
cat .mvp-kit/stack.json 2>/dev/null || echo "NO_PROFILE"
If .mvp-kit/stack.json exists — load the profile field and hold it in
memory for the rest of setup. Tell the user:
"Using stack profile: <profile>. I'll scaffold based on your tech-stack-consult decision."
Valid profiles:
nestjs-only — default, NestJS + BullMQ worker inside NestJS for jobs
nestjs-rust — NestJS + separate Rust worker for CPU-heavy jobs
go-only — frontend only; remove /api, /jobs, /shared. User writes Go backend.
python-only — frontend only; remove /api, /jobs, /shared. User writes Python backend.
If it doesn't exist — surface the tradeoff:
"No stack profile found. /setup will default to nestjs-only (NestJS + BullMQ
worker — no Rust). This is the simplest full-stack option: 1 Node runtime,
1 Dockerfile, 1 CI pipeline.
Options:
- Run
/tech-stack-consult first (5 questions, ~2 min) to evaluate all profiles, then re-run /setup
- Proceed with
nestjs-only default
Which do you want?"
Wait for user response. If they pick (1), stop the skill and ask them to run
/tech-stack-consult. If they pick (2), set profile = "nestjs-only" in memory
and continue.
Record the active profile in the session — you'll apply it in Step 2.5.
Step 1: Project Identity
Ask the user:
- Project name (kebab-case, for package.json)
- One-line description (what does this product do?)
- Team mode: Solo (1 dev + AI agents) or Team (multiple devs + AI agents)?
Then update CLAUDE.md:
- Replace
## Team Mode: [solo | team] with the user's choice
- If Team:
main branch will be protected, PRs required, file claims enabled
- If Solo: lightweight workflow, direct push to main OK
Then:
-
Update CLAUDE.md — replace [Project Name] with actual name, replace [Brief description] with actual description
-
Create package.json files from templates (DO NOT write from scratch):
The boilerplate ships .template files with ALL versions already pinned.
You only need to copy and replace __PROJECT_NAME__:
cp package.json.template package.json
cp frontend/package.json.template frontend/package.json
cp api/package.json.template api/package.json
sed -i "s/__PROJECT_NAME__/<actual-project-name>/g" package.json frontend/package.json api/package.json
That's it. All dependency versions are pre-resolved and tested in the templates.
DO NOT run npm view or change any version numbers.
Version upgrades are managed centrally through mvp-kit releases.
-
Create shared/package.json (no template needed — it's tiny):
{
"name": "<project-name>-shared",
"version": "0.1.0",
"private": true,
"main": "./types/index.ts",
"types": "./types/index.ts"
}
-
Set up .env:
.env.example and docker-compose.yml already exist with __PROJECT_NAME__ placeholder.
Replace it:
sed -i .env.example docker-compose.yml \
frontend/index.html frontend/src/app/layout.tsx frontend/src/pages/home.tsx
Step 2: Infrastructure
All infrastructure files are pre-existing in the boilerplate. Verify — do NOT regenerate:
-
docker-compose.yml — ALREADY EXISTS. Reads POSTGRES_DB from .env.
DO NOT regenerate. Only verify it's present.
-
api/prisma/schema.prisma — ALREADY EXISTS (empty, no models yet).
DO NOT regenerate. Domain models come from sprint tasks in Phase B.
Prisma 7+ compatibility (only if template pinning failed): After npm install,
check npx prisma --version. If somehow Prisma 7+ got installed:
a. Remove url line from datasource db {} in schema.prisma
b. Create api/prisma/prisma.config.ts with defineConfig pointing to env DATABASE_URL
c. Add output = "../node_modules/.prisma/client" to generator client {}
If Prisma 6 (expected) — no changes needed.
-
frontend/vite.config.ts — ALREADY EXISTS with @ and @shared resolve aliases.
frontend/tailwind.config.ts, postcss.config.js, components.json — ALL pre-existing.
DO NOT regenerate any of these.
Before running docker, check for port conflicts:
lsof -i :5432 2>/dev/null | head -5
lsof -i :6379 2>/dev/null | head -5
If ports are in use, warn the user:
"Port 5432 (or 6379) is already in use — you may have a local postgres/redis running. Either stop it or change the port in .env and docker-compose.yml."
Then ask user to run:
docker-compose up -d
docker compose ps
cd api && ln -sf ../.env .env
npx prisma migrate dev --name init
If prisma migrate fails, check:
P1012: Environment variable not found: DATABASE_URL?
→ Prisma reads .env from api/, not root. Symlink: cd api && ln -sf ../.env .env
- Is
.env present in root? (cp .env.example .env if not)
- Does DATABASE_URL in
.env match docker-compose credentials?
- Is postgres actually ready? (
docker compose logs postgres | tail -5)
- Prisma 7 error "datasource property
url is no longer supported"?
→ Follow the Prisma 7 compatibility steps above (remove url from schema, create prisma.config.ts)
Step 2.5: Apply Stack Profile
Now apply the profile chosen in Step 0.5. This adjusts the scaffold BEFORE
installing npm deps for frontend/api, so nothing that depends on the removed
parts gets installed.
If profile == nestjs-only — this is the default. No /jobs folder exists
in the repo, so there's nothing to remove. Just set up the BullMQ worker:
Tell the user:
"Applying nestjs-only profile (default): setting up BullMQ worker inside NestJS."
Then:
-
Copy the BullMQ worker template into the NestJS app:
cp -r templates/worker-bullmq/src/workers api/src/workers
Then register WorkersModule in AppModule. The user can follow the
typescript-nestjs skill's BullMQ section to add real processors.
-
Remove Rust-specific env vars from .env.example and .env (if present):
RUST_LOG
WORKER_CONCURRENCY
-
Update CLAUDE.md Project Structure: remove the - /jobs line if present.
If profile == nestjs-rust:
Tell the user:
"Applying nestjs-rust profile: copying Rust worker from templates."
Then:
-
Copy the Rust worker template to project root:
cp -r templates/jobs-rust jobs
-
Add Rust-specific env vars to .env and .env.example (if not already present):
RUST_LOG=info
WORKER_CONCURRENCY=4
-
Add a jobs: service to docker-compose.yml if not already present
(build from jobs/, depends on redis + postgres).
-
Verify Rust toolchain is installed:
rustc --version || echo "Rust not installed — run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
If profile == go-only OR python-only:
The team is not writing a NestJS backend. mvp-kit ships the React frontend;
you own the backend in Go or Python.
Let LANG = "Go" if profile == go-only, otherwise "Python".
Let WORKDIR = backend-go if profile == go-only, otherwise backend-python.
Tell the user:
"Applying <profile> profile: keeping /frontend only. Removing /api (NestJS),
/jobs (Rust), and /shared (TS types) — you'll write your backend in .
I'll leave a README in <WORKDIR>/ with the suggested layout."
Then:
-
Remove TS-backend folders:
rm -rf api/ jobs/ shared/
-
Remove TS-backend references from docker-compose.yml:
- Delete the
jobs: service (if present)
- Keep
postgres: and redis: — user's backend will use them
- Do NOT add a service for the user's backend — they run it outside Docker
until they decide how to package it.
-
Remove TS-backend env vars from .env.example and .env:
JWT_SECRET, JWT_EXPIRES_IN (NestJS-specific)
RUST_LOG, WORKER_CONCURRENCY
- KEEP
DATABASE_URL and REDIS_URL — user's backend needs these
-
Create <WORKDIR>/README.md with a suggested layout. Use exactly this template:
For go-only (backend-go/README.md):
# Backend (Go)
mvp-kit provides the React frontend. You own this Go backend.
## Suggested layout
- `cmd/api/main.go` — HTTP server entry point
- `internal/handlers/` — HTTP handlers
- `internal/models/` — domain types
- `internal/db/` — Postgres access (pgx or sqlx)
- `internal/queue/` — Redis queue consumer (optional)
## Suggested libraries
- Router: chi, gin, or net/http
- DB: pgx or sqlx
- Queue: asynq (Redis-backed job queue — matches frontend expectations)
## Frontend integration
The frontend expects `VITE_API_URL` (see `frontend/.env`) to point at this
service. Default: `http://localhost:3000/api/v1`.
in the repo root provides Postgres + Redis. Run:
Flag for the user:
"Your backend is OUT OF SCOPE for mvp-kit skills — /review, /qa, /ship
assume a NestJS API. Those skills will still work for the frontend, but
any backend QA/review is on you."
After applying the profile, run git status and show the user what changed
before continuing to Step 3.
Step 3: App Shell + Shadcn Components
EVERYTHING below is pre-existing in the boilerplate. DO NOT regenerate ANY of these files:
Backend (all pre-built):
api/src/main.ts — NestJS bootstrap with Swagger, CORS, global pipes/filters
api/src/app.module.ts — Root module importing HealthModule
api/src/common/prisma.service.ts — NestJS-managed PrismaClient
api/nest-cli.json — NestJS CLI config
- All common infrastructure, health module, DTOs, filters, interceptors
Frontend (all pre-built):
frontend/index.html — Vite entry HTML (has __PROJECT_NAME__ in title)
frontend/src/app/main.tsx — React entry point
frontend/src/app/providers.tsx — QueryClient provider
frontend/src/app/router.tsx — React Router (home + 404)
frontend/src/app/layout.tsx — Layout shell (has __PROJECT_NAME__ in header)
frontend/src/pages/home.tsx — Home page (has __PROJECT_NAME__ in heading)
frontend/src/lib/utils.ts — Shadcn cn() utility
frontend/src/styles/globals.css — Tailwind base + CSS variables
frontend/src/lib/form-utils.ts, api-client.ts, all hooks, all features
The ONLY things /setup does here are:
(__PROJECT_NAME__ replacement is already done in Step 1 via the sed command.)
-
Install Shadcn components (these are npm-installed, not in boilerplate):
cd frontend && npx shadcn@latest add button input label separator sonner
-
Fix Sonner component — Shadcn's default sonner.tsx imports useTheme from next-themes
which does NOT exist in Vite projects. After installing, edit frontend/src/components/ui/sonner.tsx:
- Remove the
import { useTheme } from "next-themes" line
- Remove the
const { theme = "system" } = useTheme() line
- Replace
theme={theme as ToasterProps["theme"]} with theme="light"
This is a known Shadcn issue — their default template assumes Next.js.
-
Run bash scripts/sync-components.sh to update COMPONENTS.md
Ask user to run npm run dev and verify both frontend (:5173) and API (:3000) are working.
Step 4: Verify & Hand Off
Once everything runs:
- Run
npx @biomejs/biome check . to verify code quality
- Run TypeScript typecheck on frontend + api
- Summarize what's been set up
Then tell the user (in their preferred language):
Setup complete! Project is up and running.
If you have existing research, prototypes, or reference code, drop them in the materials/ folder now.
Claude will review them during /office-hours so you don't have to explain everything from scratch.
Next step: run /office-hours to plan your product.
gStack will scan materials/ and ask about your product vision, target users, and core features,
then generate a PRD. From there:
MVP LITE MODE (mac dinh): /office-hours → Claude Design (neu co UI, xem docs/design-step.md) → /plan-eng-review → BACKLOG (lite) → build → ship → sua. Bo /plan-ceo-review va /plan-sprint khoi luong bat buoc.
(Full mode) /office-hours → /plan-ceo-review → /plan-eng-review → /plan-sprint
— /plan-sprint chuyen eng review thanh Epics/Tasks/Sprint backlog (chi dung khi bat lai full mvp-kit).
Useful gStack skills:
/office-hours — define product, create PRD
/plan-eng-review — validate architecture
/plan-sprint — create epics, tasks, sprint backlog
/design-consultation — discuss UX/UI approach
/review → /qa → /ship — daily dev workflow
Phase B: Build Product (via gStack)
Phase B is NOT part of this skill. It happens organically through gStack skills.
But here's the expected flow for reference (FULL mode — lite mode rut gon thanh: office-hours → design neu co UI → plan-eng-review → BACKLOG → build → ship, KHONG ceo-review/plan-sprint/retro):
/office-hours → Define product, create PRD
/plan-ceo-review → Validate product direction
/plan-eng-review → Validate architecture for the features planned
/plan-sprint → Create Epics + Tasks in BACKLOG.md, populate SPRINT.md
/plan-design-review → Validate UX approach
Then sprint by sprint:
code feature → Follow patterns in skills (typescript-nestjs, frontend-ui)
/review → Code review
/qa → Test
/ship → Ship to staging/production
/retro → Sprint retrospective
Common product decisions handled in Phase B
These are decisions that /office-hours and sprint planning will resolve:
| Decision | Depends on product | NOT in /setup |
|---|
| Auth (yes/no, method) | Blog = no auth. SaaS = JWT. Internal tool = SSO | /office-hours decides |
| Database schema | Based on PRD entities | Sprint task |
| App layout (sidebar/nav) | Admin panel = sidebar. Landing = top nav. Dashboard = both | /design-consultation decides |
| Roles & permissions | Some MVPs have none. SaaS = admin/user. Marketplace = buyer/seller | /office-hours decides |
| Deploy target | Depends on budget, scale, team | /setup-deploy handles when ready |
| Background jobs runner | Driven by stack profile (see .mvp-kit/stack.json) | /tech-stack-consult decides |
gStack Integration
Use gStack skills throughout the process:
| Situation | gStack skill | Why |
|---|
| Something fails during setup | /investigate | Debug with full context |
| Need to research a library | /browse | Web browsing (NEVER use mcp__claude-in-chrome__* tools) |
| Generating security-critical code | /careful | Extra review and caution |
| Code review after generating | /review | Validate quality |
| Ready to test | /qa | Full test suite |
| Ready to ship | /ship or /land-and-deploy | Deploy flow |
| After all features done | /document-release | Auto-generate docs |
Rules for this skill
- ALWAYS ask ONE section at a time. Never dump all questions at once.
- After generating files, ALWAYS ask user to verify they work before proceeding.
- If something fails, use
/investigate to debug, then fix before moving on.
- Communicate in the user's preferred language. All generated code, comments, and docs MUST be in English.
- Reference existing conventions — don't invent new patterns.
- If user says "skip" for any step, skip it and move to next.
- Phase A should be FAST — max 4 steps to a running dev server.
- DO NOT make product decisions (auth, schema, layout) — that's Phase B via
/office-hours.
- DO NOT generate business features — real features come from sprint plan. Skills teach the patterns.
Source: anicdh/mvp-kit — distributed by TomeVault.