UNPKG

oneie

Version:

Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.

1,678 lines (1,549 loc) 48.7 kB
--- title: Dsl dimension: knowledge category: dsl.md tags: ai, ontology related_dimensions: connections, events, things scope: global created: 2025-11-03 updated: 2025-11-03 version: 1.0.0 ai_context: | This document is part of the knowledge dimension in the dsl.md category. Location: one/knowledge/dsl.md Purpose: Provides information Related dimensions: connections, events, things For AI agents: Read this to understand dsl. --- // ============================================================================ // ONE DSL - Domain Specific Language // Purpose: Declare features in high-level syntax that compiles to Effect.ts // ============================================================================ /** * DSL SYNTAX SPECIFICATION * * The ONE DSL is a declarative language for defining features on the ONE platform. * It compiles to TypeScript with Effect.ts and plain Convex schemas (no Convex Ents). * * Core principles: * 1. Declarative - describe WHAT, not HOW * 2. Type-safe - validates against ontology * 3. Composable - features built from primitives * 4. Auditable - generates readable TypeScript * 5. Metadata-based - uses metadata field for type consolidation * * Hybrid Type Strategy: * - 25 connection types (18 specific + 7 consolidated via metadata) * - 35 event types (24 specific + 11 consolidated via metadata) * - Specific types for core domain concepts (tokens, courses, clones) * - Consolidated types for protocol-agnostic patterns (payment, content, communication) * - Metadata field stores variants and protocol identity */ // ============================================================================ // DSL PRIMITIVES // ============================================================================ /** * ENTITY DECLARATION * Creates a new entity in the ontology */ type EntityDeclaration = { entity: { type: EntityType; name: string; properties: Record<string, any>; status?: "active" | "inactive" | "draft"; }; }; /** * CONNECTION DECLARATION * Creates relationship between entities * * 25 HYBRID CONNECTION TYPES: * * Specific Types (18): * - Ownership: "owns", "created_by" * - AI: "clone_of", "trained_on", "powers" * - Content: "authored", "generated_by", "published_to", "part_of", "references" * - Community: "member_of", "following", "moderates", "participated_in" * - Business: "manages", "reports_to", "collaborates_with" * - Tokens: "holds_tokens", "staked_in", "earned_from" * - Products: "purchased", "enrolled_in", "completed", "teaching" * * Consolidated Types (7) - use metadata: * - "transacted" (metadata.transactionType + protocol) * - "notified" (metadata.channel + notificationType) * - "referred" (metadata.referralType) * - "communicated" (metadata.protocol + messageType) * - "delegated" (metadata.protocol + taskType) * - "approved" (metadata.approvalType + protocol) * - "fulfilled" (metadata.fulfillmentType + protocol) */ type ConnectionDeclaration = { connect: { from: EntityReference; to: EntityReference; type: ConnectionType; // One of 24 consolidated types metadata?: { // Type-specific metadata for consolidated types paymentType?: "subscription" | "purchase" | "tip" | "refund"; livestreamType?: "hosted" | "attended" | "moderated" | "banned_from"; notificationType?: "sent" | "received" | "read"; referralType?: "referred" | "earned_from"; actionType?: string; // For admin_action // Custom fields [key: string]: any; }; }; }; /** * EVENT DECLARATION * Logs an event * * 35 HYBRID EVENT TYPES: * * Specific Types (24): * - Entity Lifecycle: "entity_created", "entity_updated", "entity_deleted", "entity_archived" * - User: "user_registered", "user_verified", "user_login", "user_logout", "profile_updated" * - AI/Clone: "clone_created", "clone_updated", "voice_cloned", "appearance_cloned" * - Agent: "agent_created", "agent_executed", "agent_completed", "agent_failed" * - Token: "token_created", "token_minted", "token_burned", "tokens_purchased", "tokens_staked", "tokens_unstaked", "tokens_transferred" * - Course: "course_created", "course_enrolled", "lesson_completed", "course_completed", "certificate_earned" * - Analytics: "metric_calculated", "insight_generated", "prediction_made", "optimization_applied", "report_generated" * * Consolidated Types (11) - use metadata: * - "content_event" (metadata.action: created|updated|deleted|viewed|shared|liked) * - "payment_event" (metadata.status: requested|verified|processed + protocol) * - "subscription_event" (metadata.action: started|renewed|cancelled) * - "commerce_event" (metadata.eventType + protocol: ACP, AP2) * - "livestream_event" (metadata.status + metadata.action) * - "notification_event" (metadata.channel + deliveryStatus) * - "referral_event" (metadata.action: created|completed|rewarded) * - "communication_event" (metadata.protocol + messageType: A2A, ACP, AG-UI) * - "task_event" (metadata.action: delegated|completed|failed + protocol) * - "mandate_event" (metadata.mandateType: intent|cart + protocol: AP2) * - "price_event" (metadata.action: checked|changed) */ type EventDeclaration = { event: { entity: EntityReference; type: EventType; // One of 38 consolidated types actor?: EntityReference; metadata?: { // Type-specific metadata for consolidated types contentType?: "created" | "published" | "edited" | "deleted" | "viewed" | "shared"; paymentType?: "initiated" | "completed" | "failed" | "refunded" | "subscription_created" | "subscription_cancelled"; livestreamType?: "started" | "ended" | "viewer_joined" | "viewer_left" | "chat_message" | "donation_received"; notificationType?: "sent" | "delivered" | "read" | "clicked"; referralType?: "created" | "completed" | "reward_paid"; actionType?: string; // For admin_action // Custom fields [key: string]: any; }; }; }; /** * QUERY DECLARATION * Retrieves entities/connections/events */ type QueryDeclaration = { query: { from: "entities" | "connections" | "events"; where?: Array<{ field: string; operator: "eq" | "gt" | "lt" | "contains"; value: any; }>; limit?: number; orderBy?: { field: string; direction: "asc" | "desc" }; }; }; /** * FLOW DECLARATION * Multi-step workflow with branching logic */ type FlowDeclaration = { flow: { name: string; steps: Array<StepDeclaration>; error?: ErrorHandler; }; }; /** * SERVICE DECLARATION * Calls external provider */ type ServiceDeclaration = { service: { provider: | "openai" // OpenAI GPT models | "elevenlabs" // Voice cloning | "stripe" // Payment processing | "blockchain" // Blockchain interactions | "resend" // Email service | "d-id" // Appearance cloning (D-ID) | "heygen" // Alternative appearance cloning | "uniswap" // DEX integration for token trading | "alchemy" // Blockchain provider/API | "twilio" // SMS and voice communications | "sendgrid" // Email service (alternative) | "aws" // Media storage (S3) | "cloudflare"; // CDN and live streaming method: string; params: Record<string, any>; }; }; // ============================================================================ // METADATA PATTERNS - Examples of Consolidated Types // ============================================================================ /** * PAYMENT CONNECTION EXAMPLES * Single "payment" type with metadata.paymentType */ const paymentSubscriptionExample = { connect: { from: "$userId", to: "$creatorId", type: "payment", metadata: { paymentType: "subscription", amount: 999, currency: "usd", interval: "monthly", stripeSubscriptionId: "sub_123", }, }, }; const paymentTipExample = { connect: { from: "$userId", to: "$creatorId", type: "payment", metadata: { paymentType: "tip", amount: 500, currency: "usd", message: "Great content!", }, }, }; /** * CONTENT EVENT EXAMPLES * Single "content" type with metadata.contentType */ const contentPublishedEvent = { event: { entity: "$contentId", type: "content", actor: "$userId", metadata: { contentType: "published", title: "My Blog Post", visibility: "public", }, }, }; const contentViewedEvent = { event: { entity: "$contentId", type: "content", actor: "$viewerId", metadata: { contentType: "viewed", duration: 120, // seconds source: "feed", }, }, }; /** * LIVESTREAM EVENT EXAMPLES * Single "livestream" type with metadata.livestreamType */ const livestreamStartedEvent = { event: { entity: "$livestreamId", type: "livestream", actor: "$hostId", metadata: { livestreamType: "started", title: "Q&A Session", expectedDuration: 3600, }, }, }; const livestreamDonationEvent = { event: { entity: "$livestreamId", type: "livestream", actor: "$donorId", metadata: { livestreamType: "donation_received", amount: 1000, currency: "usd", message: "Love your work!", }, }, }; /** * NOTIFICATION CONNECTION EXAMPLES * Single "notification" type with metadata.notificationType */ const notificationSentConnection = { connect: { from: "$systemId", to: "$userId", type: "notification", metadata: { notificationType: "sent", title: "New follower", body: "John Doe started following you", priority: "medium", }, }, }; /** * REFERRAL CONNECTION EXAMPLES * Single "referral" type with metadata.referralType */ const referralConnection = { connect: { from: "$referrerId", to: "$referredUserId", type: "referral", metadata: { referralType: "referred", code: "FRIEND50", reward: 500, status: "pending", }, }, }; // ============================================================================ // PLAIN CONVEX SCHEMA - How DSL Compiles // ============================================================================ /** * The DSL compiles to plain Convex schemas (NO Convex Ents) * * This is the actual Convex schema that the DSL generates: */ // convex/schema.ts (Generated from DSL) import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ // Entity table - all entities stored here entities: defineTable({ type: v.string(), // Entity type (creator, ai_clone, token, etc.) name: v.string(), properties: v.any(), // Type-specific properties status: v.union(v.literal("active"), v.literal("inactive"), v.literal("draft")), createdAt: v.number(), updatedAt: v.number(), }) .index("by_type", ["type"]) .index("by_status", ["status"]) .index("by_created", ["createdAt"]), // Connection table - 24 consolidated types connections: defineTable({ fromEntityId: v.id("entities"), toEntityId: v.id("entities"), relationshipType: v.string(), // One of 24 consolidated types metadata: v.optional(v.any()), // Stores paymentType, livestreamType, etc. createdAt: v.number(), }) .index("by_from", ["fromEntityId"]) .index("by_to", ["toEntityId"]) .index("by_type", ["relationshipType"]) .index("by_from_and_type", ["fromEntityId", "relationshipType"]) .index("by_to_and_type", ["toEntityId", "relationshipType"]), // Event table - 38 consolidated types events: defineTable({ entityId: v.id("entities"), eventType: v.string(), // One of 38 consolidated types timestamp: v.number(), actorType: v.union(v.literal("user"), v.literal("system")), actorId: v.optional(v.id("entities")), metadata: v.optional(v.any()), // Stores contentType, paymentType, etc. }) .index("by_entity", ["entityId"]) .index("by_type", ["eventType"]) .index("by_timestamp", ["timestamp"]) .index("by_entity_and_type", ["entityId", "eventType"]) .index("by_actor", ["actorId"]), }); /** * KEY DIFFERENCES FROM CONVEX ENTS: * * 1. NO ent() definitions - just plain defineTable() * 2. NO edge() definitions - connections stored as regular rows * 3. NO automatic relationship traversal - use manual queries * 4. Metadata field (v.any()) stores type-specific data * 5. Simpler, more flexible, easier to understand * 6. Better for AI agents - less magic, more explicit */ // ============================================================================ // EXAMPLE 1: Create AI Clone (DSL) // ============================================================================ const createAICloneDSL = { feature: "CreateAIClone", input: { creatorId: "Id<entities>", videoUrls: "string[]", }, output: { cloneId: "Id<entities>", voiceId: "string", }, flow: [ // Step 1: Validate input { validate: { creatorId: { exists: true, type: "creator" }, videoUrls: { minLength: 3 }, }, onError: { return: { error: "InsufficientContent" } }, }, // Step 2: Extract audio samples { service: { provider: "openai", method: "extractAudioFromVideos", params: { urls: "$input.videoUrls" }, output: "audioSamples", }, }, // Step 3: Clone voice { service: { provider: "elevenlabs", method: "cloneVoice", params: { name: "$creator.name + ' Voice'", samples: "$audioSamples", }, output: "voiceId", retry: { times: 3, delay: "5s" }, timeout: "5m", }, }, // Step 4: Analyze personality { service: { provider: "openai", method: "analyzePersonality", params: { videos: "$input.videoUrls", posts: "$creator.properties.recentPosts", }, output: "personality", }, }, // Step 5: Create AI clone entity { entity: { type: "ai_clone", name: "$creator.name + ' AI Clone'", properties: { voiceId: "$voiceId", voiceProvider: "elevenlabs", systemPrompt: "$personality.systemPrompt", temperature: 0.7, totalInteractions: 0, }, status: "active", }, output: "cloneId", }, // Step 6: Create ownership connection { connect: { from: "$input.creatorId", to: "$cloneId", type: "owns", }, }, // Step 7: Log creation event { event: { entity: "$cloneId", type: "clone_created", actor: "$input.creatorId", metadata: { voiceId: "$voiceId", personality: "$personality.traits", }, }, }, // Step 8: Return result { return: { cloneId: "$cloneId", voiceId: "$voiceId", }, }, ], }; // ============================================================================ // EXAMPLE 2: Token Purchase (DSL) // ============================================================================ const tokenPurchaseDSL = { feature: "PurchaseTokens", input: { userId: "Id<entities>", tokenId: "Id<entities>", amount: "number", usdAmount: "number", }, output: { paymentId: "string", txHash: "string", }, flow: [ // Step 1: Validate inputs { validate: { userId: { exists: true, type: "audience_member" }, tokenId: { exists: true, type: "token" }, amount: { gt: 0 }, usdAmount: { gt: 0 }, }, }, // Step 2: Charge payment (atomic with step 3) { atomic: [ // 2a: Stripe payment { service: { provider: "stripe", method: "charge", params: { amount: "$input.usdAmount * 100", currency: "usd", metadata: { userId: "$input.userId", tokenId: "$input.tokenId", }, }, output: "payment", }, }, // 2b: Mint tokens on blockchain { service: { provider: "blockchain", method: "mint", params: { contractAddress: "$token.properties.contractAddress", toAddress: "$input.userId", amount: "$input.amount", }, output: "mintTx", }, }, ], onError: { rollback: [ { service: { provider: "stripe", method: "refund", params: { paymentIntentId: "$payment.id" }, }, }, { service: { provider: "blockchain", method: "burn", params: { contractAddress: "$token.properties.contractAddress", amount: "$input.amount", }, }, }, ], }, }, // Step 3a: Log payment event (using consolidated "payment" event type) { event: { entity: "$input.userId", type: "payment", actor: "$input.userId", metadata: { paymentType: "completed", amount: "$input.usdAmount", currency: "usd", paymentId: "$payment.id", purpose: "token_purchase", tokenId: "$input.tokenId", tokenAmount: "$input.amount", }, }, }, // Step 3b: Log token purchase event { event: { entity: "$input.tokenId", type: "tokens_purchased", actor: "$input.userId", metadata: { amount: "$input.amount", usdAmount: "$input.usdAmount", paymentId: "$payment.id", txHash: "$mintTx.transactionHash", }, }, }, // Step 4: Update token balance { query: { from: "connections", where: [ { field: "fromEntityId", operator: "eq", value: "$input.userId" }, { field: "toEntityId", operator: "eq", value: "$input.tokenId" }, { field: "relationshipType", operator: "eq", value: "holds_tokens" }, ], limit: 1, }, output: "existingConnection", }, { if: { condition: "$existingConnection != null", then: [ { update: { connection: "$existingConnection._id", set: { metadata: { balance: "$existingConnection.metadata.balance + $input.amount", }, }, }, }, ], else: [ { connect: { from: "$input.userId", to: "$input.tokenId", type: "holds_tokens", metadata: { balance: "$input.amount", firstPurchaseDate: Date.now(), txHash: "$mintTx.transactionHash", }, }, }, ], }, }, // Step 5a: Create payment connection record (using consolidated "payment" type) { connect: { from: "$input.userId", to: "$input.tokenId", type: "payment", metadata: { paymentType: "purchase", amount: "$input.usdAmount", currency: "usd", tokenAmount: "$input.amount", paymentId: "$payment.id", txHash: "$mintTx.transactionHash", }, }, }, // Step 6: Return result { return: { paymentId: "$payment.id", txHash: "$mintTx.transactionHash", }, }, ], }; // ============================================================================ // EXAMPLE 2B: Token Purchase with Referral (DSL) // Shows referral metadata pattern // ============================================================================ const tokenPurchaseWithReferralDSL = { feature: "PurchaseTokensWithReferral", input: { userId: "Id<entities>", tokenId: "Id<entities>", amount: "number", usdAmount: "number", referralCode: "string", }, output: { paymentId: "string", txHash: "string", referralReward: "number", }, flow: [ // Step 1: Find referral connection { query: { from: "connections", where: [ { field: "toEntityId", operator: "eq", value: "$input.userId" }, { field: "relationshipType", operator: "eq", value: "referral" }, { field: "metadata.code", operator: "eq", value: "$input.referralCode", }, { field: "metadata.status", operator: "eq", value: "pending" }, ], limit: 1, }, output: "referralConnection", }, // Step 2: Process payment (same as before) // ... payment steps ... // Step 3: Update referral status if found { if: { condition: "$referralConnection != null", then: [ { update: { connection: "$referralConnection._id", set: { metadata: { referralType: "completed", code: "$input.referralCode", reward: 500, status: "completed", completedAt: Date.now(), }, }, }, }, { event: { entity: "$referralConnection.fromEntityId", type: "referral", actor: "$input.userId", metadata: { referralType: "completed", code: "$input.referralCode", reward: 500, referredUserId: "$input.userId", }, }, }, ], }, }, // Step 4: Return result { return: { paymentId: "$payment.id", txHash: "$mintTx.transactionHash", referralReward: "$referralConnection != null ? $referralConnection.metadata.reward : 0", }, }, ], }; // ============================================================================ // EXAMPLE 3: Livestream with Notifications (DSL) // Shows livestream and notification metadata patterns // ============================================================================ const livestreamWithNotificationsDSL = { feature: "StartLivestreamWithNotifications", input: { hostId: "Id<entities>", title: "string", description: "string", }, output: { livestreamId: "Id<entities>", notificationsSent: "number", }, flow: [ // Step 1: Create livestream entity { entity: { type: "livestream", name: "$input.title", properties: { description: "$input.description", status: "live", viewerCount: 0, startedAt: Date.now(), }, status: "active", }, output: "livestreamId", }, // Step 2: Create livestream connection (using consolidated type) { connect: { from: "$input.hostId", to: "$livestreamId", type: "livestream", metadata: { livestreamType: "hosted", role: "host", startedAt: Date.now(), }, }, }, // Step 3: Log livestream started event (using consolidated type) { event: { entity: "$livestreamId", type: "livestream", actor: "$input.hostId", metadata: { livestreamType: "started", title: "$input.title", expectedDuration: 3600, }, }, }, // Step 4: Get all followers { query: { from: "connections", where: [ { field: "toEntityId", operator: "eq", value: "$input.hostId" }, { field: "relationshipType", operator: "eq", value: "following" }, ], }, output: "followers", }, // Step 5: Send notifications to all followers { forEach: { array: "$followers", do: [ { connect: { from: "$input.hostId", to: "$item.fromEntityId", type: "notification", metadata: { notificationType: "sent", title: "Livestream started!", body: "$input.title", livestreamId: "$livestreamId", sentAt: Date.now(), priority: "high", }, }, }, { event: { entity: "$item.fromEntityId", type: "notification", actor: "$input.hostId", metadata: { notificationType: "sent", channel: "push", livestreamId: "$livestreamId", }, }, }, ], output: "notificationResults", }, }, // Step 6: Return result { return: { livestreamId: "$livestreamId", notificationsSent: "$notificationResults.length", }, }, ], }; // ============================================================================ // EXAMPLE 4: ELEVATE Journey (DSL) // ============================================================================ const elevateJourneyDSL = { feature: "ELEVATEJourney", input: { userId: "Id<entities>", }, output: { completed: "boolean", }, flow: [ // Step 1: Hook - Free AI analysis { step: "hook", actions: [ { service: { provider: "openai", method: "generateBusinessAnalysis", params: { userId: "$input.userId" }, output: "analysis", }, }, { event: { entity: "$input.userId", type: "elevate_step_completed", metadata: { step: "hook", output: "$analysis" }, }, }, ], }, // Wait 24 hours { wait: "24h" }, // Step 2: Gift - Send insights { step: "gift", actions: [ { service: { provider: "resend", method: "sendInsightsReport", params: { to: "$user.properties.email", insights: "$analysis", }, }, }, { event: { entity: "$input.userId", type: "elevate_step_completed", metadata: { step: "gift" }, }, }, ], }, // Step 3: Identify - Payment gate { step: "identify", actions: [ { service: { provider: "stripe", method: "createCheckoutSession", params: { amount: 10000, currency: "usd", successUrl: "$baseUrl/elevate/success", cancelUrl: "$baseUrl/elevate/cancel", }, output: "checkout", }, }, { waitForEvent: { eventType: "payment_completed", entityId: "$input.userId", timeout: "7d", }, output: "paymentCompleted", }, { if: { condition: "$paymentCompleted == false", then: [{ return: { completed: false } }], }, }, ], }, // Steps 4-9 continue... { return: { completed: true } }, ], }; // ============================================================================ // EXAMPLE 4: Query Pattern (DSL) // ============================================================================ const getCreatorWithContentDSL = { feature: "GetCreatorWithContent", input: { creatorId: "Id<entities>", }, output: { creator: "Entity", content: "Entity[]", followerCount: "number", }, flow: [ // Step 1: Get creator entity { query: { from: "entities", where: [ { field: "_id", operator: "eq", value: "$input.creatorId" }, { field: "type", operator: "eq", value: "creator" }, ], limit: 1, }, output: "creator", }, // Step 2: Get authored content { query: { from: "connections", where: [ { field: "fromEntityId", operator: "eq", value: "$input.creatorId" }, { field: "relationshipType", operator: "eq", value: "authored" }, ], }, output: "contentConnections", }, // Step 3: Hydrate content entities { forEach: { array: "$contentConnections", do: [ { query: { from: "entities", where: [ { field: "_id", operator: "eq", value: "$item.toEntityId" }, ], }, }, ], output: "content", }, }, // Step 4: Count followers { query: { from: "connections", where: [ { field: "toEntityId", operator: "eq", value: "$input.creatorId" }, { field: "relationshipType", operator: "eq", value: "following" }, ], }, output: "followers", }, // Step 5: Return result { return: { creator: "$creator", content: "$content", followerCount: "$followers.length", }, }, ], }; // ============================================================================ // DSL COMPILER // Compiles DSL to TypeScript with Effect.ts and Plain Convex // ============================================================================ class ONECompiler { /** * Compiles DSL to TypeScript with Effect.ts * * Key Features: * - Generates plain Convex queries/mutations (NO Convex Ents) * - Uses ctx.db.insert/query/patch directly * - Metadata field stores type-specific data * - Effect.ts for composition and error handling */ compile(dsl: any): string { const feature = dsl.feature; const input = dsl.input; const output = dsl.output; const flow = dsl.flow; let code = `// Generated from ONE DSL // Compiles to Plain Convex (NO Convex Ents) + Effect.ts import { Effect } from "effect"; import { mutation, query, internalMutation } from "./_generated/server"; import { v } from "convex/values"; import { OpenAIProvider, ElevenLabsProvider, StripeProvider, BlockchainProvider, ResendProvider } from "@/convex/services/providers"; /** * Generated ${feature} function * Uses plain Convex with Effect.ts for composition */ export const ${this.toCamelCase(feature)} = mutation({ args: ${this.generateInputArgs(input)}, handler: async (ctx, args) => { return await Effect.runPromise( Effect.gen(function* () { `; // Compile each step in flow for (const step of flow) { code += this.compileStep(step, 4); } code += ` }) ); }, }); `; return code; } private compileStep(step: any, indent: number): string { const ind = " ".repeat(indent); // Entity creation (Plain Convex - NO Convex Ents) if (step.entity) { return `${ind}// Create entity using plain Convex ctx.db.insert ${ind}const ${step.output || "entity"} = yield* Effect.promise(() => ${ind} ctx.db.insert("entities", { ${ind} type: "${step.entity.type}", ${ind} name: ${this.compileExpression(step.entity.name)}, ${ind} properties: ${JSON.stringify(step.entity.properties, null, 2).replace(/\n/g, "\n" + ind + " ")}, ${ind} status: "${step.entity.status || "active"}", ${ind} createdAt: Date.now(), ${ind} updatedAt: Date.now(), ${ind} }) ${ind}); `; } // Connection creation (Plain Convex - stores metadata) if (step.connect) { const metadataStr = step.connect.metadata ? JSON.stringify(step.connect.metadata, null, 2).replace( /\n/g, "\n" + ind + " " ) : "undefined"; return `${ind}// Create connection using plain Convex ctx.db.insert ${ind}yield* Effect.promise(() => ${ind} ctx.db.insert("connections", { ${ind} fromEntityId: ${this.compileExpression(step.connect.from)}, ${ind} toEntityId: ${this.compileExpression(step.connect.to)}, ${ind} relationshipType: "${step.connect.type}", ${ind} metadata: ${metadataStr}, ${ind} createdAt: Date.now(), ${ind} }) ${ind}); `; } // Event logging (Plain Convex - stores metadata) if (step.event) { const metadataStr = step.event.metadata ? JSON.stringify(step.event.metadata, null, 2).replace( /\n/g, "\n" + ind + " " ) : "undefined"; return `${ind}// Log event using plain Convex ctx.db.insert ${ind}yield* Effect.promise(() => ${ind} ctx.db.insert("events", { ${ind} entityId: ${this.compileExpression(step.event.entity)}, ${ind} eventType: "${step.event.type}", ${ind} actorId: ${this.compileExpression(step.event.actor || '"system"')}, ${ind} timestamp: Date.now(), ${ind} actorType: "${step.event.actor ? "user" : "system"}", ${ind} metadata: ${metadataStr}, ${ind} }) ${ind}); `; } // Service call if (step.service) { const provider = this.capitalizeFirst(step.service.provider); return `${ind}const ${step.output || "result"} = yield* Effect.gen(function* () { ${ind} const ${step.service.provider} = yield* ${provider}Provider; ${ind} return yield* ${step.service.provider}.${step.service.method}(${JSON.stringify(step.service.params)}); ${ind}})${step.retry ? `.pipe(Effect.retry({ times: ${step.retry.times} }))` : ""}${step.timeout ? `.pipe(Effect.timeout("${step.timeout}"))` : ""}; `; } // Query (Plain Convex - uses ctx.db.query) if (step.query) { return `${ind}// Query using plain Convex ctx.db.query ${ind}const ${step.output || "queryResult"} = yield* Effect.promise(async () => { ${ind} let query = ctx.db.query("${step.query.from}"); ${this.compileQueryFilters(step.query.where || [], indent + 1)} ${step.query.limit ? `${ind} query = query.take(${step.query.limit});` : ""} ${ind} return await query.collect(); ${ind}}); `; } // Conditional if (step.if) { let code = `${ind}if (${this.compileExpression(step.if.condition)}) { `; for (const thenStep of step.if.then) { code += this.compileStep(thenStep, indent + 1); } if (step.if.else) { code += `${ind}} else { `; for (const elseStep of step.if.else) { code += this.compileStep(elseStep, indent + 1); } } code += `${ind}} `; return code; } // Return if (step.return) { return `${ind}return ${JSON.stringify(step.return)}; `; } return `${ind}// Unknown step type `; } private compileExpression(expr: string): string { if (expr.startsWith("$")) { // Variable reference return expr.substring(1).replace(/\./g, "?."); } return `"${expr}"`; } private compileQueryFilters(filters: any[], indent: number): string { const ind = " ".repeat(indent); let code = ""; for (const filter of filters) { // Plain Convex filter syntax (no Convex Ents) code += `${ind}query = query.filter((q) => q.eq(q.field("${filter.field}"), ${this.compileExpression(filter.value)}));\n`; } return code; } private generateInputArgs(input: Record<string, string>): string { // Generate Convex args validator object const args = Object.entries(input) .map(([key, type]) => { const convexType = this.typeToConvexValidator(type); return ` ${key}: ${convexType}`; }) .join(",\n"); return `{\n${args}\n }`; } private typeToConvexValidator(type: string): string { // Map DSL types to Convex validators if (type.includes("Id<")) return "v.id('entities')"; if (type === "string") return "v.string()"; if (type === "number") return "v.number()"; if (type === "boolean") return "v.boolean()"; if (type.includes("[]")) { const innerType = type.replace("[]", ""); return `v.array(${this.typeToConvexValidator(innerType)})`; } return "v.any()"; } private toCamelCase(str: string): string { return str.charAt(0).toLowerCase() + str.slice(1); } private capitalizeFirst(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } } // ============================================================================ // DSL VALIDATOR // Validates DSL against ontology before compilation // ============================================================================ class ONEValidator { private ontology: { entityTypes: string[]; connectionTypes: string[]; // 24 consolidated types eventTypes: string[]; // 38 consolidated types }; constructor(ontology: any) { this.ontology = ontology; } validate(dsl: any): { valid: boolean; errors: string[] } { const errors: string[] = []; // Validate all entity types used exist in ontology this.validateEntities(dsl.flow, errors); // Validate all connection types used exist in ontology this.validateConnections(dsl.flow, errors); // Validate all event types used exist in ontology this.validateEvents(dsl.flow, errors); // Validate metadata patterns for consolidated types this.validateMetadata(dsl.flow, errors); return { valid: errors.length === 0, errors, }; } private validateEntities(flow: any[], errors: string[]): void { for (const step of flow) { if (step.entity && !this.ontology.entityTypes.includes(step.entity.type)) { errors.push( `Invalid entity type: ${step.entity.type}. Must be one of: ${this.ontology.entityTypes.join(", ")}` ); } } } private validateConnections(flow: any[], errors: string[]): void { for (const step of flow) { if ( step.connect && !this.ontology.connectionTypes.includes(step.connect.type) ) { errors.push( `Invalid connection type: ${step.connect.type}. Must be one of 24 consolidated types: ${this.ontology.connectionTypes.join(", ")}` ); } } } private validateEvents(flow: any[], errors: string[]): void { for (const step of flow) { if (step.event && !this.ontology.eventTypes.includes(step.event.type)) { errors.push( `Invalid event type: ${step.event.type}. Must be one of 38 consolidated types: ${this.ontology.eventTypes.join(", ")}` ); } } } private validateMetadata(flow: any[], errors: string[]): void { const consolidatedTypes = { payment: ["subscription", "purchase", "tip", "refund"], livestream: ["hosted", "attended", "moderated", "banned_from"], notification: ["sent", "received", "read"], referral: ["referred", "earned_from"], content: ["created", "published", "edited", "deleted", "viewed", "shared"], }; for (const step of flow) { // Validate connection metadata if (step.connect && step.connect.metadata) { const type = step.connect.type; if (consolidatedTypes[type]) { const metadataType = step.connect.metadata[`${type}Type`]; if ( metadataType && !consolidatedTypes[type].includes(metadataType) ) { errors.push( `Invalid ${type}Type: ${metadataType}. Must be one of: ${consolidatedTypes[type].join(", ")}` ); } } } // Validate event metadata if (step.event && step.event.metadata) { const type = step.event.type; if (consolidatedTypes[type]) { const metadataType = step.event.metadata[`${type}Type`]; if ( metadataType && !consolidatedTypes[type].includes(metadataType) ) { errors.push( `Invalid ${type}Type: ${metadataType}. Must be one of: ${consolidatedTypes[type].join(", ")}` ); } } } } } } // ============================================================================ // USAGE EXAMPLE - Full Ontology with 24+38 Consolidated Types // ============================================================================ /** * Complete ontology with hybrid type strategy */ const FULL_ONTOLOGY = { entityTypes: [ "creator", "ai_clone", "token", "audience_member", "content", "course", "livestream", "subscription", "notification", ], // 25 HYBRID CONNECTION TYPES connectionTypes: [ // Specific Types (18) "owns", "created_by", "clone_of", "trained_on", "powers", "authored", "generated_by", "published_to", "part_of", "references", "member_of", "following", "moderates", "participated_in", "manages", "reports_to", "collaborates_with", "holds_tokens", "staked_in", "earned_from", "purchased", "enrolled_in", "completed", "teaching", // Consolidated Types (7) - use metadata "transacted", // metadata.transactionType + protocol "notified", // metadata.channel + notificationType "referred", // metadata.referralType "communicated", // metadata.protocol + messageType "delegated", // metadata.protocol + taskType "approved", // metadata.approvalType + protocol "fulfilled", // metadata.fulfillmentType + protocol ], // 35 HYBRID EVENT TYPES eventTypes: [ // Specific Types (24) "entity_created", "entity_updated", "entity_deleted", "entity_archived", "user_registered", "user_verified", "user_login", "user_logout", "profile_updated", "clone_created", "clone_updated", "voice_cloned", "appearance_cloned", "agent_created", "agent_executed", "agent_completed", "agent_failed", "token_created", "token_minted", "token_burned", "tokens_purchased", "tokens_staked", "tokens_unstaked", "tokens_transferred", "course_created", "course_enrolled", "lesson_completed", "course_completed", "certificate_earned", "metric_calculated", "insight_generated", "prediction_made", "optimization_applied", "report_generated", // Consolidated Types (11) - use metadata "content_event", // metadata.action + protocol "payment_event", // metadata.status + protocol "subscription_event", // metadata.action "commerce_event", // metadata.eventType + protocol "livestream_event", // metadata.status + metadata.action "notification_event", // metadata.channel + deliveryStatus "referral_event", // metadata.action "communication_event", // metadata.protocol + messageType "task_event", // metadata.action + protocol "mandate_event", // metadata.mandateType + protocol "price_event", // metadata.action ], }; // 1. Define feature in DSL const myFeature = livestreamWithNotificationsDSL; // 2. Validate against full ontology const validator = new ONEValidator(FULL_ONTOLOGY); const validation = validator.validate(myFeature); if (!validation.valid) { console.error("DSL validation failed:", validation.errors); process.exit(1); } // 3. Compile to TypeScript with Plain Convex const compiler = new ONECompiler(); const generatedCode = compiler.compile(myFeature); // 4. Write to file // fs.writeFileSync("convex/features/startLivestream.ts", generatedCode); console.log("Generated Plain Convex code:"); console.log(generatedCode); /** * EXAMPLE OUTPUT - What the compiler generates: * * // Generated from ONE DSL * // Compiles to Plain Convex (NO Convex Ents) + Effect.ts * import { Effect } from "effect"; * import { mutation } from "./_generated/server"; * import { v } from "convex/values"; * * export const startLivestreamWithNotifications = mutation({ * args: { * hostId: v.id('entities'), * title: v.string(), * description: v.string() * }, * handler: async (ctx, args) => { * return await Effect.runPromise( * Effect.gen(function* () { * // Create entity using plain Convex ctx.db.insert * const livestreamId = yield* Effect.promise(() => * ctx.db.insert("entities", { * type: "livestream", * name: args.title, * properties: { ... }, * ... * }) * ); * * // Create connection with metadata * yield* Effect.promise(() => * ctx.db.insert("connections", { * fromEntityId: args.hostId, * toEntityId: livestreamId, * relationshipType: "livestream", * metadata: { * livestreamType: "hosted", * ... * } * }) * ); * // ... rest of generated code * }) * ); * } * }); */ // ============================================================================ // DSL SYNTAX SUMMARY - Plain English vs Technical DSL // ============================================================================ /** * The ONE DSL supports TWO syntax styles: * * 1. PLAIN ENGLISH DSL (Non-technical users) * - Natural language commands * - Example: "Create a token named 'MyToken' with supply 1000000" * - Example: "When user purchases tokens, send them a confirmation email" * * 2. TECHNICAL DSL (Developers and AI agents) * - Structured declarative syntax (shown in this file) * - Type-safe with validation * - Compiles to Effect.ts + Plain Convex * * Both syntaxes are maintained separately but compile to the same output. * * WHY TWO SYNTAXES? * - Plain English: For product managers, designers, non-technical stakeholders * - Technical DSL: For developers, AI agents who need precision and type safety * * CURRENT STATUS: * - Technical DSL: Fully specified in this file * - Plain English DSL: Defined in separate documentation * - Both will be implemented in the compiler */ // ============================================================================ // KEY ARCHITECTURAL DECISIONS // ============================================================================ /** * 1. PLAIN CONVEX (NO CONVEX ENTS) * - Uses defineTable() not ent() * - Manual relationship queries * - More explicit, easier for AI agents * - Better for metadata-based patterns * * 2. 25 HYBRID CONNECTION TYPES * - 18 specific semantic types for core domain * - 7 consolidated types with metadata variants * - Protocol-agnostic via metadata.protocol * - Simpler queries, better AI comprehension * * 3. 35 HYBRID EVENT TYPES * - 24 specific types for core domain events * - 11 consolidated types with metadata variants * - Protocol identification via metadata * - Balance between specificity and flexibility * * 4. METADATA-BASED PATTERNS * - Consolidated types use metadata for variants * - Protocol identity in metadata.protocol * - Reduces schema complexity * - Maintains queryability * - Flexible for future protocols * * 5. EFFECT.TS INTEGRATION * - All compiled code uses Effect.ts * - Composable, type-safe operations * - Standardized error handling * - Better testability * * 6. VALIDATOR WITH METADATA CHECKING * - Validates base types (24 connections, 38 events) * - Validates metadata patterns for consolidated types * - Ensures type safety before compilation * - Prevents invalid metadata.typeType values */ // ============================================================================ // NEXT STEPS FOR IMPLEMENTATION // ============================================================================ /** * 1. Implement Plain English parser * - Parse natural language to Technical DSL AST * - Use LLM for intent extraction * - Map to Technical DSL constructs * * 2. Complete compiler implementation * - Add support for all DSL primitives * - Generate Effect.ts code * - Generate plain Convex mutations/queries * - Add error handling and retry logic * * 3. Add schema generator * - Generate Convex schema from DSL features * - Create indices based on query patterns * - Generate TypeScript types * * 4. Build testing infrastructure * - DSL validator tests * - Compiler output tests * - Generated code integration tests * * 5. Create developer tools * - VS Code extension for DSL syntax * - Real-time validation * - Auto-completion * - DSL playground */