This is a simple minimal repo for my essays, letters and thoughts that can expand or contract based on your available reading time.
Live at essays.georgestrakhov.com. Runs on Cloudflare Workers (Hono + JSX) with the essay content in D1.
essays/- one directory per essay, containing:{slug}.md- the original, hand-written version- Zoom variations:
{slug}.{zoom}.mdwhere zoom issmall,mediumorlarge img/subfolder - images (.png, .jpg, or .svg)
toc.json- the manifest: title, description, slug, timestamp, word counts per zoom level, and flags (isDraft,isAIGenerated)src/- the Worker:index.tsx- Hono routes (home, essay pages, RSS, generation endpoints, 404)db.ts- D1 queries;llm.ts- generation via OpenRouter;markdown.ts- renderingprompts.ts- zoom level definitions and system promptsviews/- JSX pages
migrations/- D1 schema (essays+essay_versionstables)scripts/- build and maintenance scripts (see below)static/- CSS and JS, copied intopublic/at build time (public/is generated, not committed)CORPUS.md- all human-written originals concatenated; used as the style reference when the LLM writes something new
The database is the source of truth for what the site serves. The markdown files are the source of truth for what goes into the database. Editing a .md does nothing until you re-seed.
- Write it into
essays/{slug}/{slug}.md. npm run update-toc- scansessays/and adds any new directory totoc.json, inferring title, description, word count and natural zoom level. Existing entries keep their hand-edited fields; re-run it any time to refresh word counts. Add"isDraft": trueby hand to keep something out of the live site.npm run build:corpus- regeneratesCORPUS.md.npm run db:seed:remote- upsertstoc.json+ the original markdown into D1. Drafts are skipped.npm run deploy- builds assets and ships the Worker.
npm install
npm run db:migrate:local # apply schema to the local D1
npm run db:seed:local # load essays into the local D1
npm run dev # wrangler dev on :8787Secrets live in .dev.vars locally and in wrangler secret in production: OPENROUTER_API_KEY, RECAPTCHA_SECRET_KEY, RESEND_API_KEY. Non-secret config (BASE_URL, RECAPTCHA_SITE_KEY, ADMIN_EMAIL, FROM_EMAIL) sits in wrangler.toml.
These essays are telescopic (inspired by TelescopicText.org), allowing readers to zoom in or out based on their current attention capacity and time availability.
small(~200 words) - TLDR with bulletsmedium(~1000 words) - the basic argumentlarge(3000+ words) - detailed exploration
Each essay has a natural zoom level: the one I actually wrote, inferred from its word count. That version is marked isOriginal and is the one served by default.
Longer versions add content and enhance the original by adding:
- Commentary from multiple perspectives
- Analysis from different viewpoints
- Related discussions and context
If a reader asks for a zoom level that doesn't exist yet, the Worker:
- Generates it with
anthropic/claude-opus-5-fastvia OpenRouter, using the original as input - Writes it into D1 so it persists and is served instantly from then on
- Emails it to me (via Resend) so I can vet it, and if I like it, commit the markdown back into the repo
Generated versions are labelled on the page (AI-generated, and whether I've reviewed them yet). Whole essays written from a 404 are hidden on the home page behind a "show AI-generated essays" toggle.
If the requested essay doesn't exist, the 404 page offers to write it on the spot, in my style, using CORPUS.md as reference. reCAPTCHA guards both generation endpoints against robot abuse.
- fix bug on showing "not yet generated" when it is
- when generating: add pre-check on validity of URLs when generating. otherwise llms invent urls. if not real url - clean it.
- add admin interface to approve, reject, regenerate, edit essays that were generated - and have programmatic github push behind the scenes, so vetted versions make it back into the repo without me copy-pasting from email
- add diagram generation with nano banana pro (need to define the style) - including when creating from 404
- add auto-listen generation with notebookLM - including when creating from 404
update-tocalways adds new essays as live; a--draftflag would be handy