One Markdown page per domain per day.
Minimal Cloudflare Worker that serves a single AI-generated markdown essay per hostname per UTC day. First request triggers generation; the result is cached at the edge and in a Durable Object so you pay for one model call per day per domain. Output is plaintext markdown displayed inside a monospace HTML shell with automatic light/dark.
What it uses
- Cloudflare Worker + Durable Object
- Cloudflare AI Gateway (OpenAI-compatible) pointing to xAI
grok-4.7with low reasoning effort - Edge cache 24h
- Durable Object request coalescing so cold misses share one daily generation
- Optional streaming path
/streamto show the first generation live on cache miss
Quick start
wrangler login(or export a CF_API_TOKEN with Workers/DO/AI Gateway edit perms).- Create an AI Gateway in the dashboard, add the xAI provider, copy the compat base
https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_id>/compat. - From repo root:
wrangler secret put XAI_API_KEY- optional:
wrangler secret put GATEWAY_TOKENif your Gateway uses a separate token - set env
GATEWAY_BASEto your compat URL (or edit the default placeholder insrc/worker.ts); the Worker adds Cloudflare's requiredgrok/model namespace for/compatURLs.
wrangler deploy- Map your domains in Cloudflare Routes/DNS to this worker. Host header drives per-domain text.
Behavior
- One generation per host per UTC day; DO overwrites one
{text, generatedAt}slot per cache version. - Edge cache keyed per host/version/day; headers:
ETag=host:version:date,X-Generated-On= date. - Prompt: philosophical, host-aware, ~220–400 words, H1 + H2 sections, optional single bullet list, italic closing line.
- Normal and streaming requests use
reasoning_effort: "low",temperature: 0.6,top_p: 0.9, andmax_tokens: 500. Cloudflare's/compatmodel ID isgrok/grok-4.7. - Both generation paths allow up to 60 seconds for the model response, including reasoning time.
- Fallback text is deterministic if the AI call fails, and is stored for that host/day.
- Footer shows generation date and a right-aligned link “a @steipete project” → https://steipete.me.
- Streaming: request
/streamto stream the first uncached generation live through the Durable Object. Concurrent/or/streammisses wait on the same in-flight generation, so streaming cannot bypass the one-generation-per-day guard. Live responses are not edge-cached; the next normal request caches the completed DO record. Interrupted streams store deterministic fallback text, never partial output, as the daily record.
Testing
- Use Node 22.13 or newer and install the pnpm version pinned in
package.jsonwithnpm install --global pnpm@11.28.4. Then runpnpm install --frozen-lockfileandpnpm checkfor formatting, types, lint, and unit tests. Installing pnpm directly avoids the outdated Corepack signing keys bundled with older Node releases. - Run
pnpm audit --audit-level=highto check dependency advisories andpnpm exec wrangler deploy --dry-runto validate the Worker bundle without credentials or a deployment. wrangler devthen curl twice:curl -H "Host: yourdomain.test" http://127.0.0.1:8787and confirmX-Generated-Onstays fixed.- Check AI Gateway analytics to verify only one upstream call per domain per day.
- Stream path test:
curl -N http://127.0.0.1:8787/streamon a fresh day to observe live output.
Config references
src/worker.ts: worker logic, DO class, Gateway call.wrangler.toml: DO bindingDOMAIN_DO, entrypoint, migration tag.docs/spec.md: deeper architecture and ops notes.- CI:
.github/workflows/ci.ymlchecks the minimum Node 22.13 runtime and the latest Node 22 release, audits dependencies, and validates the bundle withwrangler deploy --dry-run. CI does not require deployment or AI credentials. - Dependency maintenance: Dependabot checks npm dependencies weekly and groups patch/minor version updates. Keep Wrangler current to pick up Miniflare's pinned transitive security fixes; security updates remain eligible between scheduled version updates.
See RELEASING.md for the signed-tag GitHub release workflow and its no-publish rehearsal.