There's a story from the book Art & Fear about a ceramics class. The teacher splits the class in two: one half will be graded on quantity - just produce as many pots as you can. The other half will be graded on quality - produce one perfect pot. At the end of the semester, the best pots all came from the quantity group. While the quality group sat around theorising about perfection, the quantity group was learning from their mistakes, pot after pot.

I've been thinking about starting a blog for a while. I kept not doing it because I didn't have the perfect setup, the perfect design, the perfect first post. So today I decided to just make pots.

What I had to start with

Not much, but enough:

  • A domain name on Route 53 that I've been renewing for ages
  • An S3 bucket
  • A GitHub account
  • An afternoon
  • Some ideas about stuff I wanted to write about

What I asked for

I opened Claude and basically said: help me build a personal site where I can write blog posts in Markdown and have them turn into a website. I want it hosted on S3. I want it to be simple enough that I can just write a .md file and publish it. Here's roughly what I asked:

I want to create a personal website flexible enough that I can write and index blog articles, but also do scrolling visual pages with text, images, and charts. I want to ship something today. The idea is I can just write blog posts. I plan to host on S3 - I've currently got the domain set up on Route 53.

That was it. No detailed requirements doc. No framework comparison. Just: here's what I want, let's go.

What came out

A custom static site generator in TypeScript. No framework - just a build script that reads Markdown files, runs them through a parser, wraps them in HTML templates, and writes the output to a folder. That folder gets synced to S3.

The whole thing is maybe 500 lines of actual code across a handful of files:

  • Markdown parsing with frontmatter (title, date, tags - the stuff at the top of each post)
  • HTML posts for when I want to do something more visual
  • An image pipeline that generates responsive sizes and formats
  • RSS feed generation
  • Syntax highlighting for code blocks
  • Dark mode that respects your system preference

To write a new post, I create a file like 2026-04-06-my-post.md, put some metadata at the top, write the content, and push to GitHub. That's it.

The deployment

This was actually the most interesting part. The build runs in GitHub Actions - on every push to main, it installs dependencies, runs the build script, and syncs the output to S3.

The default suggestion was to store AWS access keys as GitHub secrets. I didn't love that - long-lived credentials sitting in a repo felt off. So instead I set it up with OIDC (OpenID Connect), which is genuinely a better approach and turned out to be simpler.

Here's how it works: instead of storing AWS credentials in GitHub, you create a trust relationship between GitHub and AWS. When the GitHub Action runs, it requests a short-lived token from GitHub's OIDC provider. That token proves "I am a workflow running in this specific repo." AWS sees the token, checks it against the trust policy on an IAM role, and hands back temporary credentials that last just long enough to do the deployment.

No long-lived secrets. No keys to rotate. The credentials exist for a few minutes and then they're gone. The IAM role is scoped down to only what it needs - put objects in one S3 bucket, invalidate one CloudFront distribution. Nothing else.

The whole deployment takes about 16 seconds.

The philosophy

I'm not pretending this is the best static site generator. It's not even close. There are incredible tools out there - Astro, Hugo, Next.js, Eleventy - that do far more than this. But I understand every single line of this one, and I can change anything without reading docs or fighting a framework.

More importantly: it exists. It's live. I'm writing on it right now.

The quality group is still planning their perfect pot. I'm just going to keep making pots.