<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: armin-ronacher</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/armin-ronacher.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-12-30T23:54:58+00:00</updated><author><name>Simon Willison</name></author><entry><title>Quoting Armin Ronacher</title><link href="https://simonwillison.net/2025/Dec/30/armin-ronacher/#atom-tag" rel="alternate"/><published>2025-12-30T23:54:58+00:00</published><updated>2025-12-30T23:54:58+00:00</updated><id>https://simonwillison.net/2025/Dec/30/armin-ronacher/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://lobste.rs/c/xccjtq"&gt;&lt;p&gt;[...] The puzzle is still there. What’s gone is the labor. I never enjoyed hitting keys, writing minimal repro cases with little insight, digging through debug logs, or trying to decipher some obscure AWS IAM permission error. That work wasn’t the puzzle for me. It was just friction, laborious and frustrating. The thinking remains; the hitting of the keys and the frustrating is what’s been removed.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://lobste.rs/c/xccjtq"&gt;Armin Ronacher&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &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/armin-ronacher"&gt;armin-ronacher&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="ai-assisted-programming"/><category term="generative-ai"/><category term="armin-ronacher"/><category term="ai"/><category term="llms"/></entry><entry><title>Agent design is still hard</title><link href="https://simonwillison.net/2025/Nov/23/agent-design-is-still-hard/#atom-tag" rel="alternate"/><published>2025-11-23T00:49:39+00:00</published><updated>2025-11-23T00:49:39+00:00</updated><id>https://simonwillison.net/2025/Nov/23/agent-design-is-still-hard/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://lucumr.pocoo.org/2025/11/21/agents-are-hard/"&gt;Agent design is still hard&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin Ronacher presents a cornucopia of lessons learned from building agents over the past few months.&lt;/p&gt;
&lt;p&gt;There are several agent abstraction libraries available now (my own &lt;a href="https://llm.datasette.io/"&gt;LLM library&lt;/a&gt; is edging into that territory with its &lt;a href="https://simonwillison.net/2025/May/27/llm-tools/"&gt;tools feature&lt;/a&gt;) but Armin has found that the abstractions are not worth adopting yet:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] the differences between models are significant enough that you will need to build your own agent abstraction. We have not found any of the solutions from these SDKs that build the right abstraction for an agent. I think this is partly because, despite the basic agent design being just a loop, there are subtle differences based on the tools you provide. These differences affect how easy or hard it is to find the right abstraction (cache control, different requirements for reinforcement, tool prompts, provider-side tools, etc.). Because the right abstraction is not yet clear, using the original SDKs from the dedicated platforms keeps you fully in control. […]&lt;/p&gt;
&lt;p&gt;This might change, but right now we would probably not use an abstraction when building an agent, at least until things have settled down a bit. The benefits do not yet outweigh the costs for us.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Armin introduces the new-to-me term &lt;strong&gt;reinforcement&lt;/strong&gt;, where you remind the agent of things as it goes along:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every time the agent runs a tool you have the opportunity to not just return data that the tool produces, but also to feed more information back into the loop. For instance, you can remind the agent about the overall objective and the status of individual tasks. […] Another use of reinforcement is to inform the system about state changes that happened in the background.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Claude Code’s TODO list is another example of this pattern in action.&lt;/p&gt;
&lt;p&gt;Testing and evals remains the single hardest problem in AI engineering:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We find testing and evals to be the hardest problem here. This is not entirely surprising, but the agentic nature makes it even harder. Unlike prompts, you cannot just do the evals in some external system because there’s too much you need to feed into it. This means you want to do evals based on observability data or instrumenting your actual test runs. So far none of the solutions we have tried have convinced us that they found the right approach here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Armin also has a follow-up post, &lt;a href="https://lucumr.pocoo.org/2025/11/22/llm-apis/"&gt;LLM APIs are a Synchronization Problem&lt;/a&gt;, which argues that the shape of current APIs hides too many details from us as developers, and the core challenge here is in synchronizing state between the tokens fed through the GPUs and our client applications - something that may benefit from alternative approaches developed by the local-first movement.

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


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/definitions"&gt;definitions&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/evals"&gt;evals&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-agents"&gt;ai-agents&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="definitions"/><category term="ai"/><category term="prompt-engineering"/><category term="generative-ai"/><category term="llms"/><category term="evals"/><category term="ai-agents"/></entry><entry><title>Claude Code for web - a new asynchronous coding agent from Anthropic</title><link href="https://simonwillison.net/2025/Oct/20/claude-code-for-web/#atom-tag" rel="alternate"/><published>2025-10-20T19:43:15+00:00</published><updated>2025-10-20T19:43:15+00:00</updated><id>https://simonwillison.net/2025/Oct/20/claude-code-for-web/#atom-tag</id><summary type="html">
    &lt;p&gt;Anthropic launched Claude Code for web this morning. It's an &lt;a href="https://simonwillison.net/tags/async-coding-agents/"&gt;asynchronous coding agent&lt;/a&gt; - their answer to OpenAI's &lt;a href="https://simonwillison.net/2025/May/16/openai-codex/"&gt;Codex Cloud&lt;/a&gt; and &lt;a href="https://simonwillison.net/2025/May/19/jules/"&gt;Google's Jules&lt;/a&gt;, and has a very similar shape. I had preview access over the weekend and I've already seen some very promising results from it.&lt;/p&gt;
&lt;p&gt;It's available online at &lt;a href="https://claude.ai"&gt;claude.ai/code&lt;/a&gt; and shows up as a tab in the Claude iPhone app as well:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/claude-code-for-web.jpg" alt="Screenshot of Claude AI interface showing a conversation about updating a README file. The left sidebar shows &amp;quot;Claude&amp;quot; at the top, followed by navigation items: &amp;quot;Chats&amp;quot;, &amp;quot;Projects&amp;quot;, &amp;quot;Artifacts&amp;quot;, and &amp;quot;Code&amp;quot; (highlighted). Below that is &amp;quot;Starred&amp;quot; section listing several items with trash icons: &amp;quot;LLM&amp;quot;, &amp;quot;Python app&amp;quot;, &amp;quot;Check my post&amp;quot;, &amp;quot;Artifacts&amp;quot;, &amp;quot;Summarize&amp;quot;, and &amp;quot;Alt text writer&amp;quot;. The center panel shows a conversation list with items like &amp;quot;In progress&amp;quot;, &amp;quot;Run System C&amp;quot;, &amp;quot;Idle&amp;quot;, &amp;quot;Update Rese&amp;quot;, &amp;quot;Run Matplotl&amp;quot;, &amp;quot;Run Marketin&amp;quot;, &amp;quot;WebAssembl&amp;quot;, &amp;quot;Benchmark M&amp;quot;, &amp;quot;Build URL Qu&amp;quot;, and &amp;quot;Add Read-Or&amp;quot;. The right panel displays the active conversation titled &amp;quot;Update Research Project README&amp;quot; showing a task to update a GitHub README file at https://github.com/simonw/research/blob/main/deepseek-ocr-nvidia-spark/README.md, followed by Claude's response and command outputs showing file listings with timestamps from Oct 20 17:53." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;As far as I can tell it's their latest &lt;a href="https://www.claude.com/product/claude-code"&gt;Claude Code CLI&lt;/a&gt; app wrapped in a container (Anthropic are getting &lt;em&gt;really&lt;/em&gt; &lt;a href="https://simonwillison.net/2025/Sep/9/claude-code-interpreter/"&gt;good at containers&lt;/a&gt; these days) and configured to &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;. It appears to behave exactly the same as the CLI tool, and includes a neat "teleport" feature which can copy both the chat transcript and the edited files down to your local Claude Code CLI tool if you want to take over locally.&lt;/p&gt;
&lt;p&gt;It's very straight-forward to use. You point Claude Code for web at a GitHub repository, select an environment (fully locked down, restricted to an allow-list of domains or configured to access domains of your choosing, including "*" for everything) and kick it off with a prompt.&lt;/p&gt;
&lt;p&gt;While it's running you can send it additional prompts which are queued up and executed after it completes its current step.&lt;/p&gt;
&lt;p&gt;Once it's done it opens a branch on your repo with its work and can optionally open a pull request.&lt;/p&gt;
&lt;h4 id="putting-claude-code-for-web-to-work"&gt;Putting Claude Code for web to work&lt;/h4&gt;
&lt;p&gt;Claude Code for web's PRs are indistinguishable from Claude Code CLI's, so Anthropic told me it was OK to submit those against public repos even during the private preview. Here are some examples from this weekend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/simonw/tools/pull/73"&gt;Add query-string-stripper.html tool&lt;/a&gt; against my simonw/tools repo - a &lt;em&gt;very&lt;/em&gt; simple task that creates (and deployed via GitHub Pages) this &lt;a href="https://tools.simonwillison.net/query-string-stripper"&gt;query-string-stripper&lt;/a&gt; tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/simonw/research/tree/main/minijinja-vs-jinja2"&gt;minijinja vs jinja2 Performance Benchmark&lt;/a&gt; - I ran this against a private repo and then copied the results here, so no PR. Here's &lt;a href="https://github.com/simonw/research/blob/main/minijinja-vs-jinja2/README.md#the-prompt"&gt;the prompt&lt;/a&gt; I used.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/simonw/research/pull/1"&gt;Update deepseek-ocr README to reflect successful project completion&lt;/a&gt; - I noticed that the README produced by Claude Code CLI for &lt;a href="https://simonwillison.net/2025/Oct/20/deepseek-ocr-claude-code/"&gt;this project&lt;/a&gt; was misleadingly out of date, so I had Claude Code for web fix the problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That second example is the most interesting. I saw &lt;a href="https://x.com/mitsuhiko/status/1980034078297514319"&gt;a tweet from Armin&lt;/a&gt; about his &lt;a href="https://github.com/mitsuhiko/minijinja"&gt;MiniJinja&lt;/a&gt; Rust template language &lt;a href="https://github.com/mitsuhiko/minijinja/pull/841"&gt;adding support&lt;/a&gt; for Python 3.14 free threading. I hadn't realized that project &lt;em&gt;had&lt;/em&gt; Python bindings, so I decided it would be interesting to see a quick performance comparison between MiniJinja and Jinja2.&lt;/p&gt;
&lt;p&gt;I ran Claude Code for web against a private repository with a completely open environment (&lt;code&gt;*&lt;/code&gt; in the allow-list) and prompted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m interested in benchmarking the Python bindings for &lt;a href="https://github.com/mitsuhiko/minijinja"&gt;https://github.com/mitsuhiko/minijinja&lt;/a&gt; against the equivalente template using Python jinja2&lt;/p&gt;
&lt;p&gt;Design and implement a benchmark for this. It should use the latest main checkout of minijinja and the latest stable release of jinja2. The benchmark should use the uv version of Python 3.14 and should test both the regular 3.14 and the 3.14t free threaded version - so four scenarios total&lt;/p&gt;
&lt;p&gt;The benchmark should run against a reasonably complicated example of a template, using template inheritance and loops and such like In the PR include a shell script to run the entire benchmark, plus benchmark implantation, plus markdown file describing the benchmark and the results in detail, plus some illustrative charts created using matplotlib&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I entered this into the Claude iPhone app on my mobile keyboard, hence the typos.&lt;/p&gt;
&lt;p&gt;It churned away for a few minutes and gave me exactly what I asked for. Here's one of the &lt;a href="https://github.com/simonw/research/tree/main/minijinja-vs-jinja2/charts"&gt;four charts&lt;/a&gt; it created:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2025/minijinja-timeline.jpg" alt="Line chart titled &amp;quot;Rendering Time Across Iterations&amp;quot; showing rendering time in milliseconds (y-axis, ranging from approximately 1.0 to 2.5 ms) versus iteration number (x-axis, ranging from 0 to 200+). Four different lines represent different versions: minijinja (3.14t) shown as a solid blue line, jinja2 (3.14) as a solid orange line, minijinja (3.14) as a solid green line, and jinja2 (3.14t) as a dashed red line. The green line (minijinja 3.14) shows consistently higher rendering times with several prominent spikes reaching 2.5ms around iterations 25, 75, and 150. The other three lines show more stable, lower rendering times between 1.0-1.5ms with occasional fluctuations." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;(I was surprised to see MiniJinja out-performed by Jinja2, but I guess Jinja2 has had a decade of clever performance optimizations and doesn't need to deal with any extra overhead of calling out to Rust.)&lt;/p&gt;
&lt;p&gt;Note that I would likely have got the &lt;em&gt;exact same&lt;/em&gt; result running this prompt against Claude CLI on my laptop. The benefit of Claude Code for web is entirely in its convenience as a way of running these tasks in a hosted container managed by Anthropic, with a pleasant web and mobile UI layered over the top.&lt;/p&gt;
&lt;h4 id="anthropic-are-framing-this-as-part-of-their-sandboxing-strategy"&gt;Anthropic are framing this as part of their sandboxing strategy&lt;/h4&gt;
&lt;p&gt;It's interesting how Anthropic chose to announce this new feature: the product launch is buried half way down their new engineering blog post &lt;a href="https://www.anthropic.com/engineering/claude-code-sandboxing"&gt;Beyond permission prompts: making Claude Code more secure and autonomous&lt;/a&gt;, which starts like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Claude Code's new sandboxing features, a bash tool and Claude Code on the web, reduce permission prompts and increase user safety by enabling two boundaries: filesystem and network isolation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm &lt;em&gt;very&lt;/em&gt; excited to hear that Claude Code CLI is taking sandboxing more seriously. I've not yet dug into the details of that - it looks like it's using seatbelt on macOS and &lt;a href="https://github.com/containers/bubblewrap"&gt;Bubblewrap&lt;/a&gt; on Linux.&lt;/p&gt;

&lt;p&gt;Anthropic released a new open source (Apache 2) library, &lt;a href="https://github.com/anthropic-experimental/sandbox-runtime"&gt;anthropic-experimental/sandbox-runtime&lt;/a&gt;, with their implementation of this so far.&lt;/p&gt;

&lt;p&gt;Filesystem sandboxing is relatively easy. The harder problem is network isolation, which they describe like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Network isolation&lt;/strong&gt;, by only allowing internet access through a unix domain socket connected to a proxy server running outside the sandbox. This proxy server enforces restrictions on the domains that a process can connect to, and handles user confirmation for newly requested domains. And if you’d like further-increased security, we also support customizing this proxy to enforce arbitrary rules on outgoing traffic.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is &lt;em&gt;crucial&lt;/em&gt; to protecting against both prompt injection and &lt;a href="https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/"&gt;lethal trifecta&lt;/a&gt; attacks. The best way to prevent lethal trifecta attacks is to cut off one of the three legs, and network isolation is how you remove the data exfiltration leg that allows successful attackers to steal your data.&lt;/p&gt;
&lt;p&gt;If you run Claude Code for web in "No network access" mode you have nothing to worry about.&lt;/p&gt;
&lt;p&gt;I'm a little bit nervous about their "Trusted network access" environment. It's intended to only allow access to domains relating to dependency installation, but the &lt;a href="https://docs.claude.com/en/docs/claude-code/claude-code-on-the-web#default-allowed-domains"&gt;default domain list&lt;/a&gt; has dozens of entries which makes me nervous about unintended exfiltration vectors sneaking through.&lt;/p&gt;
&lt;p&gt;You can also configure a custom environment with your own allow-list. I have one called "Everything" which allow-lists "*", because for projects like my MiniJinja/Jinja2 comparison above there are no secrets or source code involved that need protecting.&lt;/p&gt;
&lt;p&gt;I see Anthropic's focus on sandboxes as an acknowledgment that coding agents run in YOLO mode (&lt;code&gt;--dangerously-skip-permissions&lt;/code&gt; and the like) are &lt;em&gt;enormously&lt;/em&gt; more valuable and productive than agents where you have to approve their every step.&lt;/p&gt;
&lt;p&gt;The challenge is making it convenient and easy to run them safely. This kind of sandboxing kind is the only approach to safety that feels credible to me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: A note on cost: I'm currently using a Claude "Max" plan that Anthropic gave me in order to test some of their features, so I don't have a good feeling for how Claude Code would cost for these kinds of projects.&lt;/p&gt;

&lt;p&gt;From running &lt;code&gt;npx ccusage@latest&lt;/code&gt; (an &lt;a href="https://github.com/ryoppippi/ccusage"&gt;unofficial cost estimate tool&lt;/a&gt;) it looks like I'm using between $1 and $5 worth of daily Claude CLI invocations at the moment.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jinja"&gt;jinja&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sandboxing"&gt;sandboxing&lt;/a&gt;, &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/prompt-injection"&gt;prompt-injection&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/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/lethal-trifecta"&gt;lethal-trifecta&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/async-coding-agents"&gt;async-coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/disclosures"&gt;disclosures&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="armin-ronacher"/><category term="jinja"/><category term="sandboxing"/><category term="security"/><category term="ai"/><category term="prompt-injection"/><category term="generative-ai"/><category term="llms"/><category term="anthropic"/><category term="claude"/><category term="coding-agents"/><category term="claude-code"/><category term="lethal-trifecta"/><category term="async-coding-agents"/><category term="disclosures"/></entry><entry><title>Armin Ronacher: 90%</title><link href="https://simonwillison.net/2025/Sep/29/armin-ronacher-90/#atom-tag" rel="alternate"/><published>2025-09-29T16:03:54+00:00</published><updated>2025-09-29T16:03:54+00:00</updated><id>https://simonwillison.net/2025/Sep/29/armin-ronacher-90/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://lucumr.pocoo.org/2025/9/29/90-percent/"&gt;Armin Ronacher: 90%&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The idea of AI writing "90% of the code" to-date has mostly been expressed by people who sell AI tooling.&lt;/p&gt;
&lt;p&gt;Over the last few months, I've increasingly seen the same idea come coming much more credible sources.&lt;/p&gt;
&lt;p&gt;Armin is the creator of a bewildering array of valuable open source projects 
- Flask, Jinja, Click, Werkzeug, and &lt;a href="https://github.com/mitsuhiko?tab=repositories&amp;amp;type=source"&gt;many more&lt;/a&gt;. When he says something like this it's worth paying attention:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the infrastructure component I started at my new company, I’m probably north of 90% AI-written code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For anyone who sees this as a threat to their livelihood as programmers, I encourage you to think more about this section:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is easy to create systems that appear to behave correctly but have unclear runtime behavior when relying on agents. For instance, the AI doesn’t fully comprehend threading or goroutines. If you don’t keep the bad decisions at bay early it, you won’t be able to operate it in a stable manner later.&lt;/p&gt;
&lt;p&gt;Here’s an example: I asked it to build a rate limiter. It “worked” but lacked jitter and used poor storage decisions. Easy to fix if you know rate limiters, dangerous if you don’t.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In order to use these tools at this level you need to know the difference between goroutines and threads. You need to understand why a rate limiter might want to"jitter" and what that actually means. You need to understand what "rate limiting" is and why you might need it!&lt;/p&gt;
&lt;p&gt;These tools do not replace programmers. They allow us to apply our expertise at a higher level and amplify the value we can provide to other people.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/ayncvk/ai_is_writing_90_code"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&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/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/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="careers"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/></entry><entry><title>From Async/Await to Virtual Threads</title><link href="https://simonwillison.net/2025/Aug/3/virtual-threads/#atom-tag" rel="alternate"/><published>2025-08-03T18:57:56+00:00</published><updated>2025-08-03T18:57:56+00:00</updated><id>https://simonwillison.net/2025/Aug/3/virtual-threads/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://lucumr.pocoo.org/2025/7/26/virtual-threads/"&gt;From Async/Await to Virtual Threads&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin Ronacher has long been critical of async/await in Python, both for necessitating &lt;a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/"&gt;colored functions&lt;/a&gt; and because of the more subtle challenges they introduce like &lt;a href="https://lucumr.pocoo.org/2020/1/1/async-pressure/"&gt;managing back pressure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Armin &lt;a href="https://lucumr.pocoo.org/2024/11/18/threads-beat-async-await/"&gt;argued convincingly&lt;/a&gt; for the threaded programming model back in December. Now he's expanded upon that with a description of how virtual threads might make sense in Python.&lt;/p&gt;
&lt;p&gt;Virtual threads behave like real system threads but can vastly outnumber them, since they can be paused and scheduled to run on a real thread when needed. Go uses this trick to implement goroutines which can then support millions of virtual threads on a single system.&lt;/p&gt;
&lt;p&gt;Python core developer Mark Shannon &lt;a href="https://discuss.python.org/t/add-virtual-threads-to-python/91403"&gt;started a conversation&lt;/a&gt; about the potential for seeing virtual threads to Python back in May.&lt;/p&gt;
&lt;p&gt;Assuming this proposal turns into something concrete I don't expect we will see it in a production Python release for a few more years. In the meantime there are some exciting improvements to the Python concurrency story - most notably &lt;a href="https://docs.python.org/3.14/whatsnew/3.14.html#whatsnew314-pep734"&gt;around sub-interpreters&lt;/a&gt; - coming up this year in Python 3.14.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/concurrency"&gt;concurrency&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gil"&gt;gil&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/threads"&gt;threads&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="concurrency"/><category term="gil"/><category term="go"/><category term="python"/><category term="threads"/></entry><entry><title>Quoting Armin Ronacher</title><link href="https://simonwillison.net/2025/Jul/20/armin-ronacher/#atom-tag" rel="alternate"/><published>2025-07-20T10:54:45+00:00</published><updated>2025-07-20T10:54:45+00:00</updated><id>https://simonwillison.net/2025/Jul/20/armin-ronacher/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://lucumr.pocoo.org/2025/7/20/the-next-generation/"&gt;&lt;p&gt;Every day someone becomes a programmer because they figured out how to make ChatGPT build something. Lucky for us: in many of those cases the AI picks Python. We should treat this as an opportunity and anticipate an expansion in the kinds of people who might want to attend a Python conference. Yet many of these new programmers are not even aware that programming communities and conferences exist. It’s in the Python community’s interest to find ways to pull them in.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://lucumr.pocoo.org/2025/7/20/the-next-generation/"&gt;Armin Ronacher&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/pycon"&gt;pycon&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;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&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/python"&gt;python&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/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;&lt;/p&gt;



</summary><category term="pycon"/><category term="ai"/><category term="llms"/><category term="vibe-coding"/><category term="ai-assisted-programming"/><category term="python"/><category term="generative-ai"/><category term="armin-ronacher"/></entry><entry><title>TIL: Using Playwright MCP with Claude Code</title><link href="https://simonwillison.net/2025/Jul/1/using-playwright-mcp-with-claude-code/#atom-tag" rel="alternate"/><published>2025-07-01T23:55:09+00:00</published><updated>2025-07-01T23:55:09+00:00</updated><id>https://simonwillison.net/2025/Jul/1/using-playwright-mcp-with-claude-code/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://til.simonwillison.net/claude-code/playwright-mcp-claude-code"&gt;TIL: Using Playwright MCP with Claude Code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Inspired &lt;a href="https://simonwillison.net/2025/Jun/29/agentic-coding/"&gt;by Armin&lt;/a&gt; ("I personally use only one MCP - I only use Playwright") I decided to figure out how to use the official &lt;a href="https://github.com/microsoft/playwright-mcp"&gt;Playwright MCP server&lt;/a&gt; with &lt;a href="https://simonwillison.net/tags/claude-code/"&gt;Claude Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turns out it's easy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;claude mcp add playwright npx '@playwright/mcp@latest'
claude
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;claude mcp add&lt;/code&gt; command only affects the current directory by default - it gets persisted in the &lt;code&gt;~/.claude.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Now Claude can use Playwright to automate a Chrome browser! Tell it to "Use playwright mcp to open a browser to example.com" and watch it go - it can navigate pages, submit forms, execute custom JavaScript and take screenshots to feed back into the LLM.&lt;/p&gt;
&lt;p&gt;The browser window stays visible which means you can interact with it too, including signing into websites so Claude can act on your behalf.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/til"&gt;til&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/playwright"&gt;playwright&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/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/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="til"/><category term="playwright"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="claude-code"/></entry><entry><title>Agentic Coding: The Future of Software Development with Agents</title><link href="https://simonwillison.net/2025/Jun/29/agentic-coding/#atom-tag" rel="alternate"/><published>2025-06-29T23:59:31+00:00</published><updated>2025-06-29T23:59:31+00:00</updated><id>https://simonwillison.net/2025/Jun/29/agentic-coding/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=nfOVgz_omlU"&gt;Agentic Coding: The Future of Software Development with Agents&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin Ronacher delivers a 37 minute YouTube talk describing his adventures so far with Claude Code and agentic coding methods.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A friend called Claude Code catnip for programmers and it really feels like this. I haven't felt so energized and confused and just so willing to try so many new things... it is really incredibly addicting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I picked up a bunch of useful tips from this video:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Armin runs Claude Code with the &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt; option, and says this unlocks a huge amount of productivity. I haven't been brave enough to do this yet but I'm going to start using that option while running in a Docker container to ensure nothing too bad can happen.&lt;/li&gt;
&lt;li&gt;When your agentic coding tool can run commands in a terminal you can mostly avoid MCP - instead of adding a new MCP tool, write a script or add a Makefile command and tell the agent to use that instead. The only MCP Armin uses is &lt;a href="https://github.com/microsoft/playwright-mcp"&gt;the Playwright one&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Combined logs are a really good idea: have everything log to the same place and give the agent an easy tool to read the most recent N log lines.&lt;/li&gt;
&lt;li&gt;While running Claude Code, use Gemini CLI to run sub-agents, to perform additional tasks without using up Claude Code's own context&lt;/li&gt;
&lt;li&gt;Designing additional tools that provide very clear errors, so the agents can recover when something goes wrong.&lt;/li&gt;
&lt;li&gt;Thanks to Playwright, Armin has Claude Code perform all sorts of automated operations via a signed in browser instance as well. "Claude can debug your CI... it can sign into a browser, click around, debug..." - he also has it use the &lt;code&gt;gh&lt;/code&gt; GitHub CLI tool to interact with things like &lt;a href="https://cli.github.com/manual/gh_workflow"&gt;GitHub Actions workflows&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="&amp;quot;Tip 1: Unified Logging&amp;quot; at top, followed by title &amp;quot;Forward Everything Into One Log File&amp;quot; and bullet points: &amp;quot;Combine console.log + server logs + everything else&amp;quot;, &amp;quot;patch console.log in the browser -&amp;gt; forward to server via API call&amp;quot;, &amp;quot;All output streams flow to a single, tailable log file&amp;quot;, &amp;quot;Give it a way to log out SQL too!&amp;quot;, &amp;quot;Provide a make tail-logs command for easy access&amp;quot;. Bottom shows example: &amp;quot;# Example&amp;quot; and &amp;quot;make tail-logs  # Shows last 50 lines, follows new output&amp;quot;." src="https://static.simonwillison.net/static/2025/armin-logging.jpg" /&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&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/ai-assisted-programming"&gt;ai-assisted-programming&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-agents"&gt;ai-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/model-context-protocol"&gt;model-context-protocol&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/sub-agents"&gt;sub-agents&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="ai-agents"/><category term="model-context-protocol"/><category term="claude-code"/><category term="sub-agents"/></entry><entry><title>My First Open Source AI Generated Library</title><link href="https://simonwillison.net/2025/Jun/21/my-first-open-source-ai-generated-library/#atom-tag" rel="alternate"/><published>2025-06-21T23:22:45+00:00</published><updated>2025-06-21T23:22:45+00:00</updated><id>https://simonwillison.net/2025/Jun/21/my-first-open-source-ai-generated-library/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://lucumr.pocoo.org/2025/6/21/my-first-ai-library/"&gt;My First Open Source AI Generated Library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin Ronacher had Claude and Claude Code do almost &lt;em&gt;all of the work&lt;/em&gt; in building, testing, packaging and publishing a new Python library based on his design:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;It wrote ~1100 lines of code for the parser&lt;/li&gt;
&lt;li&gt;It wrote ~1000 lines of tests&lt;/li&gt;
&lt;li&gt;It configured the entire Python package, CI, PyPI publishing&lt;/li&gt;
&lt;li&gt;Generated a README, drafted a changelog, designed a logo, made it theme-aware&lt;/li&gt;
&lt;li&gt;Did multiple refactorings to make me happier&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The project? &lt;a href="https://github.com/mitsuhiko/sloppy-xml-py"&gt;sloppy-xml-py&lt;/a&gt;, a lax XML parser (and violation of everything the XML Working Group hold sacred) which ironically is necessary because LLMs themselves frequently output "XML" that includes validation errors.&lt;/p&gt;
&lt;p&gt;Claude's SVG logo design is actually pretty decent, turns out it can draw &lt;a href="https://simonwillison.net/2025/May/22/code-with-claude-live-blog/#live-update-357"&gt;more than just bad pelicans&lt;/a&gt;!&lt;/p&gt;
&lt;center&gt;&lt;img alt="Hand drawn style, orange rough rectangly containing &amp;lt; { s } &amp;gt; - then the text Sloppy XML below in black" src="https://static.simonwillison.net/static/2025/sloppy-xml.jpg"&gt;&lt;/center&gt;

&lt;p&gt;I think experiments like this are a really valuable way to explore the capabilities of these models. Armin's conclusion:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This was an experiment to see how far I could get with minimal manual effort, and to unstick myself from an annoying blocker. The result is good enough for my immediate use case and I also felt good enough to publish it to PyPI in case someone else has the same problem.&lt;/p&gt;
&lt;p&gt;Treat it as a curious side project which says more about what's possible today than what's necessarily advisable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'd like to present a slightly different conclusion here. The most interesting thing about this project is that &lt;strong&gt;the code is good&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;My criteria for good code these days is the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Solves a defined problem, well enough that I'm not tempted to solve it in a different way&lt;/li&gt;
&lt;li&gt;Uses minimal dependencies&lt;/li&gt;
&lt;li&gt;Clear and easy to understand&lt;/li&gt;
&lt;li&gt;Well tested, with tests prove that the code does what it's meant to do&lt;/li&gt;
&lt;li&gt;Comprehensive documentation&lt;/li&gt;
&lt;li&gt;Packaged and published in a way that makes it convenient for me to use&lt;/li&gt;
&lt;li&gt;Designed to be easy to maintain and make changes in the future&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;sloppy-xml-py&lt;/code&gt; fits all of those criteria. It's useful, well defined, &lt;a href="https://github.com/mitsuhiko/sloppy-xml-py/blob/main/sloppy_xml.py"&gt;the code is readable&lt;/a&gt; with just about the right level of comments, everything is tested, the documentation explains everything I need to know, and it's been shipped to PyPI.&lt;/p&gt;
&lt;p&gt;I'd be proud to have written this myself.&lt;/p&gt;
&lt;p&gt;This example is &lt;em&gt;not&lt;/em&gt; an argument for replacing programmers with LLMs. The code is good because Armin is an expert programmer who stayed in full control throughout the process. As I wrote the other day, &lt;a href="https://simonwillison.net/2025/Jun/18/coding-agents/"&gt;a skilled individual with both deep domain understanding and deep understanding of the capabilities of the agent&lt;/a&gt;.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://bsky.app/profile/mitsuhiko.at/post/3ls4ov5fk7c2l"&gt;@mitsuhiko.at&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&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/pypi"&gt;pypi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/xml"&gt;xml&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/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="open-source"/><category term="pypi"/><category term="python"/><category term="xml"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="claude"/><category term="claude-code"/></entry><entry><title>Agentic Coding Recommendations</title><link href="https://simonwillison.net/2025/Jun/12/agentic-coding-recommendations/#atom-tag" rel="alternate"/><published>2025-06-12T16:20:51+00:00</published><updated>2025-06-12T16:20:51+00:00</updated><id>https://simonwillison.net/2025/Jun/12/agentic-coding-recommendations/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://lucumr.pocoo.org/2025/6/12/agentic-coding/"&gt;Agentic Coding Recommendations&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
There's a ton of actionable advice on using Claude Code in this new piece from Armin Ronacher. He's getting excellent results from Go, especially having invested a bunch of work in making the various tools (linters, tests, logs, development servers etc) as accessible as possible through documenting them in a Makefile.&lt;/p&gt;
&lt;p&gt;I liked this tip on logging:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In general logging is super important. For instance my app currently has a sign in and register flow that sends an email to the user. In debug mode (which the agent runs in), the email is just logged to stdout. This is crucial! It allows the agent to complete a full sign-in with a remote controlled browser without extra assistance. It knows that emails are being logged thanks to a &lt;code&gt;CLAUDE.md&lt;/code&gt; instruction and it automatically consults the log for the necessary link to click.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Armin also recently shared a &lt;a href="https://www.youtube.com/watch?v=sQYXZCUvpIc"&gt;half hour YouTube video&lt;/a&gt; in which he worked with Claude Code to resolve two medium complexity issues in his &lt;code&gt;minijinja&lt;/code&gt; Rust templating library, resulting in &lt;a href="https://github.com/mitsuhiko/minijinja/pull/805"&gt;PR #805&lt;/a&gt; and &lt;a href="https://github.com/mitsuhiko/minijinja/pull/804"&gt;PR #804&lt;/a&gt;.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://bsky.app/profile/mitsuhiko.at/post/3lrfld3r74k2e"&gt;@mitsuhiko.at&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&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/ai-assisted-programming"&gt;ai-assisted-programming&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/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="go"/><category term="ai"/><category term="rust"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="coding-agents"/><category term="claude-code"/></entry><entry><title>Quoting Armin Ronacher</title><link href="https://simonwillison.net/2024/Sep/22/armin-ronacher/#atom-tag" rel="alternate"/><published>2024-09-22T20:09:27+00:00</published><updated>2024-09-22T20:09:27+00:00</updated><id>https://simonwillison.net/2024/Sep/22/armin-ronacher/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://twitter.com/mitsuhiko/status/1837540764538056925"&gt;&lt;p&gt;The problem I have with [pipenv shell] is that the act of manipulating the shell environment is crappy and can never be good. What all these "X shell" things do is just an abomination we should not promote IMO.&lt;/p&gt;
&lt;p&gt;Tools should be written so that you do not need to reconfigure shells. That we normalized this over the last 10 years was a mistake and we are not forced to continue walking down that path :)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://twitter.com/mitsuhiko/status/1837540764538056925"&gt;Armin Ronacher&lt;/a&gt;&lt;/p&gt;

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



</summary><category term="armin-ronacher"/></entry><entry><title>uv under discussion on Mastodon</title><link href="https://simonwillison.net/2024/Sep/8/uv-under-discussion-on-mastodon/#atom-tag" rel="alternate"/><published>2024-09-08T16:23:31+00:00</published><updated>2024-09-08T16:23:31+00:00</updated><id>https://simonwillison.net/2024/Sep/8/uv-under-discussion-on-mastodon/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://social.jacobian.org/@jacob/113091418140504394"&gt;uv under discussion on Mastodon&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Jacob Kaplan-Moss kicked off this fascinating conversation about &lt;a href="https://docs.astral.sh/uv/"&gt;uv&lt;/a&gt; on Mastodon recently. It's worth reading the whole thing, which includes input from a whole range of influential Python community members such as Jeff Triplett, Glyph Lefkowitz, Russell Keith-Magee, Seth Michael Larson, Hynek Schlawack, James Bennett and others. (Mastodon is a pretty great place for keeping up with the Python community these days.)&lt;/p&gt;
&lt;p&gt;The key theme of the conversation is that, while &lt;code&gt;uv&lt;/code&gt; represents a huge set of potential improvements to the Python ecosystem, it comes with additional risks due its attachment to a VC-backed company - and its reliance on Rust rather than Python.&lt;/p&gt;
&lt;p&gt;Here are a few comments that stood out to me.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cloudisland.nz/@freakboy3742/113093889194737339"&gt;Russell&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As enthusiastic as I am about the direction uv is going, I &lt;em&gt;haven't&lt;/em&gt; adopted them anywhere - because I want very much to understand Astral’s intended business model before I hook my wagon to their tools. It's definitely not clear to me how they're going to stay liquid once the VC money runs out. They could get me onboard in a hot second if they published a "This is what we're planning to charge for" blog post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://mastodon.social/@hynek/113094437303343866"&gt;Hynek&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As much as I hate VC, [...] FOSS projects flame out all the time too. If Frost loses interest, there’s no PDM anymore. Same for Ofek and Hatch(ling).&lt;/p&gt;
&lt;p&gt;I fully expect Astral to flame out and us having to fork/take over—it’s the circle of FOSS. To me uv looks like a genius sting to trick VCs into paying to fix packaging. We’ll be better off either way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://mastodon.social/@glyph/113094489295782200"&gt;Glyph&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even in the best case, Rust is more expensive and difficult to maintain, not to mention "non-native" to the average customer here. [...] And the difficulty with VC money here is that it can burn out &lt;em&gt;all&lt;/em&gt; the other projects in the ecosystem simultaneously, creating a risk of monoculture, where previously, I think we can say that "monoculture" was the &lt;em&gt;least&lt;/em&gt; of Python's packaging concerns.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://mastodon.social/@hynek/113094547139925962"&gt;Hynek on Rust&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t think y’all quite grok what uv makes so special due to your seniority. The speed is really cool, but the reason Rust is elemental is that it’s one compiled blob that can be used to bootstrap and maintain a Python development. A blob that will never break because someone upgraded Homebrew, ran pip install or any other creative way people found to fuck up their installations. Python has shown to be a terrible tech to maintain Python.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://social.coop/@chrisjrn/113094511860843571"&gt;Christopher Neugebauer&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just dropping in here to say that corporate capture of the Python ecosystem is the #1 keeps-me-up-at-night subject in my community work, so I watch Astral with interest, even if I'm not yet too worried.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm reminded of &lt;a href="https://lucumr.pocoo.org/2024/8/21/harvest-season/"&gt;this note from Armin Ronacher&lt;/a&gt;, who created Rye and later donated it to uv maintainers Astral:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However having seen the code and what uv is doing, even in the worst possible future this is a very forkable and maintainable thing. I believe that even in case Astral shuts down or were to do something incredibly dodgy licensing wise, the community would be better off than before uv existed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm currently inclined to agree with Armin and Hynek: while the risk of corporate capture for a crucial aspect of the Python packaging and onboarding ecosystem is a legitimate concern, the amount of progress that has been made here in a relatively short time combined with the open license and quality of the underlying code keeps me optimistic that &lt;code&gt;uv&lt;/code&gt; will be a net positive for Python overall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: &lt;code&gt;uv&lt;/code&gt; creator Charlie Marsh &lt;a href="https://hachyderm.io/@charliermarsh/113103564055291456"&gt;joined the conversation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don't want to charge people money to use our tools, and I don't want to create an incentive structure whereby our open source offerings are competing with any commercial offerings (which is what you see with a lost of hosted-open-source-SaaS business models).&lt;/p&gt;
&lt;p&gt;What I want to do is build software that vertically integrates with our open source tools, and sell that software to companies that are already using Ruff, uv, etc. Alternatives to things that companies already pay for today.&lt;/p&gt;
&lt;p&gt;An example of what this might look like (we may not do this, but it's helpful to have a concrete example of the strategy) would be something like an enterprise-focused private package registry. A lot of big companies use uv. We spend time talking to them. They all spend money on private package registries, and have issues with them. We could build a private registry that integrates well with uv, and sell it to those companies. [...]&lt;/p&gt;
&lt;p&gt;But the core of what I want to do is this: build great tools, hopefully people like them, hopefully they grow, hopefully companies adopt them; then sell software to those companies that represents the natural next thing they need when building with Python. Hopefully we can build something better than the alternatives by playing well with our OSS, and hopefully we are the natural choice if they're already using our OSS.&lt;/p&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jacob-kaplan-moss"&gt;jacob-kaplan-moss&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/packaging"&gt;packaging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/russell-keith-magee"&gt;russell-keith-magee&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hynek-schlawack"&gt;hynek-schlawack&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mastodon"&gt;mastodon&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/glyph"&gt;glyph&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uv"&gt;uv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/astral"&gt;astral&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/charlie-marsh"&gt;charlie-marsh&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/seth-michael-larson"&gt;seth-michael-larson&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="jacob-kaplan-moss"/><category term="open-source"/><category term="packaging"/><category term="python"/><category term="russell-keith-magee"/><category term="rust"/><category term="hynek-schlawack"/><category term="mastodon"/><category term="glyph"/><category term="uv"/><category term="astral"/><category term="charlie-marsh"/><category term="seth-michael-larson"/></entry><entry><title>MiniJinja: Learnings from Building a Template Engine in Rust</title><link href="https://simonwillison.net/2024/Aug/27/minijinja/#atom-tag" rel="alternate"/><published>2024-08-27T15:47:19+00:00</published><updated>2024-08-27T15:47:19+00:00</updated><id>https://simonwillison.net/2024/Aug/27/minijinja/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://lucumr.pocoo.org/2024/8/27/minijinja/"&gt;MiniJinja: Learnings from Building a Template Engine in Rust&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin Ronacher's &lt;a href="https://github.com/mitsuhiko/minijinja/"&gt;MiniJinja&lt;/a&gt; is his re-implemenation of the Python &lt;a href="https://jinja.palletsprojects.com/"&gt;Jinja2&lt;/a&gt; (originally built by Armin) templating language in Rust.&lt;/p&gt;
&lt;p&gt;It's nearly three years old now and, in Armin's words, "it's at almost feature parity with Jinja2 and quite enjoyable to use".&lt;/p&gt;
&lt;p&gt;The WebAssembly compiled demo in the &lt;a href="https://mitsuhiko.github.io/minijinja-playground/"&gt;MiniJinja Playground&lt;/a&gt; is fun to try out. It includes the ability to output instructions, so you can see how this:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-django"&gt;&lt;pre&gt;&amp;lt;&lt;span class="pl-ent"&gt;ul&lt;/span&gt;&amp;gt;
  &lt;span class="pl-e"&gt;{%&lt;/span&gt;- &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s"&gt;item&lt;/span&gt; &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-s"&gt;nav&lt;/span&gt; &lt;span class="pl-e"&gt;%}&lt;/span&gt;
    &amp;lt;&lt;span class="pl-ent"&gt;li&lt;/span&gt;&amp;gt;{{ item.title }}&amp;lt;/&lt;span class="pl-ent"&gt;a&lt;/span&gt;&amp;gt;
  &lt;span class="pl-e"&gt;{%&lt;/span&gt;- &lt;span class="pl-k"&gt;endfor&lt;/span&gt; &lt;span class="pl-e"&gt;%}&lt;/span&gt;
&amp;lt;/&lt;span class="pl-ent"&gt;ul&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Becomes this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0   EmitRaw "&amp;lt;ul&amp;gt;"
1   Lookup  "nav"
2   PushLoop    1
3   Iterate 11
4   StoreLocal  "item"
5   EmitRaw "\n &amp;lt;li&amp;gt;"
6   Lookup  "item"
7   GetAttr "title"
8   Emit    
9   EmitRaw "&amp;lt;/a&amp;gt;"
10  Jump    3
11  PopFrame    
12  EmitRaw "\n&amp;lt;/ul&amp;gt;"&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://hachyderm.io/@mitsuhiko/113034016600122789"&gt;@mitsuhiko&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jinja"&gt;jinja&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/templates"&gt;templates&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webassembly"&gt;webassembly&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="jinja"/><category term="templates"/><category term="rust"/><category term="webassembly"/></entry><entry><title>Quoting Armin Ronacher</title><link href="https://simonwillison.net/2024/Aug/21/armin-ronacher/#atom-tag" rel="alternate"/><published>2024-08-21T12:08:15+00:00</published><updated>2024-08-21T12:08:15+00:00</updated><id>https://simonwillison.net/2024/Aug/21/armin-ronacher/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://lucumr.pocoo.org/2024/8/21/harvest-season/"&gt;&lt;p&gt;There is an elephant in the room which is that Astral is a VC funded company. What does that mean for the future of these tools? Here is my take on this: for the community having someone pour money into it can create some challenges. For the PSF and the core Python project this is something that should be considered. However having seen the code and what uv is doing, even in the worst possible future this is a very forkable and maintainable thing. I believe that even in case Astral shuts down or were to do something incredibly dodgy licensing wise, the community would be better off than before uv existed.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://lucumr.pocoo.org/2024/8/21/harvest-season/"&gt;Armin Ronacher&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uv"&gt;uv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/astral"&gt;astral&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rye"&gt;rye&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/open-source"&gt;open-source&lt;/a&gt;&lt;/p&gt;



</summary><category term="python"/><category term="uv"/><category term="astral"/><category term="rye"/><category term="armin-ronacher"/><category term="open-source"/></entry><entry><title>uv: Python packaging in Rust</title><link href="https://simonwillison.net/2024/Feb/15/uv-python-packaging-in-rust/#atom-tag" rel="alternate"/><published>2024-02-15T19:57:13+00:00</published><updated>2024-02-15T19:57:13+00:00</updated><id>https://simonwillison.net/2024/Feb/15/uv-python-packaging-in-rust/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://astral.sh/blog/uv"&gt;uv: Python packaging in Rust&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
"uv is an extremely fast Python package installer and resolver, written in Rust, and designed as a drop-in replacement for pip and pip-tools workflows."&lt;/p&gt;
&lt;p&gt;From Charlie Marsh and Astral, the team behind &lt;a href="https://github.com/astral-sh/ruff"&gt;Ruff&lt;/a&gt;, who describe it as a milestone in their pursuit of a "Cargo for Python".&lt;/p&gt;
&lt;p&gt;Also in this announcement: Astral are taking over stewardship of Armin Ronacher's Rye packaging tool, another Rust project.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; is reported to be 8-10x faster than regular &lt;code&gt;pip&lt;/code&gt;, increasing to 80-115x faster with a warm global module cache thanks to copy-on-write and hard links on supported filesystems - which saves on disk space too.&lt;/p&gt;
&lt;p&gt;It also has a &lt;code&gt;--resolution=lowest&lt;/code&gt; option for installing the lowest available version of dependencies - extremely useful for testing, I've been wanting this for my own projects for a while.&lt;/p&gt;
&lt;p&gt;Also included: &lt;code&gt;uv venv&lt;/code&gt; - a fast tool for creating new virtual environments with no dependency on Python itself.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/charliermarsh/status/1758216803275149389"&gt;@charliermarsh&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pip"&gt;pip&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rye"&gt;rye&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ruff"&gt;ruff&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uv"&gt;uv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/astral"&gt;astral&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/charlie-marsh"&gt;charlie-marsh&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="pip"/><category term="python"/><category term="rust"/><category term="rye"/><category term="ruff"/><category term="uv"/><category term="astral"/><category term="charlie-marsh"/></entry><entry><title>Quoting Armin Ronacher</title><link href="https://simonwillison.net/2024/Feb/4/armin-ronacher/#atom-tag" rel="alternate"/><published>2024-02-04T15:12:06+00:00</published><updated>2024-02-04T15:12:06+00:00</updated><id>https://simonwillison.net/2024/Feb/4/armin-ronacher/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://lucumr.pocoo.org/2024/2/4/rye-a-vision/"&gt;&lt;p&gt;Rye lets you get from no Python on a computer to a fully functioning Python project in under a minute with linting, formatting and everything in place.&lt;/p&gt;
&lt;p&gt;[...] Because it was demonstrably designed to avoid interference with any pre-existing Python configurations, Rye allows for a smooth and gradual integration and the emotional barrier of picking it up even for people who use other tools was shown to be low.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://lucumr.pocoo.org/2024/2/4/rye-a-vision/"&gt;Armin Ronacher&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rye"&gt;rye&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="python"/><category term="rye"/></entry><entry><title>Rye</title><link href="https://simonwillison.net/2023/Apr/24/rye/#atom-tag" rel="alternate"/><published>2023-04-24T04:02:42+00:00</published><updated>2023-04-24T04:02:42+00:00</updated><id>https://simonwillison.net/2023/Apr/24/rye/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/mitsuhiko/rye"&gt;Rye&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin Ronacher's take on a Python packaging tool. There are a lot of interesting ideas in this one - it's written in Rust, configured using &lt;code&gt;pyproject.toml&lt;/code&gt; and has some very strong opinions, including completely hiding &lt;code&gt;pip&lt;/code&gt; from view and insisting you use &lt;code&gt;rye add package&lt;/code&gt; instead. Notably, it doesn't use the system Python at all: instead, it downloads a pre-compiled standalone Python from Gregory Szorc's &lt;a href="https://github.com/indygreg/python-build-standalone"&gt;python-build-standalone&lt;/a&gt; project - the same approach I used for the Datasette Desktop Electron app.&lt;/p&gt;
&lt;p&gt;Armin warns that this is just an exploration, with no guarantees of future maintenance - and even has an issue open titled &lt;a href="https://github.com/mitsuhiko/rye/discussions/6"&gt;Should Rye exist?&lt;/a&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/packaging"&gt;packaging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pypi"&gt;pypi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rye"&gt;rye&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="packaging"/><category term="pypi"/><category term="python"/><category term="rust"/><category term="rye"/></entry><entry><title>Quoting Armin Ronacher</title><link href="https://simonwillison.net/2023/Apr/11/armin-ronacher/#atom-tag" rel="alternate"/><published>2023-04-11T16:47:40+00:00</published><updated>2023-04-11T16:47:40+00:00</updated><id>https://simonwillison.net/2023/Apr/11/armin-ronacher/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://twitter.com/mitsuhiko/status/1645747519782092806"&gt;&lt;p&gt;My strong hunch is that the GIL does not need removing, if a) subinterpreters have their own GILs and b) an efficient way is provided to pass (some) data between subinterpreters lock free and c) we find good patterns to make working with subinterpreters work.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://twitter.com/mitsuhiko/status/1645747519782092806"&gt;Armin Ronacher&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gil"&gt;gil&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="gil"/><category term="python"/></entry><entry><title>mitsuhiko/insta</title><link href="https://simonwillison.net/2022/Oct/31/insta/#atom-tag" rel="alternate"/><published>2022-10-31T01:06:44+00:00</published><updated>2022-10-31T01:06:44+00:00</updated><id>https://simonwillison.net/2022/Oct/31/insta/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/mitsuhiko/insta"&gt;mitsuhiko/insta&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I asked for recommendations on Twitter for testing libraries in other languages that would give me the same level of delight that I get from pytest. Two people pointed me to insta by  Armin Ronacher, a Rust testing framework for “snapshot testing” which automatically records reference values to your repository, so future tests can spot if they change.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/david_raznick/status/1586885078457753602"&gt;@david_raznick&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pytest"&gt;pytest&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="testing"/><category term="rust"/><category term="pytest"/></entry><entry><title>Flask 0.1 Released</title><link href="https://simonwillison.net/2010/Apr/16/flask/#atom-tag" rel="alternate"/><published>2010-04-16T17:12:48+00:00</published><updated>2010-04-16T17:12:48+00:00</updated><id>https://simonwillison.net/2010/Apr/16/flask/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lucumr.pocoo.org/2010/4/16/flask-0-1-released"&gt;Flask 0.1 Released&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Armin’s Flask (a Python microframework built around Werkzeug and Jinja2) is looking pretty solid for a two week old project—extensive documentation, comprehensive unit test support (and example applications with unit tests) and some very tidy API design.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/flask"&gt;flask&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jinja"&gt;jinja&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/microframeworks"&gt;microframeworks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/werkzeug"&gt;werkzeug&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="flask"/><category term="jinja"/><category term="microframeworks"/><category term="python"/><category term="testing"/><category term="werkzeug"/></entry><entry><title>What's New In Python 3.1</title><link href="https://simonwillison.net/2009/Jun/28/python31/#atom-tag" rel="alternate"/><published>2009-06-28T15:02:09+00:00</published><updated>2009-06-28T15:02:09+00:00</updated><id>https://simonwillison.net/2009/Jun/28/python31/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://docs.python.org/3.1/whatsnew/3.1.html"&gt;What&amp;#x27;s New In Python 3.1&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Lots of stuff, but the best bits are an ordered dictionary type (congrats, Armin), a Counter class for counting unique items in an iterable (I do this on an almost daily basis) and a bunch of performance improvements including a rewrite of the Python 3.0 IO system in C.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python3"&gt;python3&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python31"&gt;python31&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/releases"&gt;releases&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="performance"/><category term="python"/><category term="python3"/><category term="python31"/><category term="releases"/></entry><entry><title>Whitespace Sensitivity</title><link href="https://simonwillison.net/2008/Jul/1/lucumr/#atom-tag" rel="alternate"/><published>2008-07-01T14:50:43+00:00</published><updated>2008-07-01T14:50:43+00:00</updated><id>https://simonwillison.net/2008/Jul/1/lucumr/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://lucumr.pocoo.org/cogitations/2008/07/01/whitespace-sensitivity/"&gt;Whitespace Sensitivity&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Amusingly, Ruby is actually far more sensitive about whitespace than Python is.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/armin-ronacher"&gt;armin-ronacher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ruby"&gt;ruby&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/whitespace"&gt;whitespace&lt;/a&gt;&lt;/p&gt;



</summary><category term="armin-ronacher"/><category term="python"/><category term="ruby"/><category term="whitespace"/></entry></feed>