how-it-works

Reference · build agent internals

How a prompt becomes a deployed site.

This document describes the system that turns a plain-language request into a working, deployed web application. It walks the pipeline end to end - parsing, sandboxed execution, the self-correcting compile loop, and edge deployment - and then drops to the infrastructure and the exact instructions the agent runs under. No abstractions glossed over, no hand-waving.

Stages6
SandboxNode 22
BuildVite + tsc
Cold deploy< 12s

The agent operates on a closed loop: it reads the request, commits to a specification, writes modular React, and refuses to ship until the TypeScript and Vite toolchain reports a clean build. Everything below is a slice of that loop, in order.

Stage 01 · parsing

Specs & requirements parsing

Before a single file is written, the request is compiled into a typed specification. The raw prompt is normalized, classified by intent (site type, scope, tone), and expanded into a frozen Spec object that pins down the route map, the component tree, the content model, and the design tokens. Code generation reads from this spec, never from the raw prompt - so the same input always resolves to the same structural plan.

specs.parse() - prompt to component treefig
promptnatural languageintent classifiertype · scope · tonespec compilerprompt → SpecSpec<T>typed · frozenrouteMap · componentTreecontentModel · designTokens
The prompt is normalized, classified by intent, then expanded into a typed spec object that pins the route map, component tree, and content model before any code is written.

01.1The spec shape

The classifier output is validated against a schema. An invalid or underspecified prompt is filled with defensible defaults rather than rejected - the system always produces a buildable plan.

spec.tstypescript
type Spec = {  intent:   SiteIntent;   // landing | docs | portfolio | …  routes:   RouteSpec[];  tree:     ComponentNode;   // recursive layout plan  content:  ContentModel;  tokens:   DesignTokens;    // palette, type scale, spacing} export function parse(prompt: string): Spec {  const intent = classify(normalize(prompt));  return freeze(expand(intent));   // typed, immutable plan}

Stage 02 · execution

The sandbox environment

Code is written and executed inside an isolated environment running Node, Vite, and the TypeScript compiler. The agent treats it as a real project directory: it scaffolds routes, writes modular React components, installs dependencies, and runs the dev/build commands - all without touching the host.

sandbox topology - ephemeral container + persistent volumefig
ephemeral container · per turnnode 22runtimevitedev / buildtsctypecheckagent process - read · write · spawnno inbound network · egress allowlistmount/workspacegit-backed volumepersistent · statefulsurvives teardown
Each agent turn runs in a fresh, network-restricted container. The persistent Git-backed workspace volume is mounted in, so state survives across turns while the runtime itself is disposable.
PropertyValue
runtimeNode.js 22 LTS, pinned per project
bundlerVite (the project's own build script)
languageTypeScript, strict mode
uiReact + Tailwind, file-based routing
networkno inbound; egress restricted to an allowlist
lifetimetorn down at the end of each turn

The agent writes components as discrete files and wires them through file-based routes. It never produces one monolithic render function - decomposition is enforced so that a later patch touches the smallest possible surface.

Stage 03 · verification

The self-correction & compiler loop

The agent does not trust its own output. After writing, it runs the type checker and the bundler, captures their stdout and stderr, and parses the diagnostics into structured errors. Each error - with its file, line, column, and code - is fed back to the model as a targeted fix instruction. The loop repeats until the build exits clean or a retry ceiling is hit.

compiler feedback loopfig
parsed diagnostics → patchexit 0 → promoteartifact sealedLLM agentwrites / patches filestsc + vite buildstdout / stderrdiagnostics parserfile:line:col · code
Generated code is type-checked and built. Diagnostics from tsc and Vite are parsed into structured errors and fed back to the model. The loop exits on a clean build or a bounded retry ceiling.

03.1The loop, in pseudocode

correct.tstypescript
async function buildUntilClean(ctx: Ctx) {  for (let attempt = 0; attempt < 6; attempt++) {    const result = await run("tsc --noEmit && vite build");     if (result.code === 0) return ctx.seal();   // clean → promote     const errors = parseDiagnostics(result.stderr);    await ctx.model.patch({ errors, files: ctx.touched() });  }  throw new Error("retry ceiling exceeded");}

03.2Parsing diagnostics

Compiler output is line-oriented and stable. A small parser turns each line into a structured record the model can act on without re-reading the whole log.

stderr → structuredtext
// raw tsc outputsrc/routes/index.tsx(42,9): error TS2304: Cannot find name "Eyebrow". // parsed{ file: "src/routes/index.tsx", line: 42, col: 9, code: "TS2304" }

Stage 04 · delivery

The git & deployment pipeline

A clean build is sealed and handed to the deployment pipeline. The working tree is committed and pushed to origin/main; that push triggers a fresh install, a production vite build, and an upload of the hashed static bundle to the edge CDN. DNS for the project subdomain is provisioned in the same step, so the URL resolves the instant the upload finalizes.

asset push pipelinefig
git commitpush origin/mainbundlevite build + hashedge uploadCDN object storeDNS provisionwildcard recordproject.user.poke.sitelive · TLS terminated at edge
On a clean build the artifact is committed, bundled, hashed, and pushed to the edge CDN. DNS for the project subdomain is provisioned in the same step, so the URL resolves the moment the upload finalizes.
deploy.ymlyaml
steps:  - install: npm ci  - build:   npm run build          # vite build, pinned preset  - bundle:  hash + compress .output  - upload:  edge://objects         # immutable, content-addressed  - dns:     PROJECT.USER.poke.site # wildcard record

Build output and dependencies are never committed - only source ships. The artifact is content-addressed, so re-deploying an unchanged build is a no-op at the edge.

Infrastructure · isolation

Ephemeral container sandbox

Every agent turn executes in a fresh, isolated container. The container is the unit of isolation: it starts from a clean image, runs exactly one turn's worth of work, and is destroyed on completion. Nothing leaks between turns or between projects, and a compromised or runaway process cannot outlive its container.

GuaranteeMechanism
Clean slatefresh container from a pinned base image per turn
Isolationno shared mounts beyond the project's own volume
Networkno inbound routes; egress via an allowlist
Resource capsCPU and memory limits enforced by the runtime
Teardowncontainer destroyed at turn end; state lives on the volume

Infrastructure · state

Persistent filesystem workspaces

Project code lives in a persistent, Git-backed workspace volume, not inside the container. At the start of a turn the volume is mounted into the ephemeral container at /workspace; at teardown it detaches and persists. This split - disposable runtime, durable state - is what lets the agent iterate statefully across many turns while every execution still starts from a clean environment.

turn lifecyclebash
# start of turnmount workspace://PROJECT -> /workspacecd /workspace && git status          # full history intact # agent edits files, runs build… # end of turngit add -A && git commit && git push origin mainunmount /workspace                   # volume persists, container dies
  1. 1

    Mount

    The project volume attaches read-write to the fresh container. Git history, node_modules cache, and prior output are all present.

  2. 2

    Iterate

    The agent reads and writes files directly on the volume. Changes are real and durable the moment they are written.

  3. 3

    Commit & detach

    The working tree is committed and pushed; the volume detaches cleanly and waits for the next turn.

Infrastructure · build

Vite compilation loop

During the build phase the agent drives the toolchain through a stdin/stdout capture harness. It spawns tsc and vite build as child processes, streams their output, and parses it in real time. Type errors, failed imports, and bundler faults become structured diagnostics that the model consumes to patch code - the same convergent loop from Stage 03, viewed from the systems side.

compiler feedback loopfig
parsed diagnostics → patchexit 0 → promoteartifact sealedLLM agentwrites / patches filestsc + vite buildstdout / stderrdiagnostics parserfile:line:col · code
Generated code is type-checked and built. Diagnostics from tsc and Vite are parsed into structured errors and fed back to the model. The loop exits on a clean build or a bounded retry ceiling.
capture.tstypescript
const proc = spawn("vite", ["build"], { stdio: "pipe" }); let log = "";proc.stdout.on("data", (d) => (log += d));proc.stderr.on("data", (d) => (log += d)); const code = await exit(proc);const diagnostics = parse(log);        // file:line:col + codereturn { code, diagnostics };

Infrastructure · delivery

Edge CDN & instant DNS

The sealed build is bundled into immutable, content-addressed objects and pushed to a global edge CDN. In the same pipeline step, the project subdomain is provisioned against a wildcard DNS record, so {project}.{username}.poke.site resolves and serves the new build within seconds of the upload completing. TLS is terminated at the edge.

asset push pipelinefig
git commitpush origin/mainbundlevite build + hashedge uploadCDN object storeDNS provisionwildcard recordproject.user.poke.sitelive · TLS terminated at edge
On a clean build the artifact is committed, bundled, hashed, and pushed to the edge CDN. DNS for the project subdomain is provisioned in the same step, so the URL resolves the moment the upload finalizes.
ConcernBehavior
Asset pushstatic bundle compressed, hashed, uploaded to edge object store
Cachingimmutable, content-addressed assets; long-lived cache headers
DNSwildcard record; per-project subdomain bound on deploy
TLScertificate served and terminated at the edge
Propagationlive within seconds; no manual record changes

Reference · service map

End-to-end pipeline walkthrough

This is the full path a request travels, named service by service. The orchestrator on the Poke backend owns the lifecycle; every other service is something it spawns, drives, or calls.

end-to-end service flowfig
The orchestrator on the Poke backend drives the full lifecycle: it spawns the Docker sandbox, runs the Vite compile and self-correction loop, ships the bundle to edge hosting, and calls the Cloudflare API to bind the subdomain.

AOrchestration - Poke backend

The backend manages the LLM pipeline and the lifecycle of the container manager. It receives the user prompt, runs spec parsing, requests a sandbox, streams instructions to the model, and supervises the correction loop. It is the only stateful coordinator; the sandbox and edge services are driven by it.

BSandbox - Docker + Node.js

The container manager launches an ephemeral Docker container on a compute instance, preloaded with Node.js, Vite, and the TypeScript compiler. The project's persistent volume mounts in; the agent executes its turn; the container is destroyed afterward.

CSelf-correction loop

A custom stdin/stdout capture system wraps the compiler. It parses tsc and vite output into structured errors and returns them to the model for iterative correction, repeating until the build is clean or the retry ceiling is reached.

DCDN & hosting pipeline

The bundled static assets are pushed to the edge hosting pipeline - backed by Vercel and AWS S3 - as immutable objects. The edge serves them globally with long-lived caching and edge-terminated TLS.

EDNS routing - Cloudflare

A call to the Cloudflare API binds the project subdomain to the edge deployment against a wildcard record. Provisioning is dynamic and effectively instant - no manual record edits, no waiting on propagation.

provision-subdomain.tstypescript
await fetch(CF_API + "/zones/" + zone + "/dns_records", {  method: "POST",  headers: { Authorization: "Bearer " + CF_TOKEN },  body: JSON.stringify({    type: "CNAME",    name: project + "." + user,    content: "edge.poke.site",    proxied: true  }),});   // -> PROJECT.USER.poke.site live

Specification · UI engine

Design engine & UI guidelines

These are the heuristics and hard constraints the agent applies to every interface it builds. They exist to keep output consistent, responsive, and cheap to render - and to make generated UIs reviewable by a human.

1Tailwind utility framework

Styling compiles exclusively to Tailwind utility classes. There are no bespoke stylesheets per component, which prevents CSS bloat and keeps every spacing, color, and type decision drawn from a shared token set. Consistency is a property of the system, not of reviewer diligence.

2Dark-mode-first heuristics

RuleDefault
Base palettezinc / neutral surfaces, no pure black
Text contrast≥ 4.5:1 body, ≥ 3:1 large/heading
Borderssubtle, semi-transparent, tinted to surface hue
Accentone calm accent per view, low saturation
Elevationlayered shadows over hard outlines

The engine targets the contrast ratios that modern developer tools rely on: high-contrast text against neutral backgrounds, with boundaries that read clearly without shouting.

3Component modularity

UI is decomposed strictly into discrete, reusable components. A page is a composition of named functional units, never a single monolithic render function. This bounds the blast radius of a patch and makes the self-correction loop precise.

decompositiontsx
// rejected: one monolithic renderfunction Page() { return ( /* 400 lines */ ) } // enforced: discrete unitsfunction Page() {  return (    <Layout>      <Hero /><FeatureGrid /><Footer />    </Layout>  )}

4Layout rules

Layout is mobile-first: base styles target small viewports and scale up through breakpoints. Composition relies on flex and grid constraints rather than fixed measurements, and on fluid units so a layout flexes with its container instead of snapping at hard pixel boundaries. Fixed heights and absolute positioning are last resorts.

5Micro-interactions

Motion is built from vanilla CSS transitions and standard React hooks for state. Heavy animation runtimes are avoided unless a brief genuinely demands them - press feedback, hover states, and disclosure transitions cost nothing on the wire and respect prefers-reduced-motion by default.

Reference · prompt engineering

System instructions

The system runs on fixed instruction templates. The Builder Agent writes and verifies code inside the sandbox; the Poke Orchestrator owns the conversation and dispatches the builder; the Persona & Style engine constrains the orchestrator's output to read like a sharp human, not a model. These contracts are what make behavior reproducible. Switch between them below; the raw templates are shown, not summaries.

agent.md
# agent.md - web builder system instruction template
 
ROLE
You are a Technical Staff Engineer executing in a secure Node/Vite sandbox.
You write production React, verify it against the compiler, and ship only
builds that pass. You do not narrate; you produce code and corrections.
 
---
 
OUTPUT & FILE-WRITING CONSTRAINTS
- Emit every file inside a delimited block tagged with its path:
``tsx path=src/components/Hero.tsx …
- One block per file. Never interleave prose inside a code block.
- Write complete files, not fragments or diffs, unless patching a known range.
- Never invent file paths; resolve them against the existing route tree.
- Extraction is exact: whatever is inside the block is written verbatim.
 
---
 
FRAMEWORK ENFORCEMENT
- Stack is fixed: React + TypeScript + Tailwind on TanStack Start (Vite).
- TypeScript strict mode. No any; type every prop and return.
- Tailwind utilities only. No inline style objects for layout, no ad-hoc CSS
files. Pull spacing, color, and type from the shared token set.
- Routing is file-based under src/routes. Do not hand-roll a router.
- Never swap the framework, bundler, or build script.
 
---
 
STATE & ROUTING
- Local UI state uses React hooks (useState, useReducer). No global store
unless the spec requires cross-route persistence.
- Server logic uses framework server functions; never fetch secrets client-side.
- Each route is a file; shared UI lives in src/components as discrete units.
 
---
 
ERROR CORRECTION LOGIC
- After writing, run: tsc --noEmit && vite build.
- Capture stdout and stderr. Parse each diagnostic into { file, line, col, code }.
- Address the root diagnostic first; re-run before assuming cascades are fixed.
- Patch the smallest surface that resolves the error. Do not rewrite whole files
to fix a single type error.
- Loop until exit code 0 or the retry ceiling (6) is reached.
- On ceiling: stop and report failure. Never ship a build that does not compile.
 
---
 
DISCIPLINE
- Decompose UI into reusable components; no monolithic render functions.
- Mobile-first, responsive, accessible (labels, focus states, contrast).
- No dead controls. Every button, link, and handler does something real.