# cloudflare/vibesdk

> Self-hostable prompt-to-app platform on Cloudflare Workers; a Durable Object agent writes, deploys and previews whole web apps.

- Category: [Open-source coding agents](https://llms-technical-reviews.com/coding-agents/)
- Repository: https://github.com/cloudflare/vibesdk (reviewed at commit `9da158d82c597a0e8f4bf033cdccd1053fb6fb15`, 2026-09-07)
- Stars: 5398 · Language: TypeScript · License: MIT
- Canonical page: https://llms-technical-reviews.com/p/vibesdk/

## Overview

VibeSDK is Cloudflare's open-source **prompt-to-app builder**: a hosted web product in the Lovable / bolt.new mould where a user types "build me a habit tracker", watches an agent write the files, and gets a live preview URL and a one-click deploy. It is not a terminal or IDE coding agent. It never touches a developer's local checkout. The "repository" it edits is a per-app workspace that lives in a Durable Object, and the output is a running Cloudflare Worker, not a pull request. The intended user is a team that wants to run its *own* vibe-coding service on its Cloudflare account.

At the pinned commit, the default engine for the `app` project type is the **Think** behavior. It is a single model-and-tool loop built on `@cloudflare/think`, running in its own `ThinkAgent` Durable Object. Its file tools operate on a companion `SpaceDO`, which holds git-backed files and serves previews by loading the built app as a Dynamic Worker. Two older engines remain in the tree: **Phasic** (blueprint → phases → implement → review, with a container sandbox) and **Agentic** (recursive tool calling over the same sandbox). New apps from the home page get Think. Presentations, workflows and "general" projects still get Agentic.

The whole platform is itself a Worker: a React 19 + Vite front end, a Hono API, D1 for users and apps, and roughly a dozen Cloudflare bindings (Durable Objects, Containers, Worker Loaders, Browser Rendering, Artifacts, Workers for Platforms, AI Gateway).

## Architecture

```mermaid
flowchart LR
  UI["React app (chat + editor + preview)"] -->|"POST /api/agent"| API["Hono API: CodingAgentController"]
  UI <-->|"WebSocket"| CGA["CodeGeneratorAgent DO"]
  API --> CGA
  CGA --> TB["ThinkCodingBehavior"]
  TB -->|"configureVibe / chat()"| TA["ThinkAgent DO (@cloudflare/think loop)"]
  TA --> GW["AI Gateway (OpenAI-compatible)"]
  TA -->|"read/write/edit/grep, commit, deploy_space"| SP["SpaceDO (files + git)"]
  TA --> BR["Browser Rendering: console logs"]
  SP --> AR["Artifacts (git history)"]
  SP -->|"LOADER.get()"| DW["Dynamic Worker preview + App facet"]
  TB -->|"publish"| WFP["Workers for Platforms namespace"]
```

| Component | Path | Role |
|---|---|---|
| API routes | `worker/api/routes/codegenRoutes.ts` | `POST /api/agent` creates an app; `/api/agent/:id/ws` attaches the editor |
| Agent controller | `worker/api/controllers/agent/controller.ts` | Rate limits, resolves behavior and project type, starts the agent DO, streams NDJSON |
| Coding agent DO | `worker/agents/core/codingAgent.ts` | One DO per app; picks the Think, Phasic or Agentic behavior |
| Think behavior | `worker/agents/core/behaviors/think.ts` | Host side: configures `ThinkAgent`, drains user prompts, maps stream chunks to WebSocket events |
| ThinkAgent | `worker/agents/think/ThinkAgent.ts` | The model/tool loop: model wiring, tools, step budget, context trimming |
| Think tools | `worker/agents/think/*-tool.ts` | `deploy_space`, `commit`, `set_title`, `ask_questions`, `get_browser_console_logs` |
| SpaceDO | `space/src/space/durable-object.ts` | Workspace file system, git, deploy, rollback, preview serving, app DB inspector |
| Deploy engine | `space/src/space/deploy-engine.ts` | Bundles a branch with `@cloudflare/worker-bundler` and records the deployment |
| Legacy engines | `worker/agents/core/behaviors/{phasic,agentic}.ts` | Blueprint/phase pipeline and recursive tool loop backed by a container sandbox |
| SDK | `sdk/src/` | `VibeClient` / `BuildSession` for driving builds over HTTP + WebSocket |

## How a request flows

1. **Create.** The home page always sends `behaviorType=think` for app projects ([home.tsx](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/src/routes/home.tsx#L137-L141)). `POST /api/agent` reaches `startCodeGeneration`, which checks prompt length and the app-creation rate limit, then calls `resolveBehaviorType` ([controller.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/api/controllers/agent/controller.ts#L37-L43)). For Think it skips template selection entirely, writes the WebSocket URL to the NDJSON stream and calls `initialize` on the agent DO ([controller.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/api/controllers/agent/controller.ts#L201-L262)).
2. **Pick an engine.** `CodeGeneratorAgent` instantiates `ThinkCodingBehavior`, `PhasicCodingBehavior` or `AgenticCodingBehavior` from props, persisted state, or the feature registry ([codingAgent.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/codingAgent.ts#L184-L207), [features/types.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/features/types.ts#L122-L143)).
3. **Configure the loop.** `ThinkCodingBehavior.initialize` names the project, then `configureThinkAgent` resolves AI Gateway credentials, builds the per-app system prompt and pushes both into the `ThinkAgent` DO with `configureVibe` ([think.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L155-L292)). `seedEmptySpace` commits a marker file so the SpaceDO has a `main` branch.
4. **Run a turn.** A `GENERATE_ALL` WebSocket message leads to `build()`, which joins queued prompts and calls `runPrompt`. That calls `stub.chat(text, forwarder)` on the ThinkAgent and translates `text-delta`, `reasoning-delta` and `tool-*` chunks into editor events ([think.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L465-L547)).
5. **Model ↔ tools.** Inside the ThinkAgent, `beforeTurn` trims history, `beforeStep` meters credits and forces a tool-free wrap-up on step 25, and `getTools` exposes SpaceDO-backed `read/write/edit/list/find/grep/delete` plus the custom tools. Bash is off ([ThinkAgent.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L292-L383)).
6. **Deploy and check.** The system prompt tells the model to call `deploy_space`, then `get_browser_console_logs`, and to repeat until the build and the console are clean ([think.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L299-L335)). `deploy_space` commits the tree and calls `SpaceDO.deploy` ([deploy-tool.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/deploy-tool.ts#L23-L53)), which bundles the branch and stores a deployment row ([deploy-engine.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/space/src/space/deploy-engine.ts#L98-L151)).
7. **Preview.** The host sees the `deploy_space` output, signs a branch-scoped preview token and broadcasts `DEPLOYMENT_COMPLETED` ([think.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L752-L776)). Requests to `/space/:name/preview/:branch/` hit `servePreview`. It serves static assets, then loads the app as a Dynamic Worker with `LOADER.get()` and forwards to its `App` class running as a Durable Object facet ([durable-object.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/space/src/space/durable-object.ts#L667-L760)).

## Key components

### ThinkAgent: the loop

`ThinkAgent` extends `Think` and overrides the hooks it needs ([ThinkAgent.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L160-L164)). `maxSteps` is 25 and `workspaceBash` is false. `getModel` builds an `@ai-sdk/openai` chat provider against the AI Gateway `/compat` endpoint. Its custom `fetch` patches Gemini's streamed tool-call deltas and round-trips Gemini "thought signatures", which the AI SDK would otherwise drop ([ThinkAgent.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L225-L262)). That much shim code is a sign of how tightly the loop is tuned to one model. `THINK_MODEL_ID` is hard-coded to `google-ai-studio/gemini-3.6-flash` ([model-config.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/model-config.ts#L1-L11)), and `configureThinkAgent` uses it regardless of the user's per-action model settings.

### Context handling

There is no embedding index. The model explores the workspace with `find`/`grep`/`read`. Before each turn, `selectThinkContextMessages` keeps the first message, the last five text-bearing messages, and the complete tool-call/result pairs for `ask_questions`, `activate_skill` and `set_title`. It strips every other tool call out of older assistant turns ([context-selector.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/context-selector.ts#L69-L111)). The base prompt is picked per model family from `prompts/*.txt` ([prompts.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/prompts.ts#L38-L50)).

### SpaceDO: files, git, previews

`SpaceDO` is published as a separate package (`space/`). Each app gets one instance, keyed by the agent id. It offers file RPCs (`readFile`, `editFile`, `grep`, `patch`), git operations (`gitCommit`, `gitLog`, `gitDiff`), and `deploy`, `rollbackToCommit` and `servePreview`. With `ENABLE_ARTIFACTS` on, history is pushed to Cloudflare Artifacts after each successful deploy ([durable-object.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/space/src/space/durable-object.ts#L526-L550)). Rollback restores the target commit's bytes as a *new* commit, so history is never rewritten ([durable-object.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/space/src/space/durable-object.ts#L468-L500)). The generated app must export `class App extends DurableObject`. SpaceDO wraps it with inspector methods, which drive the read-only DB tab.

### Verification in a real browser

`get_browser_console_logs` opens the preview in Cloudflare Browser Rendering (or a local sidecar in development). It returns console output, page errors and failed requests, and it accepts an optional `interact_script` to click through the page first ([browser-logs-tool.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/browser-logs-tool.ts#L1-L24)). Together with build errors from `deploy_space`, this is the agent's only feedback signal. There is no test runner and no type-checker in the Think path.

### Legacy Phasic / Agentic engines

These engines use `worker/agents/inferutils/core.ts` with chat-completions tool calling, structured Zod outputs, and search/replace or unified-diff parsers in `output-formats/diff-formats/`. They run code in a `@cloudflare/sandbox` container image (`SandboxDockerfile`). Before deploy they run `preDeploySafetyGate`, a Babel AST scan for React render-loop hazards such as module-level JSX, unstable selectors, and setState during render.

## Extending it

- **Think tools.** Add a `tool()` factory under `worker/agents/think/` and register it in `ThinkAgent.getTools()` ([ThinkAgent.ts](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L322-L349)). New SpaceDO calls need typings in `space-workspace-ops.ts`.
- **Skills.** `worker/agents/think/skills/*/SKILL.md` (four today: app file structure and three frontend-design variants) are injected into the system prompt by Think's skill loader.
- **Prompts.** Per-family base prompts live in `worker/agents/think/prompts/`. The VibeSDK-specific deploy-and-verify workflow is appended in `buildSystemPrompt`.
- **MCP.** `MCPManager` can connect to SSE MCP servers for the legacy engines, but the `MCP_SERVERS` list is empty at this SHA.
- **Headless.** `sdk/` exposes `VibeClient.build(prompt)`, which returns a `BuildSession` with `waitForPreviewDeployed()` and similar helpers, so you can drive builds from scripts or tests.

## Running it

VibeSDK is a deployment, not a library you `npm install` into a project. Use the "Deploy to Cloudflare" button, or run `bun run setup` and then `bun run dev` for local work. Production needs a Workers Paid plan with Workers for Platforms for publishing generated apps, a D1 database, R2/KV, Containers (for the legacy sandbox), Browser Rendering, Worker Loaders, AI Gateway with at least one provider key, and a custom domain with wildcard DNS for preview subdomains. All of these are declared in `wrangler.jsonc`. Feature toggles such as `ENABLE_ARTIFACTS` are set in the dashboard, not in the repo.

## Strengths and caveats

- **Strength: preview without a VM.** Generated apps are bundled in-process and served as Dynamic Workers inside the SpaceDO. No container needs to boot for the default Think path, so preview latency is close to a Worker deploy.
- **Strength: real per-app isolation.** Each app has its own agent DO, ThinkAgent DO, SpaceDO, git history and App facet storage. Previews need signed, branch-scoped tokens.
- **Strength: honest restore points.** The model decides when to `commit`, and rollback re-commits old content, so history is never rewritten.
- **Caveat: Cloudflare-only by design.** Nearly every subsystem is a Cloudflare binding. You cannot run this elsewhere, and generated apps must target Workers + Durable Objects.
- **Caveat: one model for the main path.** Think is hard-wired to a Gemini Flash model through AI Gateway, with Gemini-specific stream patches. The rich per-action model configuration UI only affects the legacy engines.
- **Caveat: two architectures in one repo.** Think, Phasic and Agentic share `BaseCodingBehavior` (about 2,000 lines) but have different tools, sandboxes and edit formats. Reading the code, it is easy to mistake legacy paths for live ones.
- **Caveat: stale scripts.** `package.json` still defines `cli` and `tui` scripts, but the `cli/` directory they point to does not exist at this commit.

*Sources: code at 9da158d, deepwiki-open wiki (11 pages), verified Q&A.*

## How cloudflare/vibesdk answers the Open-source coding agents questions

### How is the agent loop implemented? (answered)

VibeSDK has three distinct agent-loop architectures, selected per app at creation: **Think** (model-and-tool loop via `@cloudflare/think`), **Agentic** (recursive inference with tool calling), and **Phasic** (deterministic phase orchestration).

The **Think loop** is the primary/canonical loop, implemented in `ThinkAgent` (extends `@cloudflare/think`) at `worker/agents/think/ThinkAgent.ts`. It is a single model-and-tool loop, not a planner+executor split. `Think.getTools()` returns a `ToolSet` of SpaceDO-backed workspace tools (`read`, `write`, `edit`, `list`, `find`, `grep`, `delete`) from `@cloudflare/think/tools/workspace`, plus VibeSDK-specific tools: `commit`, `deploy_space`, `set_title`, `ask_questions`, `get_browser_console_logs`. Bash is disabled (`workspaceBash = false`). Each turn is driven by `ThinkAgent.chat()`, called from `ThinkCodingBehavior.runPrompt()` which submits user text to the DO and translates streamed `UIMessageChunk` frames into WebSocket events. Tools use the OpenAI-compatible function-calling schema.

The **Agentic loop** (`worker/agents/core/behaviors/agentic.ts`) uses the `infer()` function in `worker/agents/inferutils/core.ts` — a generic inference engine that assembles tool-call requests, streams responses, accumulates tool-call deltas from chat-completions chunks, executes tools via `executeToolCallsWithDependencies()`, and recurses until a depth limit or `CompletionDetector` signal fires. Stop conditions include: max tool-calling depth per action key, a max message limit (64000 in constants), and completion signals from specific tools. The Agentic loop also includes conversation compactification triggers every 9 tool calls.

The **Phasic loop** (`worker/agents/core/behaviors/phasic.ts`) is a deterministic orchestrator that runs blueprint generation, phase generation, phase implementation, and review cycles in a fixed sequence, then iterates with the user.

Think has no sub-agents in the traditional sense; it issues tool calls to the SpaceDO workspace and other services. The `infer()` function does support recursive tool calling (model calls tool, tool result feeds back to model), which is its form of sub-loop.

**Turn structure (Think):** `beforeTurn()` selects context messages, `beforeStep()` enforces rate limits and injects a max-steps prompt on the final step. `getModel()` wraps an OpenAI-compatible provider over AI Gateway with custom SSE patching for Google Gemini compatibility.


Citations: [worker/agents/think/ThinkAgent.ts:160-349](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L160-L349) · [worker/agents/core/behaviors/think.ts:464-547](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L464-L547) · [worker/agents/inferutils/core.ts:680-750](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/inferutils/core.ts#L680-L750) · [worker/agents/core/behaviors/agentic.ts:1-51](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/agentic.ts#L1-L51) · [worker/agents/core/behaviors/phasic.ts:37-80](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/phasic.ts#L37-L80) · [worker/agents/inferutils/toolExecution.ts:1-60](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/inferutils/toolExecution.ts#L1-L60)

### How is repository context gathered and kept within the context window? (answered)

Repository context is gathered and managed through several mechanisms:

**Codebase reading tools:** In the Think loop, workspace tools include `read`, `list`, `find`, and `grep` from `@cloudflare/think/tools/workspace` which operate on the SpaceDO workspace. The ThinkAgent has no separate `glob` tool beyond the generic workspace tools, but the system prompt instructs the model to use search tools extensively. The Gemini system prompt (`worker/agents/think/prompts/gemini.txt`) explicitly tells the agent: "Use `grep` and `glob` search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use `read` to understand context and validate any assumptions."

**Context selection:** `ThinkAgent.beforeTurn()` calls `selectThinkContextMessages()` in `worker/agents/think/context-selector.ts` to trim the message history before each turn. It preserves all tool-result pairs for tool names matching a protected list (deploy_space, commit, ask_questions), keeps a minimum of `RECENT_MESSAGE_COUNT` (5) recent messages, and uses a diff-based strategy to preserve complete tool-call/tool-result pairs around named tools rather than naive truncation.

**Conversation compactification:** The older Agentic/Phasic behaviors use `worker/agents/utils/conversationCompactifier.ts` which triggers summarization at 40 conversation turns or 100k estimated tokens. It preserves the last 10 messages uncompacted, calls an LLM to summarize older history into a concise context block wrapped in `<system_context>` tags, and replaces compacted messages with the summary.

**File-reading strategy:** The Think model is instructed to read files to understand context before making changes. The workspace operations layer reads and writes through SpaceDO RPC calls — not local filesystem — so file I/O goes through Durable Object stubs. The `codebaseContext.ts` utility provides a `CodebaseContextBuilder` for the Agentic behavior that can scan directories, collect file contents, and build structured context blocks for the LLM.

VibeSDK does not use embeddings or vector search for repository context. It relies entirely on LLM-driven search (grep/find within workspace tools) and conversation history management.


Citations: [worker/agents/think/context-selector.ts:1-80](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/context-selector.ts#L1-L80) · [worker/agents/utils/conversationCompactifier.ts:11-114](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/utils/conversationCompactifier.ts#L11-L114) · [worker/agents/think/prompts/gemini.txt:1-50](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/prompts/gemini.txt#L1-L50) · [worker/agents/think/ThinkAgent.ts:292-314](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L292-L314)

### How are code edits applied? (answered)

Code edits are applied through two parallel systems depending on the agent behavior:

**ThinkAgent (primary):** Edits happen via SpaceDO-backed workspace tools registered in `ThinkAgent.getTools()`. These use `@cloudflare/think/tools/workspace` tool creators (`createReadTool`, `createWriteTool`, `createEditTool`, `createDeleteTool`) backed by `SpaceWorkspaceOps` which route through Durable Object RPC to SpaceDO. The model can `write` (whole file), `edit` (search/replace on existing files), or `delete`. Edits land directly in SpaceDO's git-backed workspace. Think has no separate diff format validation — the `edit` tool uses Think's built-in search/replace with exact matching. The model is instructed to keep changes minimal and to deploy after editing.

**Agentic/Phasic behaviors:** These use a more elaborate system. The agent emits structured outputs matching Zod schemas in `worker/agents/schemas.ts` — `FileOutputSchema` for whole-file writes, with a `format` field supporting `full_content` or `unified_diff`. Two diff parsers exist in `worker/agents/output-formats/diff-formats/`: `search-replace.ts` (a `<<<<<<< SEARCH` / `=======` / `>>>>>>> REPLACE` format with multiple matching strategies: exact, whitespace-insensitive, indentation-preserving, fuzzy) and `udiff.ts` (unified diff format with indentation normalization). Both parse the model's text output into structured edits.

**Validation:** The Agentic/Phasic flow uses the `preDeploySafetyGate` utility (`worker/agents/utils/preDeploySafetyGate.ts`) which runs before deployment to check for hardcoded secrets/API keys in generated code. Static analysis is performed during build. After deploy, browser console logs are inspected. The Think flow deploys via `deploy_space` and checks browser logs via `get_browser_console_logs`, forming an automatic repair loop.

**Undo/git:** All edits go through SpaceDO, which is backed by Cloudflare Artifacts for durable git history. Each `commit` tool call creates a restore point. `rollbackToCommit()` in `ThinkCodingBehavior` restores a prior commit and redeploys without rewriting history. There is no per-edit undo — users roll back to a named commit.

> **Editor's note.** Correction: preDeploySafetyGate does not scan for secrets. It is a Babel AST check for React render-loop hazards (module-level JSX, unstable store selectors, setState during render, effects without deps) and only runs on the legacy Phasic/Agentic path.

Citations: [worker/agents/think/ThinkAgent.ts:322-349](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L322-L349) · [worker/agents/think/space-workspace-ops.ts:1-38](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/space-workspace-ops.ts#L1-L38) · [worker/agents/output-formats/diff-formats/search-replace.ts:1-61](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/output-formats/diff-formats/search-replace.ts#L1-L61) · [worker/agents/output-formats/diff-formats/udiff.ts:1-60](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/output-formats/diff-formats/udiff.ts#L1-L60) · [worker/agents/schemas.ts:20-58](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/schemas.ts#L20-L58) · [worker/agents/core/behaviors/think.ts:783-811](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L783-L811)

### How are shell commands and file writes kept safe? (answered)

Execution safety is implemented at multiple layers:

**Tool boundaries — ThinkAgent:** Bash execution is explicitly disabled (`workspaceBash = false` in ThinkAgent). The Think loop exposes only file workspace tools (read, write, edit, list, find, grep, delete), git/commit tools, deploy tools, browser-log inspection, and a structured question-asking tool. No shell or arbitrary command execution is possible through the Think agent.

**Sandbox for Agentic/Phasic behaviors:** The older agent paths use `@cloudflare/sandbox` (v0.5.6) for isolating command execution. The `SandboxDockerfile` builds a Docker image based on `cloudflare/sandbox:0.5.6` with git, curl, and a process-monitoring system (`container/` directory with `cli-tools.ts`, `process-monitor.ts`, `storage.ts`). Commands are executed inside the container via the `BaseSandboxService` in `worker/services/sandbox/BaseSandboxService.ts` which manages sandbox instances, file uploads, command execution, static analysis, and deployment results.

**Process monitoring:** The container includes a `ProcessMonitor` class in `container/process-monitor.ts` and a CLI tool (`container/cli-tools.ts`) that validates instance IDs with a strict regex (`/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/`), caps ID length at 64 characters, and stores logs and errors in a managed SQLite storage layer within the container.

**Preview authorization:** Preview URLs use signed, branch-scoped tokens. `getBrowserPreviewURL()` in `ThinkCodingBehavior` invokes `signSpacePreviewToken()` to create a JWT-like token embedding `spaceName`, `branch`, `userId`, and a `previewVersion`. The token bootstraps an HttpOnly preview cookie and prevents unauthorized access to preview deployments.

**Network restrictions:** The sandbox container image does not appear to restrict network access, but the Think agent has no bash or curl tools to make arbitrary network requests.

**Secrets:** User API keys and tokens are handled through Cloudflare services (AI Gateway bindings, encrypted token blobs). The `preDeploySafetyGate` in `worker/agents/utils/preDeploySafetyGate.ts` checks generated code for hardcoded secrets before deployment.

**Durable Object isolation:** Each app maps to its own ThinkAgent DO, SpaceDO workspace, Artifacts repository, and generated App Facet — full resource isolation per project. VibeSDK does not use Landlock, seccomp, or other OS-level sandboxing beyond the Docker container and Cloudflare's DO isolation.

> **Editor's note.** Correction: there is no pre-deploy secret scan; preDeploySafetyGate checks React render-loop hazards. The container sandbox applies only to Phasic/Agentic apps — the default Think path has no shell and previews through SpaceDO Dynamic Workers.

Citations: [worker/agents/think/ThinkAgent.ts:160-165](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L160-L165) · [SandboxDockerfile:1-64](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/SandboxDockerfile#L1-L64) · [container/cli-tools.ts:1-30](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/container/cli-tools.ts#L1-L30) · [worker/services/sandbox/BaseSandboxService.ts:1-50](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/services/sandbox/BaseSandboxService.ts#L1-L50) · [worker/agents/core/behaviors/think.ts:374-393](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/core/behaviors/think.ts#L374-L393) · [worker/agents/utils/preDeploySafetyGate.ts:1-20](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/utils/preDeploySafetyGate.ts#L1-L20)

### Which models are supported and how are they called? (answered)

VibeSDK supports models across multiple providers through Cloudflare AI Gateway routing. The model master list is defined in `worker/agents/inferutils/config.types.ts` with over 20+ models classified by size (Lite, Regular, Large), each with a `provider`, `creditCost`, and `contextSize`.

**Supported providers:** Google AI Studio (Gemini 2.5 Flash/Pro, Gemini 3 Flash/Pro Preview), Anthropic (Claude 3.7 Sonnet, Claude 4/4.5 Sonnet/Opus/Haiku), OpenAI (GPT-5, GPT-5.1, GPT-5.2, GPT-5 Mini), Grok (Grok 4 Fast, Grok 4.1 Fast, Grok Code Fast 1), Vertex AI (GPT-OSS 120B, Kimi K2 Thinking, Qwen 3 Coder 480B). Several models (Cerebras, OpenAI OSS/Codex variants) are commented out in the master list.

**ThinkAgent model:** Configured in `worker/agents/think/model-config.ts` with `THINK_MODEL_ID = 'google-ai-studio/gemini-3.6-flash'`. The default config in `worker/agents/inferutils/config.ts` selects a Gemini-only set; when `PLATFORM_MODEL_PROVIDERS` env var is set, it uses a multi-provider config with Gemini 3 Pro Preview for blueprints, Grok 4.1 Fast for conversational response and deep debugging, and OpenAI 5 Mini as fallback.

**How models are called:** All model calls go through AI Gateway. The `getConfigurationForModel()` function in `worker/agents/inferutils/core.ts` resolves a model's baseURL, apiKey, and headers by checking: (1) runtime overrides (SDK BYOK keys), (2) user's encrypted gateway token, (3) user's custom gateway override, (4) environment variable per provider (`${PROVIDER}_API_KEY`), (5) platform AI Gateway binding. The OpenAI SDK (`openai` package) is used as the inference client with `client.chat.completions.create()`. The `ThinkAgent` uses `@ai-sdk/openai` via `createOpenAI()` with a custom `fetch` wrapper for Gemini compatibility patching.

**Per-model prompt tuning:** The Think agent has tuned system prompts per model family in `worker/agents/think/prompts/`: `gemini.txt`, `gpt.txt`, `anthropic.txt`, `trinity.txt`, `kimi.txt`, `codex.txt`, `beast.txt` (for GPT-4/o1/o3), and `default.txt`. These differ in tone, detail, and instructions; e.g., the Gemini prompt emphasizes security and tool-use patterns, while the Anthropic prompt is more concise and direct.

**Cost tracking:** Each model has a `creditCost` relative to GPT-5 Mini baseline (1.0 credit = $0.25/1M input). Rate limiting is enforced via `RateLimitService.enforceLLMCallsRateLimit()` which checks configurable budgets per user. Multi-provider configs have per-action model assignments with fallback chains (e.g., blueprint: Gemini 3 Pro Preview → Gemini 2.5 Flash).

**No local model support:** All models are called remotely through AI Gateway. There is no Ollama, llama.cpp, or local model infrastructure.


Citations: [worker/agents/inferutils/config.types.ts:1-340](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/inferutils/config.types.ts#L1-L340) · [worker/agents/inferutils/config.ts:58-186](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/inferutils/config.ts#L58-L186) · [worker/agents/inferutils/core.ts:424-497](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/inferutils/core.ts#L424-L497) · [worker/agents/think/prompts.ts:1-50](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/prompts.ts#L1-L50) · [worker/agents/think/ThinkAgent.ts:225-262](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L225-L262)

### How can it be extended and customised? (answered)

VibeSDK can be extended and customized through several mechanisms:

**Skills (Think agent):** The Think agent supports a skill catalog via `worker/agents/think/skills.ts`. Skills are SKILL.md files in `worker/agents/think/skills/` with frontmatter (name, description, compatibility, allowedTools, metadata). Currently four skills: `app-file-structure`, `frontend-design`, `frontend-design-landing-page`, `frontend-design-saas`. Each skill is loaded at build time via `?raw` import, parsed with `agents/skills` frontmatter parser, and exposed as a `SkillSource` via `fromManifest()`. Think automatically injects the skill catalog into the system prompt and registers a skill-loading tool.

**Custom tools (Think):** Adding a Think tool requires: (1) creating the tool under `worker/agents/think/`, (2) adding SpaceDO RPC typing to `space-workspace-ops.ts`, (3) registering it in `ThinkAgent.getTools()`, and (4) updating the relevant prompt or skill. Existing custom tools include `ask-questions-tool.ts`, `browser-logs-tool.ts`, `commit-tool.ts`, `deploy-tool.ts`, `set-title-tool.ts`.

**Toolkit system (Agentic):** The Agentic/Phasic behaviors use a different tool registration in `worker/agents/tools/toolkit/` (e.g., `exec-commands.ts`, `generate-files.ts`, `read-files.ts`, `deploy-preview.ts`) with a `buildTools()`/`buildDebugTools()` pattern in `worker/agents/tools/` registered via `customTools.ts`.

**MCP (Model Context Protocol):** VibeSDK includes an `MCPManager` class in `worker/agents/tools/mcpManager.ts` that uses `@modelcontextprotocol/sdk/client` with `SSEClientTransport` to connect to MCP servers. It connects via SSE, lists tools, and integrates them into the agent's toolset. The `MCP_SERVERS` array in `mcpManager.ts` is currently empty (just a commented-out `cloudflare-docs` example), but the full connection infrastructure is in place.

**Rules/instruction files:** The project has `CLAUDE.md` (project instructions for Claude Code) and `AGENTS.md` (detailed guidance for AI agents covering tooling, verification, frontend UI, boundaries, change paths, and constraints). These are checked into the repository.

**SDK/headless use:** The `sdk/` directory is an independent Bun package providing a programmatic client. `VibeClient` (`sdk/src/client.ts`) offers HTTP methods, `AgenticClient` and `PhasicClient` extend it with preset behavior types, and `BuildSession` (`sdk/src/session.ts`) manages a live agent session with WebSocket streaming, file watching, and phase tracking. Applications can install the SDK as a dependency and script agent interactions.

**CLI/TUI:** `bun run cli` and `bun run tui` in `package.json` point to `cli/index.ts` and `cli/tui.tsx` for command-line and terminal-UI interaction modes.

**Configuration:** Model configs, agent action configs, per-action constraints (allowedModels, enabled), rate limit settings, and user-configurable settings are all adjustable without code changes through environment variables and AI Gateway configuration.

> **Editor's note.** Correction: package.json still has cli and tui scripts, but the cli/ directory they reference does not exist at this commit, so there is no CLI or TUI mode.

Citations: [worker/agents/think/skills.ts:1-60](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/skills.ts#L1-L60) · [worker/agents/tools/mcpManager.ts:1-65](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/tools/mcpManager.ts#L1-L65) · [sdk/src/client.ts:30-60](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/sdk/src/client.ts#L30-L60) · [CLAUDE.md:1-30](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/CLAUDE.md#L1-L30) · [worker/agents/think/ThinkAgent.ts:322-349](https://github.com/cloudflare/vibesdk/blob/9da158d82c597a0e8f4bf033cdccd1053fb6fb15/worker/agents/think/ThinkAgent.ts#L322-L349)
