Use this architecture map to locate a request, choose the right trust boundary, or follow a change into storage. Energon runs as one Cloudflare Worker with three request surfaces because humans, agents, and public-link readers carry different authority. One Worker coordinates those surfaces against the same D1 catalog and R2 object store.
Architecture
System map
Three surfaces, one domain model
The hub origin (PUBLIC_ORIGIN) serves the hub and /v1, but those paths do not share authentication. Cloudflare Access establishes a production human identity for setup, tokens, and account operations. /v1 bypasses Access. Authenticated file and site operations call the same domain functions with an actor created from an Energon-issued agent key. Discovery and connection request/poll endpoints are public; connection delivery still waits for human approval. The content origin (CONTENT_ORIGIN) is a distinct production hostname that serves published /{handle}/s/{id}/{slug}/... and /{handle}/f/{id}/{filename} paths, guest PUT and site-path DELETE when a write password is set, a guest-only /llms.txt, and, from v1.12.0, this Energon’s well-known skill under /.well-known/agent-skills/. It does not serve hub account routes or /v1 help; those content-host API paths return 404 naming GET /llms.txt.
The router handles health, runtime docs, and host separation before normal schema-backed dispatch. Most other requests call ensureSchema first. Supported older databases can gain additive columns before indexes are created. Append-only migrations still carry deployment history, and operators must apply them before deploying the Worker.
You can observe the public edge without a credential:
ENERGON_ORIGIN="https://energon.your-company.example"
curl -fsS "$ENERGON_ORIGIN/v1/health"
curl -fsS "$ENERGON_ORIGIN/v1/help" | jq '{hub, content_origin, identity, retention, limits}'Pages and browser assets
The same Worker server-renders the Svelte interface and serves compiled assets for interactive hub pages. Public Markdown and password gates do not load the application JavaScript bundle; Diagrams in Markdown load their own renderer, Pele, with Mermaid as the fallback. This adds no separate application server. See Architecture and integrity for source and build ownership.
D1 coordinates; R2 holds bytes
D1 stores users, token hashes, object identities, ownership and write policy, expiry, share-password and write-password hashes, upload grant secret hashes and state, recoverable Hub phrases, mutation claims, deployment sessions, site version catalogs, read leases, storage allocations, and the platform quota ledger. R2 stores the actual bytes. Cloudflare does not provide one transaction across both services, so Energon writes bytes to R2 first and makes them visible only through a conditional D1 commit.
Sites publish immutable versions
A site is a stable identity that points at one immutable site version. A version is a complete catalog of paths, each mapped to an R2 object written under a fresh key. Publishing never overwrites a live object.
Commit is one D1 update that moves the site’s active version pointer only if the site’s content_generation still equals the generation the session started from. A competing or failed candidate therefore cannot partially replace the live site, and a stale one fails with a conflict instead of overwriting a newer release. Single-path writes, ZIP merges, guest writes, and one-path upload grants use the same mechanism: each builds a full new version that changes only its paths.
Each site request takes a short D1 read lease on the version it selected, so cleanup cannot delete objects a response is still streaming. A superseded version is kept for a five-minute grace and while any lease remains, then its storage is reclaimed and its quota charge released. Selection happens per request. An HTML page and the assets it loads later can come from different versions if a commit lands in between; Energon does not pin a page to one version.
Loose files keep their own single-object replacement path, with conditional D1 commits plus storage snapshots and explicit recovery errors when compensation fails.
Caching
Site requests always reach the Worker. The Worker checks expiry, the share password, and the active version before it consults an internal cache keyed by that immutable version, so publication never depends on purging a cache. Outer cache headers for site responses are private and no-store. The internal cache saves the R2 body read, not the D1 lease. This replaces the earlier design, where public site responses sat in the edge cache and every site write had to purge the site’s prefix.
Loose-file responses without a password may still be cached at the edge for at most one day, or less when remaining content TTL is shorter. Successful writes, policy changes, deletes, and expiry purges invalidate that file’s prefix. Password-protected responses and rendered Markdown are private. Because loose-file cache hits never reach the Worker, last read on a loose file can lag real reads by at most about a day plus an hourly stamp throttle; site reads are stamped by the Worker, subject to the same hourly throttle.
Expiry has two enforcement paths
The scheduled handler bootstraps schema and sweeps bounded batches of expired sites and loose files. Reads and writes also check expiry and return 410 Gone immediately. An expired site is first marked as removed; its versions and storage are reclaimed after read leases end and cleanup guards allow it. For loose files, a D1 purge claim prevents cleanup from racing a TTL reset or replacement; the purge removes R2 bytes and catalog rows, invalidates cache, and releases quota. The same sweep removes expired deployment sessions and superseded site versions, and advances older-site conversion when an operator has enabled it.
The content hostname is a security boundary, not a cosmetic alias. Do not put the human Access session on it or configure it to equal the production hub origin. Published HTML, XHTML, SVG, and XML are sandboxed as an additional defense, not as a substitute for origin separation.
Follow one object through these components in Data flow. Operators should pair this map with Deploy an Energon host and Set safe Energon boundaries; contributors can go deeper in Architecture and integrity.