DreamLake

Generate & Hosted Pages

A hosted page is a React app written by an AI agent and kept alive in its own container. There is no build and no deploy: the page runs a dev server, so an edit made from chat appears in the open browser within seconds — at the same URL, forever.

Quick experience

The whole loop from the command line — no build, no deploy, one URL throughout.

bash
# 1. Install and sign in
curl -fsSL https://dl.dreamlake.ai/install.sh | sh
dreamlake login --env prod

# 2. Generate — the URL is printed within seconds
dreamlake page generate \
  --description "Three stat cards: Total, Reviewed, Pending."
#   https://host.dreamlake.ai/page/eba91469e21e/

# 3. Edit — applied over HMR, same URL
dreamlake page edit --workspace-id eba91469e21e \
  --description "Switch to a dark theme with a blue accent."

# 4. Inspect and remove
dreamlake page status --workspace-id eba91469e21e
dreamlake page delete --workspace-id eba91469e21e

Run step 3 with the page open in another window: nothing reloads, nothing rebuilds, and the URL never changes.

Generating a page

page generateone CLI commandagentwrites a Vite projectpnpm devin its own containerpage_urllive and permanentNo build step. The URL works as soon as Vite is ready, and never changes again.

The agent writes an ordinary Vite React project. A container starts, runs pnpm dev, and the page is reachable. Nothing is compiled, uploaded, or published.

Serving

browseriframe/page/<id>/dl-routerCaddypage-a1b2vite dev :5173page-c3d4vite dev :5173page-e5f6stopped (idle)One container per page — a page can only ever break itself.

Each page has its own container and its own dev server. The router maps the URL path to the right one.

Editing a live page

This is the part that replaces "rebuild and redeploy".

chat / CLIpage editdreamlakeauth · SSE relaypage agentClaude Agent SDKcontainer page-<id>src/App.jsxedited in placevite devsees the changeHMR updateover wssbrowserupdates liveNo build, no redeploy, no new URL — the page that is already open changes.

The agent edits the source code inside the container. Vite notices, and pushes just the changed module to every browser that has the page open. A page being watched on a wall display updates without anyone reloading it.

When an edit breaks the page

edit appliedvite recompileserrordev log · browseragent readsboth error sourcesfixedHMR againup to 3 roundsA broken edit is caught and repaired before the agent reports success.

The agent can read the dev server's compile output and the browser's runtime errors, so it sees its own mistakes and fixes them before reporting success.

Idle pages

idle 30 minnobody visitingstoppedno CPU, no memorya visitorrouter wakes itliveabout 2 secondsThe URL stays valid the whole time — a waking page shows a brief waiting screen.

A page nobody is looking at costs nothing. It stops after 30 minutes and comes back on the next visit.

Security model

Isolation

Edit instructions come from end users, in plain language. So the agent never touches the host.

The agent can reach/app — this page’s source codenode · pnpm · viteits own dev serverIt cannot reachthe host filesystemevery other pagedocker · ssh · secrets

A malicious or simply confused instruction can corrupt one page's source code — which the same mechanism can then repair. It cannot reach the machine, the other pages, or anything sensitive.

Kernel isolation

Containers run under gVisor (runsc) rather than the normal runtime.

page containernode · vite · whatever the agent was told to dogVisor kernel (runsc)a second Linux kernel, running in user spacehost kernelnever called by the container directlyevery syscall lands herea small, filtered subsetuname -r4.19.0-gvisorWithout gVisor the top box would be calling the bottom one directly.

gVisor implements Linux itself, in user space. The container's syscalls are answered by that kernel — the host kernel sits behind it and is never called directly. The container even reports its own kernel version, 4.19.0-gvisor.

The usual way out of a container is a host-kernel bug. Here the host kernel is not the thing on the other side of the syscall boundary, so that class of escape has nothing to aim at.

Shell / data separation

Two modes. A page built from a plain description has no business data to protect. A page wired to real records does — and even then, its source code contains no business data and no credentials.

Source code (in the container)API base URLannotation_result_id✕ business data · ✕ credentialsruntimeRuntime (browser)annotation data (via API)user token (via postMessage)write-back result (via API)

Only two things are written into the page — the API base URL and the annotation result ID. Everything else is fetched at runtime. Access control lives in the API layer, not in the page, so a leaked URL exposes an empty shell.

Not embeddable by third parties

DreamLake consoleholds login tokentoken responder(origin allowlist)Hosted Page (iframe)pure shell, no data① auth-request② token ✓③ Bearer tokenDreamLake APIverify + access controlno reply → blank auth screen

When the page loads, it asks its parent window for the current user's token, then calls the DreamLake API with it. The token never appears in the page's source code.

If no parent responds — the URL is opened directly, or embedded in someone else's site — the page shows a blank auth-required screen. There is nothing to extract without a live token from a trusted parent.

frame-ancestors CSPbrowser rejects third-party embeds at the network levelOrigin allowlisttoken responder only replies to trusted originsAPI JWT authevery request is verified server-side with namespace access control
LayerMechanismDescription
Outerframe-ancestors CSPA response header restricts embedding to *.dreamlake.ai — the browser rejects third-party embeds before any JavaScript runs
MiddleOrigin allowlistThe console's token responder only replies to requests from trusted origins, so a page embedded elsewhere never receives a token
InnerAPI JWT authEvery API call carries the user's JWT; the server verifies it and enforces namespace access control — the same rules as everywhere else in DreamLake