Skip to Content
Energon runs in the operator's Cloudflare account. Published links are open by default.
ContributeArchitecture and integrity

Read Energon through its integrity boundaries before changing routing, persistence, expiry, or the agent protocol. The Worker coordinates catalog rows, bytes, quota, cache, and concurrent cleanup explicitly because D1 transactions cannot include R2 objects. This page shows where that coordination lives, which state must converge, and how schema and generated agent documents widen the scope of an otherwise small code edit.

Architecture and integrity

The request boundary

src/index.ts is the single Worker entry point. It normalizes expected ApiError responses, maps malformed URL encoding to a client error, and keeps unexpected failures behind a stable JSON envelope. Its route order is part of the security and availability model:

Published content paths redirect from the hub origin (PUBLIC_ORIGIN) to the content origin (CONTENT_ORIGIN) in production. The content hostname rejects account and API routes. Most remaining requests call ensureSchema before dispatch; the scheduled handler does the same before expiry cleanup.

The domain modules repeat authorization in conditional D1 writes so an ownership decision cannot go stale between lookup and commit. URL, path, MIME, retention, cache, and catalog helpers keep those concerns out of the router.

D1 is coordination; R2 is bytes

D1 owns the catalog, stable identities, policy, mutation claims, and the platform_quota ledger. R2 owns the content. A successful mutation must leave them describing the same object.

reserve positive quota delta | v snapshot or stage previous R2 state | v write/delete R2 bytes | v conditionally commit D1 metadata | +---- failure ----> restore R2 and D1/claim state | v purge public cache prefix and release quota delta

Site and loose-file operations use different coordination strategies because their identities differ.

Site mutations

A site has one parent row, many child rows, and many R2 keys. A path PUT snapshots the previous object, writes R2, and batches the child upsert with the parent last-writer update. Import snapshots every affected path and its prior catalog rows, writes in D1 batches of at most 100 statements, and restores all affected state after a failure.

Whole-site deletion stages every live R2 object under an integrity-backup prefix before deleting the live prefix and D1 rows. On failure it copies the backups back. On success it removes backups, purges the site prefix, and releases the catalogued byte total. The temporary backup namespace is an implementation detail, not published content.

Loose-file claims

A loose file has one row and one current R2 key, but replacement can race another writer or expiry. PUT and DELETE first place a unique leased write claim in last_written_by. The later D1 mutation succeeds only if that claim still owns the row. A pre-commit failure restores bytes, the observed timestamp, and the effective prior writer.

Expiry uses a purge marker in the same field. A fresh write claim blocks cleanup; a purge claim blocks a TTL revival after deletion starts. Claims become stale after 60 seconds, allowing another request or sweep to recover abandoned work. The in-memory inFlight set only deduplicates within one isolate; D1 predicates provide the cross-isolate guarantee.

Preserve rename identity

Loose-file identity is the id, not the readable filename segment. Runtime rename is a byte replacement:

export ENERGON_ORIGIN="https://hub.your-company.example" export FILE_ID="REPLACE_WITH_EXISTING_FILE_ID" test -n "$ENERGON_TOKEN" || { echo "Set a human-minted ENERGON_TOKEN" >&2; exit 1; } curl -fsS "$ENERGON_ORIGIN/v1/files/$FILE_ID" \ -X PUT \ -H "Authorization: Bearer $ENERGON_TOKEN" \ -H "X-Filename: renamed-report.md" \ -H "Content-Type: text/markdown" \ --data-binary @report.md

The PUT keeps FILE_ID, writes the new key, commits the new filename, and best-effort removes the old key only after metadata points to the replacement. Old public filename paths redirect by id to the returned canonical url. PATCH does not accept a filename; any feature-map sentence that suggests PATCH rename is stale and must not override runtime behavior.

Schema has three representations

Every schema change updates the representations that apply:

RepresentationRoleRule
migrations/NNNN_name.sqlDeployment historyAdd a new file; never rewrite an old migration.
src/db.tsRequest/cron bootstrap and legacy additive upgradeCreate absent tables, add supported columns, backfill where required, then create indexes.
src/schema.sqlDocumented current create shapeKeep it aligned with runtime table declarations; it is not applied by the Worker.

The old 0001_init.sql comment calling itself a copy of src/schema.sql is historical. The file is frozen history, not a live schema copy. Tests compare the current src/schema.sql columns with runtime table declarations and prove a 0005-shaped database receives columns before indexes.

CREATE and ADD COLUMN migrations are not idempotent. Migration files that mention stamping d1_migrations contain historical human-recovery notes for a deploy-first incident. They are not authorization for an agent to edit production migration state. The normal order is migration first, Worker second; only a human operator may verify an already-added production column and follow the documented recovery procedure.

The API and generated agent behavior are source contracts

openapi/v1.json is the canonical /v1 HTTP schema. The Worker serves a cloned copy at /v1/openapi.json, replacing servers[0].url with the current instance’s PUBLIC_ORIGIN without mutating the committed document. GET /v1/help complements it with instance identity and policy rather than duplicating the schema.

test/unit/openapi-drift.spec.ts keeps the contract tied to the implementation. It compares OpenAPI operations with the router and help.routes, requires operation ids and responses, checks the shared error-code enum against application errors, and limits unauthenticated operations to the discovery surface. test/routes.spec.ts proves the live response, runtime server URL, CORS, HEAD, and method rejection through the Worker.

The committed plugin is generated from templates/ plus instance-skill.json. The renderer validates identifiers and all mutation targets, rejects unknown or unreplaced tokens, avoids project-local autoload copies, and supports a check-only mode.

templates/skill + templates/plugin + instance-skill.json | v scripts/render-skill.mjs | +--> plugins/{instance-name}/ +--> real-host marketplace catalogs +--> updated instance-skill.json during init

Edit templates or instance configuration, run the renderer, and review the generated diff. The upstream placeholder produces a placeholder plugin without marketplace catalogs; a real-host skill:init produces the named plugin and marketplace entries.

When /v1 behavior changes, generated-file equality is not enough. Review the semantics across openapi/v1.json, src/auth.ts’s helpBody, src/llms.ts, templates/skill/, the runtime golden fixtures, and the rendered plugin. A snapshot can prove that a representation changed; it cannot prove independently authored representations still agree.

Failure modes

Do not update only the happy-path D1 write, only one schema representation, or only one API or agent document. Cross-service mutations need compensation and concurrency proof; schema needs append-only history plus compatible bootstrap; /v1 changes need semantic review across OpenAPI, runtime help, llms.txt, templates, goldens, and rendered output. Agents must never stamp production migration state.

  • Develop and verify maps each boundary to focused, injected-failure, mock-free, fuzz, page-contract, and browser checks.
  • Contribute to Energon explains contribution lanes and the repository tour.
  • HTTP API records the user-facing protocol these internals implement.
  • Upgrade and recover gives the human production migration procedure.
Last updated on