> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vibely.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Mode Overview

> How Vibely turns a natural-language prompt into a running web or mobile app

Build mode is the path that takes a user prompt all the way to a live preview URL. There is **one** while loop, **one** agent, and **one** flat message history — Claude Code style. Everything else orbits this.

<Frame>
  <img src="https://cdn.vibely.sh/doc/v1/engine-overview.webp" alt="Build Mode Overview" width="1200" height="675" />
</Frame>

## Request lifecycle

```
SSE / WS request
  └─ src/routes/vibe.ts
       └─ handleVibeStream()                        src/orchestrator/orchestrator.ts
            ├─ credit / budget / entitlement gates
            ├─ resolve provider + model
            ├─ get-or-create sandbox                (WorkspaceManager.getOrCreate)
            ├─ restore project files from DB
            ├─ start dev server EARLY → emit preview_url
            └─ run agent loop                       src/agent/agent-loop.ts
                  while turnCount < maxTurns:
                    streamText({ maxSteps: 1, tools, messages })
                    execute returned tool-calls in Promise.all
                    yield events (text, tool-call, file_streaming_chunk, …)
                    route up at 75 % context, compact at 90 %
                    self-heal at most 3× per error
```

The dev server is started by the orchestrator **before** the agent ever runs. The system prompt asserts to the model that the dev server is already up — that promise is load-bearing for HMR timing, which is why `bash` short-circuits any `npm run dev` the model tries to issue.

## Two project types

| Type | Template | Platform | Build pipeline |
| - | - | - | - |
| `web` | `vibely-web` (Vite + React) | web | Vite dev server, port 8080 |
| `mobile` | `vibely-expo` (Expo) | mobile | Expo / Metro, web preview |

Project type is locked at session creation — it picks the sandbox template image, the system prompt variant, and which tools are registered.

## Hard rules (load-bearing — don't "simplify")

1. **One while loop, one agent.** The build loop is a single agent, not a swarm — parallel tool calls go through `Promise.all`. The one delegation that exists is bounded and read-only: `spawn_subagent` hands an investigation to up to four research agents that cannot write. See [Subagents](/features/agent/subagents).
2. **Stream everything** — tool-call start, file write chunks, thinking, status.
3. **`ask_user`** stores a `resolve` and fires when the frontend POSTs `/vibe/answer`.
4. **Route to a larger-context model at 75 %, compact at 90 %.** Compacting earlier thrashes memory; later trips provider context-overflow rejections.
5. **`.mana/memory.md`** survives compaction — it lives on disk in the sandbox.
6. **3-attempt cap per error** in self-heal. Past that, the error surfaces.
7. **No placeholder text.** Real content only.
8. **Templates come from GitHub via `git clone --depth 1`.**
9. **Dev server is started by the orchestrator, not the agent.** `bash` short-circuits `npm run dev`.
10. **`toolCalls.clear()` fires on `finish_reason` of `"tool_calls"` OR `"stop"`** — some providers send tool calls with `stop`.
11. **Failover only activates for the default provider.** Explicitly chosen models are not silently swapped on failure.

## Where to look first when something breaks

| Symptom | Start |
| - | - |
| Agent runs but writes no files | `provider-options.ts` (reasoning\_effort), `agent-loop.ts` empty-retry |
| Preview URL never arrives | `orchestrator.ts` early-preview block, `preview-manager.ts:startDevServer` |
| Preview arrives but iframe blank | `cloudflare/worker.js` header stripping, `preview-manager.ts:detectPort` |
| Tool call ignored after returning | `src/ai/stream-text.ts` message append, `provider.ts` `buildMessages` |
| "Sandbox not found" mid-run | Auto-recovery in `tools/registry.ts` — check logs for the retry |
| 401 on a previously-working route | `middleware/auth-exempt.ts` (`isAuthExempt`), `config/supabase.ts` JWT parse |
| SSE dies at \~30 s | Keep-alive comment in `routes/vibe.ts`; check the proxy in front |
| Queue mode events not reaching client | Redis pub/sub channel in `src/queue/` + relay generator in `routes/vibe.ts` |


## Related topics

- [Implement changes in Build mode](/features/agent/build-mode.md)
- [Iterate](/features/web-apps/iterate.md)
- [Dashboard overview](/introduction/dashboard.md)
- [Plan a change in Plan mode](/features/agent/plan-mode.md)
- [API Overview](/api-reference/overview.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.