WRITING · 2026 · 2 min read
First post
An opening note on the writing surface — what lives here, how it gets here, and the small set of conventions I'm holding myself to.
Most of the site is finished work. The writing surface is the part that isn’t — by design.
These pages collect the half-formed thoughts that don’t fit anywhere else: notes-in-progress on apps I’m building, vulnerabilities I’m reading about, the occasional film essay when something hits hard enough to write about. The voice is closer to a notebook than a journal.
How it gets here
The pipeline is deliberately small. Each essay is an .mdx file, validated by Zod against a shared schema in src/content/config.ts. Authoring looks like this:
const essays = defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/essays" }), schema: baseFrontmatter.extend({ heroImage: z.string().min(1).optional(), heroImageAlt: z.string().min(1).optional(), ogImageOverride: z.string().min(1).optional(), }),});The same MDX renders here, in the RSS feed, and (eventually) on the throwback surface — three views of the same single source. Code blocks pick up syntax highlighting at build time; outbound links carry the right rel attributes automatically; per-post Open Graph cards get rendered to PNG at build and served as static assets.
What I’m holding myself to
Three small rules:
- One topic per post. If I find myself writing two posts in one, I split.
- No dates in titles. The frontmatter has the date; saying it twice is fluff.
- Outbound links earn their place. If a link doesn’t add something the prose can’t, it doesn’t go in.
That’s it. The rest of the surface — typography, rhythm, the voice — is doing the real work.