System diagram
Data flow
User describes an app
The user types or speaks a description in
VibraCreateAppScreen. The mobile app calls the backend API (POST /api/create-session) with the prompt, chosen template, and any attached images or audio.Session created in Convex
The backend creates a
sessions record in Convex with status IN_PROGRESS. The mobile app subscribes to this session via Convex’s real-time client — any future status change streams to the phone immediately.Inngest queues sandbox creation
The backend triggers an Inngest event that queues the
create-session function. Inngest handles retries, timeouts, and fan-out, so the Next.js request returns immediately without waiting for the sandbox to be ready.E2B sandbox starts and clones the template
The
create-session Inngest function spawns an E2B sandbox from the pre-built template image. Inside the sandbox, the Expo template repository is cloned, npm dependencies are installed, the Expo dev server is started, and a public tunnel URL is created. The session status in Convex advances through each phase:IN_PROGRESS → CLONING_REPO → INSTALLING_DEPENDENCIES → STARTING_DEV_SERVER → CREATING_TUNNEL → RUNNINGAI agent generates code
Once the sandbox is ready, Inngest runs the
run-agent function. The AI agent (Claude Code, Cursor, or Gemini — configured by AGENT_TYPE) reads the user’s prompt and system prompt from lib/prompts.ts, then writes, edits, and runs files inside the sandbox. Every tool operation (file read, file edit, bash command) is written to the messages table in Convex as it happens.Updates stream to the phone in real time
The mobile app’s Convex subscription receives each new
messages record the moment it is written. The native chat UI (built with Texture + IGListKit) renders each message type in a different cell: blue for file reads, orange for file edits, green for bash commands, and Liquid Glass cards for todo task lists.Phone previews the running app via tunnel URL
When the tunnel URL is available in the
sessions record, the mobile app loads the live preview. For Expo React Native templates, the preview renders natively. For Next.js and other web templates, a WKWebView is used. The user can send follow-up messages to the same session — the agent resumes in the existing sandbox without re-cloning.Backend stack
| Component | Technology | Purpose |
|---|---|---|
| API server | Next.js 15 (App Router) | Handles client requests, webhooks, and server actions |
| Real-time database | Convex | Stores sessions, messages, and users; streams changes to clients |
| Background jobs | Inngest | Queues and runs create-session, run-agent, and push-to-github |
| Cloud sandboxes | E2B | Isolated environments for code generation and execution |
| AI agent | Claude Agent SDK / Cursor / Gemini CLI | Writes and edits project files inside the sandbox |
| Auth | Clerk | User identity for both backend and mobile app |
| Payments | Stripe (web) + RevenueCat (mobile) | Optional subscription billing |
Mobile stack
| Component | Technology | Purpose |
|---|---|---|
| Runtime | React Native / Expo SDK 54 | Cross-platform native mobile foundation |
| Auth | Clerk | Shared with backend; same user identity |
| Real-time sync | Convex | Symlinked schema from backend; subscribes to sessions and messages |
| Chat UI | Texture (AsyncDisplayKit) + IGListKit | 60 fps off-main-thread rendering |
| Navigation | React Navigation | Stack + bottom tab navigator (Home, Create, Profile) |
| In-app purchases | RevenueCat | Optional mobile subscription management |
Convex schema overview
The Convex database is shared between the backend and mobile app. The mobileconvex/ directory is a symlink to vibracode-backend/convex/.
users table
Stores Clerk user profiles alongside billing and credit state.
| Field | Type | Description |
|---|---|---|
clerkId | string | Primary identifier from Clerk |
subscriptionPlan | string | free, weekly_plus, pro, business, enterprise |
billingMode | tokens | credits | Token mode for Cursor agent; credit mode for Claude agent |
creditsUSD | number | Available credits (Claude agent, 2× multiplier of real cost) |
messagesRemaining | number | Messages remaining this period (Cursor/token mode) |
agentType | claude | cursor | gemini | Per-user agent override |
pushToken | string | Expo push token for notifications |
sessions table
Each build is one session. The session record tracks the full lifecycle from sandbox creation to completion.
| Field | Type | Description |
|---|---|---|
name | string | App name provided by the user |
templateId | string | Which template was used (expo, nextjs, etc.) |
status | union | Current phase — see session status lifecycle below |
tunnelUrl | string | Public preview URL from the sandbox tunnel |
totalCostUSD | number | Accumulated AI API cost for this session |
envs | record | Environment variables injected into the sandbox |
githubRepository | string | Populated after a GitHub push (owner/repo) |
messages table
Every agent action and user message is stored as a messages record. The mobile chat UI reads these in real time.
| Field | Type | Description |
|---|---|---|
sessionId | ID | Reference to the parent session |
role | user | assistant | Who sent this message |
content | string | Text content of the message |
edits | object | File path, old string, new string (for edit operations) |
bash | object | Command, output, and exit code (for bash operations) |
read | object | File path (for file read operations) |
todos | array | Task list items with status and priority |
costUSD | number | API cost for this message |
modelUsed | string | Model identifier (e.g., claude-sonnet-4-20250514) |
Session status lifecycle
A session advances through the following statuses as the sandbox is created and the agent runs. All transitions are written to Convex and stream to the mobile app in real time.CUSTOM status is used when the agent sends a status message of its own (for example, “Building the authentication flow”). Additional statuses (CREATING_GITHUB_REPO, PUSHING_TO_GITHUB, PUSH_COMPLETE) are used during the optional GitHub push flow.
Project structure
Ready to set up your own instance? Follow the quick start to get the backend and mobile app running end to end.