2026-07-03 · 2 min read
How this site works
This site's entire content system is two TypeScript files. That is not a temporary hack on the way to a real setup — it is the setup, and this note explains why.
Content as data
Every project and every post is a typed object in a content/ directory. Publishing means editing an array:
// content/projects.ts
export const projects: Project[] = [
{
slug: "research-workbench",
name: "AI research workbench",
status: "egg", // "hatched" | "incubating" | "egg"
tags: ["llm", "agents"],
description: "An agent that runs the boring half of research…",
},
];The type checker is the editor. Forget a field, misspell a status, break a slug — the site refuses to build. For a one-person site this beats any CMS: the whole editing workflow is a text editor and git, which are the two tools I already live in. No admin panel to secure, no database to migrate, no drafts rotting in a web UI I never open.
Everything is static
Next.js prerenders every page at build time — including the sitemap, the robots file, and each note — and the result is plain files on a CDN. At runtime the server does nothing but hand them out. Fast everywhere, free to host, and nothing to patch at 2 a.m.
Route (app)
┌ ○ /
├ ○ /about
├ ○ /projects
├ ● /notes/[slug]
└ ○ /sitemap.xml
○ static ● prerendered from content/What's deliberately missing
No CMS, no MDX, no comments, no analytics, no newsletter popup. Each of those gets added the day the pain is real, not the day a tutorial suggests it. The upgrade paths are written down in the repo's README, so adding one later is a decision, not a research project.
Total runtime dependencies: three — React, Next.js, and Tailwind. The most complex asset on the site is the chicken, and it's six circles and a triangle.