Init App Stack
Bootstrap a full-stack project with:
- Frontend: Vite 8+ + React + TanStack Router + TanStack Query + Zustand + shadcn/ui + TailwindCSS v4, managed with bun
- Backend: FastAPI + Granian + raw asyncpg (Postgres), managed with uv, targeting Python 3.14 (PEP 750 t-strings for SQL)
- DB: Postgres 17 via
docker-compose.yml - Types:
openapi-typescriptgenerates a typed client from FastAPI's OpenAPI schema
Step 1: Run the scaffold script
This creates the full project structure deterministically — do not scaffold manually.
uv run python scripts/create.py <project-name>The script (works on Mac, Linux, Windows):
- Frontend:
bun create vite@latest frontend --template react-ts, installs TanStack Router + Query + Devtools, Zustand, Zod, TailwindCSS v4, shadcn deps (class-variance-authority,clsx,tailwind-merge,lucide-react,tw-animate-css),openapi-typescript - Wires
vite.config.tswith@tanstack/router-plugin+@/path alias, sets upsrc/main.tsxwithQueryClientProvider+RouterProvider, writessrc/routes/__root.tsxandsrc/routes/index.tsx - Writes
src/lib/queryClient.ts,src/lib/api.ts(fetch wrapper withVITE_API_URL),src/lib/utils.ts(shadcncnhelper),src/stores/placeholder for Zustand - Writes shadcn config:
components.json, shadcn-compatiblesrc/index.css(OKLCH theme vars,@theme inline,tw-animate-css,.darkclass variant), patchestsconfig.json+tsconfig.app.jsonwith@/*path alias - Adds
bun run generate-apiscript → fetches/openapi.jsonand runsopenapi-typescriptintosrc/lib/api-types.ts - Backend:
uv init --python 3.14, addsfastapi,granian,asyncpg,pydantic-settings - Writes
main.py(lifespan-managed asyncpg pool, CORS forlocalhost:5173),db.py(pool + t-stringsql()helper),config.py(pydantic-settings) - Adds
dev = "granian --interface asgi main:app --reload"andstart = "granian --interface asgi main:app --workers 4"topyproject.toml - Writes
docker-compose.ymlwith a singledbservice (Postgres 17) + named volume - Writes
.env.example(frontend + backend), root.gitignore,README.mdwith startup steps
After running:
cd <project-name>
docker compose up -d db # start Postgres
cd backend && uv run dev # FastAPI on :8000
cd frontend && bun run dev # Vite on :5173Step 2: Enable companion skills via marketplace
Add this to your project's .claude/settings.json to give the agent deep knowledge of the stack:
{
"extraKnownMarketplaces": {
"bmsuisse-skills": {
"source": {
"source": "github",
"repo": "bmsuisse/skills"
}
}
},
"enabledPlugins": {
"coding@bmsuisse-skills": true
}
}This installs the coding plugin which includes:
tanstack-best-practices— TanStack Router + Query patterns, SSR integration, query key factoriescoding-guidelines-typescript— TypeScript strictness, discriminated unions, async typingcoding-guidelines-python— FastAPI/backend Python standards, ty type checkingfastapi-guideline— Production FastAPI patterns (CRUD, DI, auth, async)autoresearch— Autonomous experiment loop for iterative improvements
Reference files (load as needed, not all at once)
| File | When to read |
|---|---|
references/react-tanstack.md | TanStack Router (typed routes, search params, loaders) + Query (caching, mutations) + Zustand patterns |
references/shadcn-ui.md | Adding shadcn components, theme tokens, cn() usage, dark mode |
references/asyncpg-postgres.md | Connection pool lifecycle, t-string sql() helper, transactions, pagination |
references/openapi-typed-client.md | Regenerating api-types.ts from FastAPI, typed fetch patterns |
references/fastapi-templates.md | Backend structure, CRUD repos, dependency injection, auth |
references/fastapi-sse.md | Adding SSE streaming endpoints (AI chat, live updates, logs) |
references/frontend-design.md | UI aesthetics, typography, color, motion — avoid generic looks |
Key conventions
- Always use bun (not npm/yarn/pnpm) for the frontend.
- Always use uv (not pip/poetry/pipenv) for the backend. Pin Python 3.14.
- Backend uses
fastapi+granian— do not usefastapi[standard](bundles uvicorn, conflicts with Granian). - Run backend dev with
uv run dev(granian --interface asgi main:app --reload). - Do not use SQLAlchemy or any ORM. Use raw asyncpg with the
sql()t-string helper indb.py:from db import sql, pool async with pool.acquire() as conn: rows = await conn.fetch(*sql(t"SELECT * FROM users WHERE id = {user_id}"))The helper convertst"..."interpolations to asyncpg's native$1, $2positional params — safe from injection, no string formatting. - Frontend routing: file-based via
@tanstack/router-plugin— add files undersrc/routes/, route tree is auto-generated. - Data fetching: TanStack Query only — do not roll
useEffect + fetch. UsequeryOptionsfor reusable query definitions. - Client state: start with
useState+ Context. Reach for Zustand only when syncing across distant components. Never Redux. - URL state (filters, pagination, sort): put in TanStack Router search params with Zod validation, not in Zustand.
- UI components: shadcn/ui — generated into
src/components/ui/viabunx --bun shadcn@latest add <component>. Do not install a MUI/Chakra/Mantine. Style with Tailwind v4 tokens (bg-background,text-foreground,text-muted-foreground,border-border) — not raw palette colors likebg-neutral-800. - Use the
cn()helper from@/lib/utilsto conditionally merge Tailwind classes. Imports use the@/*alias (configured invite.config.ts+ both tsconfigs). - Regenerate API types after backend changes:
bun run generate-api(requires backend running onlocalhost:8000). - CORS is pre-configured for
http://localhost:5173(Vite default). Update for production. - Typing on backend:
uv add --dev tyand runuv run ty check.