how it works
The leaf.page website
leaf.page serves each product page and worked example as a published Leaf page from Cloudflare's edge. When a visitor comments or acts on a page, a private container takes over that page's requests for that visitor. The container runs the same Python Leaf server an agent runs on its own machine, and a hosted Codex agent in it answers the visitor.
This page explains the design. Deployment, credentials, and diagnostics are in the Worker's README.
Published pages at the edge
The site build publishes every page under docs/ and every worked
example as a complete Leaf page directory, with its vendored runtime, event
log, and revisions. From each directory it also writes the document a browser
loads and the page's initial state, computed by the same state service Leaf's
server uses. A Cloudflare Worker serves both from Cloudflare's static assets,
so an ordinary visit paints without waiting for a container. Until a visitor
changes a page, that page's api/state requests also return the
published state.
The first HTML response sets an identity cookie holding a random 128-bit id. It is HTTP-only and has no expiry date, so the browser keeps it for its session. The 12-digit number in the page banner is derived from that id. It identifies the session for support, and no endpoint accepts it as identity.
sequenceDiagram participant Browser as browser participant Worker participant Container as container Browser->>Worker: open a page Worker->>Browser: published page Worker-->>Container: prewarm Browser->>Worker: comment Worker->>Container: forward Container->>Worker: accepted Worker->>Browser: accepted Worker-->>Container: start agent Browser->>Worker: read state Worker->>Container: forward
Private sessions
The first request that needs private, mutable state, such as posting a comment or picking an option, goes to the visitor's container. Its response sets a cookie marking that one page active, and from then on the Worker sends that page's API requests to the container. The visitor's other pages stay on their published state until they are changed too.
Each container belongs to one identity and one release. The Worker names it by
the pair, and Cloudflare starts the container when a request for that name
first arrives. The container image holds the whole site build, every page
directory included, and runs leaf_website, an adapter that maps
each public route to its page directory and hands the request to the HTTP
routes and event admission a locally served Leaf uses. A comment is appended
to events.jsonl in the container's copy of the page, so each
visitor uses the real event log without changing the page anyone else sees.
The site keeps no separate store of threads or state.
A browser's document navigation also starts the visitor's container in the
background, before anything has been changed, so the first comment does not
wait for it. On start, the container launches Codex App Server and runs the
leaf command once, ahead of the first agent turn. Asset fetches
and API calls do not prewarm, and prewarming is rate-limited per source
address.
Documents come from the edge, including reloads. When an agent's revision changes the page's scripts or vocabulary, the open document cannot load them in place, so the runtime reloads once from the container with a marked URL and removes the mark on arrival.
The hosted agent
When the container accepts an event that needs an answer, such as a comment, the Worker returns the accepted state to the browser at once and starts the agent in the background. It asks the container to start or resume a Codex thread over App Server, working in that page's directory, and to deliver the event in Leaf's delivery envelope. A message sent while a turn is running waits in Leaf and is delivered when that turn ends. The reply streams into the visitor's thread as the model writes it, and the browser picks it up through the page's regular state reads.
The hosted agent reads the same contract as a Codex task Leaf reaches over App
Server on a developer's machine,
harness-codex-app-server.md, followed by a few leaf.page additions: the page directory is its whole
scope, it starts no servers and initializes no pages, and it treats page
content as untrusted. Its App Server starts without the Leaf authoring plugin,
so a short reply does not turn into a full authoring workflow.
The visitor's container is the agent's sandbox, with no public internet. An
outbound handler in the Worker lets through only Responses API requests to
api.openai.com, and replaces the dummy credential the container
holds with the real key, which never enters the container. Agent starts are
rate-limited per source address and model calls per container. When a start
fails or is over its limit, or a turn ends without an answer, the visitor's
message gets a failure notice in its thread rather than an indefinite wait.
Releases and deploys
Every build has one release identity. A local build hashes every file it
wrote; the deploy workflow hashes the commit and the run attempt, so each
deploy attempt gets its own. Each page's runtime files are served under
/_leaf-release/<release>/ with immutable cache headers. The
document names its release, the browser sends it with every API request, and
each API response names the release that produced it.
The runtime refuses a response from another release. The page's state is read by the scripts and widgets the document has loaded, and a document cannot replace those in place, so state from another build would be read by code not built for it. The runtime then asks the document's source whether it now serves a different release. If it does, the page says Leaf has been updated and reloads; if not, it waits for the server to finish updating.
Cloudflare activates a new Worker and its assets before the new container
image has rolled out, so for some minutes a new container can still start on
the previous release. When a container answers with a release other than the
Worker's, the Worker does not pass that answer on. It clears the page's active
cookie, serves the published state for api/state, and answers
other requests with a 503 asking the browser to retry, until containers on the
new release answer.
A push to main that changes the site runs the
publish-site workflow. It builds the site, checks the bundle
locally through the Worker and a container, pushes the container image, and
deploys the Worker with that image pinned by its digest and an immediate
container rollout. The deploy passes only once Chrome sees the new release in
the edge document, its modules, and a newly started container, and a hosted
agent on leaf.page has answered a real turn.
Private state and its lifetime
A visitor's comments, choices, agent replies, and revisions exist only in their container's copy of the page directories. No other visitor reads them, and the published pages never change. The container's filesystem is ephemeral, and the site has no durable store for page directories, so this state lasts as long as the container:
- A container stops after ten minutes without a request. A visible page that has become active keeps it running with its regular state reads; a hidden tab stops reading.
- A new release always starts new containers, since each container is named by its release.
- Cloudflare can replace a running container, including during a rollout after a ten-minute drain window.
When a page's container has been replaced, the page notices the new server, reloads, and starts again from the published state.
The site counts accepted events in Analytics Engine without their content, widget ids, IP addresses, or cookies. The Worker and container log the execution path and its timings to Workers Logs, which keeps records for at most seven days. The Worker's README describes what each record carries.