惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
B
Blog
博客园_首页
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog RSS Feed
M
MIT News - Artificial intelligence
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
量子位
V
V2EX
Y
Y Combinator Blog
Hugging Face - Blog
Hugging Face - Blog
Martin Fowler
Martin Fowler
Recent Announcements
Recent Announcements
I
InfoQ
博客园 - 【当耐特】

Simon Willison's Weblog

Release: datasette 1.0a29 Thoughts on GitLab’s workforce reduction A quote from James Shore Your AI Use Is Breaking My Brain TIL: Using LLM in the shebang line of a script Learning on the Shop floor A quote from New York Times Editors’ Note A quote from Andrew Quinn A quote from Luke Curley Release: llm-gemini 0.31 Tool: Big Words Behind the Scenes Hardening Firefox with Claude Mythos Preview Notes on the xAI/Anthropic data center deal Tool: GitHub Repo Stats Live blog: Code w/ Claude 2026 Vibe coding and agentic engineering are getting closer than I’d like Release: datasette-referrer-policy 0.1 Release: datasette-llm 0.1a7 Release: llm-echo 0.5a0 Granite 4.1 3B SVG Pelican Gallery A quote from Andy Masley April 2026 newsletter Research: TRE Python binding — ReDoS robustness demo Tool: Redis Array Playground A quote from Anthropic Sightings iNaturalist Sightings Codex CLI 0.128.0 adds /goal Our evaluation of OpenAI's GPT-5.5 cyber capabilities Quoting Andrew Kelley
Adding a new content type to my blog-to-newsletter tool -...
2026-04-18 · via Simon Willison's Weblog

Here's an example of a deceptively short prompt that got a quite a lot of work done in a single shot.

First, some background. I send out a free Substack newsletter around once a week containing content copied-and-pasted from my blog. I'm effectively using Substack as a lightweight way to allow people to subscribe to my blog via email.

I generate the newsletter with my blog-to-newsletter tool - an HTML and JavaScript app that fetches my latest content from this Datasette instance 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.

I recently added a new type of content 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) and other external content.

I wanted to include these in the generated newsletter. Here's the prompt I ran against the simonw/tools repository that hosts my blog-to-newsletter tool, using Claude Code on the web.

This got me the exact solution I needed. Let's break down the prompt.

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.

The simonw/simonwillisonblog repository contains the source code for my Django-powered 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

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.

My blog includes a way for me to add additional descriptions to any beat, which provides extra commentary but also marks that beat as being more interesting than those that I haven't annotated in some way.

I already use this as a distinction to decide which beats end up in my site's Atom feed. Telling Claude to imitate that saves me from having to describe the logic in any extra detail.

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.

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 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. 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.

I figured that telling Claude to compare the results in the newsletter to the content of my blog's homepage would be enough for it to confidently verify that the new changes were working correctly, since I had recently posted content that matched the new requirements.

You can see the full session here, or if that doesn't work I have an alternative transcript showing all of the individual tool calls.

The resulting PR 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:

...
union all
select
  id,
  'beat' as type,
  title,
  created,
  slug,
  'No HTML' as html,
  json_object(
    'created', date(created),
    'beat_type', beat_type,
    'title', title,
    'url', url,
    'commentary', commentary,
    'note', note
  ) as json,
  url as external_url
from blog_beat
where coalesce(note, '') != '' and is_draft = 0
union all
...

And it figured out a mapping of beat types to their formal names, presumably derived from the Django ORM definition that it read while it was exploring the reference codebase:

const beatTypeDisplay = {
  release: 'Release',
  til: 'TIL',
  til_update: 'TIL updated',
  research: 'Research',
  tool: 'Tool',
  museum: 'Museum'
};

Telling agents to use another codebase as reference is a powerful shortcut for communicating complex concepts with minimal additional information needed in the prompt.