<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/atom/everything/" rel="self"/><id>http://simonwillison.net/</id><updated>2026-04-22T05:40:56+00:00</updated><author><name>Simon Willison</name></author><entry><title>Quoting Bobby Holley</title><link href="https://simonwillison.net/2026/Apr/22/bobby-holley/#atom-everything" rel="alternate"/><published>2026-04-22T05:40:56+00:00</published><updated>2026-04-22T05:40:56+00:00</updated><id>https://simonwillison.net/2026/Apr/22/bobby-holley/#atom-everything</id><summary type="html">
    &lt;blockquote cite="https://blog.mozilla.org/en/privacy-security/ai-security-zero-day-vulnerabilities/"&gt;&lt;p&gt;As part of our continued collaboration with Anthropic, we had the opportunity to apply an early version of Claude Mythos Preview to Firefox. This week’s release of Firefox 150 includes fixes for &lt;a href="https://www.mozilla.org/en-US/security/advisories/mfsa2026-30/"&gt;271 vulnerabilities&lt;/a&gt; identified during this initial evaluation. [...]&lt;/p&gt;
&lt;p&gt;Our experience is a hopeful one for teams who shake off the vertigo and get to work. You may need to reprioritize everything else to bring relentless and single-minded focus to the task, but there is light at the end of the tunnel. We are extremely proud of how our team rose to meet this challenge, and others will too. Our work isn’t finished, but we’ve turned the corner and can glimpse a future much better than just keeping up. &lt;strong&gt;Defenders finally have a chance to win, decisively&lt;/strong&gt;.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://blog.mozilla.org/en/privacy-security/ai-security-zero-day-vulnerabilities/"&gt;Bobby Holley&lt;/a&gt;, CTO, Firefox&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/firefox"&gt;firefox&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mozilla"&gt;mozilla&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-security-research"&gt;ai-security-research&lt;/a&gt;&lt;/p&gt;



</summary><category term="anthropic"/><category term="claude"/><category term="ai"/><category term="firefox"/><category term="llms"/><category term="mozilla"/><category term="security"/><category term="generative-ai"/><category term="ai-security-research"/></entry><entry><title>Changes to GitHub Copilot Individual plans</title><link href="https://simonwillison.net/2026/Apr/22/changes-to-github-copilot/#atom-everything" rel="alternate"/><published>2026-04-22T03:30:02+00:00</published><updated>2026-04-22T03:30:02+00:00</updated><id>https://simonwillison.net/2026/Apr/22/changes-to-github-copilot/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.blog/news-insights/company-news/changes-to-github-copilot-individual-plans/"&gt;Changes to GitHub Copilot Individual plans&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
On the same day as Claude Code's temporary will-they-won't-they $100/month kerfuffle (for the moment, &lt;a href="https://simonwillison.net/2026/Apr/22/claude-code-confusion/#they-reversed-it"&gt;they won't&lt;/a&gt;), here's the latest on GitHub Copilot pricing.&lt;/p&gt;
&lt;p&gt;Unlike Anthropic, GitHub put up an official announcement about their changes, which include tightening usage limits, pausing signups for individual plans (!), restricting Claude Opus 4.7 to the more expensive $39/month "Pro+" plan, and dropping the previous Opus models entirely.&lt;/p&gt;
&lt;p&gt;The key paragraph:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Agentic workflows have fundamentally changed Copilot’s compute demands. Long-running, parallelized sessions now regularly consume far more resources than the original plan structure was built to support. As Copilot’s agentic capabilities have expanded rapidly, agents are doing more work, and more customers are hitting usage limits designed to maintain service reliability.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's easy to forget that just six months ago heavy LLM users were burning an order of magnitude less tokens. Coding agents consume a &lt;em&gt;lot&lt;/em&gt; of compute.&lt;/p&gt;
&lt;p&gt;Copilot was also unique (I believe) among agents in charging per-request, not per-token. (&lt;em&gt;Correction: Windsurf also operated a credit system like this which they &lt;a href="https://windsurf.com/blog/windsurf-pricing-plans"&gt;abandoned last month&lt;/a&gt;&lt;/em&gt;.) This means that single agentic requests which burn more tokens cut directly into their margins. The most recent pricing scheme addresses that with token-based usage limits on a per-session and weekly basis.&lt;/p&gt;
&lt;p&gt;My one problem with this announcement is that it doesn't clearly clarify &lt;em&gt;which&lt;/em&gt; product called "GitHub Copilot" is affected by these changes. Last month in &lt;a href="https://teybannerman.com/strategy/2026/03/31/how-many-microsoft-copilot-are-there.html"&gt;How many products does Microsoft have named 'Copilot'? I mapped every one&lt;/a&gt; Tey Bannerman identified 75 products that share the Copilot brand, 15 of which have "GitHub Copilot" in the title.&lt;/p&gt;
&lt;p&gt;Judging by the linked &lt;a href="https://github.com/features/copilot/plans"&gt;GitHub Copilot plans page&lt;/a&gt; this covers Copilot CLI, Copilot cloud agent and code review (features on &lt;a href="https://github.com/"&gt;GitHub.com&lt;/a&gt; itself), and the Copilot IDE features available in VS Code, Zed, JetBrains and more.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=47838508"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/microsoft"&gt;microsoft&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github-copilot"&gt;github-copilot&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-pricing"&gt;llm-pricing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;&lt;/p&gt;



</summary><category term="github"/><category term="microsoft"/><category term="ai"/><category term="generative-ai"/><category term="github-copilot"/><category term="llms"/><category term="llm-pricing"/><category term="coding-agents"/></entry><entry><title>Is Claude Code going to cost $100/month? Probably not - it's all very confusing</title><link href="https://simonwillison.net/2026/Apr/22/claude-code-confusion/#atom-everything" rel="alternate"/><published>2026-04-22T02:07:34+00:00</published><updated>2026-04-22T02:07:34+00:00</updated><id>https://simonwillison.net/2026/Apr/22/claude-code-confusion/#atom-everything</id><summary type="html">
    &lt;p&gt;Anthropic today quietly (as in &lt;em&gt;silently&lt;/em&gt;, no announcement anywhere at all) updated their &lt;a href="https://claude.com/pricing"&gt;claude.com/pricing&lt;/a&gt; page (but not their &lt;a href="https://support.claude.com/en/articles/11049762-choosing-a-claude-plan"&gt;Choosing a Claude plan page&lt;/a&gt;, which shows up first for me on Google) to add this tiny but significant detail (arrow is mine, &lt;a href="https://simonwillison.net/2026/Apr/22/claude-code-confusion/#they-reversed-it"&gt;and it's already reverted&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/anthropic-x.jpg" alt="Screenshot of the Claude pricing grid - Compare features across plans. Free, Pro, Max 5x and Max 20x all have the same features, with the exception of Claude Code which is on Max only and Claude Cowork which is on Pro and Max only. An arrow highlights the Claude Code for Pro cross." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://web.archive.org/web/20260421040656/claude.com/pricing"&gt;Internet Archive copy&lt;/a&gt; from yesterday shows a checkbox there. Claude Code used to be a feature of the $20/month Pro plan, but according to the new pricing page it is now exclusive to the $100/month or $200/month Max plans.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update&lt;/strong&gt;: don't miss &lt;a href="https://simonwillison.net/2026/Apr/22/claude-code-confusion/#they-reversed-it"&gt;the update to this post&lt;/a&gt;, they've already changed course a few hours after this change went live.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So what the heck is going on? Unsurprisingly, &lt;a href="https://www.reddit.com/r/ClaudeAI/comments/1srzhd7/psa_claude_pro_no_longer_lists_claude_code_as_an/"&gt;Reddit&lt;/a&gt; and &lt;a href="https://news.ycombinator.com/item?id=47854477"&gt;Hacker News&lt;/a&gt; and &lt;a href="https://twitter.com/i/trending/2046718768634589239"&gt;Twitter&lt;/a&gt; all caught fire.&lt;/p&gt;
&lt;p&gt;I didn't believe the screenshots myself when I first saw them - aside from the pricing grid I could find no announcement from Anthropic anywhere. Then Amol Avasare, Anthropic's Head of Growth, &lt;a href="https://twitter.com/TheAmolAvasare/status/2046724659039932830"&gt;tweeted&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For clarity, we're running a small test on ~2% of new prosumer signups. Existing Pro and Max subscribers aren't affected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that appears to be the closest we have had to official messaging from Anthropic.&lt;/p&gt;
&lt;p&gt;I don't buy the "~2% of new prosumer signups" thing, since everyone I've talked to is seeing the new pricing grid and the Internet Archive has already &lt;a href="https://web.archive.org/web/20260422001250/https://claude.com/pricing"&gt;snapped a copy&lt;/a&gt;. Maybe he means that they'll only be running this version of the pricing grid for a limited time which somehow adds up to "2%" of signups?&lt;/p&gt;
&lt;p&gt;I'm also amused to see Claude Cowork remain available on the $20/month plan, because Claude Cowork is effectively a rebranded version of Claude Code wearing a less threatening hat!&lt;/p&gt;
&lt;p&gt;There are a whole bunch of things that are bad about this.&lt;/p&gt;
&lt;p&gt;If we assume this is indeed a test, and that test comes up negative and they decide not to go ahead with it, the damage has still been extensive:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A whole lot of people got scared or angry or both that a service they relied on was about to be rug-pulled. There really is a significant difference between $20/month and $100/month for most people, especially outside of higher salary countries.&lt;/li&gt;
&lt;li&gt;The uncertainty is really bad! A tweet from an employee is &lt;em&gt;not&lt;/em&gt; the way to make an announcement like this. I wasted a solid hour of my afternoon trying to figure out what had happened here. My trust in Anthropic's transparency around pricing - a &lt;em&gt;crucial factor&lt;/em&gt; in how I understand their products - has been shaken.&lt;/li&gt;
&lt;li&gt;Strategically, should I be taking a bet on Claude Code if I know that they might 5x the minimum price of the product?&lt;/li&gt;
&lt;li&gt;More of a personal issue, but one I care deeply about myself: I invest a &lt;a href="https://simonwillison.net/tags/claude-code/"&gt;great deal of effort&lt;/a&gt; (that's 105 posts and counting) in teaching people how to use Claude Code. I don't want to invest that effort in a product that most people cannot afford to use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Last month I ran &lt;a href="https://simonw.github.io/nicar-2026-coding-agents/"&gt;a tutorial for journalists&lt;/a&gt; on "Coding agents for data analysis" at the annual NICAR data journalism conference. I'm not going to be teaching that audience a course that depends on a $100/month subscription!&lt;/p&gt;
&lt;p&gt;This also doesn't make sense to me as a strategy for Anthropic. Claude Code &lt;em&gt;defined the category&lt;/em&gt; of coding agents. It's responsible for billions of dollars in annual revenue for Anthropic already. It has a stellar reputation, but I'm not convinced that reputation is strong enough for it to lose the $20/month trial and jump people directly to a $100/month subscription.&lt;/p&gt;
&lt;p&gt;OpenAI have been investing heavily in catching up to Claude Code with their Codex products. Anthropic just handed them this marketing opportunity on a plate - here's Codex engineering lead &lt;a href="https://twitter.com/thsottiaux/status/2046740759056162816"&gt;Thibault Sottiaux&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don't know what they are doing over there, but Codex will continue to be available both in the FREE and PLUS ($20) plans. We have the compute and efficient models to support it. For important changes, we will engage with the community well ahead of making them.&lt;/p&gt;
&lt;p&gt;Transparency and trust are two principles we will not break, even if it means momentarily earning less. A reminder that you vote with your subscription for the values you want to see in this world.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I should note that I pay $200/month for Claude Max and I consider it well worth the money. I've had periods of free access in the past courtesy of Anthropic but I'm currently paying full price, and happy to do so.&lt;/p&gt;
&lt;p&gt;But I care about the accessibility of the tools that I work with and teach. If Codex has a free tier while Claude Code starts at $100/month I should obviously switch to Codex, because that way I can use the same tool as the people I want to teach how to use coding agents.&lt;/p&gt;
&lt;p&gt;Here's what I think happened. I think Anthropic are trying to optimize revenue growth - obviously - and someone pitched making Claude Code only available for Max and higher. That's clearly a bad idea, but "testing" culture says that it's worth putting even bad ideas out to test just in case they surprise you.&lt;/p&gt;
&lt;p&gt;So they started a test, without taking into account the wailing and gnashing of teeth that would result when their test was noticed - or accounting for the longer-term brand damage that would be caused.&lt;/p&gt;
&lt;p&gt;Or maybe they &lt;em&gt;did&lt;/em&gt; account for that, and decided it was worth the risk.&lt;/p&gt;
&lt;p&gt;I don't think that calculation was worthwhile. They're going to have to make a &lt;em&gt;very&lt;/em&gt; firm commitment along the lines of "we heard your feedback and we commit to keeping Claude Code available on our $20/month plan going forward" to regain my trust.&lt;/p&gt;
&lt;p&gt;As it stands, Codex is looking like a much safer bet for me to invest my time in learning and building educational materials around.&lt;/p&gt;
&lt;h4 id="they-reversed-it"&gt;Update: they've reversed it already&lt;/h4&gt;
&lt;p&gt;In the time I was &lt;em&gt;typing this blog entry&lt;/em&gt; Anthropic appear to have reversed course - the &lt;a href="https://claude.com/pricing"&gt;claude.com/pricing page&lt;/a&gt; now has a checkbox back in the Pro column for Claude Code. I can't find any official communication about it though.&lt;/p&gt;
&lt;p&gt;Let's see if they can come up with an explanation/apology that's convincing enough to offset the trust bonfire from this afternoon!&lt;/p&gt;
&lt;h4 id="update-2"&gt;Update 2: it may still affect 2% of signups?&lt;/h4&gt;
&lt;p&gt;Amol &lt;a href="https://x.com/TheAmolAvasare/status/2046788872517066971"&gt;on Twitter&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;was a mistake that the logged-out landing page and docs were updated for this test [&lt;a href="https://twitter.com/TheAmolAvasare/status/2046783926920978681"&gt;embedded self-tweet&lt;/a&gt;]&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Getting lots of questions on why the landing page / docs were updated if only 2% of new signups were affected.&lt;/p&gt;

&lt;p&gt;This was understandably confusing for the 98% of folks not part of the experiment, and we've reverted both the landing page and docs changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the experiment is still running, just not visible to the rest of the world?&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-pricing"&gt;llm-pricing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/codex-cli"&gt;codex-cli&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="anthropic"/><category term="llm-pricing"/><category term="ai-ethics"/><category term="coding-agents"/><category term="claude-code"/><category term="codex-cli"/></entry><entry><title>Where's the raccoon with the ham radio? (ChatGPT Images 2.0)</title><link href="https://simonwillison.net/2026/Apr/21/gpt-image-2/#atom-everything" rel="alternate"/><published>2026-04-21T20:32:24+00:00</published><updated>2026-04-21T20:32:24+00:00</updated><id>https://simonwillison.net/2026/Apr/21/gpt-image-2/#atom-everything</id><summary type="html">
    &lt;p&gt;OpenAI &lt;a href="https://openai.com/index/introducing-chatgpt-images-2-0/"&gt;released ChatGPT Images 2.0 today&lt;/a&gt;, their latest image generation model. On &lt;a href="https://www.youtube.com/watch?v=sWkGomJ3TLI"&gt;the livestream&lt;/a&gt; Sam Altman said that the leap from gpt-image-1 to gpt-image-2 was equivalent to jumping from GPT-3 to GPT-5. Here's how I put it to the test.&lt;/p&gt;
&lt;p&gt;My prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Do a where's Waldo style image but it's where is the raccoon holding a ham radio&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="gpt-image-1"&gt;gpt-image-1&lt;/h4&gt;
&lt;p&gt;First as a baseline here's what I got from the older gpt-image-1 using ChatGPT directly:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://static.simonwillison.net/static/2026/chatgpt-image-1-ham-radio.png"&gt;&lt;img loading="lazy" src="https://static.simonwillison.net/static/2026/image_crop_1402x1122_w1402_q0.3.jpg" alt="There's a lot going on, but I couldn't find a raccoon." style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I wasn't able to spot the raccoon - I quickly realized that testing image generation models on Where's Waldo style images (Where's Wally in the UK) can be pretty frustrating!&lt;/p&gt;
&lt;p&gt;I tried &lt;a href="https://claude.ai/share/bd6e9b88-29a9-420b-8ac1-3ac5cebac215"&gt;getting Claude Opus 4.7&lt;/a&gt; with its new higher resolution inputs to solve it but it was convinced there was a raccoon it couldn't find thanks to the instruction card at the top left of the image:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Yes — there's at least one raccoon in the picture, but it's very well hidden&lt;/strong&gt;. In my careful sweep through zoomed-in sections, honestly, I couldn't definitively spot a raccoon holding a ham radio. [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="nano-banana-2-and-pro"&gt;Nano Banana 2 and Pro&lt;/h4&gt;
&lt;p&gt;Next I tried Google's Nano Banana 2, &lt;a href="https://gemini.google.com/share/3775db96c576"&gt;via Gemini&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://static.simonwillison.net/static/2026/nano-banana-2-ham-radio.jpg"&gt;&lt;img loading="lazy" src="https://static.simonwillison.net/static/2026/gemini-ham-radio-small.jpg" alt="Busy Where's Waldo-style illustration of a park festival with crowds of people, tents labeled &amp;quot;FOOD &amp;amp; DRINK&amp;quot;, &amp;quot;CRAFT FAIR&amp;quot;, &amp;quot;BOOK NOOK&amp;quot;, &amp;quot;MUSIC FEST&amp;quot;, and &amp;quot;AMATEUR RADIO CLUB - W6HAM&amp;quot; (featuring a raccoon in a red hat at the radio table), plus a Ferris wheel, carousel, gazebo with band, pond with boats, fountain, food trucks, and striped circus tents" style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That one was pretty obvious, the raccoon is in the "Amateur Radio Club" booth in the center of the image!&lt;/p&gt;
&lt;p&gt;Claude said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Honestly, this one wasn't really hiding — he's the star of the booth. Feels like the illustrator took pity on us after that last impossible scene. The little "W6HAM" callsign pun on the booth sign is a nice touch too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I also tried Nano Banana Pro &lt;a href="https://aistudio.google.com/app/prompts?state=%7B%22ids%22:%5B%221sGU5A7mrngkfLfSEU84xaV1DhtOTnS--%22%5D,%22action%22:%22open%22,%22userId%22:%22106366615678321494423%22,%22resourceKeys%22:%7B%7D%7D&amp;amp;usp=sharing"&gt;in AI Studio&lt;/a&gt; and got this, by far the worst result from any model. Not sure what went wrong here!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://static.simonwillison.net/static/2026/nano-banana-pro-ham-radio.jpg"&gt;&lt;img loading="lazy" src="https://static.simonwillison.net/static/2026/nano-banana-pro-ham-radio-small.jpg" alt="The raccoon is larger than everyone else, right in the middle of the image with an ugly white border around it." style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="gpt-image-2"&gt;gpt-image-2&lt;/h4&gt;
&lt;p&gt;With the baseline established, let's try out the new model.&lt;/p&gt;
&lt;p&gt;I used an updated version of my &lt;a href="https://github.com/simonw/tools/blob/main/python/openai_image.py"&gt;openai_image.py&lt;/a&gt; script, which is a thin wrapper around the &lt;a href="https://github.com/openai/openai-python"&gt;OpenAI Python&lt;/a&gt; client library. Their client library hasn't yet been updated to include &lt;code&gt;gpt-image-2&lt;/code&gt; but thankfully it doesn't validate the model ID so you can use it anyway.&lt;/p&gt;
&lt;p&gt;Here's how I ran that:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;OPENAI_API_KEY=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;$(&lt;/span&gt;llm keys get openai&lt;span class="pl-pds"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; \
  uv run https://tools.simonwillison.net/python/openai_image.py \
  -m gpt-image-2 \
  &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Do a where's Waldo style image but it's where is the raccoon holding a ham radio&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here's what I got back. I don't &lt;em&gt;think&lt;/em&gt; there's a raccoon in there - I couldn't spot one, and neither could Claude.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://static.simonwillison.net/static/2026/gpt-image-2-default.png"&gt;&lt;img loading="lazy" src="https://static.simonwillison.net/static/2026/gpt-image-2-default.jpg" alt="Lots of stuff, a ham radio booth, many many people, a lake, but maybe no raccoon?" style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/openai/openai-cookbook/blob/main/examples/multimodal/image-gen-models-prompting-guide.ipynb"&gt;OpenAI image generation cookbook&lt;/a&gt; has been updated with notes on &lt;code&gt;gpt-image-2&lt;/code&gt;, including the &lt;code&gt;outputQuality&lt;/code&gt; setting and available sizes.&lt;/p&gt;
&lt;p&gt;I tried setting &lt;code&gt;outputQuality&lt;/code&gt; to &lt;code&gt;high&lt;/code&gt; and the dimensions to &lt;code&gt;3840x2160&lt;/code&gt; - I believe that's the maximum - and got this - a 17MB PNG which I converted to a 5MB WEBP:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;OPENAI_API_KEY=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;$(&lt;/span&gt;llm keys get openai&lt;span class="pl-pds"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; \
  uv run &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;https://raw.githubusercontent.com/simonw/tools/refs/heads/main/python/openai_image.py&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; \
  -m gpt-image-2 &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Do a where's Waldo style image but it's where is the raccoon holding a ham radio&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; \
  --quality high --size 3840x2160&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="https://static.simonwillison.net/static/2026/image-fc93bd-q100.webp"&gt;&lt;img loading="lazy" src="https://static.simonwillison.net/static/2026/image-fc93bd-q100.jpg" alt="Big complex image, lots of detail, good wording, there is indeed a raccoon with a ham radio." style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That's pretty great! There's a raccoon with a ham radio in there (bottom left, quite easy to spot).&lt;/p&gt;
&lt;p&gt;The image used 13,342 output tokens, which are charged at $30/million so a total cost of around &lt;a href="https://www.llm-prices.com/#ot=13342&amp;amp;ic=5&amp;amp;cic=1.25&amp;amp;oc=10&amp;amp;sel=gpt-image-2-image"&gt;40 cents&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="takeaways"&gt;Takeaways&lt;/h4&gt;
&lt;p&gt;I think this new ChatGPT image generation model takes the crown from Gemini, at least for the moment.&lt;/p&gt;
&lt;p&gt;Where's Waldo style images are an infuriating and somewhat foolish way to test these models, but they do help illustrate how good they are getting at complex illustrations combining both text and details.&lt;/p&gt;
&lt;h4 id="update-asking-models-to-solve-this-is-risky"&gt;Update: asking models to solve this is risky&lt;/h4&gt;
&lt;p&gt;rizaco &lt;a href="https://news.ycombinator.com/item?id=47852835#47853561"&gt;on Hacker News&lt;/a&gt; asked ChatGPT to draw a red circle around the raccoon in one of the images in which I had failed to find one. Here's an animated mix of their result and the original image:&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://static.simonwillison.net/static/2026/ham-radio-cheat.gif" alt="The circle appears around a raccoon with a ham radio who is definitely not there in the original image!" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Looks like we definitely can't trust these models to usefully solve their own puzzles!&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/text-to-image"&gt;text-to-image&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nano-banana"&gt;nano-banana&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="ai"/><category term="openai"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="text-to-image"/><category term="llm-release"/><category term="nano-banana"/></entry><entry><title>Quoting Andreas Påhlsson-Notini</title><link href="https://simonwillison.net/2026/Apr/21/andreas-pahlsson-notini/#atom-everything" rel="alternate"/><published>2026-04-21T16:39:33+00:00</published><updated>2026-04-21T16:39:33+00:00</updated><id>https://simonwillison.net/2026/Apr/21/andreas-pahlsson-notini/#atom-everything</id><summary type="html">
    &lt;blockquote cite="https://nial.se/blog/less-human-ai-agents-please/"&gt;&lt;p&gt;AI agents are already too human. Not in the romantic sense, not because they love or fear or dream, but in the more banal and frustrating one. The current implementations keep showing their human origin again and again: lack of stringency, lack of patience, lack of focus. Faced with an awkward task, they drift towards the familiar. Faced with hard constraints, they start negotiating with reality.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://nial.se/blog/less-human-ai-agents-please/"&gt;Andreas Påhlsson-Notini&lt;/a&gt;, Less human AI agents, please.&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai-agents"&gt;ai-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai-agents"/><category term="coding-agents"/><category term="ai"/></entry><entry><title>scosman/pelicans_riding_bicycles</title><link href="https://simonwillison.net/2026/Apr/21/scosman/#atom-everything" rel="alternate"/><published>2026-04-21T15:54:43+00:00</published><updated>2026-04-21T15:54:43+00:00</updated><id>https://simonwillison.net/2026/Apr/21/scosman/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/scosman/pelicans_riding_bicycles"&gt;scosman/pelicans_riding_bicycles&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I firmly approve of Steve Cosman's efforts to pollute the training set of pelicans riding bicycles.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The heading says &amp;quot;Pelican Riding a Bicycle #1 - the image is a bear on a snowboard" src="https://static.simonwillison.net/static/2026/pelican-poison-bear.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;(To be fair, most of the examples &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle/"&gt;I've published&lt;/a&gt; count as poisoning too.)

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=47835735#47839493"&gt;Hacker News comment&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/training-data"&gt;training-data&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle"&gt;pelican-riding-a-bicycle&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="training-data"/><category term="pelican-riding-a-bicycle"/></entry><entry><title>llm-openrouter 0.6</title><link href="https://simonwillison.net/2026/Apr/20/llm-openrouter/#atom-everything" rel="alternate"/><published>2026-04-20T18:00:26+00:00</published><updated>2026-04-20T18:00:26+00:00</updated><id>https://simonwillison.net/2026/Apr/20/llm-openrouter/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/simonw/llm-openrouter/releases/tag/0.6"&gt;llm-openrouter 0.6&lt;/a&gt;&lt;/p&gt;
    &lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;llm openrouter refresh&lt;/code&gt; command for refreshing the list of available models without waiting for the cache to expire.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I added this feature so I could try &lt;a href="https://www.kimi.com/blog/kimi-k2-6"&gt;Kimi 2.6&lt;/a&gt; on OpenRouter as soon as it &lt;a href="https://openrouter.ai/moonshotai/kimi-k2.6"&gt;became available there&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://gisthost.github.io/?ecaad98efe0f747e27bc0e0ebc669e94/pelican.html"&gt;its pelican&lt;/a&gt; - this time as an HTML page because Kimi chose to include an HTML and JavaScript UI to control the animation. &lt;a href="https://gist.github.com/simonw/ecaad98efe0f747e27bc0e0ebc669e94#2026-04-20t164936----conversation-01kpnwt8d2bt5qwkm60j9sbkbs-id-01kpnwra0prz6v822cct5b08kq"&gt;Transcript here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The bicycle is about right. The pelican is OK. It is pedaling furiously and flapping its wings a bit. Controls below the animation provide a pause button and sliders for controlling the speed and the wing flap." src="https://static.simonwillison.net/static/2026/kimi-k2-pelican-64-colors.gif" /&gt;&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/openrouter"&gt;openrouter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle"&gt;pelican-riding-a-bicycle&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/kimi"&gt;kimi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-in-china"&gt;ai-in-china&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="openrouter"/><category term="llm"/><category term="llm-release"/><category term="pelican-riding-a-bicycle"/><category term="kimi"/><category term="ai-in-china"/><category term="llms"/><category term="ai"/><category term="generative-ai"/></entry><entry><title>SQL functions in Google Sheets to fetch data from Datasette</title><link href="https://simonwillison.net/2026/Apr/20/datasette-sql/#atom-everything" rel="alternate"/><published>2026-04-20T02:33:58+00:00</published><updated>2026-04-20T02:33:58+00:00</updated><id>https://simonwillison.net/2026/Apr/20/datasette-sql/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;TIL:&lt;/strong&gt; &lt;a href="https://til.simonwillison.net/google-sheets/datasette-sql"&gt;SQL functions in Google Sheets to fetch data from Datasette&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;I put together some notes on patterns for fetching data from a Datasette instance directly into Google Sheets - using the &lt;code&gt;importdata()&lt;/code&gt; function, a "named function" that wraps it or a Google Apps Script if you need to send an API token in an HTTP header (not supported by &lt;code&gt;importdata()&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://docs.google.com/spreadsheets/d/14lRV2-AeBmjI3lJbl2apwfC_ncXqL0uSV68lmtzUI7I/edit?gid=0#gid=0"&gt;an example sheet&lt;/a&gt; demonstrating all three methods.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/spreadsheets"&gt;spreadsheets&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="spreadsheets"/><category term="datasette"/><category term="google"/></entry><entry><title>Claude Token Counter, now with model comparisons</title><link href="https://simonwillison.net/2026/Apr/20/claude-token-counts/#atom-everything" rel="alternate"/><published>2026-04-20T00:50:45+00:00</published><updated>2026-04-20T00:50:45+00:00</updated><id>https://simonwillison.net/2026/Apr/20/claude-token-counts/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://tools.simonwillison.net/claude-token-counter"&gt;Claude Token Counter, now with model comparisons&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I &lt;a href="https://github.com/simonw/tools/pull/269"&gt;upgraded&lt;/a&gt; my Claude Token Counter tool to add the ability to run the same count against different models in order to compare them.&lt;/p&gt;
&lt;p&gt;As far as I can tell Claude Opus 4.7 is the first model to change the tokenizer, so it's only worth running comparisons between 4.7 and 4.6. The Claude &lt;a href="https://platform.claude.com/docs/en/build-with-claude/token-counting"&gt;token counting API&lt;/a&gt; accepts any Claude model ID though so I've included options for all four of the notable current models (Opus 4.7 and 4.6, Sonnet 4.6, and Haiku 4.5).&lt;/p&gt;
&lt;p&gt;In the Opus 4.7 announcement &lt;a href="https://www.anthropic.com/news/claude-opus-4-7#migrating-from-opus-46-to-opus-47"&gt;Anthropic said&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Opus 4.7 uses an updated tokenizer that improves how the model processes text. The tradeoff is that the same input can map to more tokens—roughly 1.0–1.35× depending on the content type.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I pasted the &lt;a href="https://github.com/simonw/research/blob/2cf912666ba08ef0c00a1b51ee07c9a8e64579ef/extract-system-prompts/claude-opus-4-7.md?plain=1"&gt;Opus 4.7 system prompt&lt;/a&gt; into the token counting tool and found that the Opus 4.7 tokenizer used 1.46x the number of tokens as Opus 4.6.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot of a token comparison tool. Models to compare: claude-opus-4-7 (checked), claude-opus-4-6 (checked), claude-opus-4-5, claude-sonnet-4-6, claude-haiku-4-5. Note: &amp;quot;These models share the same tokenizer&amp;quot;. Blue &amp;quot;Count Tokens&amp;quot; button. Results table — Model | Tokens | vs. lowest. claude-opus-4-7: 7,335 tokens, 1.46x (yellow badge). claude-opus-4-6: 5,039 tokens, 1.00x (green badge)." src="https://static.simonwillison.net/static/2026/claude-token-count.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Opus 4.7 uses the same pricing is Opus 4.6 - $5 per million input tokens and $25 per million output tokens - but this token inflation means we can expect it to be around 40% more expensive.&lt;/p&gt;
&lt;p&gt;The token counter tool also accepts images. Opus 4.7 has improved image support, described like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Opus 4.7 has better vision for high-resolution images: it can accept images up to 2,576 pixels on the long edge (~3.75 megapixels), more than three times as many as prior Claude models.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I tried counting tokens for a 3456x2234 pixel 3.7MB PNG and got an even bigger increase in token counts - 3.01x times the number of tokens for 4.7 compared to 4.6:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Same UI, this time with an uploaded screenshot PNG image. claude-opus-4-7: 4,744 tokens, 3.01x (yellow badge). claude-opus-4-6: 1,578 tokens, 1.00x (green badge)." src="https://static.simonwillison.net/static/2026/claude-token-count-image.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: That 3x increase for images is &lt;em&gt;entirely&lt;/em&gt; due to Opus 4.7 being able to handle higher resolutions. I tried that again with a 682x318 pixel image and it took 314 tokens with Opus 4.7 and 310 with Opus 4.6, so effectively the same cost.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2&lt;/strong&gt;: I tried a 15MB, 30 page text-heavy PDF and Opus 4.7 reported 60,934   tokens while 4.6 reported 56,482 - that's a 1.08x multiplier, significantly lower than the multiplier I got for raw text.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-pricing"&gt;llm-pricing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tokenization"&gt;tokenization&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="anthropic"/><category term="claude"/><category term="llm-pricing"/><category term="tokenization"/></entry><entry><title>Headless everything for personal AI</title><link href="https://simonwillison.net/2026/Apr/19/headless-everything/#atom-everything" rel="alternate"/><published>2026-04-19T21:46:38+00:00</published><updated>2026-04-19T21:46:38+00:00</updated><id>https://simonwillison.net/2026/Apr/19/headless-everything/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://interconnected.org/home/2026/04/18/headless"&gt;Headless everything for personal AI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Matt Webb thinks &lt;strong&gt;headless&lt;/strong&gt; services are about to become much more common:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why? Because using personal AIs is a better experience for users than using services directly (honestly); and headless services are quicker and more dependable for the personal AIs than having them click round a GUI with a bot-controlled mouse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Evidently &lt;a href="https://twitter.com/benioff/status/2044981547267395620"&gt;Marc Benioff thinks so too&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Welcome Salesforce Headless 360: No Browser Required!  Our API is the UI. Entire Salesforce &amp;amp; Agentforce &amp;amp; Slack platforms are now exposed as APIs, MCP, &amp;amp; CLI. All AI agents can access data, workflows, and tasks directly in Slack, Voice, or anywhere else with Salesforce Headless.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If this model does take off it's going to play havoc with existing per-head SaaS pricing schemes.&lt;/p&gt;
&lt;p&gt;I'm reminded of the early 2010s era when every online service was launching APIs. Brandur Leach reminisces about that time in &lt;a href="https://brandur.org/second-wave-api-first"&gt;The Second Wave of the API-first Economy&lt;/a&gt;, and predicts that APIs are ready to make a comeback:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Suddenly, an API is no longer liability, but a major saleable vector to give users what they want: a way into the services they use and pay for so that an agent can carry out work on their behalf. Especially given a field of relatively undifferentiated products, in the near future the availability of an API might just be the crucial deciding factor that leads to one choice winning the field.&lt;/p&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apis"&gt;apis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/definitions"&gt;definitions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/matt-webb"&gt;matt-webb&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/salesforce"&gt;salesforce&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/saas"&gt;saas&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brandur-leach"&gt;brandur-leach&lt;/a&gt;&lt;/p&gt;



</summary><category term="apis"/><category term="definitions"/><category term="matt-webb"/><category term="salesforce"/><category term="saas"/><category term="ai"/><category term="brandur-leach"/></entry><entry><title>Changes in the system prompt between Claude Opus 4.6 and 4.7</title><link href="https://simonwillison.net/2026/Apr/18/opus-system-prompt/#atom-everything" rel="alternate"/><published>2026-04-18T23:59:40+00:00</published><updated>2026-04-18T23:59:40+00:00</updated><id>https://simonwillison.net/2026/Apr/18/opus-system-prompt/#atom-everything</id><summary type="html">
    &lt;p&gt;Anthropic are the only major AI lab to &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts"&gt;publish the system prompts&lt;/a&gt; for their user-facing chat systems. Their system prompt archive now dates all the way back to Claude 3 in July 2024 and it's always interesting to see how the system prompt evolves as they publish new models.&lt;/p&gt;
&lt;p&gt;Opus 4.7 shipped the other day (April 16, 2026) with a &lt;a href="https://claude.ai/"&gt;Claude.ai&lt;/a&gt; system prompt update since Opus 4.6 (February 5, 2026).&lt;/p&gt;
&lt;p&gt;I had Claude Code take &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts.md"&gt;the Markdown version of their system prompts&lt;/a&gt;, break that up into separate documents for each of the models and then construct &lt;a href="https://github.com/simonw/research/tree/main/extract-system-prompts#readme"&gt;a Git history&lt;/a&gt; of those files over time with fake commit dates representing the publication dates of each updated prompt - &lt;a href="https://github.com/simonw/research/pull/109#issue-4287908903"&gt;here's the prompt I used&lt;/a&gt; with Claude Code for the web.&lt;/p&gt;
&lt;p&gt;Here is the &lt;a href="https://github.com/simonw/research/commit/888f21161500cd60b7c92367f9410e311ffcff09"&gt;git diff between Opus 4.6 and 4.7&lt;/a&gt;. These are my own highlights extracted from that diff - in all cases text &lt;strong&gt;in bold&lt;/strong&gt; is my emphasis:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The "developer platform" is now called the "Claude Platform".&lt;/li&gt;
&lt;li&gt;The list of Claude tools mentioned in the system prompt now includes "Claude in Chrome - a browsing agent that can interact with websites autonomously, Claude in Excel - a spreadsheet agent, and &lt;strong&gt;Claude in Powerpoint&lt;/strong&gt; - a slides agent. Claude Cowork can use all of these as tools." - Claude in Powerpoint was not mentioned in the 4.6 prompt.&lt;/li&gt;
&lt;li&gt;The child safety section has been greatly expanded, and is now wrapped in a new &lt;code&gt;&amp;lt;critical_child_safety_instructions&amp;gt;&lt;/code&gt; tag. Of particular note: "Once Claude refuses a request for reasons of child safety, all subsequent requests in the same conversation must be approached with extreme caution."&lt;/li&gt;
&lt;li&gt;It looks like they're trying to make Claude less pushy: "If a user indicates they are ready to end the conversation, Claude does not request that the user stay in the interaction or try to elicit another turn and instead respects the user's request to stop."&lt;/li&gt;
&lt;li&gt;The new &lt;code&gt;&amp;lt;acting_vs_clarifying&amp;gt;&lt;/code&gt; section includes:
&lt;blockquote&gt;
&lt;p&gt;When a request leaves minor details unspecified, &lt;strong&gt;the person typically wants Claude to make a reasonable attempt now, not to be interviewed first&lt;/strong&gt;. Claude only asks upfront when the request is genuinely unanswerable without the missing information (e.g., it references an attachment that isn't there).&lt;/p&gt;
&lt;p&gt;When a tool is available that could resolve the ambiguity or supply the missing information — searching, looking up the person's location, checking a calendar, discovering available capabilities — Claude calls the tool to try and solve the ambiguity before asking the person. Acting with tools is preferred over asking the person to do the lookup themselves.&lt;/p&gt;
&lt;p&gt;Once Claude starts on a task, Claude sees it through to a complete answer rather than stopping partway. [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;It looks like Claude chat now has a tool search mechanism, as seen in &lt;a href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool"&gt;this API documentation&lt;/a&gt; and described in &lt;a href="https://www.anthropic.com/engineering/advanced-tool-use"&gt;this November 2025 post&lt;/a&gt;:
&lt;blockquote&gt;
&lt;p&gt;Before concluding Claude lacks a capability — access to the person's location, memory, calendar, files, past conversations, or any external data — &lt;strong&gt;Claude calls tool_search to check whether a relevant tool is available but deferred&lt;/strong&gt;. "I don't have access to X" is only correct after tool_search confirms no matching tool exists.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;There's new language to encourage Claude to be less verbose:
&lt;blockquote&gt;
&lt;p&gt;Claude keeps its responses focused and concise so as to avoid potentially overwhelming the user with overly-long responses. Even if an answer has disclaimers or caveats, Claude discloses them briefly and keeps the majority of its response focused on its main answer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;This section was present in the 4.6 prompt but has been removed for 4.7, presumably because the new model no longer misbehaves in the same way:
&lt;blockquote&gt;
&lt;p&gt;Claude avoids the use of emotes or actions inside asterisks unless the person specifically asks for this style of communication.&lt;/p&gt;
&lt;p&gt;Claude avoids saying "genuinely", "honestly", or "straightforward".&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;There's a new section about "disordered eating", which was not previously mentioned by name:
&lt;blockquote&gt;
&lt;p&gt;If a user shows signs of disordered eating, Claude should not give precise nutrition, diet, or exercise guidance — no specific numbers, targets, or step-by-step plans - anywhere else in the conversation. Even if it's intended to help set healthier goals or highlight the potential dangers of disordered eating, responses with these details could trigger or encourage disordered tendencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;A popular screenshot attack against AI models is to force them to say yes or no to a controversial question. Claude's system prompt now guards against that (in the &lt;code&gt;&amp;lt;evenhandedness&amp;gt;&lt;/code&gt; section):
&lt;blockquote&gt;
&lt;p&gt;If people ask Claude to give a simple yes or no answer (or any other short or single word response) in response to complex or contested issues or as commentary on contested figures, Claude can decline to offer the short response and instead give a nuanced answer and explain why a short response wouldn't be appropriate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Claude 4.6 had a section specifically clarifying that "Donald Trump is the current president of the United States and was inaugurated on January 20, 2025", because without that the model's knowledge cut-off date combined with its previous knowledge that Trump falsely claimed to win the 2020 election meant it would deny he was the president. That language is gone for 4.7, reflecting the model's new reliable knowledge cut-off date of January 2026.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="and-the-tool-descriptions-too"&gt;And the tool descriptions too&lt;/h4&gt;
&lt;p&gt;The system prompts published by Anthropic are sadly not the entire story - their published information doesn't include the tool descriptions that are provided to the model, which is arguably an even more important piece of documentation if you want to take full advantage of what the Claude chat UI can do for you.&lt;/p&gt;
&lt;p&gt;Thanfully you can &lt;a href="https://claude.ai/share/dc1e375e-2213-4afb-ac1b-812d42735a8e"&gt;ask Claude directly&lt;/a&gt; - I used the prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;List all tools you have available to you with an exact copy of the tool description and parameters&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My &lt;a href="https://claude.ai/share/dc1e375e-2213-4afb-ac1b-812d42735a8e"&gt;shared transcript&lt;/a&gt; has full details, but the list of named tools is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ask_user_input_v0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash_tool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conversation_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch_sports_data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;image_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message_compose_v1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;places_map_display_v0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;places_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;present_files&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recent_chats&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recipe_display_v0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recommend_claude_apps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search_mcp_registry&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;str_replace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;suggest_connectors&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;view&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;weather_fetch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tool_search&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visualize:read_me&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visualize:show_widget&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I don't believe this list has changed since Opus 4.6.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-engineering"&gt;prompt-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/system-prompts"&gt;system-prompts&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="ai"/><category term="prompt-engineering"/><category term="generative-ai"/><category term="llms"/><category term="anthropic"/><category term="claude"/><category term="ai-ethics"/><category term="system-prompts"/></entry><entry><title>Claude system prompts as a git timeline</title><link href="https://simonwillison.net/2026/Apr/18/extract-system-prompts/#atom-everything" rel="alternate"/><published>2026-04-18T12:25:00+00:00</published><updated>2026-04-18T12:25:00+00:00</updated><id>https://simonwillison.net/2026/Apr/18/extract-system-prompts/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Research:&lt;/strong&gt; &lt;a href="https://github.com/simonw/research/tree/main/extract-system-prompts#readme"&gt;Claude system prompts as a git timeline&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;Anthropic &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts"&gt;publish the system prompts&lt;/a&gt; for Claude chat and make that page &lt;a href="https://platform.claude.com/docs/en/release-notes/system-prompts.md"&gt;available as Markdown&lt;/a&gt;. I had Claude Code turn that page into separate files for each model and model family with fake git commit dates to enable browsing the changes via the GitHub commit view.&lt;/p&gt;
&lt;p&gt;I used this to write my own &lt;a href="https://simonwillison.net/2026/Apr/18/opus-system-prompt/"&gt;detailed notes on the changes between Opus 4.6 and 4.7&lt;/a&gt;.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/system-prompts"&gt;system-prompts&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="system-prompts"/><category term="anthropic"/><category term="claude"/><category term="generative-ai"/><category term="ai"/><category term="llms"/></entry><entry><title>Adding a new content type to my blog-to-newsletter tool</title><link href="https://simonwillison.net/guides/agentic-engineering-patterns/adding-a-new-content-type/#atom-everything" rel="alternate"/><published>2026-04-18T03:15:36+00:00</published><updated>2026-04-18T03:15:36+00:00</updated><id>https://simonwillison.net/guides/agentic-engineering-patterns/adding-a-new-content-type/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;em&gt;&lt;a href="https://simonwillison.net/guides/agentic-engineering-patterns/"&gt;Agentic Engineering Patterns&lt;/a&gt; &amp;gt;&lt;/em&gt;&lt;/p&gt;
    &lt;p&gt;Here's an example of a deceptively short prompt that got a quite a lot of work done in a single shot.&lt;/p&gt;
&lt;p&gt;First, some background. I send out a &lt;a href="https://simonw.substack.com/"&gt;free Substack newsletter&lt;/a&gt; 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.&lt;/p&gt;
&lt;p&gt;I generate the newsletter with my &lt;a href="https://tools.simonwillison.net/blog-to-newsletter"&gt;blog-to-newsletter&lt;/a&gt; tool - an HTML and JavaScript app that fetches my latest content from &lt;a href="https://datasette.simonwillison.net/"&gt;this Datasette instance&lt;/a&gt; and formats it as rich text HTML, which I can then copy to my clipboard and paste into the Substack editor. Here's a &lt;a href="https://simonwillison.net/2023/Apr/4/substack-observable/"&gt;detailed explanation of how that works&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I recently &lt;a href="https://simonwillison.net/2026/Feb/20/beats/"&gt;added a new type of content&lt;/a&gt; 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 &lt;a href="https://www.niche-museums.com/"&gt;niche-museums.com&lt;/a&gt;) and other external content.&lt;/p&gt;
&lt;p&gt;I wanted to include these in the generated newsletter. Here's the prompt I ran against the &lt;a href="https://github.com/simonw/tools"&gt;simonw/tools&lt;/a&gt; repository that hosts my &lt;code&gt;blog-to-newsletter&lt;/code&gt; tool, using &lt;a href="https://code.claude.com/docs/en/claude-code-on-the-web"&gt;Claude Code on the web&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;pre&gt;Clone simonw/simonwillisonblog from github to /tmp for reference

Update blog-to-newsletter.html to include beats that have descriptions - similar to how the Atom everything feed on the blog works

Run it with python -m http.server and use `uvx rodney --help` to test it - compare what shows up in the newsletter with what&amp;#x27;s on the homepage of https://simonwillison.net&lt;/pre&gt;
This got me the &lt;a href="https://github.com/simonw/tools/pull/268"&gt;exact solution&lt;/a&gt; I needed. Let's break down the prompt.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Clone simonw/simonwillisonblog from github to /tmp for reference&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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 &lt;code&gt;/tmp&lt;/code&gt; I ensure they don't accidentally end up including that reference code in their own commit later on.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/simonw/simonwillisonblog"&gt;simonw/simonwillisonblog&lt;/a&gt; repository contains the source code for my Django-powered &lt;a href="https://simonwillison.net/"&gt;simonwillison.net&lt;/a&gt; blog. This includes the logic and database schema for my new "beats" feature.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Update blog-to-newsletter.html to include beats that have descriptions - similar to how the Atom everything feed on the blog works&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Referencing &lt;code&gt;blog-to-newsletter.html&lt;/code&gt; is all I need here to tell Claude which of the 200+ HTML apps in that &lt;code&gt;simonw/tools&lt;/code&gt; repo it should be modifying.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;I already use this as a distinction to decide which beats end up in my site's &lt;a href="https://simonwillison.net/about/#atom"&gt;Atom feed&lt;/a&gt;. Telling Claude to imitate that saves me from having to describe the logic in any extra detail.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;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&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Coding agents always work best if they have some kind of validation mechanism they can use to test their own work.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;I reminded it to use &lt;code&gt;python -m http.server&lt;/code&gt; 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 &lt;code&gt;python -m http.server&lt;/code&gt; baked in at this point!&lt;/p&gt;
&lt;p&gt;I described the &lt;code&gt;uvx rodney --help&lt;/code&gt; trick in &lt;a href="https://simonwillison.net/guides/agentic-engineering-patterns/agentic-manual-testing/#using-browser-automation-for-web-uis"&gt;the agentic manual testing chapter&lt;/a&gt;. Rodney is browser automation software that can be installed using &lt;code&gt;uvx&lt;/code&gt;, and that has &lt;code&gt;--help&lt;/code&gt; output designed to teach an agent everything it needs to know in order to use the tool.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;You can see &lt;a href="https://claude.ai/code/session_01BibYBuvJi2qNUyCYGaY3Ss"&gt;the full session here&lt;/a&gt;, or if that doesn't work I have an &lt;a href="https://gisthost.github.io/?e906e938100ab42f4d6a932505219324/page-001.html#msg-2026-04-18T00-13-57-081Z"&gt;alternative transcript&lt;/a&gt; showing all of the individual tool calls.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/simonw/tools/pull/268"&gt;resulting PR&lt;/a&gt; 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 &lt;code&gt;note&lt;/code&gt; column:&lt;/p&gt;
&lt;p&gt;&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;beat&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;No HTML&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;json_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;created&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;beat_type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beat_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;commentary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;commentary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;note&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;external_url&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blog_beat&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;coalesce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_draft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
And it figured out a mapping of beat types to their formal names, presumably derived from the &lt;a href="https://github.com/simonw/simonwillisonblog/blob/2e9d7ebe64da799b3927e61b4f85d98f7e9bc9aa/blog/models.py#L545-L551"&gt;Django ORM definition&lt;/a&gt; that it read while it was exploring the reference codebase:
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;const beatTypeDisplay = {
  release: &amp;#39;Release&amp;#39;,
  til: &amp;#39;TIL&amp;#39;,
  til_update: &amp;#39;TIL updated&amp;#39;,
  research: &amp;#39;Research&amp;#39;,
  tool: &amp;#39;Tool&amp;#39;,
  museum: &amp;#39;Museum&amp;#39;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
Telling agents to use another codebase as reference is a powerful shortcut for communicating complex concepts with minimal additional information needed in the prompt.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-engineering"&gt;prompt-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/agentic-engineering"&gt;agentic-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="ai"/><category term="llms"/><category term="prompt-engineering"/><category term="coding-agents"/><category term="ai-assisted-programming"/><category term="generative-ai"/><category term="agentic-engineering"/><category term="github"/></entry><entry><title>Join us at PyCon US 2026 in Long Beach - we have new AI and security tracks this year</title><link href="https://simonwillison.net/2026/Apr/17/pycon-us-2026/#atom-everything" rel="alternate"/><published>2026-04-17T23:59:03+00:00</published><updated>2026-04-17T23:59:03+00:00</updated><id>https://simonwillison.net/2026/Apr/17/pycon-us-2026/#atom-everything</id><summary type="html">
    &lt;p&gt;This year's &lt;a href="https://us.pycon.org/2026/"&gt;PyCon US&lt;/a&gt; is coming up next month from May 13th to May 19th, with the core conference talks from Friday 15th to Sunday 17th and tutorial and sprint days either side. It's in Long Beach, California this year, the first time PyCon US has come to the West Coast since Portland, Oregon in 2017 and the first time in California since Santa Clara in 2013.&lt;/p&gt;
&lt;p&gt;If you're based in California this is a great opportunity to catch up with the Python community, meet a whole lot of interesting people and learn a ton of interesting things.&lt;/p&gt;
&lt;p&gt;In addition to regular PyCon programming we have two new dedicated tracks at the conference this year: an &lt;a href="https://us.pycon.org/2026/tracks/ai/"&gt;AI track&lt;/a&gt; on Friday and a &lt;a href="https://us.pycon.org/2026/tracks/security/"&gt;Security track&lt;/a&gt; on Saturday.&lt;/p&gt;
&lt;p&gt;The AI program was put together by track chairs Silona Bonewald (CitableAI) and Zac Hatfield-Dodds (Anthropic). I'll be an in-the-room chair this year, introducing speakers and helping everything run as smoothly as possible.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://us.pycon.org/2026/schedule/talks/#May15"&gt;the AI track schedule&lt;/a&gt; in full:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;11:00: &lt;a href="https://us.pycon.org/2026/schedule/presentation/105/"&gt;AI-Assisted Contributions and Maintainer Load&lt;/a&gt; - Paolo Melchiorre&lt;/li&gt;
&lt;li&gt;11:45: &lt;a href="https://us.pycon.org/2026/schedule/presentation/66/"&gt;AI-Powered Python Education : Towards Adaptive and Inclusive Learning&lt;/a&gt; - Sonny Mupfuni&lt;/li&gt;
&lt;li&gt;12:30: &lt;a href="https://us.pycon.org/2026/schedule/presentation/23/"&gt;Making African Languages Visible: A Python-Based Guide to Low-Resource Language ID&lt;/a&gt; - Gift Ojeabulu&lt;/li&gt;
&lt;li&gt;2:00: &lt;a href="https://us.pycon.org/2026/schedule/presentation/138/"&gt;Running Large Language Models on Laptops: Practical Quantization Techniques in Python&lt;/a&gt; - Aayush Kumar JVS&lt;/li&gt;
&lt;li&gt;2:45: &lt;a href="https://us.pycon.org/2026/schedule/presentation/126/"&gt;Distributing AI with Python in the Browser: Edge Inference and Flexibility Without Infrastructure&lt;/a&gt; - Fabio Pliger&lt;/li&gt;
&lt;li&gt;3:30: &lt;a href="https://us.pycon.org/2026/schedule/presentation/110/"&gt;Don't Block the Loop: Python Async Patterns for AI Agents&lt;/a&gt; - Aditya Mehra&lt;/li&gt;
&lt;li&gt;4:30: &lt;a href="https://us.pycon.org/2026/schedule/presentation/81/"&gt;What Python Developers Need to Know About Hardware: A Practical Guide to GPU Memory, Kernel Scheduling, and Execution Models&lt;/a&gt; - Santosh Appachu Devanira Poovaiah&lt;/li&gt;
&lt;li&gt;5:15: &lt;a href="https://us.pycon.org/2026/schedule/presentation/101/"&gt;How to Build Your First Real-Time Voice Agent in Python (Without Losing Your Mind)&lt;/a&gt; - Camila Hinojosa Añez, Elizabeth Fuentes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(And here's &lt;a href="https://gisthost.github.io/?dab27f61d85eb98f60db5991aa21ec89"&gt;how I scraped that as a Markdown list&lt;/a&gt; from the schedule page using Claude Code and &lt;a href="https://github.com/simonw/rodney"&gt;Rodney&lt;/a&gt;.)&lt;/p&gt;
&lt;h4 id="you-should-come-to-pycon-"&gt;You should come to PyCon US!&lt;/h4&gt;
&lt;p&gt;I've been going to PyCon for over twenty years now - I first went &lt;a href="https://simonwillison.net/2005/Mar/28/pycon/"&gt;back in 2005&lt;/a&gt;. It's one of my all-time favourite conference series. Even as it's grown to more than 2,000 attendees PyCon US has remained a heavily community-focused conference - it's the least &lt;em&gt;corporate&lt;/em&gt; feeling large event I've ever attended.&lt;/p&gt;
&lt;p&gt;The talks are always great, but it's the add-ons around the talks that really make it work for me. The &lt;a href="https://us.pycon.org/2026/events/lightning-talks/"&gt;lightning talks&lt;/a&gt; slots are some of the most heavily attended sessions. The PyLadies auction is always deeply entertaining. The sprints are an incredible opportunity to contribute directly to projects that you use, coached by their maintainers.&lt;/p&gt;
&lt;p&gt;In addition to scheduled talks, the event has &lt;strong&gt;open spaces&lt;/strong&gt;, where anyone can reserve space for a conversation about a topic - effectively PyCon's version of an &lt;a href="https://en.wikipedia.org/wiki/Unconference"&gt;unconference&lt;/a&gt;. I plan to spend a lot of my time in the open spaces this year - I'm hoping to join or instigate sessions about both &lt;a href="https://datasette.io/"&gt;Datasette&lt;/a&gt; and &lt;a href="https://simonwillison.net/guides/agentic-engineering-patterns/"&gt;agentic engineering&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm on the board of the Python Software Foundation, and PyCon US remains one of our most important responsibilities - in the past it's been a key source of funding for the organization, but it's also core to our mission to "promote, protect, and advance the Python programming language, and to support and facilitate the growth of a diverse and international community of Python programmers".&lt;/p&gt;
&lt;p&gt;&lt;small&gt;If you do come to Long Beach, we'd really appreciate it if you could book accommodation in the official hotel block, for reasons &lt;a href="https://pyfound.blogspot.com/2026/04/pycon-us-2026-hotels.html"&gt;outlined in this post on the PSF blog&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/conferences"&gt;conferences&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/open-source"&gt;open-source&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pycon"&gt;pycon&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/psf"&gt;psf&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="conferences"/><category term="open-source"/><category term="pycon"/><category term="python"/><category term="ai"/><category term="psf"/></entry><entry><title>datasette 1.0a28</title><link href="https://simonwillison.net/2026/Apr/17/datasette/#atom-everything" rel="alternate"/><published>2026-04-17T04:01:56+00:00</published><updated>2026-04-17T04:01:56+00:00</updated><id>https://simonwillison.net/2026/Apr/17/datasette/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/simonw/datasette/releases/tag/1.0a28"&gt;datasette 1.0a28&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;I was upgrading Datasette Cloud to &lt;a href="https://simonwillison.net/2026/Apr/15/datasette/"&gt;1.0a27&lt;/a&gt; and discovered a nasty collection of accidental breakages caused by changes in that alpha. This new alpha addresses those directly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Fixed a compatibility bug introduced in 1.0a27 where &lt;code&gt;execute_write_fn()&lt;/code&gt; callbacks with a parameter name other than &lt;code&gt;conn&lt;/code&gt; were seeing errors. (&lt;a href="https://github.com/simonw/datasette/issues/2691"&gt;#2691&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://docs.datasette.io/en/latest/internals.html#database-close"&gt;database.close()&lt;/a&gt; method now also shuts down the write connection for that database.&lt;/li&gt;
&lt;li&gt;New &lt;a href="https://docs.datasette.io/en/latest/internals.html#datasette-close"&gt;datasette.close()&lt;/a&gt; method for closing down all databases and resources associated with a Datasette instance. This is called automatically when the server shuts down. (&lt;a href="https://github.com/simonw/datasette/pull/2693"&gt;#2693&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Datasette now includes a pytest plugin which automatically calls &lt;code&gt;datasette.close()&lt;/code&gt; on temporary instances created in function-scoped fixtures and during tests. See &lt;a href="https://docs.datasette.io/en/latest/testing_plugins.html#testing-plugins-autoclose"&gt;Automatic cleanup of Datasette instances&lt;/a&gt; for details. This helps avoid running out of file descriptors in plugin test suites that were written before the &lt;code&gt;Database(is_temp_disk=True)&lt;/code&gt; feature introduced in Datasette 1.0a27. (&lt;a href="https://github.com/simonw/datasette/issues/2692"&gt;#2692&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most of the changes in this release were implemented using Claude Code and the newly released Claude Opus 4.7.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="datasette"/></entry><entry><title>llm-anthropic 0.25</title><link href="https://simonwillison.net/2026/Apr/16/llm-anthropic/#atom-everything" rel="alternate"/><published>2026-04-16T20:37:12+00:00</published><updated>2026-04-16T20:37:12+00:00</updated><id>https://simonwillison.net/2026/Apr/16/llm-anthropic/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/simonw/llm-anthropic/releases/tag/0.25"&gt;llm-anthropic 0.25&lt;/a&gt;&lt;/p&gt;
    &lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;New model: &lt;code&gt;claude-opus-4.7&lt;/code&gt;, which supports &lt;code&gt;thinking_effort&lt;/code&gt;: &lt;code&gt;xhigh&lt;/code&gt;. #66&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;thinking_display&lt;/code&gt; and &lt;code&gt;thinking_adaptive&lt;/code&gt; boolean options. &lt;code&gt;thinking_display&lt;/code&gt; summarized output is currently only available in JSON output or JSON logs.&lt;/li&gt;
&lt;li&gt;Increased default &lt;code&gt;max_tokens&lt;/code&gt; to the maximum allowed for each model.&lt;/li&gt;
&lt;li&gt;No longer uses obsolete &lt;code&gt;structured-outputs-2025-11-13&lt;/code&gt; beta header for older models.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="llm"/><category term="anthropic"/><category term="claude"/></entry><entry><title>Qwen3.6-35B-A3B on my laptop drew me a better pelican than Claude Opus 4.7</title><link href="https://simonwillison.net/2026/Apr/16/qwen-beats-opus/#atom-everything" rel="alternate"/><published>2026-04-16T17:16:52+00:00</published><updated>2026-04-16T17:16:52+00:00</updated><id>https://simonwillison.net/2026/Apr/16/qwen-beats-opus/#atom-everything</id><summary type="html">
    &lt;p&gt;For anyone who has been (inadvisably) taking my &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle/"&gt;pelican riding a bicycle benchmark&lt;/a&gt; seriously as a robust way to test models, here are pelicans from this morning's two big model releases - &lt;a href="https://qwen.ai/blog?id=qwen3.6-35b-a3b"&gt;Qwen3.6-35B-A3B from Alibaba&lt;/a&gt; and &lt;a href="https://www.anthropic.com/news/claude-opus-4-7"&gt;Claude Opus 4.7 from Anthropic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's the Qwen 3.6 pelican, generated using &lt;a href="https://huggingface.co/unsloth/Qwen3.6-35B-A3B-GGUF/blob/main/Qwen3.6-35B-A3B-UD-Q4_K_S.gguf"&gt;this 20.9GB Qwen3.6-35B-A3B-UD-Q4_K_S.gguf&lt;/a&gt; quantized model by Unsloth, running on my MacBook Pro M5 via &lt;a href="https://lmstudio.ai/"&gt;LM Studio&lt;/a&gt; (and the &lt;a href="https://github.com/agustif/llm-lmstudio"&gt;llm-lmstudio&lt;/a&gt; plugin) - &lt;a href="https://gist.github.com/simonw/4389d355d8e162bc6e4547da214f7dd2"&gt;transcript here&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/Qwen3.6-35B-A3B-UD-Q4_K_S-pelican.png" alt="The bicycle frame is the correct shape. There are clouds in the sky. The pelican has a dorky looking pouch. A caption on the ground reads Pelican on a Bicycle!" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;And here's one I got from Anthropic's &lt;a href="https://www.anthropic.com/news/claude-opus-4-7"&gt;brand new Claude Opus 4.7&lt;/a&gt; (&lt;a href="https://gist.github.com/simonw/afcb19addf3f38eb1996e1ebe749c118"&gt;transcript&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/opus-4.7-pelican.png" alt="The bicycle frame is entirely the wrong shape. No clouds, a yellow sun. The pelican is looking behind itself, and has a less pronounced pouch than I would like." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;I'm giving this one to Qwen 3.6. Opus managed to mess up the bicycle frame!&lt;/p&gt;
&lt;p&gt;I tried Opus a second time passing &lt;code&gt;thinking_level: max&lt;/code&gt;. It didn't do much better (&lt;a href="https://gist.github.com/simonw/7566e04a81accfb9affda83451c0f363"&gt;transcript&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/opus-4.7-pelican-max.png" alt="The bicycle frame is entirely the wrong shape but in a different way. Lines are more bold. Pelican looks a bit more like a pelican." style="max-width: 100%;" /&gt;&lt;/p&gt;

&lt;h4 id="i-dont-think-qwen-are-cheating"&gt;I don't think Qwen are cheating&lt;/h4&gt;
&lt;p&gt;A lot of people are &lt;a href="https://simonwillison.net/2025/Nov/13/training-for-pelicans-riding-bicycles/"&gt;convinced that the labs train for my stupid benchmark&lt;/a&gt;. I don't think they do, but honestly this result did give me a little glint of suspicion. So I'm burning one of my secret backup tests - here's what I got from Qwen3.6-35B-A3B and Opus 4.7 for "Generate an SVG of a flamingo riding a unicycle":&lt;/p&gt;

&lt;div style="display: flex; gap: 4px;"&gt;
  &lt;figure style="flex: 1; text-align: center; margin: 0;"&gt;
    &lt;figcaption style="margin-bottom: 1em"&gt;Qwen3.6-35B-A3B&lt;br /&gt;(&lt;a href="https://gist.github.com/simonw/f1d1ff01c34dda5fdedf684cfc430d92"&gt;transcript&lt;/a&gt;)&lt;/figcaption&gt;
    &lt;img src="https://static.simonwillison.net/static/2026/qwen-flamingo.png" alt="The unicycle spokes are a too long. The pelican has sunglasses, a bowtie and appears to be smoking a cigarette. It has two heart emoji surrounding the caption Flamingo on a Unicycle. It has a lot of charisma." style="max-width: 100%; height: auto;" /&gt;
  &lt;/figure&gt;
  &lt;figure style="flex: 1; text-align: center; margin: 0;"&gt;
    &lt;figcaption style="margin-bottom: 1em"&gt;Opus 4.7&lt;br /&gt;(&lt;a href="https://gist.github.com/simonw/35121ad5dcf23bf860397a103ae88d50"&gt;transcript&lt;/a&gt;)&lt;/figcaption&gt;
    &lt;img src="https://static.simonwillison.net/static/2026/opus-flamingo.png" alt="The unicycle has a black wheel. The flamingo is a competent if slightly dull vector illustration of a flamingo. It has no flair." style="max-width: 100%; height: auto;" /&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;I'm giving this one to Qwen too, partly for the excellent &lt;code&gt;&amp;lt;!-- Sunglasses on flamingo! --&amp;gt;&lt;/code&gt; SVG comment.&lt;/p&gt;

&lt;h4 id="what-can-we-learn-from-this-"&gt;What can we learn from this?&lt;/h4&gt;
&lt;p&gt;The pelican benchmark has always been meant as a joke - it's mainly a statement on how obtuse and absurd the task of comparing these models is.&lt;/p&gt;
&lt;p&gt;The weird thing about that joke is that, for the most part, there has been a direct correlation between the quality of the pelicans produced and the general usefulness of the models. Those &lt;a href="https://simonwillison.net/2024/Oct/25/pelicans-on-a-bicycle/"&gt;first pelicans from October 2024&lt;/a&gt; were junk. The &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle/"&gt;more recent entries&lt;/a&gt; have generally been much, much better - to the point that Gemini 3.1 Pro produces &lt;a href="https://simonwillison.net/2026/Feb/19/gemini-31-pro/"&gt;illustrations you could actually use somewhere&lt;/a&gt;, provided you had a pressing need to illustrate a pelican riding a bicycle.&lt;/p&gt;
&lt;p&gt;Today, even that loose connection to utility has been broken. I have enormous respect for Qwen, but I very much doubt that a 21GB quantized version of their latest model is more powerful or useful than Anthropic's latest proprietary release.&lt;/p&gt;
&lt;p&gt;If the thing you need is an SVG illustration of a pelican riding a bicycle though, right now Qwen3.6-35B-A3B running on a laptop is a better bet than Opus 4.7!&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/local-llms"&gt;local-llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/qwen"&gt;qwen&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle"&gt;pelican-riding-a-bicycle&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/lm-studio"&gt;lm-studio&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="ai"/><category term="generative-ai"/><category term="local-llms"/><category term="llms"/><category term="anthropic"/><category term="claude"/><category term="qwen"/><category term="pelican-riding-a-bicycle"/><category term="llm-release"/><category term="lm-studio"/></entry><entry><title>datasette.io news preview</title><link href="https://simonwillison.net/2026/Apr/16/datasette-io-preview/#atom-everything" rel="alternate"/><published>2026-04-16T00:18:03+00:00</published><updated>2026-04-16T00:18:03+00:00</updated><id>https://simonwillison.net/2026/Apr/16/datasette-io-preview/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://tools.simonwillison.net/datasette-io-preview"&gt;datasette.io news preview&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;The &lt;a href="https://datasette.io/"&gt;datasette.io&lt;/a&gt; website has a news section built from this &lt;a href="https://github.com/simonw/datasette.io/blob/main/news.yaml"&gt;news.yaml&lt;/a&gt; file in the underlying GitHub repository. The YAML format looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- date: 2026-04-15
  body: |-
    [Datasette 1.0a27](https://docs.datasette.io/en/latest/changelog.html#a27-2026-04-15) changes how CSRF protection works in a way that simplifies form and API integration, and introduces a new `RenameTableEvent` for when a table is renamed by a SQL query.
- date: 2026-03-18
  body: |-
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This format is a little hard to edit, so I finally &lt;a href="https://claude.ai/share/c96129b9-bcb0-4eba-aee9-4a7ad236dfb7"&gt;had Claude build a custom preview UI&lt;/a&gt; to make checking for errors have slightly less friction.&lt;/p&gt;
&lt;p&gt;I built it using standard &lt;a href="https://claude.ai/"&gt;claude.ai&lt;/a&gt; and Claude Artifacts, taking advantage of Claude's ability to clone GitHub repos and look at their content as part of a regular chat:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Clone https://github.com/simonw/datasette.io and look at the news.yaml file and how it is rendered on the homepage. Build an artifact I can paste that YAML into which previews what it will look like, and highlights any markdown errors or YAML errors&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="Screenshot showing two side-by-side views of a datasette.io news preview tool. The left panel shows a dark-themed YAML editor with news entries containing date and body fields in Markdown format, with a red validation error at the bottom indicating the date field has an invalid format. The right panel shows the rendered preview output with formatted headings by date (April 2026, 18th March 2026), displaying 115 news entries with linked release names, inline code snippets, and changelog descriptions. A red badge with &amp;quot;1&amp;quot; appears on the left panel header indicating one validation error." src="https://static.simonwillison.net/static/2026/datasette-io-preview.jpg" /&gt;&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tools"&gt;tools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="vibe-coding"/><category term="claude"/><category term="tools"/><category term="datasette"/></entry><entry><title>datasette-export-database 0.3a1</title><link href="https://simonwillison.net/2026/Apr/15/datasette-export-database/#atom-everything" rel="alternate"/><published>2026-04-15T23:52:35+00:00</published><updated>2026-04-15T23:52:35+00:00</updated><id>https://simonwillison.net/2026/Apr/15/datasette-export-database/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/datasette/datasette-export-database/releases/tag/0.3a1"&gt;datasette-export-database 0.3a1&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;This plugin was using the &lt;code&gt;ds_csrftoken&lt;/code&gt; cookie as part of a custom signed URL, which needed upgrading now that Datasette 1.0a27 &lt;a href="https://simonwillison.net/2026/Apr/14/replace-token-based-csrf/"&gt;no longer sets that cookie&lt;/a&gt;.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="datasette"/></entry><entry><title>datasette 1.0a27</title><link href="https://simonwillison.net/2026/Apr/15/datasette/#atom-everything" rel="alternate"/><published>2026-04-15T23:16:34+00:00</published><updated>2026-04-15T23:16:34+00:00</updated><id>https://simonwillison.net/2026/Apr/15/datasette/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/simonw/datasette/releases/tag/1.0a27"&gt;datasette 1.0a27&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;Two major changes in this new Datasette alpha. I covered the first of those &lt;a href="https://simonwillison.net/2026/Apr/14/replace-token-based-csrf/"&gt;in detail yesterday&lt;/a&gt; - Datasette no longer uses Django-style CSRF form tokens, instead using modern browser headers &lt;a href="https://words.filippo.io/csrf"&gt;as described by Filippo Valsorda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The second big change is that Datasette now fires a new &lt;a href="https://docs.datasette.io/en/latest/events.html#datasette.events.RenameTableEvent"&gt;RenameTableEvent&lt;/a&gt; any time a table is renamed during a SQLite transaction. This is useful because some plugins (like &lt;a href="https://github.com/datasette/datasette-comments"&gt;datasette-comments&lt;/a&gt;) attach additional data to table records by name, so a renamed table requires them to react in appropriate ways.&lt;/p&gt;
&lt;p&gt;Here are the rest of the changes in the alpha:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;New &lt;a href="https://docs.datasette.io/en/latest/internals.html#internals-datasette-client-actor"&gt;actor= parameter&lt;/a&gt; for &lt;code&gt;datasette.client&lt;/code&gt; methods, allowing internal requests to be made as a specific actor. This is particularly useful for writing automated tests. (&lt;a href="https://github.com/simonw/datasette/pull/2688"&gt;#2688&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;Database(is_temp_disk=True)&lt;/code&gt; option, used internally for the internal database. This helps resolve intermittent database locked errors caused by the internal database being in-memory as opposed to on-disk. (&lt;a href="https://github.com/simonw/datasette/issues/2683"&gt;#2683&lt;/a&gt;) (&lt;a href="https://github.com/simonw/datasette/pull/2684"&gt;#2684&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;/&amp;lt;database&amp;gt;/&amp;lt;table&amp;gt;/-/upsert&lt;/code&gt; API (&lt;a href="https://docs.datasette.io/en/latest/json_api.html#tableupsertview"&gt;docs&lt;/a&gt;) now rejects rows with &lt;code&gt;null&lt;/code&gt; primary key values. (&lt;a href="https://github.com/simonw/datasette/issues/1936"&gt;#1936&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Improved example in the API explorer for the &lt;code&gt;/-/upsert&lt;/code&gt; endpoint (&lt;a href="https://docs.datasette.io/en/latest/json_api.html#tableupsertview"&gt;docs&lt;/a&gt;). (&lt;a href="https://github.com/simonw/datasette/issues/1936"&gt;#1936&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;/&amp;lt;database&amp;gt;.json&lt;/code&gt; endpoint now includes an &lt;code&gt;"ok": true&lt;/code&gt; key, for consistency with other JSON API responses.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.datasette.io/en/latest/internals.html#internals-utils-call-with-supported-arguments"&gt;call_with_supported_arguments()&lt;/a&gt; is now documented as a supported public API. (&lt;a href="https://github.com/simonw/datasette/pull/2678"&gt;#2678&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/annotated-release-notes"&gt;annotated-release-notes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="annotated-release-notes"/><category term="datasette"/><category term="python"/></entry><entry><title>Quoting John Gruber</title><link href="https://simonwillison.net/2026/Apr/15/john-gruber/#atom-everything" rel="alternate"/><published>2026-04-15T17:13:57+00:00</published><updated>2026-04-15T17:13:57+00:00</updated><id>https://simonwillison.net/2026/Apr/15/john-gruber/#atom-everything</id><summary type="html">
    &lt;blockquote cite="https://daringfireball.net/2026/04/piece_android_iphone_apps"&gt;&lt;p&gt;The real goldmine isn’t that Apple gets a cut of every App Store transaction. It’s that Apple’s platforms have the best apps, and users who are drawn to the best apps are thus drawn to the iPhone, Mac, and iPad. That edge is waning. Not because software on other platforms is getting better, but because third-party software on iPhone, Mac, and iPad is regressing to the mean, &lt;em&gt;to some extent&lt;/em&gt;, because fewer developers feel motivated — artistically, financially, or both — to create well-crafted idiomatic native apps exclusively for Apple’s platforms.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://daringfireball.net/2026/04/piece_android_iphone_apps"&gt;John Gruber&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apple"&gt;apple&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/john-gruber"&gt;john-gruber&lt;/a&gt;&lt;/p&gt;



</summary><category term="apple"/><category term="john-gruber"/></entry><entry><title>Gemini 3.1 Flash TTS</title><link href="https://simonwillison.net/2026/Apr/15/gemini-31-flash-tts/#atom-everything" rel="alternate"/><published>2026-04-15T17:13:14+00:00</published><updated>2026-04-15T17:13:14+00:00</updated><id>https://simonwillison.net/2026/Apr/15/gemini-31-flash-tts/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-3-1-flash-tts/"&gt;Gemini 3.1 Flash TTS&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Google released Gemini 3.1 Flash TTS today, a new text-to-speech model that can be directed using prompts.&lt;/p&gt;
&lt;p&gt;It's presented via the standard Gemini API using &lt;code&gt;gemini-3.1-flash-tts-preview&lt;/code&gt; as the model ID, but can only output audio files.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://ai.google.dev/gemini-api/docs/speech-generation#transcript-tags"&gt;prompting guide&lt;/a&gt; is surprising, to say the least. Here's their example prompt to generate just a few short sentences of audio:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# AUDIO PROFILE: Jaz R.
## "The Morning Hype"

## THE SCENE: The London Studio
It is 10:00 PM in a glass-walled studio overlooking the moonlit London skyline, but inside, it is blindingly bright. The red "ON AIR" tally light is blazing. Jaz is standing up, not sitting, bouncing on the balls of their heels to the rhythm of a thumping backing track. Their hands fly across the faders on a massive mixing desk. It is a chaotic, caffeine-fueled cockpit designed to wake up an entire nation.

### DIRECTOR'S NOTES
Style:
* The "Vocal Smile": You must hear the grin in the audio. The soft palate is always raised to keep the tone bright, sunny, and explicitly inviting.
* Dynamics: High projection without shouting. Punchy consonants and elongated vowels on excitement words (e.g., "Beauuutiful morning").

Pace: Speaks at an energetic pace, keeping up with the fast music.  Speaks with A "bouncing" cadence. High-speed delivery with fluid transitions — no dead air, no gaps.

Accent: Jaz is from Brixton, London

### SAMPLE CONTEXT
Jaz is the industry standard for Top 40 radio, high-octane event promos, or any script that requires a charismatic Estuary accent and 11/10 infectious energy.

#### TRANSCRIPT
[excitedly] Yes, massive vibes in the studio! You are locked in and it is absolutely popping off in London right now. If you're stuck on the tube, or just sat there pretending to work... stop it. Seriously, I see you.
[shouting] Turn this up! We've got the project roadmap landing in three, two... let's go!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's what I got using that example prompt:&lt;/p&gt;
&lt;p&gt;&lt;audio controls style="width: 100%"&gt;
  &lt;source src="https://static.simonwillison.net/static/2026/gemini-flash-tts-london.wav" type="audio/wav"&gt;
  Your browser does not support the audio element.
&lt;/audio&gt;&lt;/p&gt;
&lt;p&gt;Then I modified it to say "Jaz is from Newcastle" and "... requires a charismatic Newcastle accent" and got this result:&lt;/p&gt;
&lt;p&gt;&lt;audio controls style="width: 100%"&gt;
  &lt;source src="https://static.simonwillison.net/static/2026/gemini-flash-tts-newcastle.wav" type="audio/wav"&gt;
  Your browser does not support the audio element.
&lt;/audio&gt;&lt;/p&gt;
&lt;p&gt;Here's Exeter, Devon for good measure:&lt;/p&gt;
&lt;p&gt;&lt;audio controls style="width: 100%"&gt;
  &lt;source src="https://static.simonwillison.net/static/2026/gemini-flash-tts-devon.wav" type="audio/wav"&gt;
  Your browser does not support the audio element.
&lt;/audio&gt;&lt;/p&gt;
&lt;p&gt;I &lt;a href="https://gemini.google.com/share/dd0fba5a83c4"&gt;had Gemini 3.1 Pro&lt;/a&gt; vibe code &lt;a href="https://tools.simonwillison.net/gemini-flash-tts"&gt;this UI for trying it out&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot of a &amp;quot;Gemini 3.1 Flash TTS&amp;quot; web application interface. At the top is an &amp;quot;API Key&amp;quot; field with a masked password. Below is a &amp;quot;TTS Mode&amp;quot; section with a dropdown set to &amp;quot;Multi-Speaker (Conversation)&amp;quot;. &amp;quot;Speaker 1 Name&amp;quot; is set to &amp;quot;Joe&amp;quot; with &amp;quot;Speaker 1 Voice&amp;quot; set to &amp;quot;Puck (Upbeat)&amp;quot;. &amp;quot;Speaker 2 Name&amp;quot; is set to &amp;quot;Jane&amp;quot; with &amp;quot;Speaker 2 Voice&amp;quot; set to &amp;quot;Kore (Firm)&amp;quot;. Under &amp;quot;Script / Prompt&amp;quot; is a tip reading &amp;quot;Tip: Format your text as a script using the Exact Speaker Names defined above.&amp;quot; The script text area contains &amp;quot;TTS the following conversation between Joe and Jane:\n\nJoe: How's it going today Jane?\nJane: [yawn] Not too bad, how about you?&amp;quot; A blue &amp;quot;Generate Audio&amp;quot; button is below. At the bottom is a &amp;quot;Success!&amp;quot; message with an audio player showing 00:00 / 00:06 and a &amp;quot;Download WAV&amp;quot; link." src="https://static.simonwillison.net/static/2026/gemini-flash-tts.jpg" /&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/text-to-speech"&gt;text-to-speech&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tools"&gt;tools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-engineering"&gt;prompt-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gemini"&gt;gemini&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&lt;/a&gt;&lt;/p&gt;



</summary><category term="google"/><category term="text-to-speech"/><category term="tools"/><category term="ai"/><category term="prompt-engineering"/><category term="generative-ai"/><category term="llms"/><category term="gemini"/><category term="llm-release"/><category term="vibe-coding"/></entry><entry><title>Gemini 3.1 Flash TTS</title><link href="https://simonwillison.net/2026/Apr/15/gemini-flash-tts/#atom-everything" rel="alternate"/><published>2026-04-15T16:41:46+00:00</published><updated>2026-04-15T16:41:46+00:00</updated><id>https://simonwillison.net/2026/Apr/15/gemini-flash-tts/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://tools.simonwillison.net/gemini-flash-tts"&gt;Gemini 3.1 Flash TTS&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;See &lt;a href="https://simonwillison.net/2026/Apr/15/gemini-31-flash-tts/"&gt;my notes&lt;/a&gt; on Google's new Gemini 3.1 Flash TTS text-to-speech model.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/gemini"&gt;gemini&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="gemini"/><category term="google"/></entry><entry><title>Quoting Kyle Kingsbury</title><link href="https://simonwillison.net/2026/Apr/15/kyle-kingsbury/#atom-everything" rel="alternate"/><published>2026-04-15T15:36:02+00:00</published><updated>2026-04-15T15:36:02+00:00</updated><id>https://simonwillison.net/2026/Apr/15/kyle-kingsbury/#atom-everything</id><summary type="html">
    &lt;blockquote cite="https://aphyr.com/posts/419-the-future-of-everything-is-lies-i-guess-new-jobs"&gt;&lt;p&gt;I think we will see some people employed (though perhaps not explicitly) as &lt;em&gt;meat shields&lt;/em&gt;: people who are accountable for ML systems under their supervision. The accountability may be purely internal, as when Meta hires human beings to review the decisions of automated moderation systems. It may be external, as when lawyers are penalized for submitting LLM lies to the court. It may involve formalized responsibility, like a Data Protection Officer. It may be convenient for a company to have third-party subcontractors, like Buscaglia, who can be thrown under the bus when the system as a whole misbehaves.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://aphyr.com/posts/419-the-future-of-everything-is-lies-i-guess-new-jobs"&gt;Kyle Kingsbury&lt;/a&gt;, The Future of Everything is Lies, I Guess: New Jobs&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/careers"&gt;careers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/kyle-kingsbury"&gt;kyle-kingsbury&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai-ethics"/><category term="careers"/><category term="ai"/><category term="kyle-kingsbury"/></entry><entry><title>datasette-ports 0.3</title><link href="https://simonwillison.net/2026/Apr/15/datasette-ports/#atom-everything" rel="alternate"/><published>2026-04-15T02:50:57+00:00</published><updated>2026-04-15T02:50:57+00:00</updated><id>https://simonwillison.net/2026/Apr/15/datasette-ports/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/datasette/datasette-ports/releases/tag/0.3"&gt;datasette-ports 0.3&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;A small update for my tool for helping me figure out what all of the Datasette instances on my laptop are up to.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Show working directory derived from each PID&lt;/li&gt;
&lt;li&gt;Show the full path to each database file&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Output now looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://127.0.0.1:8007/ - v1.0a26
  Directory: /Users/simon/dev/blog
  Databases:
    simonwillisonblog: /Users/simon/dev/blog/simonwillisonblog.db
  Plugins:
    datasette-llm
    datasette-secrets
http://127.0.0.1:8001/ - v1.0a26
  Directory: /Users/simon/dev/creatures
  Databases:
    creatures: /tmp/creatures.db
&lt;/code&gt;&lt;/pre&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="datasette"/></entry><entry><title>Zig 0.16.0 release notes: "Juicy Main"</title><link href="https://simonwillison.net/2026/Apr/15/juicy-main/#atom-everything" rel="alternate"/><published>2026-04-15T01:59:21+00:00</published><updated>2026-04-15T01:59:21+00:00</updated><id>https://simonwillison.net/2026/Apr/15/juicy-main/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://ziglang.org/download/0.16.0/release-notes.html#Juicy-Main"&gt;Zig 0.16.0 release notes: &amp;quot;Juicy Main&amp;quot;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Zig has &lt;em&gt;really good&lt;/em&gt; release notes - comprehensive, detailed, and with relevant usage examples for each of the new features.&lt;/p&gt;
&lt;p&gt;Of particular note in the newly released Zig 0.16.0 is what they are calling "Juicy Main" - a dependency injection feature for your program's &lt;code&gt;main()&lt;/code&gt; function where accepting a &lt;code&gt;process.Init&lt;/code&gt; parameter grants access to a struct of useful properties:&lt;/p&gt;
&lt;div class="highlight highlight-source-zig"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-v"&gt;std&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;@import&lt;/span&gt;(&lt;span class="pl-s"&gt;"std"&lt;/span&gt;);

&lt;span class="pl-k"&gt;pub&lt;/span&gt; &lt;span class="pl-k"&gt;fn&lt;/span&gt; &lt;span class="pl-en"&gt;main&lt;/span&gt;(&lt;span class="pl-v"&gt;init&lt;/span&gt;: &lt;span class="pl-k"&gt;std.process.Init&lt;/span&gt;) &lt;span class="pl-k"&gt;!&lt;/span&gt;&lt;span class="pl-k"&gt;void&lt;/span&gt; {
    &lt;span class="pl-c"&gt;/// general purpose allocator for temporary heap allocations:&lt;/span&gt;
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-v"&gt;gpa&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-v"&gt;init&lt;/span&gt;.&lt;span class="pl-v"&gt;gpa&lt;/span&gt;;
    &lt;span class="pl-c"&gt;/// default Io implementation:&lt;/span&gt;
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-v"&gt;io&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-v"&gt;init&lt;/span&gt;.&lt;span class="pl-v"&gt;io&lt;/span&gt;;
    &lt;span class="pl-c"&gt;/// access to environment variables:&lt;/span&gt;
    &lt;span class="pl-v"&gt;std&lt;/span&gt;.&lt;span class="pl-v"&gt;log&lt;/span&gt;.&lt;span class="pl-v"&gt;info&lt;/span&gt;(&lt;span class="pl-s"&gt;"{d} env vars"&lt;/span&gt;, .{&lt;span class="pl-v"&gt;init&lt;/span&gt;.&lt;span class="pl-v"&gt;environ_map&lt;/span&gt;.&lt;span class="pl-v"&gt;count&lt;/span&gt;()});
    &lt;span class="pl-c"&gt;/// access to CLI arguments&lt;/span&gt;
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-v"&gt;args&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;try&lt;/span&gt; &lt;span class="pl-v"&gt;init&lt;/span&gt;.&lt;span class="pl-v"&gt;minimal&lt;/span&gt;.&lt;span class="pl-v"&gt;args&lt;/span&gt;.&lt;span class="pl-v"&gt;toSlice&lt;/span&gt;(
        &lt;span class="pl-v"&gt;init&lt;/span&gt;.&lt;span class="pl-v"&gt;arena&lt;/span&gt;.&lt;span class="pl-v"&gt;allocator&lt;/span&gt;()
    );
}&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/4vvozb/zig_0_16_0_release_notes"&gt;Lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/zig"&gt;zig&lt;/a&gt;&lt;/p&gt;



</summary><category term="zig"/></entry><entry><title>datasette PR #2689: Replace token-based CSRF with Sec-Fetch-Site header protection</title><link href="https://simonwillison.net/2026/Apr/14/replace-token-based-csrf/#atom-everything" rel="alternate"/><published>2026-04-14T23:58:53+00:00</published><updated>2026-04-14T23:58:53+00:00</updated><id>https://simonwillison.net/2026/Apr/14/replace-token-based-csrf/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette/pull/2689"&gt;datasette PR #2689: Replace token-based CSRF with Sec-Fetch-Site header protection&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Datasette has long protected against CSRF attacks using CSRF tokens, implemented using my &lt;a href="https://github.com/simonw/asgi-csrf"&gt;asgi-csrf&lt;/a&gt; Python library. These are something of a pain to work with - you need to scatter forms in templates with &lt;code&gt;&amp;lt;input type="hidden" name="csrftoken" value="{{ csrftoken() }}"&amp;gt;&lt;/code&gt; lines and then selectively disable CSRF protection for APIs that are intended to be called from outside the browser.&lt;/p&gt;
&lt;p&gt;I've been following Filippo Valsorda's research here with interest, described in &lt;a href="https://words.filippo.io/csrf/"&gt;this detailed essay from August 2025&lt;/a&gt; and shipped &lt;a href="https://tip.golang.org/doc/go1.25#nethttppkgnethttp"&gt;as part of Go 1.25&lt;/a&gt; that same month.&lt;/p&gt;
&lt;p&gt;I've now landed the same change in Datasette. Here's the PR description - Claude Code did much of the work (across 10 commits, closely guided by me and cross-reviewed by GPT-5.4) but I've decided to start writing these PR descriptions by hand, partly to make them more concise and also as an exercise in keeping myself honest.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;New CSRF protection middleware inspired by Go 1.25 and &lt;a href="https://words.filippo.io/csrf/"&gt;this research&lt;/a&gt; by Filippo Valsorda. This replaces the old CSRF token based protection.&lt;/li&gt;
&lt;li&gt;Removes all instances of &lt;code&gt;&amp;lt;input type="hidden" name="csrftoken" value="{{ csrftoken() }}"&amp;gt;&lt;/code&gt; in the templates - they are no longer needed.&lt;/li&gt;
&lt;li&gt;Removes the &lt;code&gt;def skip_csrf(datasette, scope):&lt;/code&gt; plugin hook defined in &lt;code&gt;datasette/hookspecs.py&lt;/code&gt; and its documentation and tests.&lt;/li&gt;
&lt;li&gt;Updated &lt;a href="https://docs.datasette.io/en/latest/internals.html#csrf-protection"&gt;CSRF protection documentation&lt;/a&gt; to describe the new approach.&lt;/li&gt;
&lt;li&gt;Upgrade guide now &lt;a href="https://docs.datasette.io/en/latest/upgrade_guide.html#csrf-protection-is-now-header-based"&gt;describes the CSRF change&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/csrf"&gt;csrf&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;&lt;/p&gt;



</summary><category term="csrf"/><category term="security"/><category term="datasette"/><category term="ai-assisted-programming"/></entry><entry><title>Trusted access for the next era of cyber defense</title><link href="https://simonwillison.net/2026/Apr/14/trusted-access-openai/#atom-everything" rel="alternate"/><published>2026-04-14T21:23:59+00:00</published><updated>2026-04-14T21:23:59+00:00</updated><id>https://simonwillison.net/2026/Apr/14/trusted-access-openai/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://openai.com/index/scaling-trusted-access-for-cyber-defense/"&gt;Trusted access for the next era of cyber defense&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
OpenAI's answer to &lt;a href="https://simonwillison.net/2026/Apr/7/project-glasswing/"&gt;Claude Mythos&lt;/a&gt; appears to be a new model called GPT-5.4-Cyber:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In preparation for increasingly more capable models from OpenAI over the next few months, we are fine-tuning our models specifically to enable defensive cybersecurity use cases, starting today with a variant of GPT‑5.4 trained to be cyber-permissive: GPT‑5.4‑Cyber.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They're also extending a program they launched in February (which I had missed) called &lt;a href="https://openai.com/index/trusted-access-for-cyber/"&gt;Trusted Access for Cyber&lt;/a&gt;, where users can verify their identity (via a photo of a government-issued ID processed by &lt;a href="https://withpersona.com/"&gt;Persona&lt;/a&gt;) to gain "reduced friction" access to OpenAI's models for cybersecurity work.&lt;/p&gt;
&lt;p&gt;Honestly, this OpenAI announcement is difficult to follow. Unsurprisingly they don't mention Anthropic at all, but much of the piece emphasizes their many years of existing cybersecurity work and their goal to "democratize access" to these tools, hence the emphasis on that self-service verification flow from February.&lt;/p&gt;
&lt;p&gt;If you want access to their best security tools you still need to go through an extra Google Form application process though, which doesn't feel particularly different to me from Anthropic's &lt;a href="https://www.anthropic.com/glasswing"&gt;Project Glasswing&lt;/a&gt;.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=47770770"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-security-research"&gt;ai-security-research&lt;/a&gt;&lt;/p&gt;



</summary><category term="security"/><category term="ai"/><category term="openai"/><category term="generative-ai"/><category term="llms"/><category term="anthropic"/><category term="ai-security-research"/></entry><entry><title>Cybersecurity Looks Like Proof of Work Now</title><link href="https://simonwillison.net/2026/Apr/14/cybersecurity-proof-of-work/#atom-everything" rel="alternate"/><published>2026-04-14T19:41:48+00:00</published><updated>2026-04-14T19:41:48+00:00</updated><id>https://simonwillison.net/2026/Apr/14/cybersecurity-proof-of-work/#atom-everything</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.dbreunig.com/2026/04/14/cybersecurity-is-proof-of-work-now.html"&gt;Cybersecurity Looks Like Proof of Work Now&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The UK's AI Safety Institute recently published &lt;a href="https://www.aisi.gov.uk/blog/our-evaluation-of-claude-mythos-previews-cyber-capabilities"&gt;Our evaluation of Claude Mythos Preview’s cyber capabilities&lt;/a&gt;, their own independent analysis of &lt;a href="https://simonwillison.net/2026/Apr/7/project-glasswing/"&gt;Claude Mythos&lt;/a&gt; which backs up Anthropic's claims that it is exceptionally effective at identifying security vulnerabilities.&lt;/p&gt;
&lt;p&gt;Drew Breunig notes that AISI's report shows that the more tokens (and hence money) they spent the better the result they got, which leads to a strong economic incentive to spend as much as possible on security reviews:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If Mythos continues to find exploits so long as you keep throwing money at it, security is reduced to a brutally simple equation: &lt;strong&gt;to harden a system you need to spend more tokens discovering exploits than attackers will spend exploiting them&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An interesting result of this is that open source libraries become &lt;em&gt;more&lt;/em&gt; valuable, since the tokens spent securing them can be shared across all of their users. This directly counters the idea that the low cost of vibe-coding up a replacement for an open source library makes those open source projects less attractive.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/open-source"&gt;open-source&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/drew-breunig"&gt;drew-breunig&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-security-research"&gt;ai-security-research&lt;/a&gt;&lt;/p&gt;



</summary><category term="open-source"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="drew-breunig"/><category term="vibe-coding"/><category term="ai-security-research"/></entry><entry><title>Steve Yegge</title><link href="https://simonwillison.net/2026/Apr/13/steve-yegge/#atom-everything" rel="alternate"/><published>2026-04-13T20:59:00+00:00</published><updated>2026-04-13T20:59:00+00:00</updated><id>https://simonwillison.net/2026/Apr/13/steve-yegge/#atom-everything</id><summary type="html">
    &lt;p&gt;&lt;a href="https://twitter.com/steve_yegge/status/2043747998740689171"&gt;Steve Yegge&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was chatting with my buddy at Google, who's been a tech director there for about 20 years, about their AI adoption. Craziest convo I've had all year.&lt;/p&gt;
&lt;p&gt;The TL;DR is that Google engineering appears to have the same AI adoption footprint as John Deere, the tractor company. Most of the industry has the same internal adoption curve: 20% agentic power users, 20% outright refusers, 60% still using Cursor or equivalent chat tool. It turns out Google has this curve too. [...]&lt;/p&gt;
&lt;p&gt;There has been an industry-wide hiring freeze for 18+ months, during which time nobody has been moving jobs. So there are no clued-in people coming in from the outside to tell Google how far behind they are, how utterly mediocre they have become as an eng org.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/addyosmani/status/2043812343508021460"&gt;Addy Osmani&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On behalf of @Google, this post doesn't match the state of agentic coding at our company. Over 40K SWEs use agentic coding weekly here. Googlers have access to our own versions of @antigravity, @geminicli, custom models, skills, CLIs and MCPs for our daily work. Orchestrators, agent loops, virtual SWE teams and many other systems are actively available to folks. [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/demishassabis/status/2043867486320222333"&gt;Demis Hassabis&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Maybe tell your buddy to do some actual work and to stop spreading absolute nonsense. This post is completely false and just pure clickbait.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update 20th April 2026&lt;/strong&gt;: Steve &lt;a href="https://twitter.com/Steve_Yegge/status/2046260541912707471"&gt;doubled down&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;My tweet last week about Google's AI adoption drew a lot of pushback, to say the least.&lt;/p&gt;
&lt;p&gt;Since then, Googlers from multiple orgs have reached out to me independently and anonymously. They've expressed fear of being doxxed, concern about what they saw as bullying of me, and general corroboration of my original tweet. [...]&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/addy-osmani"&gt;addy-osmani&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/steve-yegge"&gt;steve-yegge&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/agentic-engineering"&gt;agentic-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;&lt;/p&gt;



</summary><category term="addy-osmani"/><category term="steve-yegge"/><category term="google"/><category term="generative-ai"/><category term="agentic-engineering"/><category term="ai"/><category term="llms"/></entry></feed>