Tech · Note
How this site is built
This site used to be WordPress. It worked, but every time I wanted to write something down I ended up fiddling with themes, plugins or updates instead. Building the site was competing with writing in it. This is the rebuild, and this post is the overview: what I wanted, what I picked and why. The posts linked at the bottom go into each part with enough detail to set it up yourself.
What I wanted
- Getting something down should be almost free, ideally from my phone, before it is polished.
- Content as plain files in git. Nothing locked into a service, and a full history of every change.
- A site that feels personal, soft and painterly, not like a documentation portal.
- AI help that suggests rather than acts. Tidying, structuring and tagging, but always as something I can see and accept, and it never invents a tag on its own.
- Small on purpose. Two kinds of post (recipes and notes), a handful of sections and nothing else until real content asks for it.
What I tried first
The first attempt was MkDocs with the Material theme, deployed to GitHub Pages. It took an afternoon and it was fine, but it looked and felt like product documentation. I scrapped it the same day.
The obvious next step would have been a framework like Astro. I went for a small custom generator instead, for three reasons:
- Building it with Claude was cheap. The generator is under a thousand lines of glue. The hard parts (markdown, code highlighting, image resizing, search) are all off-the-shelf libraries.
- One renderer everywhere. The phone admin previews posts with the same code that builds the site, so what I preview is what gets published.
- No framework upgrade churn. Nothing to migrate when a major version lands.
How it fits together
laptop: Claude Code ─┐
├──► private GitHub repo ──push──► Cloudflare Pages build ──► bla.ckmo.re
phone: admin PWA ────┘ (markdown) (npm run build)
│
└── Cloudflare Access ──► Cloudflare Worker ──► GitHub API (commits)
- Content lives in
content/<section>/<slug>/index.md, one folder per post, with its images beside it. The URL is always/<section>/<slug>/. taxonomy.ymlis the single list of sections, post types and tags. The build fails on anything that is not in it, so tags cannot quietly sprawl.- The generator turns the folder into static HTML, plus RSS, a sitemap and a search index.
- Cloudflare Pages builds the site on every push to
mainand serves it. It is free and works with a private repo. - The admin is a tiny web app on a Cloudflare Worker, behind Cloudflare Access, for tweaking posts from my phone. Saving commits straight to the repo, and Pages rebuilds as usual.
Claude as the CMS
The plan had a full admin app with drafts, an editor and AI buttons. I parked most of it once I
noticed that a Claude Code session on the repo already did the job better. I describe a recipe or
paste rough notes, and Claude writes the post in the house format, picks existing tags, generates a
cover, runs the build and pushes. The git diff is the review step. The rules it follows live in the
repo (CLAUDE.md, taxonomy.yml and the validator), so they apply whether I’m on the laptop or
on a cloud session from my phone.
The admin that does exist fills the one gap that was left: quick edits from my phone without starting a session.
Choices I’d make again
- Drafts are not a thing yet. It is a low-stakes personal site, so posts go straight to
main. Drafts can come back if I miss them. - Status is a tag (
wip,needs-tweak), not a field, so half-tested recipes are honest about it. - Generated covers, no food photography. Every post gets a painted, low-detail banner. It sets the tone without me needing to photograph anything.
The rest of the series
- A small static site generator: the build, the libraries and the content rules.
- Hosting on Cloudflare Pages: the build settings, custom domain and cache headers.
- A phone admin on Cloudflare Workers: Workers, Access and wrangler, step by step.
- Writing posts with Claude Code: the workflow and the cover images.