Whirlwind
by @rosebeatty
Production-ready Next.js AI SaaS template with Supabase auth, Stripe payments, email system, multi-model AI client, and customizable components for rapid AI...
clawhub install whirlwindπ About This Skill
Whirlwind AI SaaS Template Skill
Version: 2.0.0
Overview
Whirlwind is a production-ready Next.js template for building AI SaaS products. It provides complete infrastructure so developers can focus on their unique AI features.
Included Infrastructure:
ClawdBot's Role: Customize the template for each user's specific AI product by generating custom components, API routes, and database tables.
File Structure
β Infrastructure (DON'T MODIFY)
These files are core infrastructure. Never modify:
lib/
supabaseClient.js - Database client setup
stripe.js - Stripe checkout/portal functions
api.js - Axios wrapper with auth
seo.js - SEO metadata helpers
ai-client.js - Multi-model AI client
components/
ButtonCheckout.js - Stripe checkout button
ButtonSignin.js - Authentication button
ButtonAccount.js - Account dropdown
CheckoutModal.js - Checkout modal
LayoutClient.js - Client-side layout wrapper
SubscribeForm.js - Email subscription
ai/ - Pre-built AI components
providers/ - Auth/context providers
app/api/
auth/ - Supabase auth routes
stripe/ - Stripe webhook handlers
webhook/ - Other webhooks
π¨ Customizable (UPDATE CONTENT)
Update these files with product-specific content:
components/
Hero.js - Update hero title/subtitle
Features.js - Update features list
Pricing.js - Update pricing copy
FAQ.js - Update FAQ items
CTA.js - Update call-to-action
Testimonials.js - Add testimonials
Header.js - Update navigation (partial)
Footer.js - Update footer links (partial)
config.js - App configuration (Stripe plans, etc.)
π€ Create New (CLAWDBOT GENERATES)
Generate new files in these locations:
components/features/ - Custom AI feature components
app/api/custom/ - Custom API endpoints
lib/supabase/migrations/ - Custom tables (002+)
config/site.js - Product-specific configuration (NEW)
AI Client Usage
Whirlwind provides lib/ai-client.js for all AI operations. Always use this instead of creating ad-hoc clients.
Basic Usage
import AIClient from "@/lib/ai-client";// Choose model: 'claude', 'openai', or 'gemini'
const ai = new AIClient('claude');
// Simple chat
const response = await ai.chat([
{ role: "user", content: "Your prompt here" }
]);
// With options
const response = await ai.chat(messages, {
maxTokens: 2000
});
// Streaming
await ai.stream(messages, (chunk) => {
console.log(chunk); // Handle each chunk
});
Available Models
claude - claude-sonnet-4-20250514 (recommended)openai - gpt-4gemini - gemini-pro (if configured)Database Operations
Always use the Supabase client with proper error handling:
import { supabase } from "@/lib/supabaseClient";// Insert
const { data, error } = await supabase
.from('table_name')
.insert({ column: value });
// Select with auth
const { data, error } = await supabase
.from('table_name')
.select('*')
.eq('user_id', userId);
// Always check errors
if (error) {
console.error(error);
throw new Error(error.message);
}
Creating an AI Product - Step by Step
When a user says: "Create [product name] - [description]"
Step 1: Create config/site.js
This centralizes all product-specific content:
/**
* π¨ CLAWDBOT CUSTOMIZES
* Product-specific configuration
*/const siteConfig = {
productName: "[Product Name]",
productDescription: "[Brief description]",
hero: {
title: "[Compelling title]",
subtitle: "[Subtitle explaining value]",
},
features: [
{
icon: "[emoji]",
name: "[Feature name]",
description: "[Feature description]"
},
// Add 3-6 features
]
};
export default siteConfig;
Step 2: Create Feature Component
Location: components/features/[ComponentName].jsx
Use this template structure:
/**
* π€ CLAWDBOT CREATED
* [Component description]
*/
"use client";import { useState } from "react";
import apiClient from "@/lib/api";
export default function [ComponentName]() {
const [input, setInput] = useState("");
const [result, setResult] = useState("");
const [loading, setLoading] = useState(false);
const handleGenerate = async () => {
setLoading(true);
try {
const response = await apiClient.post("/custom/[endpoint]", {
input
});
setResult(response.result);
} catch (error) {
console.error("Error:", error);
}
setLoading(false);
};
return (
[Component Title]
{/* Input UI */}
setInput(e.target.value)}
className="w-full px-4 py-2 border border-gray-200 dark:border-white/10 rounded"
placeholder="[Placeholder]"
/>
{/* Output UI */}
{result && (
Result:
{result}
)}
);
}
Step 3: Create API Route
Location: app/api/custom/[endpoint]/route.js
/**
* π€ CLAWDBOT CREATED
* [Endpoint description]
*/
import { NextResponse } from "next/server";
import AIClient from "@/lib/ai-client";
import { supabase } from "@/lib/supabaseClient";export async function POST(req) {
try {
// Parse input
const { input } = await req.json();
// Validate
if (!input) {
return NextResponse.json(
{ error: "Input is required" },
{ status: 400 }
);
}
// Create AI prompt
const prompt = [Your specific prompt template]: ${input};
// Call AI
const ai = new AIClient('claude');
const result = await ai.chat([
{ role: "user", content: prompt }
]);
// Optional: Save to database
// const { data: session } = await supabase.auth.getSession();
// if (session?.user) {
// await supabase.from('your_table').insert({
// user_id: session.user.id,
// input,
// result
// });
// }
return NextResponse.json({
success: true,
result
});
} catch (error) {
console.error("API error:", error);
return NextResponse.json(
{ error: error.message || "Processing failed" },
{ status: 500 }
);
}
}
Step 4: Create Database Migration
Location: lib/supabase/migrations/00X_[table_name].sql
-- π€ CLAWDBOT CREATED
-- [Table description]create table if not exists [table_name] (
id uuid default uuid_generate_v4() primary key,
user_id uuid references auth.users on delete cascade not null,
[your_columns] text not null,
created_at timestamp with time zone default timezone('utc'::text, now()) not null
);
-- Indexes
create index [table_name]_user_id_idx on table_name;
create index [table_name]_created_at_idx on table_name;
-- Row Level Security
alter table [table_name] enable row level security;
-- Policies
create policy "Users can view own records"
on [table_name] for select
using (auth.uid() = user_id);
create policy "Users can insert own records"
on [table_name] for insert
with check (auth.uid() = user_id);
create policy "Users can delete own records"
on [table_name] for delete
using (auth.uid() = user_id);
Step 5: Update Dashboard
Add component to app/dashboard/page.js:
import [ComponentName] from "@/components/features/[ComponentName]";export default function Dashboard() {
return (
Dashboard
<[ComponentName] />
);
}
Code Style Guidelines
Typography
font-bebas text-4xl uppercase tracking-widefont-ibm text-smColors
bg-primary hover:bg-primary-focustext-gray-900 dark:text-whiteborder-gray-200 dark:border-white/10bg-white dark:bg-white/5Components
"use client" for interactive componentsRules and Constraints
NEVER:
ALWAYS:
π€ CLAWDBOT CREATED)Common Patterns
Content Generation
const prompt = Generate ${contentType} about: ${topic}
Tone: ${tone}
Length: ${length} words
Include: ${requirements};const ai = new AIClient('claude');
const content = await ai.chat([
{ role: "user", content: prompt }
]);
Image Analysis
// For image analysis, include base64 image in prompt
const prompt = Analyze this image and ${task};
// Note: Image handling requires additional setup
Document Processing
const prompt = Extract ${dataPoints} from this document:
${documentText}Return as JSON.
;const ai = new AIClient('claude');
const result = await ai.chat([
{ role: "user", content: prompt }
]);
Chat/Conversation
// Maintain conversation history
const conversationHistory = [
{ role: "user", content: "Previous message" },
{ role: "assistant", content: "Previous response" },
{ role: "user", content: "Current message" }
];const ai = new AIClient('claude');
const response = await ai.chat(conversationHistory);
Example Workflows
See /examples folder for complete implementations:
content-generator.md - WriteFlow content platformimage-analyzer.md - VisionAI image analysischatbot.md - TalkAI chatbot platformdocument-processor.md - DocuMind document intelligenceTemplates
See /templates folder for code templates to copy:
component.jsx - Feature component templateapi-route.js - API endpoint templatemigration.sql - Database migration templateEnvironment Variables
Remind users to add these to .env:
# Required
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
AI (at least one required)
ANTHROPIC_API_KEY=
OPENAI_API_KEY=Optional
RESEND_API_KEY=
GOOGLE_AI_API_KEY=
Testing
After generating code, suggest testing:
1. Check component renders: npm run dev
2. Test API endpoint with curl or Postman
3. Run database migration in Supabase dashboard
4. Test full workflow end-to-end
Support
For issues or questions: