487 lines
13 KiB
Markdown
487 lines
13 KiB
Markdown
Prompt to paste into Cursor for Sonnet
|
||
You are helping me implement a clean, provider-agnostic AI foundation for a product called Vibn.
|
||
|
||
Vibn’s job:
|
||
- Pull a product idea out of a founder’s head
|
||
- Turn it into a structured product model
|
||
- Derive an MVP plan and marketing model from that
|
||
|
||
Runtime requirement:
|
||
- The *runtime* “Vibn agent” will use **Gemini 2.5 Pro** as the LLM.
|
||
- The architecture must be **model-agnostic**, so we can later add GPT / Claude if we want.
|
||
- Right now, you (Claude Sonnet in Cursor) are only a **coding assistant**, not part of the runtime.
|
||
|
||
I want you to design and implement the following foundation inside this repo.
|
||
|
||
==================================================
|
||
🏛 1. HIGH-LEVEL ARCHITECTURE
|
||
==================================================
|
||
|
||
We want a simple, explicit architecture with four core concepts:
|
||
|
||
1. Project – a single product idea
|
||
2. Knowledge base – all raw materials for a project (notes, chats, docs, etc.)
|
||
3. Canonical Product Model – the structured representation of the product
|
||
4. Derived artifacts – MVP plan and Marketing model
|
||
|
||
Plus:
|
||
|
||
- A small pipeline that goes:
|
||
1) knowledge → product insights
|
||
2) product insights → canonical model
|
||
3) canonical model → MVP plan
|
||
4) canonical model → marketing model
|
||
|
||
- A provider-agnostic **LlmClient** that can talk to Gemini now and later GPT/Sonnet.
|
||
|
||
Use the existing stack / frameworks in this repo (TypeScript / Next / Prisma / etc. as appropriate).
|
||
|
||
|
||
==================================================
|
||
🧱 2. DATA MODEL TO IMPLEMENT
|
||
==================================================
|
||
|
||
Please implement or adapt the following data model (adjust names to match repo conventions).
|
||
|
||
### 2.1 Project
|
||
|
||
Represents one product idea.
|
||
|
||
TypeScript shape:
|
||
|
||
```ts
|
||
export type Phase =
|
||
| "collector" // collecting knowledge
|
||
| "analyzed" // product_insights written
|
||
| "vision_ready" // canonical product model written
|
||
| "mvp_ready" // mvp_plan written
|
||
| "marketing_ready"; // marketing_model written
|
||
|
||
export interface Project {
|
||
id: string;
|
||
ownerId: string;
|
||
name: string;
|
||
description: string | null;
|
||
currentPhase: Phase;
|
||
createdAt: Date;
|
||
updatedAt: Date;
|
||
}
|
||
|
||
|
||
Create or align an existing database table with this shape (Prisma, SQL, or whatever ORM we use).
|
||
|
||
2.2 Knowledge base (all user raw materials)
|
||
|
||
All docs, past chats, notes, specs, etc. roll into a single table.
|
||
|
||
export type SourceType =
|
||
| "user_chat"
|
||
| "imported_chat"
|
||
| "doc"
|
||
| "note"
|
||
| "spec"
|
||
| "research"
|
||
| "other";
|
||
|
||
export interface KnowledgeItem {
|
||
id: string;
|
||
projectId: string;
|
||
sourceType: SourceType;
|
||
title: string | null;
|
||
content: string; // normalized text
|
||
sourceMeta: {
|
||
origin?: "chatgpt" | "notion" | "github" | "file_upload" | "manual";
|
||
url?: string;
|
||
filename?: string;
|
||
createdAtOriginal?: string;
|
||
};
|
||
createdAt: Date;
|
||
updatedAt: Date;
|
||
}
|
||
|
||
|
||
Implement a knowledge_items table (or equivalent) and any necessary migration.
|
||
|
||
2.3 Canonical Product Model (central brain)
|
||
|
||
This is the single source of truth for the product’s understanding in the system.
|
||
|
||
export interface CanonicalProductModel {
|
||
projectId: string; // PK/FK to Project.id
|
||
|
||
basics: {
|
||
productName: string | null;
|
||
oneLiner: string | null;
|
||
};
|
||
|
||
users: {
|
||
primaryUser: string | null;
|
||
userSegments: Array<{
|
||
id: string;
|
||
description: string;
|
||
jobsToBeDone: string[];
|
||
context: string | null;
|
||
}>;
|
||
};
|
||
|
||
problemSpace: {
|
||
primaryProblem: string | null;
|
||
secondaryProblems: string[];
|
||
currentAlternatives: string[];
|
||
pains: string[];
|
||
};
|
||
|
||
solutionSpace: {
|
||
coreSolution: string | null;
|
||
keyFeatures: string[];
|
||
differentiators: string[];
|
||
constraints: string[];
|
||
};
|
||
|
||
business: {
|
||
valueProposition: string | null;
|
||
whyNow: string | null;
|
||
roughPricingIdeas: string[];
|
||
};
|
||
|
||
meta: {
|
||
lastUpdatedFromExtraction: string | null; // ISO date
|
||
lastManualEditAt: string | null; // ISO date
|
||
};
|
||
}
|
||
|
||
|
||
Store this as a single row per project, with a JSON column if we’re using a relational DB. Name could be product_model or canonical_product_model.
|
||
|
||
2.4 Product Insights (evidence layer)
|
||
|
||
This is the “extracted signals” from raw knowledge.
|
||
|
||
export interface ProductInsights {
|
||
projectId: string;
|
||
|
||
problems: Array<{ id: string; description: string; evidence: string[] }>;
|
||
users: Array<{ id: string; description: string; evidence: string[] }>;
|
||
desires: Array<{ id: string; description: string; evidence: string[] }>;
|
||
features: Array<{ id: string; description: string; evidence: string[] }>;
|
||
constraints: Array<{ id: string; description: string; evidence: string[] }>;
|
||
competitors: Array<{ id: string; description: string; evidence: string[] }>;
|
||
|
||
uncertainties: Array<{ id: string; description: string; relatedTo?: string }>;
|
||
missingInformation: Array<{ id: string; question: string }>;
|
||
|
||
lastRunAt: string; // ISO date
|
||
modelUsed: "gemini" | "gpt" | "sonnet";
|
||
}
|
||
|
||
|
||
Again: one row per project, as JSON.
|
||
|
||
2.5 MVP Plan (derived from canonical model)
|
||
export interface MvpPlan {
|
||
projectId: string;
|
||
|
||
guidingPrinciples: string[];
|
||
coreUserFlows: Array<{
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
steps: string[];
|
||
successCriteria: string[];
|
||
}>;
|
||
coreFeatures: Array<{
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
userFlowIds: string[];
|
||
}>;
|
||
supportingFeatures: Array<{
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
}>;
|
||
outOfScope: Array<{
|
||
id: string;
|
||
description: string;
|
||
reasonDeferred: string;
|
||
}>;
|
||
|
||
lastRunAt: string; // ISO date
|
||
modelUsed: "gemini" | "gpt" | "sonnet";
|
||
}
|
||
|
||
2.6 Marketing Model (also derived from canonical model)
|
||
export interface MarketingModel {
|
||
projectId: string;
|
||
|
||
icp: {
|
||
summary: string;
|
||
segments: Array<{
|
||
id: string;
|
||
description: string;
|
||
jobsToBeDone: string[];
|
||
keyPains: string[];
|
||
buyingTriggers: string[];
|
||
}>;
|
||
};
|
||
|
||
positioning: {
|
||
category: string;
|
||
targetAudience: string;
|
||
primaryBenefit: string;
|
||
reasonsToBelieve: string[];
|
||
};
|
||
|
||
messaging: {
|
||
hero: {
|
||
headline: string;
|
||
subheadline: string;
|
||
primaryCta: string;
|
||
bullets: string[];
|
||
};
|
||
sections: Array<{
|
||
id: string;
|
||
title: string;
|
||
body: string;
|
||
bullets: string[];
|
||
}>;
|
||
};
|
||
|
||
launchIdeas: {
|
||
initialChannels: string[];
|
||
angles: string[];
|
||
exampleCampaigns: string[];
|
||
};
|
||
|
||
lastRunAt: string; // ISO
|
||
modelUsed: "gemini" | "gpt" | "sonnet";
|
||
}
|
||
|
||
|
||
Please create appropriate types in something like /lib/ai/types.ts (or adapt to existing file) and DB schema/migrations to persist these models.
|
||
|
||
==================================================
|
||
🤖 3. LLM CLIENT ABSTRACTION (WITH GEMINI RUNTIME)
|
||
|
||
Implement a small, provider-agnostic LLM client.
|
||
|
||
3.1 Interface
|
||
|
||
Create something like /lib/ai/llm-client.ts:
|
||
|
||
export type LlmModel = "gemini" | "gpt" | "sonnet";
|
||
|
||
export interface LlmMessage {
|
||
role: "system" | "user" | "assistant";
|
||
content: string;
|
||
}
|
||
|
||
export interface StructuredCallArgs<TOutput> {
|
||
model: LlmModel;
|
||
systemPrompt: string;
|
||
messages: LlmMessage[];
|
||
schema: import("zod").ZodSchema<TOutput>;
|
||
temperature?: number;
|
||
}
|
||
|
||
export interface LlmClient {
|
||
structuredCall<TOutput>(args: StructuredCallArgs<TOutput>): Promise<TOutput>;
|
||
}
|
||
|
||
3.2 Gemini implementation (runtime)
|
||
|
||
Implement a GeminiLlmClient that:
|
||
|
||
Ignores other models for now (only supports model: "gemini").
|
||
|
||
Uses the existing Gemini 2.5 Pro client in this repo.
|
||
|
||
Requests JSON / structured responses if the API supports it (e.g., response_mime_type: "application/json").
|
||
|
||
Validates the result against the provided Zod schema.
|
||
|
||
On parse/validation error:
|
||
|
||
Optionally retry once with a “fix your JSON” system hint.
|
||
|
||
Otherwise throw a well-typed error.
|
||
|
||
Wire this into where we currently call Gemini so that future GPT/Sonnet support only touches this layer.
|
||
|
||
==================================================
|
||
🧠 4. AGENT FUNCTIONS / PIPELINE
|
||
|
||
Create a small pipeline that uses the LlmClient to transform data through four steps.
|
||
|
||
Place them in something like /lib/ai/agents/:
|
||
|
||
extractorAgent – knowledge → ProductInsights
|
||
|
||
productModelAgent – ProductInsights → CanonicalProductModel
|
||
|
||
mvpAgent – CanonicalProductModel → MvpPlan
|
||
|
||
marketingAgent – CanonicalProductModel → MarketingModel
|
||
|
||
4.1 extractorAgent
|
||
|
||
Signature:
|
||
|
||
export async function extractorAgent(
|
||
knowledge: KnowledgeItem[],
|
||
llm: LlmClient
|
||
): Promise<ProductInsights>
|
||
|
||
|
||
Behavior:
|
||
|
||
Serialize the knowledge array to JSON.
|
||
|
||
Use a clear system prompt that says: “You are a Product Insight Extraction Agent. Read the knowledge items and output only JSON matching this schema: (ProductInsights).”
|
||
|
||
Call llm.structuredCall<ProductInsights>({ model: "gemini", ... }).
|
||
|
||
Return the validated result.
|
||
|
||
4.2 productModelAgent
|
||
|
||
Signature:
|
||
|
||
export async function productModelAgent(
|
||
insights: ProductInsights,
|
||
existingModel: CanonicalProductModel | null,
|
||
llm: LlmClient
|
||
): Promise<CanonicalProductModel>
|
||
|
||
|
||
Behavior:
|
||
|
||
Prompt: “You are a Product Model Builder. Given product insights, create or refine the canonical product model JSON matching this schema…”
|
||
|
||
If existingModel is present, include it in the prompt and ask the model to refine rather than start from scratch.
|
||
|
||
Use structuredCall with the CanonicalProductModel schema.
|
||
|
||
4.3 mvpAgent
|
||
|
||
Signature:
|
||
|
||
export async function mvpAgent(
|
||
model: CanonicalProductModel,
|
||
llm: LlmClient
|
||
): Promise<MvpPlan>
|
||
|
||
|
||
Behavior:
|
||
|
||
Prompt: “You are an MVP Planner. Given this canonical product model, produce the smallest sellable V1 plan as JSON matching the MvpPlan schema…”
|
||
|
||
Uses structuredCall and returns MvpPlan.
|
||
|
||
4.4 marketingAgent
|
||
|
||
Signature:
|
||
|
||
export async function marketingAgent(
|
||
model: CanonicalProductModel,
|
||
llm: LlmClient
|
||
): Promise<MarketingModel>
|
||
|
||
|
||
Behavior:
|
||
|
||
Prompt: “You are a Marketing Strategist. Given this canonical product model, produce an ICP + positioning + messaging + launch ideas as JSON matching the MarketingModel schema…”
|
||
|
||
Uses structuredCall and returns MarketingModel.
|
||
|
||
==================================================
|
||
🔀 5. ORCHESTRATOR / PIPELINE RUNNER
|
||
|
||
Create a small pipeline runner, e.g. /lib/ai/pipeline.ts:
|
||
|
||
export async function runFullPipeline(projectId: string, llm: LlmClient) {
|
||
const project = await loadProject(projectId);
|
||
const knowledge = await loadKnowledgeItems(projectId);
|
||
const current = await loadAllModels(projectId); // insights, canonical, mvp, marketing
|
||
|
||
// 1) knowledge -> insights
|
||
const insights = await extractorAgent(knowledge, llm);
|
||
await saveProductInsights(projectId, insights);
|
||
await updateProjectPhase(projectId, "analyzed");
|
||
|
||
// 2) insights -> canonical product model
|
||
const canonical = await productModelAgent(
|
||
insights,
|
||
current.canonicalProductModel ?? null,
|
||
llm
|
||
);
|
||
await saveCanonicalProductModel(projectId, canonical);
|
||
await updateProjectPhase(projectId, "vision_ready");
|
||
|
||
// 3) canonical -> MVP
|
||
const mvp = await mvpAgent(canonical, llm);
|
||
await saveMvpPlan(projectId, mvp);
|
||
await updateProjectPhase(projectId, "mvp_ready");
|
||
|
||
// 4) canonical -> marketing
|
||
const marketing = await marketingAgent(canonical, llm);
|
||
await saveMarketingModel(projectId, marketing);
|
||
await updateProjectPhase(projectId, "marketing_ready");
|
||
|
||
return { insights, canonical, mvp, marketing };
|
||
}
|
||
|
||
|
||
Please implement the helper functions (loadProject, loadKnowledgeItems, saveProductInsights, etc.) against whatever DB / ORM we use.
|
||
|
||
==================================================
|
||
🌐 6. API ENDPOINTS
|
||
|
||
Implement or refactor API routes so that:
|
||
|
||
POST /api/projects
|
||
|
||
Creates a new project.
|
||
|
||
Sets currentPhase = "collector".
|
||
|
||
GET /api/projects/:id
|
||
|
||
Returns project and which artifacts exist (hasInsights, hasProductModel, hasMvp, hasMarketing).
|
||
|
||
GET /api/projects/:id/knowledge and POST /api/projects/:id/knowledge
|
||
|
||
Manage KnowledgeItems (list and add).
|
||
|
||
POST /api/projects/:id/run-pipeline
|
||
|
||
Calls runFullPipeline(projectId, llmClient).
|
||
|
||
Returns the updated artifacts + project phase.
|
||
|
||
GET /api/projects/:id/artifacts
|
||
|
||
Returns { productInsights, canonicalProductModel, mvpPlan, marketingModel }.
|
||
|
||
You may reuse existing routes where it makes sense; the important thing is that the data model and pipeline above exist and are wired to Gemini via the LlmClient abstraction.
|
||
|
||
==================================================
|
||
✅ 7. HOW TO PROCEED
|
||
|
||
Scan the repo and see what already exists that overlaps with this design.
|
||
|
||
Propose a mapping (which existing files/types you’ll reuse vs replace).
|
||
|
||
Implement the data model (types + DB schema) and LlmClient abstraction.
|
||
|
||
Implement the four agents and the runFullPipeline function.
|
||
|
||
Hook up the API endpoints.
|
||
|
||
Keep changes incremental and explain major decisions as code comments.
|
||
|
||
Throughout, remember:
|
||
|
||
At runtime, the Vibn agent uses Gemini 2.5 Pro via our LlmClient.
|
||
|
||
You (Sonnet in Cursor) are here to design and write the code, not to be the runtime model |