Setup and context — Topics in Part 2
Part 1 covered Antigravity fundamentals. Part 2 focuses on production environment complexity, sophisticated system design, and business strategies. Learn advanced implementation patterns essential for real-world work through specific code examples.
Multi-Agent Orchestration Design
Coordinate multiple agents efficiently with clear design patterns.
Router Pattern (TypeScript)
A "router" manages multiple agents, assigning tasks to optimal agents by type.
Architecture
Request
↓
Agent Router (classify)
├→ Frontend Agent (UI)
├→ Backend Agent (API)
├→ Data Agent (DB)
└→ Infra Agent (DevOps)
Implementation
// lib/agent-router.ts
import type { AgentType, Task, TaskResult } from '@/types';
interface AgentConfig {
name: AgentType;
keywords: string[];
filePatterns: RegExp[];
maxConcurrent: number;
}
const AGENT_CONFIGS: AgentConfig[] = [
{
name: 'frontend',
keywords: ['component', 'ui', 'page', 'styled'],
filePatterns: [/src\/(components|app|pages)\//, /\.tsx?$/],
maxConcurrent: 2,
},
{
name: 'backend',
keywords: ['api', 'endpoint', 'database', 'query'],
filePatterns: [/src\/(api|server|db)\//, /route\.(ts|js)$/],
maxConcurrent: 3,
},
{
name: 'data',
keywords: ['migration', 'schema', 'index', 'optimize'],
filePatterns: [/migrations\//, /schema\.(sql|ts)$/],
maxConcurrent: 1,
},
{
name: 'infra',
keywords: ['deploy', 'ci', 'github', 'docker'],
filePatterns: [/\.github/, /dockerfile/i, /\.env/i],
maxConcurrent: 1,
},
];
export class AgentRouter {
private activeAgents: Map<AgentType, number> = new Map();
constructor() {
AGENT_CONFIGS.forEach(config => {
this.activeAgents.set(config.name, 0);
});
}
routeTask(task: Task): AgentType {
// Extract keywords from task description
const taskLower = task.description.toLowerCase();
const matchedAgents = AGENT_CONFIGS
.filter(config =>
config.keywords.some(kw => taskLower.includes(kw)) ||
config.filePatterns.some(pattern =>
task.affectedFiles?.some(f => pattern.test(f))
)
);
if (matchedAgents.length === 0) {
// Default to frontend
return 'frontend';
}
// Select agent with lowest load
let selectedAgent = matchedAgents[0];
for (const agent of matchedAgents) {
const current = this.activeAgents.get(agent.name) || 0;
const selected = this.activeAgents.get(selectedAgent.name) || 0;
if (current < selected) {
selectedAgent = agent;
}
}
return selectedAgent.name;
}
async executeTask(task: Task): Promise<TaskResult> {
const agentType = this.routeTask(task);
const current = this.activeAgents.get(agentType) || 0;
// Check connection limits
const config = AGENT_CONFIGS.find(c => c.name === agentType)!;
if (current >= config.maxConcurrent) {
throw new Error(
`Agent ${agentType} at max capacity (${config.maxConcurrent})`
);
}
// Start execution
this.activeAgents.set(agentType, current + 1);
try {
const result = await this.sendToAgent(agentType, task);
return result;
} finally {
this.activeAgents.set(agentType, current);
}
}
private async sendToAgent(
agentType: AgentType,
task: Task
): Promise<TaskResult> {
// Call Antigravity Agent API
const response = await fetch('/api/agents/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ agentType, task }),
});
return response.json();
}
}Pipeline Pattern (TypeScript)
Execute a series of steps sequentially, each using a different agent.
Example: SaaS Deploy Pipeline
// lib/deployment-pipeline.ts
interface PipelineStep {
name: string;
agent: AgentType;
dependencies: string[];
execute: (context: PipelineContext) => Promise<void>;
}
interface PipelineContext {
commitHash: string;
environment: 'staging' | 'production';
artifacts: Map<string, any>;
}
export class DeploymentPipeline {
private steps: PipelineStep[] = [
{
name: 'lint',
agent: 'frontend',
dependencies: [],
execute: async (ctx) => {
console.log('Linting code...');
// Frontend Agent runs ESLint/Prettier
ctx.artifacts.set('lint-report', { status: 'pass' });
},
},
{
name: 'test',
agent: 'frontend',
dependencies: ['lint'],
execute: async (ctx) => {
console.log('Running tests...');
// Frontend Agent runs Jest
ctx.artifacts.set('test-coverage', { percent: 87 });
},
},
{
name: 'build-frontend',
agent: 'frontend',
dependencies: ['test'],
execute: async (ctx) => {
console.log('Building frontend...');
// Frontend Agent builds Next.js
ctx.artifacts.set('frontend-bundle', { size: '2.3MB' });
},
},
{
name: 'build-backend',
agent: 'backend',
dependencies: [],
execute: async (ctx) => {
console.log('Building backend...');
// Backend Agent builds Node.js
ctx.artifacts.set('backend-bundle', { size: '1.8MB' });
},
},
{
name: 'db-migration',
agent: 'data',
dependencies: [],
execute: async (ctx) => {
console.log('Running database migrations...');
// Data Agent executes DB migration
ctx.artifacts.set('migration-status', { applied: 3 });
},
},
{
name: 'deploy',
agent: 'infra',
dependencies: [
'build-frontend',
'build-backend',
'db-migration',
],
execute: async (ctx) => {
console.log('Deploying to cloud...');
// Infra Agent deploys to Vercel/Render
ctx.artifacts.set('deploy-status', {
url: 'https://staging.app.com',
time: '3m 45s',
});
},
},
{
name: 'e2e-test',
agent: 'frontend',
dependencies: ['deploy'],
execute: async (ctx) => {
console.log('Running E2E tests...');
// Frontend Agent runs Playwright
ctx.artifacts.set('e2e-result', { passed: 45, failed: 0 });
},
},
];
async run(commitHash: string, environment: 'staging' | 'production') {
const context: PipelineContext = {
commitHash,
environment,
artifacts: new Map(),
};
const completed = new Set<string>();
for (const step of this.steps) {
// Wait for dependencies
while (!step.dependencies.every(dep => completed.has(dep))) {
await new Promise(r => setTimeout(r, 100));
}
try {
await step.execute(context);
completed.add(step.name);
console.log(`✓ ${step.name} completed by ${step.agent}`);
} catch (error) {
console.error(`✗ ${step.name} failed:`, error);
throw error;
}
}
return context;
}
}Browser Sub-Agent E2E Test Automation
Auto-generate and run complex E2E tests with Playwright + Browser Sub-Agent.
// tests/e2e/checkout.spec.ts
import { test, expect } from '@playwright/test';
test('complete checkout flow', async ({ page }) => {
// Auto-generated by Browser Sub-Agent
// Step 1: Login
await page.goto('/login');
await page.fill('input[name="email"]', 'user@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await page.waitForNavigation();
// Step 2: Add to cart
await page.goto('/products');
await page.click('text=Add to Cart');
await expect(page).toHaveURL('/cart');
// Step 3: Checkout
await page.click('button:has-text("Proceed to Checkout")');
// Step 4: Enter shipping info
await page.fill('input[name="address"]', '123 Main St');
await page.select('select[name="country"]', 'US');
// Step 5: Payment
await page.click('text=Pay with Stripe');
// Auto-fill card in Stripe iframe
// Step 6: Confirm
await expect(page).toHaveURL('/order-confirmation');
await expect(page).toContainText('Thank you for your order');
});Production App Development
SwiftUI + CloudKit iCloud Sync App
iOS app with automatic iCloud synchronization.
// Models/Note.swift
import Foundation
import CloudKit
struct Note: Identifiable {
let id: UUID
var title: String
var content: String
var modifiedDate: Date
// CloudKit integration
var cloudKitRecord: CKRecord?
func toCKRecord() -> CKRecord {
let record = CKRecord(recordType: "Note", recordID: CKRecordID(recordName: id.uuidString))
record["title"] = title
record["content"] = content
record["modifiedDate"] = modifiedDate
return record
}
static func fromCKRecord(_ record: CKRecord) -> Note {
return Note(
id: UUID(uuidString: record.recordID.recordName) ?? UUID(),
title: record["title"] as? String ?? "",
content: record["content"] as? String ?? "",
modifiedDate: record["modifiedDate"] as? Date ?? Date(),
cloudKitRecord: record
)
}
}// ViewModels/NoteViewModel.swift
import CloudKit
import Observation
@Observable
class NoteViewModel {
var notes: [Note] = []
var isLoading = false
private let database = CKContainer.default().publicCloudDatabase
@MainActor
func fetchNotes() async {
isLoading = true
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "Note", predicate: predicate)
do {
let records = try await database.records(matching: query)
notes = records.compactMap { Note.fromCKRecord($0) }
} catch {
print("Error fetching notes: \(error)")
}
isLoading = false
}
@MainActor
func saveNote(_ note: Note) async {
let record = note.toCKRecord()
do {
_ = try await database.save(record)
if let index = notes.firstIndex(where: { $0.id == note.id }) {
notes[index] = Note.fromCKRecord(record)
} else {
notes.append(Note.fromCKRecord(record))
}
} catch {
print("Error saving note: \(error)")
}
}
}Android Jetpack Compose + MVI Architecture
Latest Android best practices implementation.
// mvi/PostIntent.kt
sealed class PostIntent {
data class LoadPosts(val page: Int) : PostIntent()
data class RefreshPosts : PostIntent()
data class DeletePost(val id: String) : PostIntent()
data class FavoritePost(val id: String) : PostIntent()
}// mvi/PostViewState.kt
data class PostViewState(
val posts: List<Post> = emptyList(),
val isLoading: Boolean = false,
val error: String? = null,
val selectedPost: Post? = null,
)// mvi/PostViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
class PostViewModel(
private val postRepository: PostRepository
) : ViewModel() {
private val intentFlow = MutableSharedFlow<PostIntent>()
val viewState: StateFlow<PostViewState> = intentFlow
.scan(PostViewState()) { state, intent ->
when (intent) {
is PostIntent.LoadPosts -> {
state.copy(isLoading = true)
}
is PostIntent.RefreshPosts -> {
state.copy(isLoading = true)
}
is PostIntent.DeletePost -> {
state.copy(
posts = state.posts.filter { it.id != intent.id }
)
}
is PostIntent.FavoritePost -> {
state.copy(
posts = state.posts.map { post ->
if (post.id == intent.id) {
post.copy(isFavorite = !post.isFavorite)
} else post
}
)
}
}
}
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
PostViewState()
)
fun sendIntent(intent: PostIntent) {
viewModelScope.launch {
intentFlow.emit(intent)
}
}
}// ui/PostScreen.kt
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
@Composable
fun PostScreen(viewModel: PostViewModel) {
val state by viewModel.viewState.collectAsState()
LaunchedEffect(Unit) {
viewModel.sendIntent(PostIntent.LoadPosts(1))
}
when {
state.isLoading -> {
CircularProgressIndicator()
}
state.error != null -> {
Text("Error: ${state.error}")
}
else -> {
LazyColumn {
items(state.posts.size) { index ->
PostItem(
post = state.posts[index],
onDelete = {
viewModel.sendIntent(PostIntent.DeletePost(state.posts[index].id))
},
onFavorite = {
viewModel.sendIntent(PostIntent.FavoritePost(state.posts[index].id))
}
)
}
}
}
}
}Cloudflare Workers AI Edge AI App
Low-latency AI via Cloudflare Workers integration.
// src/index.ts (Cloudflare Worker)
import { Hono } from 'hono';
const app = new Hono();
interface AIRequest {
prompt: string;
maxTokens?: number;
}
app.post('/api/ai/generate', async (c) => {
const { prompt, maxTokens = 100 } = await c.req.json<AIRequest>();
// @ts-ignore - Cloudflare Workers AI API
const response = await c.env.AI.run('@cf/mistral/mistral-7b-instruct-v0.1', {
prompt,
max_tokens: maxTokens,
});
return c.json({
prompt,
generated: response.response,
model: '@cf/mistral/mistral-7b-instruct-v0.1',
});
});
app.post('/api/ai/classify', async (c) => {
const { text } = await c.req.json();
// Sentiment analysis
const sentiment = await c.env.AI.run('@cf/huggingface/distilbert-sst-2-en', {
text,
});
return c.json({
text,
sentiment: sentiment.result,
});
});
export default app;Custom MCP Server Development
Build custom tools for Antigravity.
TypeScript MCP Server
// mcp-server/src/index.ts
import Anthropic from '@anthropic-ai/sdk';
interface Tool {
name: string;
description: string;
inputSchema: {
type: string;
properties: Record<string, any>;
required: string[];
};
}
interface Resource {
uri: string;
name: string;
mimeType: string;
description: string;
}
class CustomMCPServer {
private tools: Tool[] = [
{
name: 'fetch_analytics',
description: 'Fetch analytics from company dashboard',
inputSchema: {
type: 'object',
properties: {
metric: {
type: 'string',
description: 'Metric: revenue, users, retention',
},
period: {
type: 'string',
description: 'Period: daily, weekly, monthly',
},
},
required: ['metric', 'period'],
},
},
{
name: 'list_deployments',
description: 'List recent cloud deployments',
inputSchema: {
type: 'object',
properties: {
environment: {
type: 'string',
enum: ['staging', 'production'],
},
limit: {
type: 'number',
description: 'Max deployments to return',
},
},
required: ['environment'],
},
},
];
private resources: Resource[] = [
{
uri: 'internal://company/design-system',
name: 'Design System',
mimeType: 'text/markdown',
description: 'Company design system and components',
},
{
uri: 'internal://company/api-spec',
name: 'API Specification',
mimeType: 'application/json',
description: 'OpenAPI spec for company APIs',
},
];
async listTools(): Promise<Tool[]> {
return this.tools;
}
async listResources(): Promise<Resource[]> {
return this.resources;
}
async callTool(
toolName: string,
params: Record<string, string | number>
): Promise<string> {
switch (toolName) {
case 'fetch_analytics':
return this.fetchAnalytics(params);
case 'list_deployments':
return this.listDeployments(params);
default:
throw new Error(`Unknown tool: ${toolName}`);
}
}
private async fetchAnalytics(params: Record<string, string | number>) {
const { metric, period } = params;
// Call analytics dashboard API
const response = await fetch('https://analytics.company.com/api/metrics', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.ANALYTICS_API_KEY}` },
body: JSON.stringify({ metric, period }),
});
const data = await response.json();
return JSON.stringify(data);
}
private async listDeployments(params: Record<string, string | number>) {
const { environment, limit = 10 } = params;
// Call deploy history API
const response = await fetch(
`https://deploy.company.com/api/deployments?env=${environment}&limit=${limit}`,
{
headers: { Authorization: `Bearer ${process.env.DEPLOY_API_KEY}` },
}
);
const data = await response.json();
return JSON.stringify(data);
}
}
// Start server
const server = new CustomMCPServer();
// REST API endpoints
import express from 'express';
const app = express();
app.post('/mcp/tools', async (req, res) => {
res.json({ tools: await server.listTools() });
});
app.post('/mcp/resources', async (req, res) => {
res.json({ resources: await server.listResources() });
});
app.post('/mcp/call', async (req, res) => {
try {
const { tool, params } = req.body;
const result = await server.callTool(tool, params);
res.json({ result });
} catch (error) {
res.status(400).json({ error: (error as Error).message });
}
});
app.listen(3001, () => {
console.log('MCP Server listening on port 3001');
});SaaS Monetization Pipeline
Antigravity × Stripe Full-Stack SaaS
// app/api/stripe/create-subscription.ts
import Stripe from 'stripe';
import { supabaseAdmin } from '@/lib/supabase';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { userId, priceId } = await req.json();
// 1. Get or create Stripe customer
const { data: user } = await supabaseAdmin
.from('users')
.select('stripe_customer_id, email')
.eq('id', userId)
.single();
let customerId = user?.stripe_customer_id;
if (!customerId) {
const customer = await stripe.customers.create({
email: user.email,
metadata: { userId },
});
customerId = customer.id;
await supabaseAdmin
.from('users')
.update({ stripe_customer_id: customerId })
.eq('id', userId);
}
// 2. Create subscription
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
});
// 3. Record in Supabase
await supabaseAdmin
.from('subscriptions')
.insert({
user_id: userId,
stripe_subscription_id: subscription.id,
status: subscription.status,
current_period_end: new Date(subscription.current_period_end * 1000),
});
return new Response(JSON.stringify(subscription), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}YouTube Tutorial Video Auto-Production
Antigravity auto-generates YouTube scripts and cutting instructions.
// scripts/generate-tutorial.ts
import { Anthropic } from '@anthropic-ai/sdk';
const client = new Anthropic();
async function generateYouTubeTutorial(topic: string): Promise<string> {
const message = await client.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 4000,
messages: [
{
role: 'user',
content: `
Generate YouTube tutorial video script.
Topic: ${topic}
Target: Beginner to intermediate
Duration: 10 minutes
Format:
[Scene 1]
Time: 0:00-0:30
Narration: ...
Visual: ...
[Scene 2]
...
`,
},
],
});
return message.content[0].type === 'text' ? message.content[0].text : '';
}
// Execution
const script = await generateYouTubeTutorial(
'Multi-Agent Development with Antigravity'
);
console.log(script);Kindle Technical Book Efficient Writing
// scripts/generate-ebook.ts
interface EbookChapter {
title: string;
sections: {
heading: string;
content: string;
}[];
}
async function generateEbookChapter(chapterTopic: string): Promise<EbookChapter> {
const response = await fetch('/api/ai/generate', {
method: 'POST',
body: JSON.stringify({
prompt: `
Write Kindle technical book chapter.
Chapter: ${chapterTopic}
Style: Technical, practical, code examples included
Length: 3000-4000 words
Sections:
1. Overview
2. Fundamentals
3. Implementation (with code)
4. Best Practices
5. FAQ
`,
}),
});
const data = (await response.json()) as { generated: string };
// Parse Markdown to structured format
return parseMarkdownToChapter(data.generated);
}
function parseMarkdownToChapter(markdown: string): EbookChapter {
// Markdown → structured data conversion
return {
title: 'Chapter Title',
sections: [],
};
}Summary — Related Premium Articles
Part 2 taught production-level development technology with Antigravity.
Next Premium Article Series
- "Multi-Agent System Design Pattern Collection"
- "Production iOS/Android App Operations Techniques"
- "Achieving Rapid SaaS Growth with AI Automation"
- "Writing Kindle Bestsellers with Antigravity"
Join Antigravity Lab Premium to experience cutting-edge AI-driven development.