I’ve been playing around with blogs for some time now. However, the medium and level of interest has changed over the years. This page details how my blog has evolved and what I’m currently using to host it.

We’re currently on version 4 of the blog. Version 1 was WordPress — boring, basic, does the job. Version 2 was a bit more interesting, using Notion and then a Notion-to-HTML hosting tool. Version 3 was a simpler (and hopefully more robust) markdown-to-HTML approach, also a lot cheaper — all I was paying for was the domain. Version 4 (current) uses Quartz with Cloudflare Pages, and I’ve added Claude Code skills to automate the whole publishing workflow.

Infrastructure

My blog is a collection of .md files, kept locally and managed with Obsidian (free tier). I use Quartz to convert the markdown files into a static site, hosted on Cloudflare Pages (also free tier).

Quartz is an open-source static site generator built specifically for Obsidian-style markdown. It takes a folder of .md files — including wikilinks, frontmatter, and embedded images — and builds a full website with navigation, search, backlinks, and a graph view. It runs as a Node.js build step, and Cloudflare Pages rebuilds the site automatically on every push to the repo.

The full workflow looks like this:

  1. I write or update a post in Obsidian
  2. I run a Claude Code skill (/update-blog) which compares the Obsidian vault against the blog repo, detects new or changed posts, syncs them across, adds frontmatter if missing, updates the front page index, and pushes to GitHub
  3. Cloudflare Pages picks up the push, runs npx quartz build, and deploys the updated site — usually within a couple of minutes

I also have two other Claude Code skills: /blog-generate-assets, which scans a post for inline instructions in curly brackets and generates graphs or diagrams (using a temporary Python venv), and /blog-improve-post, which handles copy editing, formatting, frontmatter validation, and SEO interlinking.

One of the fun challenges is trying to get this blog to be as performant and lightweight as possible. Cloudflare does a lot of the heavy lifting — I don’t have to worry about CDNs, hosting, or performance on their end. But there are a few optimisations we can make on ours. A lot of this was done using Google’s PageSpeed Insights. There were some easy wins — like changing how requests were loaded, or restricting certain libraries to the pages that actually need them (e.g., LaTeX libraries only load on pages that use LaTeX). Right now PageSpeed Insights is pretty happy, with performance scores of 98 and 90 on desktop and mobile respectively. I’d like to get the mobile score slightly higher though.

There’s also the balance between making the site as lean as possible while still having some artistic flair. I’ve not found that balance yet. Some voice and humour come through in the text, but it’d be cool to have something more interesting in the blog itself.

V2: Notion + simple.ink

Version 2 was more complex. I used simple.ink to host the blog, which connected to Notion and turned publicly available Notion pages into website pages. There were SEO benefits, but the main benefit was accessibility — it got rid of Notion’s ugly public URLs and subdomains.

Data collection

I wanted a subscription form for people to put in their email addresses. This is done through Tally. I tried simple.ink’s own form builder and also notionforms.io. All had identical creation processes, but I was most impressed with Tally’s ease of use.

Hosting graphs and code

I used to use DeepNote as a Jupyter competitor, with most Python scripts running on their VMs. For V2, I could embed their graphs directly into Notion as code extracts — that was great and easy. With the current markdown approach, images are stored in subfolders alongside each post in the Obsidian vault (e.g., Post Name/image.png), and embedded using Obsidian’s ![[image.png]] syntax. Quartz handles the conversion to standard HTML image tags during the build.

Copywriting

I was a big fan of OpenAI’s ChatGPT. Since their recent work with the Pentagon, I’m boycotting them and have since switched to Anthropic (both personally and for our work business account). I’ve also been a huge fan of Claude Code, and Anthropic are a key part of this blog. Some of the pages are AI-assisted — every new coding project has an index.md file which gets fleshed out into a blog post, with human edits on top.

Analytics

I use Cloudflare’s built-in Web Analytics for tracking page views and visitor stats. It’s privacy-friendly (no cookies, no client-side JS tracking), free, and just works since the site is already hosted on Cloudflare Pages.