name: module-add
description: 'Wire a backend or infrastructure module (auth, database, payments, email, file storage, deploy config) into an already-scaffolded app. Reads .workflow/meta.json#stack for the chosen tech (better-auth, drizzle+neon, stripe, resend, vercel, etc.) and modifies the codebase at the project root to install + configure the module end-to-end. Always idempotent — running twice does not duplicate config. Use when the user says "add auth", "wire up the database", "set up Stripe", "add file uploads", "configure deploy", "module aggiungi auth", or the orchestrator routes here from phase scaffolded / page_generated. Not for: scaffolding the app (design-md-to-app) or building UI (screenshot-to-page).'
module-add — wire a backend/infra module into the scaffold
This skill is the bridge between a styled-but-empty app and a functional product. Every "module" follows the same shape: install packages, generate config, write a small reference implementation (one route or one server function), update meta.json#stack to record the choice, and bump phase.
Modules supported in v1:
| Module | Default tech | Reference file | Status |
|---|---|---|---|
auth |
better-auth (email/password + magic link) | references/module-auth.md |
✅ implemented |
db |
Drizzle ORM + Neon Postgres | references/module-db.md |
✅ implemented |
payments |
Stripe (subscriptions + one-time) | references/module-payments.md |
✅ implemented |
email |
Resend + React Email | references/module-email.md |
✅ implemented |
test |
Vitest + Testing Library + Playwright | references/module-test.md |
✅ implemented |
ci |
husky + lint-staged + GitHub Actions | references/module-ci.md |
✅ implemented |
motion |
Motion (rebranded framer-motion) + opinionated wrappers | references/module-motion.md |
✅ implemented |
storage |
UploadThing | references/module-stubs.md |
🚧 planned — contributions welcome |
deploy |
Vercel | references/module-stubs.md |
🚧 planned — contributions welcome |
The user can override any default. If they say "add auth with Clerk", read references/module-auth.md for the Clerk variant if present; otherwise refuse and explain — better-auth is the default and adding new variants is a contract change.
For modules marked "stub", the reference file gives the shape (packages, env vars, out-of-band steps) but doesn't provide the install templates. Implement the stub on first request — copy module-auth.md or module-db.md as the structural template and fill in.
When this skill applies
- A
<project-root>/exists (phase >= scaffolded). - The user names a module: "add auth", "wire the db", "add stripe", "set up resend".
- The orchestrator routes here from
scaffoldedorpage_generated.
Contract
This skill follows the dev-flow contract — see references/contracts.md. Key facts:
- Reads
<root>/.workflow/meta.json#stackto honor existing choices. - Modifies
<project-root>/(installs deps, writes config, writes one example route or function). - Updates
meta.json#stackto record the module's tech choice (e.g.,stack.auth = "better-auth"). - Sets
phase = "module_added"(only if current phase is earlier in the enum). - Idempotent: re-running the same module check whether it's already wired and skips/updates instead of duplicating.
Monorepo awareness
Before Step 1: check meta.json#stack.framework.
- If
"monorepo": this skill operates insideapps/web/(cwd =<project-root>/apps/web/) for web-specific modules (motion, email server actions, queries), AND insidepackages/api/for modules consumed by both apps (auth, db, storage, realtime, payments — these are backend client wiring, not web-specific UI). Runmonorepo-sync-typesafterdbandauthmodules to propagate types topackages/shared/. - If
"next"/"vite-react"/"remix"/"astro"/ etc.: operate at project root (current behavior, unchanged). - If
"expo-rn": refuse — usern-module-addinstead.
For the monorepo case, "install + generate" means: install npm packages into the appropriate workspace (pnpm add --filter @<slug>/web or pnpm add --filter @<slug>/api), and generate code into the right sub-folder. Use the workspace-relative paths in all references below.
Workflow
Step 1 — Determine the target module + tech
The user tells you which module (one per invocation: auth, db, etc.). Sub-decision: which tech?
- If
meta.json#stack.<module>is set, use that tech. Don't ask again. - If not set, propose the default from the table above with a one-line rationale ("Suggerisco better-auth perché è leggero, self-hosted, e si integra naturalmente con Drizzle"), then accept whatever the user picks.
If the user picks a tech the skill doesn't have a reference file for, refuse and offer to add it (i.e., they want a new variant — that's a contract update, not a runtime choice).
Step 2 — Read the variant reference
Open references/module-<name>.md for the chosen module. The reference is the source of truth for the install steps and the file paths. Read it end-to-end before doing anything.
Each reference describes:
- Install commands — packages to add, optional dev deps, environment variables to set.
- Config files — paths and templates (e.g.,
<project-root>/lib/auth.ts,drizzle.config.ts). - Schema or migration setup — for
db, the Drizzle schema folder layout; forpayments, the webhook secret rotation. - Reference implementation — exactly one route or server function showing the module in use (e.g., a
/sign-inpage for auth, a/api/stripe/webhookfor payments). The user can copy-paste-evolve from there. - Idempotency check — how to detect the module is already installed (typically a
package.jsondependency check + a config file check). On re-run, skip install + config but offer to regenerate the reference implementation if the user asks. - Environment variables required — list with descriptions; write a
.env.local.exampleentry, never the real values.
Step 3 — Apply the changes
Run install commands. Write config files from the templates. Write the reference implementation. Update .env.local.example.
If the framework-specific path conventions differ (Next App Router vs. Vite vs. Remix), the variant reference handles it — don't hand-edit paths in the skill body.
Never run npm install for a non-reference module. Stick to what the variant reference declares. If the user wants additional libraries, that's a separate module-add invocation or a manual step.
Step 4 — Verify
After install + config:
- Run
npm run buildin<project-root>/. If it fails, the most common cause is a missing env var (placeholders accepted) — fix the placeholder and retry once. If still failing, stop and tell the user what's missing. - For modules that need a connection (db, stripe, email), do not try to actually connect — that requires real credentials the user will set in
.env.local. Just verify the code compiles and imports resolve. - For
db, rundrizzle-kit pushagainst a placeholder URL to confirm the schema is valid syntactically. Ifdrizzle-kitrequires a real URL, skip this and tell the user "runnpm run db:pushonce yourDATABASE_URLis set".
Step 5 — Update state and report
Update .workflow/meta.json:
- if current phase is earlier than
module_added, setphase = "module_added". (Phase is monotonic — runningmodule-addmultiple times keeps the phase, just appends to history.) - record the chosen tech:
stack.<module> = "<tech>". - bump
updated_at. - append history:
{ "skill": "module-add", "ran_at": "<now>", "inputs": {"module": "auth", "tech": "better-auth"}, "outputs": ["lib/auth.ts", "lib/auth-client.ts", "app/api/auth/[...all]/route.ts", "app/sign-in/page.tsx", ".env.local.example"], "phase_before": "<prev>", "phase_after": "module_added" }
Tell the user:
- What was installed and where (paths).
- Required environment variables, with a pointer to
.env.local.example. - The reference implementation route/function (so they know where to start customizing).
- Any out-of-band steps the user must do themselves (create a Neon project, get a Stripe API key, configure DNS for Resend, etc.) — be concrete and link to the relevant dashboard.
- Next-step proposal: another
module-addfor a different module, orscreenshot-to-pageto keep building UI.
Important constraints
- One module per invocation. "Add auth and db" is two runs — keep history clean.
- Idempotent. Re-running
module-add authon a project that already has it should detect, skip install, and offer to regenerate examples or rotate env vars — not double-install. - No real credentials. Always use placeholders in
.env.local.example. The user fills.env.localthemselves. - Don't pick alternative tech silently. If the variant reference doesn't cover the user's tech of choice, refuse and explain.
- Preserve user code. If the user has already written something at the path the reference implementation would land (e.g., they made a custom
/sign-inpage), don't overwrite. Ask, or write to<route>-example/instead. - Stay within
<project-root>/. Don't touch other parts of.workflow/. Other skills own those.
Cross-module dependencies
Some modules depend on others. If the user runs them out of order, the skill must:
authrequiresdb. Ifstack.dbisnull, ask: "auth needs a database to store sessions. Set updbfirst?" and route there beforeauth.paymentsrequiresauthanddb. Same pattern.emailis independent.storageis mostly independent (some providers integrate with auth for signed URLs, but it's optional).testis independent — best run afterdbso server-action smoke tests have a schema to mock against, but works without it.ciis mostly independent — works best aftertest(so CI has tests to run) but writes a workflow that gracefully skips test steps when none exist.motionis fully independent — pure UI concern, no backend dependency. Run only when a project genuinely needs JS-driven motion (gestures, magnetic hover, shared-element transitions); for plain reveal-on-scroll,tw-animate-css(already installed via shadcn) is enough and lighter.deployshould be last — it reads the configured stack and produces deploy config.
When dependencies are missing, ask, don't block silently. "I see you're trying to add auth but there's no database yet. Want me to set up db (Neon + Drizzle) first, then come back to auth?"
Folder structure rules (canonical)
When this skill wires a module, respect the canonical folder structure (spec: docs/superpowers/specs/2026-06-06-folder-structure-refactor.md):
authmodule: UI components (sign-in form, sign-up form) go inapp/(auth)/_components/. Auth client + helpers go inlib/auth/. The<AuthGuard>redirect lives inapp/(app)/layout.tsx.dbmodule: client + schema inlib/db/. No components written by this module.paymentsmodule: client wiring inlib/payments/. UI (paywall, checkout button) suggested inapp/(app)/<context>/_components/or page-specific. Pricing comparison table eventually promotes tocomponents/shared/billing/PricingTable.tsx.storagemodule: client inlib/storage/. Upload UI co-located with the page that uses it.emailmodule: server-side only; no components.deploymodule: config files at project root only.