Simon Willison’s Weblog

Subscribe

Guides > Agentic Engineering Patterns > Adding a new content type to my blog-to-newsletter tool

Changes to Adding a new content type to my blog-to-newsletter tool

April 18, 2026, 3:15 a.m. #

Draft status changed from draft to published.

April 18, 2026, 3:15 a.m. #

--- +++ @@ -4,7 +4,7 @@ I generate the newsletter with my [blog-to-newsletter](https://tools.simonwillison.net/blog-to-newsletter) tool - an HTML and JavaScript app that fetches my latest content from [this Datasette instance](https://datasette.simonwillison.net/) and formats it as rich text HTML, which I can then copy to my clipboard and paste into the Substack editor. Here's a [detailed explanation of how that works](https://simonwillison.net/2023/Apr/4/substack-observable/). -I recently [added a new type of content](https://simonwillison.net/2026/Feb/20/beats/) to my blog to capture content that I post elsewhere, which I called "beats". These include things like releases of my open source projects, new tools that I've built, museums that I've visited (on [niche-museums.com](https://www.niche-museums.com/)) and other external content. +I recently [added a new type of content](https://simonwillison.net/2026/Feb/20/beats/) to my blog to capture content that I post elsewhere, which I called "beats". These include things like releases of my open source projects, new tools that I've built, museums that I've visited (from [niche-museums.com](https://www.niche-museums.com/)) and other external content. I wanted to include these in the generated newsletter. Here's the prompt I ran against the [simonw/tools](https://github.com/simonw/tools) repository that hosts my `blog-to-newsletter` tool, using [Claude Code on the web](https://code.claude.com/docs/en/claude-code-on-the-web). @@ -19,13 +19,13 @@ > `Clone simonw/simonwillisonblog from github to /tmp for reference` -I use this pattern a lot. Coding Agents can clone code from GitHub, and the best way to explain a problem is often to have them look at relevant code. By telling them to clone to `/tmp` I ensure they don't accidentally end up including that reference code in their own commit later on. +I use this pattern a lot. Coding agents can clone code from GitHub, and the best way to explain a problem is often to have them look at relevant code. By telling them to clone to `/tmp` I ensure they don't accidentally end up including that reference code in their own commit later on. The [simonw/simonwillisonblog](https://github.com/simonw/simonwillisonblog) repository contains the source code for my Django-powered [simonwillison.net](https://simonwillison.net/) blog. This includes the logic and database schema for my new "beats" feature. > `Update blog-to-newsletter.html to include beats that have descriptions - similar to how the Atom everything feed on the blog works` -Referincing `blog-to-newsletter.html` is all I need here to tell Claude which of the 200+ HTML apps in that `simonw/tools` repo it should be modifying. +Referencing `blog-to-newsletter.html` is all I need here to tell Claude which of the 200+ HTML apps in that `simonw/tools` repo it should be modifying. Beats are automatically imported from multiple sources. Often they aren't very interesting - a dot-release bug fix for one of my smaller open source projects, for example. @@ -35,11 +35,11 @@ > ``Run it with python -m http.server and use `uvx rodney --help` to test it - compare what shows up in the newsletter with what's on the homepage of https://simonwillison.net`` -Coding Agents always work best if they have some kind of validation mechanism they can use to test their own work. +Coding agents always work best if they have some kind of validation mechanism they can use to test their own work. In this case I wanted Claude Code to actively check that the changes it made to my tool would correctly fetch and display the latest data. -I reminded it to use `python -m http.server` as a static server because I've had issues in the past with applications that fetch data which work when running on a localhost server but fail if served as a file from disk. In this particular case that may not have been necessary, but my prompting muscle-memory has `python -m http.server` baked in at this point! +I reminded it to use `python -m http.server` as a static server because I've had issues in the past with applications that fetch data and break when served as a file from disk instead of a localhost server. In this particular case that may not have been necessary, but my prompting muscle memory has `python -m http.server` baked in at this point! I described the `uvx rodney --help` trick in [the agentic manual testing chapter](https://simonwillison.net/guides/agentic-engineering-patterns/agentic-manual-testing/#using-browser-automation-for-web-uis). Rodney is browser automation software that can be installed using `uvx`, and that has `--help` output designed to teach an agent everything it needs to know in order to use the tool. @@ -47,7 +47,7 @@ You can see [the full session here](https://claude.ai/code/session_01BibYBuvJi2qNUyCYGaY3Ss), or if that doesn't work I have an [alternative transcript](https://gisthost.github.io/?e906e938100ab42f4d6a932505219324/page-001.html#msg-2026-04-18T00-13-57-081Z) showing all of the individual tool calls. -The [resulting PR](https://github.com/simonw/tools/pull/268) made exactly the right change. It added an additional UNION clause to the SQL query that fetched the blog's content, filtering out draft beats and beats that had nothing in their `note` column: +The [resulting PR](https://github.com/simonw/tools/pull/268) made exactly the right change. It added an additional UNION clause to the SQL query that fetched the blog's content, filtering out draft beats and beats that have nothing in their `note` column: ```sql ...

April 18, 2026, 3:10 a.m. #

Initial version.