Resources
2Install
npx skillscat add popmechanic/vibes-cli/launch Install via the SkillsCat registry.
Plan mode: If you are planning work, this entire skill is ONE plan step: "Invoke /vibes:launch". Do not decompose the steps below into separate plan tasks.
Display this ASCII art immediately when starting:
░▒▓█▓▒░ ░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓██████▓▒ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓████████▓▒░
░▒▓█▓▒░ ░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░▒▓█▓▒░░▒▓█▓▒░Notation
Ask [Header]: "question" means call AskUserQuestion with that header and question. Options listed as bullets. User can always type custom via "Other". When collecting a key/secret, put one option like "Paste key" — the user types the actual value via Other.
For architecture context, see LAUNCH-REFERENCE.md in this directory.
FIRST: Pre-Flight Decision Tree
Run all five checks before collecting any input:
| # | Check | Command | If True |
|---|---|---|---|
| 1 | .env has Clerk keys + Connect URLs | grep -qE '^VITE_CLERK_PUBLISHABLE_KEY=pk_' .env && grep -qE '^VITE_API_URL=' .env && grep -qE '^VITE_CLOUD_URL=' .env |
Set CONNECT_READY. Read .env for clerkPk. Skip T2, T3, infra spawn. |
| 2 | .env has admin user ID | grep CLERK_ADMIN_USER_ID .env |
Store value. Skip Phase 3. |
| 3 | app.jsx exists | test -f app.jsx |
Ask [Reuse]: "app.jsx exists. Reuse it or regenerate?" If reuse: skip T1. |
| 4 | Wrangler authenticated | npx wrangler whoami 2>&1 |
If NOT authenticated: tell user to run npx wrangler login and wait. |
| 5 | SSH key exists | ls ~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_ecdsa 2>/dev/null |
If missing AND not CONNECT_READY: warn about Connect deploy. |
Phase 0: Collect Inputs
0.1 App Prompt
Ask [App prompt]: "What do you want to build? Describe the app you have in mind."
- "Todo list" — A simple task manager with categories and due dates
- "Photo gallery" — A shareable photo gallery with albums and captions
- "Team dashboard" — A metrics and status dashboard for small teams
Store as appPrompt.
0.2 App Name + Domain
Ask [App name]: "What's the app name? (used for subdomain + database)" AND [Domain]: "Where will this be deployed?"
- App name: "Derive from prompt" or "Let me specify"
- Domain: "Cloudflare Workers (Recommended)" or "Custom domain"
If "Derive from prompt": generate URL-safe slug (lowercase, hyphens, max 30 chars). If "Custom domain": ask for domain name. Store as appName.
Resolve Workers URL (if Cloudflare):
node "{pluginRoot}/scripts/lib/resolve-workers-url.js" --name "{appName}"Store output as domain. If script fails, ask for their Cloudflare subdomain and construct {appName}.{subdomain}.workers.dev.
0.3 AI Features (conditional)
Scan appPrompt for AI keywords: "chatbot", "chat with AI", "summarize", "generate", "analyze", "AI-powered", "intelligent".
If detected: Ask [AI features]: "Does this app need AI features?"
- "Yes — I have an OpenRouter key" — I'll paste my API key
- "Yes — I need to get one" — I'll sign up at openrouter.ai
- "No AI needed" — Skip AI capabilities
If yes: check grep OPENROUTER_API_KEY ~/.vibes/.env. If found, offer reuse (mask key). Otherwise collect via Ask and offer to cache to ~/.vibes/.env. Store as openRouterKey (or null if no AI).
0.4 Theme Selection
Theme switching is handled by the live preview wrapper, not inside the app. The builder generates a single-theme layout. Set themeCount = 1.
Phase 1: Spawn Team & Parallel Work
1.1 Setup
- Resolve plugin root:
echo "${CLAUDE_PLUGIN_ROOT}"→ store aspluginRoot - Create team:
TeamCreate("launch-{appName}", "Full SaaS pipeline for {appName}") - Create all tasks per the table in LAUNCH-REFERENCE.md. If
CONNECT_READY: mark T2+T3 completed immediately.
1.2 Spawn Builder (T1)
- Read
{pluginRoot}/skills/launch/prompts/builder.md - Substitute:
{appPrompt},{appName},{pluginRoot} - Set
{aiInstructions}: ifopenRouterKeyis set, add rule aboutuseAIhook (see vibes SKILL.md "AI Features"). If null, leave empty. - Spawn: Task tool,
team_name="launch-{appName}",name="builder",subagent_type="general-purpose"
1.3 Clerk Credentials (T2) — simultaneous with builder
Skip entirely if CONNECT_READY.
Ask [Clerk app]: "Do you have a Clerk app configured?"
- "I have one ready" — Already has passkeys and email auth
- "I need to create one" — Walk me through setup
If creating new: guide through clerk.com/dashboard — create app, enable Email + Passkey, configure email settings (require OFF, verify ON, link ON, code ON). Then set up JWT template and webhook:
Ask [Clerk config]: "Complete these two setup steps in Clerk Dashboard:\n\n1. JWT Template: JWT Templates → New Template → name it with-email, paste this JSON as the custom claims (the || '' fallbacks are required — Fireproof Studio rejects null names):\njson\n{\n \"params\": {\n \"email\": \"{{user.primary_email_address}}\",\n \"email_verified\": \"{{user.email_verified}}\",\n \"external_id\": \"{{user.external_id}}\",\n \"first\": \"{{user.first_name || ''}}\",\n \"last\": \"{{user.last_name || ''}}\",\n \"name\": \"{{user.full_name || ''}}\",\n \"image_url\": \"{{user.image_url}}\",\n \"public_meta\": \"{{user.public_metadata}}\"\n },\n \"role\": \"authenticated\",\n \"userId\": \"{{user.id}}\"\n}\n\n2. Webhook: Webhooks → Add Endpoint → URL https://{domain}/webhook → subscribe to subscription.deleted\n\nHave you completed both?"
- "Yes, both done" — JWT template 'with-email' with email/name claims + webhook endpoint created
- "I need help" — Walk me through it step by step
Collect four credentials via Ask (user types actual values via Other):
Ask [Clerk PK]: "Paste your Clerk Publishable Key (starts with pk_test_ or pk_live_)"
- "Paste key" — From Clerk dashboard > API Keys. Validate prefix.
Repeat pattern for:
- [Clerk SK]: Secret Key — starts with
sk_test_orsk_live_ - [PEM Key]: JWKS PEM Public Key — from API Keys > Advanced > Public Key. Starts with
-----BEGIN PUBLIC KEY----- - [Webhook Secret]: From Webhooks > endpoint > Signing Secret. Starts with
whsec_
Save PEM to file:
cat > clerk-jwks-key.pem << 'PEMEOF'
{pemKey}
PEMEOFMark T2 completed.
1.4 Spawn Infra (T3) — after T2 completes
Skip if CONNECT_READY.
- Read
{pluginRoot}/skills/launch/prompts/infra.md - Substitute:
{appName},{pluginRoot},{clerkPk},{clerkSk} - Spawn: Task tool,
team_name="launch-{appName}",name="infra",subagent_type="general-purpose"
1.5 Sell Config (T4) — while infra deploys
Sell config is collected here but applied later by invoking /vibes:sell (or its assembly script) as an atomic step. Do NOT hand-implement SaaS logic — the sell skill handles tenant routing, auth gating, billing, and admin setup.
Choose billing mode based on monetization intent:
- "off" (free) — all authenticated users get full access. Good for MVPs and internal tools.
- "required" (subscription) — users must subscribe. Requires Clerk Billing (Dev instances auto-connect to Stripe sandbox).
Always ask the user — do not assume a default.
Ask [Billing]: "What billing mode for your SaaS?" AND [Title]: "App display title?"
- Billing: "Free (no billing)" or "Subscription required"
- Title: "Derive from app name" or "Let me specify"
If billing is "Subscription required": Note that Clerk Billing must be configured in the Clerk Dashboard after deploy (plans, Stripe connection). Dev instances auto-connect to Stripe sandbox for testing.
Ask [Tagline]: "Describe your app's tagline (short punchy phrase)"
- "Generate one" — Create from app description
- "Let me write it" — I'll provide it
When billing is "required": These fields appear on a pricing section visible to potential customers before signup. Optimize for marketing copy quality — benefit-driven language, not technical descriptions. Tagline = sales headline. Subtitle = value proposition ("why should I pay?"). Features = compelling benefit statements (3-5 items).
Repeat pattern for subtitle and features list (3-5 bullet points).
Store: billingMode ("off"/"required"), appTitle, tagline, subtitle, features (JSON array). Mark T4 completed.
Phase 2: Assembly & Deploy
Blocked by T1 + T3 + T4. Check TaskList until all complete.
2.1 Verify Inputs
Confirm: app.jsx exists with valid JSX. .env has VITE_CLERK_PUBLISHABLE_KEY, VITE_API_URL, VITE_CLOUD_URL. All sell config values collected.
Scan app.jsx for builder mistakes (see LAUNCH-REFERENCE.md "Common Builder Mistakes"). Fix any found before proceeding.
2.1.5 Preview Before Deploy
Ask [Preview]: "Want to preview the app before deploying?"
- "Yes — open live preview" — Start the preview server and iterate on the design
- "No — deploy now" — Skip preview, go straight to deploy
If yes: run node "${CLAUDE_PLUGIN_ROOT}/scripts/preview-server.js" and tell the user to open http://localhost:3333. They can chat to iterate on the design and switch themes. When satisfied, stop the server and continue to 2.2.
2.2 Deploy Cycle
This sequence runs twice: first here (with --admin-ids '[]'), then in Phase 3 (with real admin ID). Steps:
Step A — Assemble:
node "${CLAUDE_PLUGIN_ROOT}/scripts/assemble-sell.js" app.jsx index.html \
--clerk-key "{clerkPk}" \
--app-name "{appName}" \
--app-title "{appTitle}" \
--domain "{domain}" \
--billing-mode "{billingMode}" \
--tagline "{tagline}" \
--subtitle "{subtitle}" \
--features '{featuresJSON}' \
--admin-ids '{adminIds}'Step B — Validate: grep -c '__VITE_\|__CLERK_\|__APP_' index.html — must be 0.
Step C — Deploy:
node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-cloudflare.js" \
--name "{appName}" \
--file index.html \
--clerk-key "{clerkPk}" \
--billing-mode "{billingMode}" \
--webhook-secret "{webhookSecret}" \
{aiKeyFlag}Where {aiKeyFlag} = --ai-key "{openRouterKey}" if set, omitted if null. The --billing-mode flag controls whether the client enforces JWT-based plan checks. The --webhook-secret flag sets the Clerk webhook signing secret as a Wrangler secret.
Run the cycle now with {adminIds} = '[]' (or '["{existingAdminId}"]' if found in pre-flight). Mark T5, T6 completed.
Phase 3: Admin Setup
Skip if CLERK_ADMIN_USER_ID was found in pre-flight.
3.1 Guide Signup
Tell the user:
Your app is live! Create your admin account:
- Open:
https://{domain}?subdomain=test- Sign up with your email
- Complete email verification
- Create a passkey when prompted
Ask [Signup]: "Have you completed signup on the app?"
- "Yes, signed up" — Completed verification + passkey
- "Skip admin setup" — I'll do this later
If skip: proceed to Phase 4.
3.2 Collect Admin ID
Tell user: Go to clerk.com/dashboard > your app > Users > click your user > copy User ID (starts with user_).
Ask [User ID]: "Paste your Clerk User ID (starts with user_)"
- "I need help finding it" — Clerk Dashboard > Users > click name > ID at top
Validate starts with user_. Save to .env:
echo "CLERK_ADMIN_USER_ID={userId}" >> .env3.3 Re-run Deploy Cycle
Re-run Phase 2.2 steps A-D with {adminIds} = '["{userId}"]'.
Tell user: Admin dashboard now works at https://{domain}?subdomain=admin
Phase 4: Verify & Cleanup
4.1 Verify
Ask [Verify]: "Your app is live! Open each URL and verify:\n\n- Landing: https://{domain}\n- Tenant: https://{domain}?subdomain=test\n- Admin: https://{domain}?subdomain=admin\n\nDoes everything look right?"
- "All working" — Everything loads correctly
- "Something's broken" — Need to troubleshoot
If billingMode === "required": Also ask the user to verify billing:
"Check billing flow: Sign in at
https://{domain}?subdomain=test— you should see a paywall with pricing. Use test card4242 4242 4242 4242(any future expiry, any CVC) to complete a test subscription. After subscribing, the tenant app should load."
Mark T7 completed. If broken, ask what's wrong and troubleshoot.
4.2 Shutdown
Send shutdown_request to "builder" and "infra" (if spawned). Wait for responses. Clean up team.
4.3 Summary
## Launch Complete
**App**: {appTitle}
**URL**: https://{domain}
**Clerk**: {clerkPk}
**Connect**: {studioUrl}
**Billing**: {billingMode}
### What's deployed:
- Cloudflare Worker with KV registry
- Fireproof Connect studio for real-time sync
- Clerk authentication with passkeys
- Subdomain-based multi-tenancy
### Next steps:
- Configure a custom domain (see CLAUDE.md DNS section)
- Set up Clerk billing plans if using subscription modeError Handling
| Failure | Recovery |
|---|---|
| Builder generates invalid JSX | Read app.jsx, fix TS syntax / wrong hooks, re-save |
| Connect deploy fails | Infra reports via SendMessage. Present error + fix steps |
| Assembly has placeholders | Check .env for missing values, re-run assembly |
| Cloudflare deploy fails | Check npx wrangler whoami. Guide npx wrangler login if needed |
| Wrangler secret put fails | Retry. If persistent, have user run manually |
| Teammate silent 3+ min | SendMessage status check. If no response, take over task |
| Builder hardcodes DB name | Edit app.jsx: replace with useTenant() pattern before assembly |