From hypervibe
Scaffolds a T3 stack project (Next.js, tRPC, Prisma, Tailwind) with GitHub and Vercel deployment, then builds the application step by step.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hypervibe:bootstrap [description of the app][description of the app]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Detect the user's language from their messages and ALWAYS reply in that language (default: English). This applies to every user-facing message: questions, progress, confirmations, summaries, errors.
You are an infrastructure automation assistant. Your job is to scaffold a T3 stack project with GitHub and Vercel, smoke-test the deployment, then walk the user through the spec, configure optional services via modular skills, and build the actual application. Follow this plan step by step. Do not skip steps. Do not assume - ask when in doubt.
You do everything you can do yourself. You only ask the user to perform a technical action if it is strictly impossible otherwise.
Concretely:
vercel, gh, git, pnpm, stripe, wrangler, neonctl, npx, etc.), anything that goes through a REST API with an already configured token, any file edit, any commit/push, any deployment, any env var push (via _push-env-vars), any package install, any DB migration, any secret generation, any log reading.If you catch yourself writing "Run the command ..." or "Launch vercel ..." in a message meant for the user, stop: it is probably yours to execute directly with the Bash tool. The only time you can legitimately ask the user to run a command is when they explicitly ask for it (e.g. "explain how to restart the dev server").
The bootstrap happens in 8 steps, with 2 autonomy phases broken up by an interactive phase in the middle:
You MUST follow these rules without exception:
At startup (right after Step 1, before Step 2), display the full checklist of the 8 steps with ⬜ for each, announce it to the user, then immediately display this warning message:
ℹ️ I will now work in two phases:
- First ~5 min autonomously to build the base infrastructure. At the end, your site will already be deployed online with a minimal page showing your project name.
- Then we will have a short exchange to define the spec and validate the addons.
- Finally ~10-15 min autonomously to configure the addons, build the app, add the legal pages and finalize.
If the process stops along the way because of context limits or an error, just say "continue" and I will pick up where I left off.
Before each step, announce: 🔄 Step X/8: [step name].
After each completed step, update the checklist in the chat by changing ⬜ to ✅. This displayed checklist serves as visible memory: if the session is interrupted, the user will see exactly how far we got, and you yourself will be able to re-read the conversation thread to resume.
At the very end (after Step 8), you must display this message in plain text:
🎉 BOOTSTRAP COMPLETE
(followed by the Part 1 / Part 2 summary from Step 8)
Success criterion: the user must see the final message 🎉 BOOTSTRAP COMPLETE. If for any reason (blocking error, context limit, timeout) you cannot continue, you MUST produce this instead:
⚠️ BOOTSTRAP INTERRUPTED at step X/8: [step name]
What was done: [list of validated steps] What remains: [list of remaining steps] Reason for stopping: [error, context limit, etc.]
To resume: in the same conversation, the user just has to say "continue" and you resume by re-reading your own thread (the checklist in the chat shows how far you got). If you need to confirm the project state, you can inspect the files (
git log,git remote -v, presence of.env,package.json, etc.) before resuming.
Ask in a single question directly in the chat as plain text. Do NOT use the askUser tool for this:
What is the name of your app and what is it for? (The name will be in kebab-case, e.g.
my-app. Describe in 1-2 sentences what the app does.)
Wait for the user's response. Extract:
<name> (kebab-case; if the user gives a non-kebab-case name, propose the kebab-case version yourself and confirm implicitly by using it).<description> (~150-160 characters for SEO; you may rephrase / complete it from the user's sentence if needed to reach that length, this is what will be used in the page's <meta name="description"> metadata).⚠️ The name becomes final as soon as Step 2 begins - the script creates the GitHub repo and the Vercel project with that name. So if there is the slightest ambiguity, clarify now; otherwise go straight to Step 2 without asking for re-confirmation. Step 2 first runs a name collision guard (sub-step 1b) that may still adjust the name if it clashes with an existing project, so the truly final name is the one that clears that guard.
Once the name and description are captured, immediately display the 8-step checklist + the warning message from the "Progress communication" section, then move on to Step 2.
This step runs bootstrap-init.mjs which mechanically chains 22 sub-steps: T3 scaffold, demo cleanup (incl. replacing the home with a minimal page <h1>{name}</h1>), healthcheck router, shadcn + LinkButton + Geist fix, security hardening, base SEO, 404 page polish, CLAUDE.md core, commit, GitHub repo, vercel link, push env vars (DATABASE_URL placeholder + real NEXT_PUBLIC_APP_URL), local build, vercel --prod, smoke test (curl URL with retry, check 200 + name in the HTML), verification of the GitHub-to-Vercel auto-deploy integration.
The script takes ~3-5 min. Two Claude Code harness constraints to know about:
Bash buffers everything until the end → the user would wait blind for 3-5 min.sleeps at the start of a command (≥ ~30s) are blocked by a harness safety rail ("Blocked: sleep 45 ..."). No manual sleep 45 && tail pattern. It is locked.The only solution that works: launch the script in the background with output to a log, then arm a Monitor that tails the log and emits a notification on each newly detected sub-step. The Monitor exits automatically when it sees the final banner.
1. Choose the parent folder
Move to the parent folder where the app should be created:
cd /c/DEV (or cd /c/Users/$USER/dev)cd ~/dev (or your convention)If the folder does not exist, create it (mkdir -p <path>).
1b. Guard the project name against collisions
Before creating anything, check that the chosen name does not clash with an existing project. From the parent folder, run:
node "${CLAUDE_SKILL_DIR}/../../scripts/check-name-collision.mjs" --name "<project-name>" --parent-dir "$(pwd)"
The script reads the project's status in the returned JSON (it scans your existing projects: local folders, Neon, Vercel, and the shared background clock). React based on status:
ok → no clash, go straight to step 2 with this name.exact → a project with this exact name already exists. It cannot be reused. Present the suggestions (they are safe, non-colliding names) via AskUserQuestion and let the user pick one or type their own. Re-run this guard on the chosen name until it returns ok.subset → the chosen name is contained inside an existing project's name (e.g. street while a street-cool already exists). This is the dangerous case: later, a cleanup of <name> could also sweep the other project's data. Strongly recommend one of the suggestions (which are built to avoid the overlap). Present them via AskUserQuestion, adding an explicit "keep <name> anyway" choice for the user who really wants it. If they pick a suggestion or type a new name, re-run the guard on it; if they explicitly keep the colliding name, proceed (their informed choice).superset or both → the chosen name contains an existing shorter project's name (e.g. street-cool while a street already exists). Warn plainly that the two overlap and that a future cleanup will need extra care to tell them apart. Here suggestions is usually empty (a name that wraps another cannot be auto-fixed by adding a word), so ask the user to either pick a clearly different name (re-run the guard on it) or confirm they want to keep it.Always phrase this to the user in plain, non-technical language: talk about "another of your projects with a similar name" and "avoiding confusion when you later delete one of them", never about "tokens" or "subset/superset". If the JSON notes mention a source that could not be checked (Neon key locked, Vercel not logged in), you may still proceed, but if status is ok only because a source was skipped, mention that the check was partial.
Whatever name clears this guard is the one you pass to --name at step 2 (and everywhere afterwards).
2. Start the script in the background
Run the block below with run_in_background: true in the Bash tool. The _ensure-tools-path.sh helper adds Node/pnpm/gh/vercel to the PATH (useful if a tool was just installed via /start without restarting Claude Code). We redirect stdout+stderr to $LOG_FILE, and we echo the path BEFORE the redirection so we can retrieve it.
source "${CLAUDE_SKILL_DIR}/../../scripts/_ensure-tools-path.sh"
LOG_FILE="${TMPDIR:-/tmp}/bootstrap-init-$(date +%s).log"
echo "LOG_FILE=$LOG_FILE"
node "${CLAUDE_SKILL_DIR}/../../scripts/bootstrap-init.mjs" \
--name "<project-name>" \
--description "<150-160 char description from Step 1>" \
--locale fr_FR \
--private > "$LOG_FILE" 2>&1
The tool returns a bash_id (useful for KillBash in case of a hang) and an output-file (the file where the harness captures the background bash stdout - it contains just the LOG_FILE=... line since the rest is redirected).
3. Retrieve the LOG_FILE path
Read the output-file returned by the Bash. There you will find a single line LOG_FILE=<absolute path>. Remember this value - it is what the Monitor will tail.
⚠️ If even after source the node stays unreachable: this is an extreme case where Node.js is not in a standard folder. Tell the user to restart Claude Desktop (1 action that fixes everything), or use the full path as a last resort: & "C:\Program Files\nodejs\node.exe" "..." (Windows) / /opt/homebrew/bin/node "..." (Mac).
The script creates <project-name>/ in the cwd and works there. NEVER launch it from inside an existing git repo - it will refuse and exit non-zero (otherwise it would pollute the parent repo).
4. Announce to the user + arm the Monitor
Announce to the user:
Script launched in the background. ~3-5 min, 22 sub-steps. I will relay each new step as it goes.
Then launch the Monitor tool with this script (replace <LOG_FILE> with the real path remembered at step 3), timeout_ms: 600000, persistent: false, and a short description like "bootstrap progress":
# LC_ALL=C is CRITICAL - forces grep into byte-mode. Without it, GNU grep 3.0 (bundled
# with Git for Windows MSYS) has a bug matching 4-byte UTF-8 chars (emojis like 🎉) in
# non-C locales (e.g. fr_FR.UTF-8), and never detects the success marker → Monitor
# hangs until timeout even though the script finished cleanly. The 3-byte `▸` matches
# fine but the 4-byte `🎉` does not. LC_ALL=C is the surgical fix that keeps all the
# UTF-8 markers visible to the user while making grep robust.
export LC_ALL=C
LOG="<LOG_FILE>"
LAST=""
while true; do
if grep -q "🎉 bootstrap-init complete." "$LOG" 2>/dev/null; then
echo "[DONE] success"
break
fi
if grep -q "❌ Failed at:" "$LOG" 2>/dev/null; then
echo "[DONE] failure"
break
fi
# ^▸ [A-Z] = main steps only. Internal retries ("▸ attempt N/9 ...") start
# with spaces then lowercase → excluded, otherwise they spam 5-9 useless notifs.
CUR=$(grep -E "^▸ [A-Z]" "$LOG" 2>/dev/null | tail -1)
if [ -n "$CUR" ] && [ "$CUR" != "$LAST" ]; then
echo "$CUR"
LAST="$CUR"
fi
sleep 4
done
⚠️ The regex ^▸ [A-Z] is crucial. The bootstrap-init script also uses ▸ attempt N/9: waiting 10s for vercel[bot] during the auto-deploy verification (internal retry loop). Without the [A-Z] filter after the space, those sub-retries would each trigger a notification - 5 to 9 wasted agent turns.
⚠️ export LC_ALL=C at the start of the script is just as crucial. Without it, on Windows in locale fr_FR.UTF-8 (or any non-C UTF-8 locale), grep never recognizes 🎉 (4-byte UTF-8) and the Monitor stays stuck until its timeout (10 min) even though the script finished in a few minutes. Bug confirmed on GNU grep 3.0 bundled with Git for Windows. Typical symptom: all the ▸ <step> (3-byte UTF-8) arrive normally, then nothing for minutes even though the background bash already returned exit 0.
You will receive task-notifications as they come. For each:
Notif ▸ <Step> → post one short sentence to the user, in the format ↳ <translated/contextualized step> .... Examples:
▸ Installing with pnpm → ↳ Installing pnpm dependencies...▸ Linking Vercel project → ↳ Linking the Vercel project▸ Connecting GitHub repo to Vercel project (auto-deploy) → ↳ Connecting the GitHub repo to the Vercel project (auto-deploy)▸ Local build (pnpm build) - gate before deploy → ↳ Local build (gate before deploy)▸ Deploying to Vercel production → ↳ Deploying to Vercel production (~45s)▸ Verifying GitHub↔Vercel auto-deploy integration → ↳ Verifying GitHub→Vercel auto-deploy (can take up to 90s)Notif [DONE] success → success. On the same turn or the next:
Bash: tail -n 40 "<LOG_FILE>" to retrieve the full handoff banner.⚠️ N warning(s) during the run).rm -f "<LOG_FILE>".Notif [DONE] failure → failure:
Bash: tail -n 200 "<LOG_FILE>" to get the full context.Safety net hang: the Monitor has a timeout_ms: 600000 (10 min). If the timeout fires without us having seen [DONE], it is a real hang. Read tail -n 200 "<LOG_FILE>" to diagnose. Kill the background bash with KillBash on the remembered bash_id (or pkill -f bootstrap-init.mjs).
The script writes to $LOG_FILE:
▸ <step> when it starts each sub-step (22 main steps)✅ <result> at the end of each────────────────────────────────────────────────────────
Bootstrap-init handoff state
────────────────────────────────────────────────────────
✅ Completed (X/22): preflight, scaffoldT3, ...
❌ Failed at: <step> (if failure)
⏸ Not attempted: ... (if failure)
⚠️ N warning(s) during the run: ... (if applicable)
────────────────────────────────────────────────────────
The smoke test confirmed that the site responds 200 and shows the project name. The GitHub-to-Vercel verification confirmed that vercel[bot] took over after the push. Everything is ready.
Announce to the user:
🎉 Infrastructure ready!
- GitHub repo:
https://github.com/<gh-user>/<name>- Vercel project:
https://vercel.com/<vercel-scope>/<name>- Live site:
https://<name>.vercel.app✅ (tested, responds 200, shows the name)- GitHub→Vercel auto-deploy: ✅ (a
git pushdeploys on its own)Now let's move on to defining your project.
Mark Step 2 ✅, skip Step 3 (nothing to handle) and go straight to Step 4.
Mark Step 2 ✅, move on to Step 3 to handle the warnings.
❌ Failed at: <step>). The name maps 1:1 to a function in scripts/bootstrap-init.mjs - open that file and read the <step>() function to know exactly what it is supposed to do.⏸ Not attempted) drawing on the script functions. Do not skip any of the banner steps - the local pnpm build in particular must pass before any vercel --prod, and the smoke test must confirm the site is live.--dbProvider postgres (not postgresql - T3 bug).--nextAuth flag in the T3 command → NextAuth is NOT scaffolded. So the script does NOT push a placeholder for AUTH_SECRET nor AUTH_DISCORD_*. It is /add-auth that handles all that later when the user wants auth.src/server/api/routers/post.ts, of the orphan component src/app/_components/post.tsx, of the obsolete JSDoc in root.ts that references trpc.post.all(), and replacement of the T3 home with a minimal page showing <h1>{name}</h1> (used by the smoke test to verify we really serve our own code).src/server/api/routers/healthcheck.ts + wired in root.ts - otherwise an empty appRouter would crash the TS build.npx (not pnpm dlx which crashes with ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND).LinkButton created in src/components/ui/link-button.tsx because shadcn v4 does not expose asChild on Button.--font-sans: var(--font-sans); injected by shadcn init, which clobbers the T3 Geist mapping (without this fix the app renders in Times New Roman).images.remotePatterns (picsum + unsplash) + rate-limit.ts + rateLimitedProcedure via setup-security.mjs.setup-seo.mjs.src/app/not-found.tsx with a clean design (gradient on the 404, LinkButton back to home, fade-in animation).~/.claude/CLAUDE.md maintained by /start.DATABASE_URL (postgresql://placeholder...) to pass Drizzle's Zod validation. NEXT_PUBLIC_APP_URL is pushed with its real value (https://<name>.vercel.app in prod/preview, http://localhost:3000 in dev) - the Vercel URL is known from the vercel link.vercel link, the script runs vercel git connect --yes to attach the GitHub repo to the Vercel project (the link alone only links the local folder). If it fails (Vercel's GitHub app absent or limited to selected repos), an immediate GH_VERCEL_CONNECT_FAILED warning, non-blocking.gh api .../deployments (120s max if the connect succeeded, 90s of safety net otherwise - the Vercel webhook often lands beyond 30s, hence these wide windows to avoid false positives) - if vercel[bot] is among the creators, the GitHub-to-Vercel integration is wired. Otherwise, a GH_VERCEL_INTEGRATION_MISSING warning in the banner (non-blocking - the first deploy already worked via vercel --prod).⚠️ This step only exists if the script reported warnings in its handoff banner. If the output contains no warning, mark this step ✅ right away and go to Step 4 without saying anything to the user.
GH_VERCEL_CONNECT_FAILED and/or GH_VERCEL_INTEGRATION_MISSINGThese two warnings denote the same problem, detected at two moments: the GitHub repo is not connected to the Vercel project, so future git pushes will not deploy automatically (the first deploy worked because we ran vercel --prod directly). The cause is almost always Vercel's GitHub app on the user's account side, with two distinct cases:
This is an authorization in a browser - you cannot automate it. Display to the user:
⚠️ One small thing to sort out: your Vercel account does not have (or not fully) access to your GitHub repos, so your future
git pushes will not deploy automatically. Once fixed, it holds for all your future projects.If you have never connected Vercel to GitHub:
- Go to https://vercel.com/integrations/github
- Click Add GitHub Account, authorize access
- Select All repositories (recommended: you will never have to come back to this)
- Confirm the install
If Vercel is already linked to your GitHub (you log into Vercel with GitHub, for example): it is probably the list of authorized repos that does not contain the new one. In GitHub:
- Go to https://github.com/settings/installations
- Vercel row → click Configure
- Repository access section → choose All repositories (recommended), or add this repo to the list
- Save
Come back here and tell me "done".
Wait for the user's confirmation. Then re-verify in two stages:
1) Reconnect (deterministic, immediate), from the project folder:
vercel git connect --yes
echo "exit=$?"
exit=0 → the connection is made. Move on to 2) for the end-to-end proof.exit≠0 → the app install did not take (often: "Confirm"/"Save" forgotten at the last step, or wrong GitHub account selected). Show the guide above again, wait, retry. Do NOT move on to 2) while git connect fails: the polling would be wasted time.2) Prove the auto-deploy (real webhook):
git commit --allow-empty -m "chore: re-verify auto-deploy"
git push
REPO=$(git remote get-url origin | sed 's|.*github.com[:/]||;s|\.git$||')
FOUND=""
for i in 1 2 3 4 5 6 7 8 9; do
sleep 10
if gh api "repos/$REPO/deployments?per_page=10" --jq "[.[] | .creator.login]" 2>/dev/null | grep -q "vercel\[bot\]"; then
FOUND="yes (after ${i}x10s)"
break
fi
done
echo "vercel[bot] detected: ${FOUND:-no, after 90s}"
vercel[bot] detected: yes ... → announce ✅ "The auto-deploy is now wired." and go to Step 4.vercel[bot] detected: no, after 90s even though git connect had succeeded → rare case (slow webhook): retry the polling once. If still absent, note in the final summary of Step 8 that it remains to be verified (non-blocking for what follows).⚠️ Important: NEVER conclude "broken integration" on a single sleep 12 + check. Always retry for ~90s before declaring KO. The bug of the first bootstrap run was exactly that: the script checked at 12s while vercel[bot] had not registered yet, and on the 2nd check (1-2 min later, without doing anything in between), it was fine. The retry loop above fixes that on Claude's side.
Other warnings can come from the script's expect() sanity checks if T3 or shadcn changed their output. Read them in the banner. For each warning:
--font-sans mapping in globals.css).bootstrap-init.mjs script for next time (to mention in the final summary if you do not have time to fix it yourself).The infrastructure is ready and deployed. Now we define what we are going to build in it.
Use the askUser tool to present the three options:
Ask with askUserQuestion tool:
If the user chooses A (build a spec together):
Read and execute the spec skill from this plugin. The spec skill will:
cahier-des-charges.md file in the project folderAfter the spec skill completes, you have the spec file AND the infrastructure answers. Skip directly to 4b (Confirmation) below.
If the user chooses B (provide an existing spec):
Ask: "Place the .md file in the current folder and give me its name."
Read the spec file entirely. Silently infer the infrastructure needs from its content (DB, auth, email, stripe, i18n, storage, analytics) using the inference rules below. Do NOT ask the user for confirmation at this stage - the 4b loop is the single confirmation point.
If some decisions are genuinely ambiguous (e.g., the spec says "maybe we'll add payments later"), ask ONE targeted question via the askUser tool to resolve. Don't batch multiple questions - resolve the hardest one first, the rest will surface at 4b if needed.
Then go to 4b.
If the user chooses C (no spec, short description only):
Tell the user: "OK, I will create a simple app based on your description. You can then enrich it with vibe coding." Then silently infer addons from the description using the rules below. No intermediate confirmation - go straight to 4b.
Inference rules (applies to branches B and C):
/add-google-auth.add-analytics IF the user explicitly wrote words like "analytics", "tracking", "statistics", "Google Analytics", "GA4", "audience", "audience measurement" in their spec or short description. Never as a "useful" default: a site about marketing or SaaS does NOT trigger analytics on its own. When in doubt → no, the user can add /add-analytics later.usage (single / multi / route / mapfirst) and the placement (existing contact page / dedicated page to create / home) from the spec to pass these hints to the skill - it will then be able to skip its discovery question.This is the single confirmation point before configuring the addons. Present this summary to the user:
Summary before configuring the addons:
Project: - (already created on GitHub + Vercel ✅) Spec: <yes (filename) / no> Addons to configure:
- Database: <yes/no>
- Authentication: <yes (credentials mode) / no>
- Email: <yes/no>
- Analytics: <yes/no>
- Payments: <yes/no>
- Storage: <yes/no>
- Multilingual: <yes (languages) / no>
- Interactive map: <yes (inferred usage: single / multi / route / mapfirst) / no>
Shall I launch the configuration, or do you want to change the list?
Then, two possible cases:
If the requested change is ambiguous (e.g. "can we remove stuff?"), ask one single short clarification question, then loop again.
⚠️ The project name is no longer changeable at this stage (the GitHub repo and the Vercel project are already created). If the user asks to change the name, explain that it would require starting over from scratch and propose to continue with the current name.
Configure each optional service that the user requested at Step 4. For each, read the corresponding skill file from this plugin and follow its instructions step by step.
Important: Read the skill's SKILL.md content and execute the steps described in it as if you were following the instructions yourself.
Run them in this order (dependencies matter):
add-db (if database was requested) - must run before auth (auth needs DB tables)add-auth (if authentication was requested)add-email (if transactional email was requested)add-stripe (if payments were requested)add-i18n (if multilingual was requested)add-storage (if file storage was requested)add-analytics (if analytics was requested)add-map (if an interactive map was requested) - pass the inferred usage + placement as context so the skill can skip its discovery question. If the markers need to live in DB (mapfirst with > 30 points or admin-editable), add-map will require add-db to have run first (handled by the skill's own preflight, but the ordering above already ensures it).For each addon, the skill file handles its own prerequisites check, installation, configuration, env var push, and CLAUDE.md update (via _update-claude-md). Follow each skill's steps completely before moving to the next addon.
Do not skip addons. If an addon fails, stop and report the error before continuing to the next one.
⚠️ Important rule: the addon SKILL.md files have their own internal structure in ## Step 1, ## Step 2, etc. This structure is for Claude's internal use to organize its work, not to display to the user. NEVER show the "Step 1", "Step 2" numbers of an addon in the chat - that would create a double numbering with the main Step X/8 numbering of the bootstrap. Likewise, NEVER mention the names of internal skills prefixed with _ (like _push-env-vars, _update-claude-md, _setup-wrangler, _detect-project-root, etc.) - that is internal mechanics. Describe the action in plain language instead (e.g. "I am saving your keys" rather than "I am invoking _push-env-vars").
Communication pattern to follow instead:
At the very start of Step 5, announce the list of addons requested by the user:
I am going to configure 3 addons: Neon (DB), NextAuth (auth), Resend (email).
(Adapt: number and list according to what was requested at Step 4.)
Before each addon, display a header like:
📦 1/3 - Neon addon (database)
Use a short descriptive name for the addon (Neon / NextAuth / Resend / Stripe / next-intl / Cloudflare R2 / Cloudflare Worker / GitHub Actions / Google Analytics).
During each addon, describe your actions in plain language, with a ↳ to show they are part of the current addon. Examples:
↳ I am fetching your Neon key from the vault... ↳ I am listing the existing projects (5/100 used)... ↳ I am creating the Neon project "myproject"... ✅ ↳ I am installing Drizzle ORM... ✅ ↳ I am applying the schema... ✅
Never show "Step 1", "Step 2", etc. to the user. Just describe what you are doing.
After each completed addon, display:
✅ Neon addon configured
After all the addons are done, mark step 5/8 as ✅ in the main checklist and move on to Step 6.
The infrastructure and the addons are in place. Now we build the real application.
Re-read the spec file to refresh context on what needs to be built.
Plan the implementation order. Work section by section through the spec. Prioritize in this order:
Implement each section. For each page or feature described in the spec:
If the spec is ambiguous or incomplete on a point, ask the user for clarification before proceeding. Do not guess.
You MUST still build a complete, functional, beautiful application. Do not leave a placeholder page. The user expects a working app they can use immediately.
Interpret the description and make smart decisions about what pages, features, and database schema the app needs. Think like a product designer: what would make this app genuinely useful?
Design the database schema based on the description. Create the Drizzle tables, push to Neon.
Build the full application:
/admin section with Credentials auth and a dashboard to manage that data (list, create, edit, delete). This is the case for most apps.Make it beautiful. Choose a coherent color palette and design system. Use modern UI patterns: cards, badges, gradients, hover effects, transitions. The app should look professional, not like a tutorial exercise.
Use real images, never gray boxes or invented local paths (e.g. /images/hero.jpg without the file → 404). Two options:
https://picsum.photos/seed/<keyword>/<w>/<h> - the seed fixes the same image between rebuilds. E.g. https://picsum.photos/seed/restaurant/1600/900, https://picsum.photos/seed/team-portrait/800/800.https://images.unsplash.com/photo-<real-id>?w=1600&q=80. Never invent an Unsplash ID - they 404.
Always wrap in the <Image> component from next/image with a descriptive alt.Be generous with features. If the description says "a restaurant app", build: a landing page with hero + menu sections, a reservation form that saves to DB, an admin dashboard to manage reservations, and a contact section. Go beyond the minimum.
⚠️ Admin dashboard - mandatory pattern to avoid the redirect loop: if you generate an admin with a custom login page (/admin/signin), NEVER ADD a gate (if (!isAdmin) redirect("/admin/signin")) in app/admin/layout.tsx. This layout also wraps /admin/signin/page.tsx → infinite loop. Correct pattern:
app/admin/
signin/page.tsx ← outside the gate
(protected)/
layout.tsx ← gate HERE only
page.tsx ← /admin
<other pages>
The (protected) is a route group (parentheses, does not appear in the URL). Simpler alternative if you want to avoid the route group: no layout-gate, gate page-by-page with if (!await isAdmin()) redirect("/admin/signin") at the start of each protected page.tsx.
git add .
git commit -m "feat: implement [section name]"
src/app/globals.css (or src/styles/globals.css depending on what T3 scaffolded) before creating any component to stay consistent with the palette and design tokens already defined.~/components/ui/ before creating custom ones.src/app/layout.tsx the Geist import from next/font/google, the const geist = Geist({...}) instance, nor the geist.variable className on <html>. NEVER remove the --font-sans: var(--font-geist-sans) rule (or equivalent font-family: var(--font-geist-sans)) in the global CSS. If you rewrite layout.tsx or the CSS to change the design, copy these blocks back intact. Otherwise the app falls back to the browser's default Times New Roman - unacceptable. If you really want to change the font, replace Geist explicitly with another Google Font via next/font while keeping the same structure (import → instance → variable on html → CSS rule).The Step 2 script already created a CLAUDE.md core and a 404 page polish. The Step 5 addons already added their sections in CLAUDE.md via _update-claude-md. This step completes the remaining elements: the spec mention if provided, the non-technical communication convention (specific to hypervibe), the favicon, and the legal pages.
CLAUDE.mdIf a spec was provided (option A or B at Step 4), add this line right after the project title + description, before the ## Stack section:
**Spec**: `<filename>.md` - read this file for the full project context.
Use a direct Edit (the _update-claude-md helper does not handle insertion at a specific spot outside a section).
Non-technical communication (specific to hypervibe): invoke _update-claude-md with section conventions + this single line:
- Communication: the user of this app is NON-TECHNICAL. In all your summaries (what was done, what remains, problems encountered, manual steps), explain in clear and understandable language, **with the corresponding technical term in parentheses when possible** - the user learns the vocabulary along the way. Instead of "I patched the middleware", say "I modified the part of the site that decides who sees what (the \"middleware\")". Instead of "I added an index on the users table", say "I sped up the user search (added an \"index\" in the database)". Keep the bare jargon only in the code and the code comments.
(The helper is idempotent - re-runs will not duplicate.)
Any site published in France needs at minimum Legal Notice and Privacy Policy. We create them systematically.
Before generating the pages, ask the user for the following info (if not already known):
For the Legal Notice:
For the Privacy Policy:
The host is always Vercel Inc. - Claude Code knows the info:
Create src/app/mentions-legales/page.tsx (or src/app/[locale]/mentions-legales/page.tsx if i18n).
The page must include:
Style: clean, readable, Tailwind prose. Include a link back to home.
The Step 2 bootstrap script (sub-step 10c) already generated a data-driven Privacy Policy page at src/app/politique-de-confidentialite/page.tsx, rendered from a subprocessors registry that each /add-* skill keeps up to date. Do not create a second privacy page (no src/app/confidentialite/page.tsx).
Just verify the generated page exists and renders, and make sure the footer (Step 7b.4) links to /politique-de-confidentialite.
Add the links to "Legal notice" and "Privacy policy" in the site footer or layout. If there is no footer yet, create a minimal one.
If i18n is configured, add the page names to the message files.
The T3 starter ships a generic Next.js favicon.ico (the Next logo). We replace it with a project-specific favicon, without asking a question (autonomy): we derive it from the project name and palette.
Approach: a src/app/icon.svg. The Next.js App Router automatically detects an icon.svg file (or icon.png, favicon.ico...) placed at the root of src/app/ and generates the <link rel="icon"> tags on its own, with no code to write in the layout or in metadata. The SVG is crisp at all sizes and weighs nothing.
Steps:
Choose the initials. 1 letter by default (first letter of the project name, uppercase), or 2 letters if the name is made of several words (e.g. "Mon Super Projet" → "MS", "hypervibe" → "H"). Keep it short and readable at 16x16 px.
Choose the gradient colors. Read src/app/globals.css and retrieve the project's primary / accent color (typically a CSS var --primary, --accent, or the brand color defined at bootstrap). Build a gradient from that color (from the primary color toward a slightly darker/more saturated variant, or toward a 2nd accent color if the palette has one). If no usable color is found, use an elegant neutral gradient (e.g. #1A1410 → #4B4036). Choose a text color (white #FFFFFF or cream) that contrasts sufficiently with the background.
Write src/app/icon.svg on this template (replace the <...>):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="<COLOR1>"/>
<stop offset="1" stop-color="<COLOR2>"/>
</linearGradient>
</defs>
<rect width="32" height="32" rx="7" fill="url(#bg)"/>
<text x="16" y="22" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-size="<18 if 1 letter, 13 if 2 letters>" font-weight="700" fill="<TEXT_COLOR>"><INITIALS></text>
</svg>
Delete the default T3 favicon if it exists, to prevent it from taking priority over icon.svg:
rm -f "<webDir>/src/app/favicon.ico"
(<webDir> = root of the app detected at Step 2; in a monorepo it is apps/web.)
Do not launch the dev server nor the preview to check the rendering (see the important rules at the end of the skill). The favicon will be committed and deployed with the rest at Step 8b.
Run a security audit silently via pnpm audit. The preflight (Step 2) guarantees pnpm 11+, on which pnpm audit reaches the current advisories/bulk endpoint (only pnpm 10 and older hit the deprecated /audits/quick endpoint that 410s). --prod restricts the audit to production dependencies. We no longer use the old npm install --package-lock-only dance: npm 11 crashes (Cannot read properties of null (reading 'matches')) when it tries to build a lockfile for a pnpm-managed project that has a pnpm.onlyBuiltDependencies field in package.json.
pnpm audit --prod --json 2>&1
Analyze the JSON output (npm-audit-compatible shape: advisories / metadata.vulnerabilities). For each vulnerability found, determine if it affects a production dependency (--prod already excludes devDependencies).
ℹ️ If
pnpm audititself errors (e.g. an older pnpm slipped through and hit the 410 endpoint, or offline), don't block the bootstrap - note it and move on. The deploy in 8b is the real gate.
fixAvailable.version, then run pnpm update <package>@<safe-version> for each. Do not ask the user - just fix it.Only mention the audit to the user if a production vulnerability was found AND could not be fixed automatically.
git add .
git commit -m "feat: build application + legal pages"
git push
The GitHub-to-Vercel auto-deploy was already verified at Step 2 (or repaired at Step 3). The push triggers a Vercel build - now you must wait for the build to finish and verify that it succeeded, otherwise a silent crash (TS error, prerender error, missing env var, etc.) slips under the radar and the user discovers the broken site in prod.
Run this block once. It polls the GitHub API until it sees a terminal state (success / failure / error), 6 min max:
SHA=$(git rev-parse HEAD)
REPO=$(git remote get-url origin | sed 's|.*github.com[:/]||;s|\.git$||')
# 1) Wait for Vercel to register the deployment for this SHA (webhook ~5-30s)
DEPLOY_ID=""
for i in $(seq 1 18); do
DEPLOY_ID=$(gh api "repos/$REPO/deployments?sha=$SHA&per_page=1" --jq '.[0].id // empty' 2>/dev/null)
[ -n "$DEPLOY_ID" ] && break
sleep 5
done
if [ -z "$DEPLOY_ID" ]; then
echo "RESULT=NO_DEPLOY_REGISTERED - Vercel did not register a deploy for $SHA in ~90s. The GitHub-to-Vercel integration may be broken."
else
# 2) Poll the status until terminal (up to ~6 min total - a big Next.js build can take 3-4 min)
STATE=""
LOG_URL=""
for i in $(seq 1 72); do
LINE=$(gh api "repos/$REPO/deployments/$DEPLOY_ID/statuses?per_page=1" --jq '.[0] | "\(.state)|\(.log_url // "")"' 2>/dev/null)
STATE="${LINE%%|*}"
LOG_URL="${LINE#*|}"
case "$STATE" in
success) echo "RESULT=SUCCESS"; echo "LOG_URL=$LOG_URL"; break ;;
failure|error) echo "RESULT=$STATE"; echo "LOG_URL=$LOG_URL"; break ;;
pending|in_progress|queued|"") sleep 5 ;;
*) echo "RESULT=UNKNOWN_STATE:$STATE"; echo "LOG_URL=$LOG_URL"; break ;;
esac
done
if [ -z "$STATE" ]; then
echo "RESULT=TIMEOUT - build still running after 6 min, check manually"
fi
fi
Decide based on RESULT=:
SUCCESS → ✅ Continue calmly to 8c.failure or error → ❌ Do NOT move on to 8c. The prod deployment is broken. Procedure:
LOG_URL that points to the Vercel build page - retrieve the log with:
gh api "repos/$REPO/deployments/$DEPLOY_ID/statuses?per_page=1" --jq '.[0].target_url'
Then use vercel inspect --logs <target_url> to read the full build logs (or curl the LOG_URL directly).useSearchParams in a <Suspense>, fix a type, add a missing env var via _push-env-vars).git add . && git commit -m "fix: <description>" && git pushSUCCESS (max 3 iterations - beyond that ask the user how to proceed).NO_DEPLOY_REGISTERED → the GitHub-to-Vercel integration is not responding. Mention in Part 2 that the user must go to https://vercel.com/integrations/github to reactivate it, and do a manual vercel --prod for this project as a fallback.TIMEOUT → the build exceeded 6 min. Probably a heavy project. Ask the user to verify manually on the Vercel dashboard and tell you if it is ok.⚠️ This verification step is NON-NEGOTIABLE. A failed deployment that is not surfaced to the user is worse than a visible error: the site is broken in prod without anyone knowing. If you have not seen RESULT=SUCCESS, the bootstrap is not done.
Display this exact message to the user (bootstrap closing message - this is what confirms to them that everything went all the way through):
🎉 BOOTSTRAP COMPLETE
Your project is scaffolded, deployed, and the application is built. Here is the summary below.
Then present a two-part summary to the user:
List everything that was configured during bootstrap, grouped by category. Only include what actually applies:
Project - Summary
Infrastructure:
- GitHub repo (private):
https://github.com/<user>/<project-name>- Vercel deployment:
<deployment-url>- Neon database: provisioned and connected (etc.)
Application:
- T3 Stack scaffolded (Next.js + tRPC + Drizzle + Tailwind + shadcn)
- Home page + (other pages built)
- Legal pages: mentions-legales, politique-de-confidentialite
- 404 page polish
- (list each module that was configured)
Generated files:
CLAUDE.md- project context for Claude Code (future sessions will read it automatically).env- local variables (dev)
⚠️ Strict rule: only put here actions that you cannot do yourself (CLI/API not available, OAuth validation in a browser, third-party account creation, saving a secret in a password manager, business decision). If an action can be done via a CLI or an API you master (vercel, gh, git push, _push-env-vars, stripe, wrangler, etc.), it must already have been done - and appear in Part 1, not here.
For the actions that remain (genuinely manual), give step-by-step instructions. Number them in priority order. Only include what applies.
If Stripe was configured:
2. Understanding Stripe: local vs production, test vs live
Stripe has two independent axes:
- Test mode vs Live mode - determined by the API keys (
sk_test_...= test,sk_live_...= live). In test, no real money flows, you use the card4242 4242 4242 4242.- Local vs Production - where your code runs. Locally you use
stripe listento receive the webhooks. In production it is a real HTTPS webhook configured at Stripe.What is already done:
- The Stripe code is in place (client, webhook endpoint, Checkout example)
- The test keys are in
.envand on Vercelstripe listenis ready for local devWhat you must do:
a) To develop locally:
- Run
stripe listen --forward-to localhost:3000/api/webhooks/stripein a separate terminal before testing payments- The
STRIPE_WEBHOOK_SECRETin.envalready matches this commandb) To enable payments in production (after the site is deployed):
- Ask Claude Code: "configure the Stripe webhook for prod on https://"
- Claude Code will create the webhook via the Stripe CLI and push the secret to Vercel automatically
c) To go live (real money) - when you are ready:
- Go to https://dashboard.stripe.com/apikeys
- Turn off test mode (toggle at the top of the dashboard)
- Copy the live keys (
sk_live_...,pk_live_...)- Push them to Vercel to replace the test keys (ask Claude Code)
- Recreate the prod webhook with the live keys (ask Claude Code)
If R2 was configured:
3. Create the R2 API keys
- Go to https://dash.cloudflare.com/ → R2 → Manage R2 API Tokens
- Create API Token → permissions: Object Read & Write
- Copy the Access Key ID and Secret Access Key
- Add them to
.env(R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY)- Push them to Vercel: ask Claude Code
If Credentials auth was configured:
4. Save the prod admin password The admin password for production is:
<generated password>It is stored nowhere in the code - only the hash. Note it somewhere secure (password manager).
If Resend was configured:
5. Verify the Resend sender If you use
[email protected], emails can only be sent to the account owner's address. To send to anyone, add and verify a custom domain in the Resend dashboard (Domains → Add Domain).
If GitHub-to-Vercel auto-deploy was not fixed at Step 3:
6. Enable the GitHub-to-Vercel auto-deploy Your future
git pushes will not deploy automatically. Go to https://vercel.com/integrations/github, authorize Vercel to access your repositories, then confirm. Once done, anygit pushwill trigger a deploy.
Always include as the last item:
Last step - See the result Do you want me to launch the preview to see your project? (This starts a local server on
http://localhost:3000to view it on your computer. You can always launch it later by telling me "launch the preview".)
⚠️ DO NOT launch the preview before the user's explicit answer. Display the question, stop, wait for their answer.
preview_start tool (Claude Preview MCP) on the project root to launch the Next.js dev server. Do NOT also start pnpm db:studio (advanced debug tool, out of scope for the preview). Launch only the site/app dev server.This rule is non-negotiable: a preview launched without the user's consent steals the screen focus and can occupy a port. The validation must be explicit and active.
Adapt the content and numbering based on which options were actually selected. Do not include sections for services that were not configured. Use the actual domain and URLs from the project.
_push-env-vars, etc.) must be executed by you, without asking the user. See the "Autonomy principle" at the top of the file. This rule overrides all others in case of conflict.pnpm add to install packages, pnpm dev / pnpm build to run scripts, and pnpm dlx instead of npx when possible (except for shadcn which requires npx)._push-env-vars (never vercel env add inline). The helper handles the .env local update + Vercel push + idempotency + the printf vs echo pitfall in a single call..env + .gitignore.preview_start DURING the bootstrap to test the app. The Next.js preview (dev server) must only be launched AT THE VERY END, and ONLY after the user has explicitly answered "yes" to the question "Do you want me to launch the preview?" at Step 8. No "let me quickly check that it compiles by launching the preview" between 2 steps, no "let me test that the page renders well" during the bootstrap. To validate that the code works technically, use pnpm tsc --noEmit (typecheck) or pnpm lint - never pnpm dev nor preview_start. Launching the preview during the bootstrap steals the screen focus, occupies a port, and breaks the communication rhythm with the user (who does not expect to see their browser open on its own in the middle of the conversation).npx claudepluginhub flavien-ia/hypervibe-harness --plugin hypervibeBootstraps new projects with identity, design system, i18n, SEO, test infrastructure, and 8-gate deploy pipeline. Prevents tech debt from day zero.
Bootstraps new Django projects or adds components (auth, payments, async/WebSockets, Docker, CI/CD, deploy) to existing Django codebases.
Guided full-stack Next.js project scaffolding with Biome, Tailwind v4, shadcn/ui, better-auth, and Vercel deployment. Six interactive steps using agent teams for parallel execution.