| layout | default |
|---|---|
| title | Chapter 2: System Architecture |
| nav_order | 2 |
| parent | VibeSDK Tutorial |
Welcome to Chapter 2: System Architecture. In this part of VibeSDK Tutorial: Build a Vibe-Coding Platform on Cloudflare, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.
VibeSDK combines a React frontend, Worker API plane, Durable Object orchestration, and Cloudflare-managed infrastructure into one app-generation platform.
By the end of this chapter, you should be able to:
- explain how user requests become generated/deployed applications
- identify where state lives across the platform
- distinguish responsibilities between API, orchestration, and runtime layers
- navigate the main code locations confidently
graph TD
U[User] --> FE[React + Vite Frontend]
FE --> API[Cloudflare Worker API Router]
API --> AG[Code Generator Agent DO]
AG --> AI[AI Gateway and Providers]
AG --> SB[Sandbox Service]
API --> D1[D1]
API --> KV[KV]
API --> R2[R2]
| Layer | Core Responsibilities | Typical Code Locations |
|---|---|---|
| frontend | prompt input, live status UI, preview controls, auth UX | src/ |
| API plane | request auth, routing, app/session endpoints | worker/api/, worker/app.ts |
| orchestration | phase engine, generation loops, state transitions | worker/agents/ |
| data and infra | relational state, cache/session data, artifacts, runtime bindings | wrangler.jsonc, D1/KV/R2 bindings |
| execution runtime | preview container lifecycle, deployment actions | sandbox and dispatch service paths |
Generation sessions need ordered, stateful, resumable execution. Durable Objects provide per-session state and deterministic event handling so VibeSDK can support long-lived agent workflows without forcing fragile client-side orchestration.
- user submits prompt from frontend
- API validates identity/session and routes to agent
- Durable Object agent runs blueprint and phase logic
- model calls route through AI Gateway/provider config
- generated output is assembled and sent to sandbox runtime
- preview/deploy events stream back to UI in real time
| State Type | Where It Lives | Why It Matters |
|---|---|---|
| user/app metadata | D1 | source of truth for account and app records |
| session/transient keys | KV | fast lookups and ephemeral coordination |
| generated assets/templates | R2 | persistent artifact storage and handoff |
| in-flight generation state | Durable Object state | continuity for active build sessions |
worker/agents/for orchestration internalsworker/api/for control-plane contractsworker/agents/inferutils/config.tsfor model routing setupwrangler.jsoncfor Cloudflare binding topologysrc/for frontend event and status handling
Before extending the platform, verify:
- where new state should persist (D1 vs KV vs DO vs R2)
- whether the change belongs in API plane or agent orchestration
- how failures will surface back to user-facing status
- whether new dependencies alter deployment or permission requirements
You now have a clear system map for VibeSDK and can reason about where to implement changes without cross-layer confusion.
Next: Chapter 3: AI Pipeline and Phase Engine
The SafeCleanup class in container/cli-tools.ts handles a key part of this chapter's functionality:
}
class SafeCleanup {
/**
* Safely close storage manager.
* Storage.close() is synchronous, so we just wrap it in try-catch.
*/
static closeStorage(storage: StorageManager | null): void {
if (!storage) return;
try {
storage.close();
} catch (error) {
console.warn('Storage close error:', error);
// Don't throw - we're in cleanup
}
}
}
class OutputFormatter {
static formatOutput(data: unknown, format: 'json' | 'table' | 'raw' = 'json'): void {
switch (format) {
case 'json':
console.log(SafeJSON.stringify(data, 2));
break;
case 'raw':
if (typeof data === 'string') {
console.log(data);
} else {
console.log(String(data));
}
break;This class is important because it defines how VibeSDK Tutorial: Build a Vibe-Coding Platform on Cloudflare implements the patterns covered in this chapter.
The OutputFormatter class in container/cli-tools.ts handles a key part of this chapter's functionality:
}
class OutputFormatter {
static formatOutput(data: unknown, format: 'json' | 'table' | 'raw' = 'json'): void {
switch (format) {
case 'json':
console.log(SafeJSON.stringify(data, 2));
break;
case 'raw':
if (typeof data === 'string') {
console.log(data);
} else {
console.log(String(data));
}
break;
case 'table':
// Table formatting is handled by specific formatters
console.log(SafeJSON.stringify(data, 2));
break;
}
}
static formatError(error: string, additionalData?: Record<string, unknown>): void {
const errorResponse = {
success: false,
error,
...additionalData
};
console.log(SafeJSON.stringify(errorResponse, 2));
}
static formatSuccess(message: string, data?: unknown): void {This class is important because it defines how VibeSDK Tutorial: Build a Vibe-Coding Platform on Cloudflare implements the patterns covered in this chapter.
The ProcessCommands class in container/cli-tools.ts handles a key part of this chapter's functionality:
}
class ProcessCommands {
private static activeRunners = new Map<string, ProcessRunner>();
static async start(options: {
instanceId: string;
command: string;
args: string[];
cwd?: string;
port?: string;
healthCheckInterval?: number;
maxRestarts?: number;
restartDelay?: number;
maxErrors?: number;
retentionDays?: number;
logRetentionHours?: number;
}): Promise<void> {
try {
// Check if already running
if (this.activeRunners.has(options.instanceId)) {
OutputFormatter.formatError(`Process ${options.instanceId} is already running`);
process.exit(1);
}
// Set PORT environment variable if provided
if (options.port) {
process.env.PORT = options.port;
}
// Build configuration
const envVars: Record<string, string> = {};This class is important because it defines how VibeSDK Tutorial: Build a Vibe-Coding Platform on Cloudflare implements the patterns covered in this chapter.
The ProcessRunner class in container/cli-tools.ts handles a key part of this chapter's functionality:
import { ProcessMonitor } from './process-monitor.js';
import {
ProcessRunnerConfig,
ProcessInfo,
MonitoringOptions,
LogStoreOptions as LogStoreOptionsType,
ErrorStoreOptions as ErrorStoreOptionsType,
LogFilter,
LogCursor,
LogLevel,
StoredError,
StoredLog,
SimpleError,
Result,
DEFAULT_MONITORING_OPTIONS,
DEFAULT_STORAGE_OPTIONS,
DEFAULT_LOG_STORE_OPTIONS,
getDataDirectory,
getErrorDbPath,
getLogDbPath
} from './types.js';
// Instance ID validation pattern - alphanumeric with dashes and underscores
const INSTANCE_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
const MAX_INSTANCE_ID_LENGTH = 64;
/**
* Validate instance ID format to prevent path traversal and other issues
*/
function validateInstanceId(id: string): void {
if (!id || id.length === 0) {
throw new Error('Instance ID is required');This class is important because it defines how VibeSDK Tutorial: Build a Vibe-Coding Platform on Cloudflare implements the patterns covered in this chapter.
flowchart TD
A[SafeCleanup]
B[OutputFormatter]
C[ProcessCommands]
D[ProcessRunner]
E[ErrorCommands]
A --> B
B --> C
C --> D
D --> E