Skip to content
Predictive Perception
Go back

Rebuilding My Blog with Claude Code

Problem

The old version of this site ran on Jekyll with a Bootstrap theme called Clean Blog. It worked, and I was proud of my early web development accomplishment, but it had accumulated friction. The posts themselves were .html files with inline styles and GA4 scripts copied into every one. Customizations were painful.

Honestly, the site looked and felt like a default template, and that bothered me. So I decided to experiment with making it more on-brand.

The goal was a modern stack with a content collection system, Tailwind, component-based layouts, and a design I actually configured. Astro was the obvious move. The interesting part was using Claude Code to get there.

Solution

I set up a new private repo (predictive-perception2) and kept the old Jekyll site live on AWS Amplify throughout the build. No downtime, no pressure to rush.

The migration happened in two passes. First pass: scaffold AstroPaper as a base, port the existing posts from .html to clean markdown, wire GA4 through the site config, and set up a _drafts/ directory for future posts. Second pass: replace the AstroPaper theme entirely with a custom design. Navy OKLCH dark palette, Hubot Sans for headings, Inter for body copy, cover images on posts.

Claude Code handled most of the implementation. My job was steering: deciding what to keep, what to scrap, and what the output should feel like. That distinction matters more than it sounds. Claude Code is fast and capable, but it will fill in gaps with its own judgment. If you want specific results you have to be specific. “Dark mode navy palette” got me something close. “oklch(19% 0.055 250) for the background, not oklch(12%) which reads as black” got me exactly what I wanted.

Writing a post or page takes five or six rounds. Claude drafts, I rewrite, Claude refines. That back and forth is where it shines.

Learnings

Astro’s content schema has an image() validator that only works for files in src/assets/. I used it for post cover images stored in public/, which Astro serves directly without going through the optimizer. The result was a cryptic ImageNotFound error at dev time. The fix was changing the schema from image().or(z.string()) to just z.string(). Claude caught it faster than I would have.

Case sensitivity will trip you in production even if it doesn’t locally. I had an image filename with capital letters. macOS does not care. Linux, which is what Amplify runs on, does. The file would have 404’d in production. Renaming everything to lowercase before launch is wise.

Clear the .astro/ cache when things get stuck. Astro’s dev server caches generated content in a .astro/ directory. After a schema change, the cached content-assets.mjs still had the old import. The server was not picking up my fix. rm -rf .astro && npm run dev cleared it. Not obvious in the moment.

Claude Code does not automatically clean up after itself. If you ask it to remove a feature, check that the related imports, types, and references go with it. I removed the Mail entry from the social links and had to go back for the orphaned import separately. Loose ends compound on bigger projects.

The about page is harder than the code. I spent more time on four paragraphs of bio copy than on most of the technical implementation. Coding with Claude can be easy. Writing with Claude is medium. The challenge is being authentic and not just more slop.

Next Steps

More posts, which is the point. The site only gets better with more content.

I also have an automation pipeline in development. The goal is to have drafts land ready for review rather than starting from scratch every time, so there is less friction between building something and writing about it.