Simon Willison on Paint.NET’s AI Direct2D Rewrite
Simon Willison’s note on Paint.NET’s Claude-built Direct2D rewrite shows where AI coding helps and where review still hurts.

Simon Willison’s note on Rick Brewster’s Paint.NET Direct2D rewrite is a short pointer to a remarkable engineering story: Paint.NET now carries its own clean-room Direct2D implementation for Wine, largely produced with Claude, Anthropic’s AI assistant. It deals with a hard compatibility wall: Direct2D was the blocker for running Paint.NET well on Wine, and Brewster says the normal Wine implementation was not complete enough for Paint.NET’s needs. The useful answer for Codex users is blunt: AI code generation can buy an impossible amount of exploration, but it also creates a review surface that has to be bounded before it becomes real software. For anyone measuring ai coding solutions roi for large teams, this is the rare public example where the win and the debt are visible in the same diff.
Understand what Brewster actually shipped
Rick Brewster is the maintainer of Paint.NET, the long-running Windows image editor. In the post Willison quotes, Brewster says Paint.NET now includes an internal Direct2D rewrite that is used when the app runs on Wine, triggered with /wine and packaged as PaintDotNet.Windows.Direct2D1.Managed.dll.
A clean-room rewrite is a new implementation of an existing system written without copying the original source code. In this case, the target is Direct2D, Microsoft’s 2D graphics API, because Paint.NET depends on it deeply enough that Brewster could not simply turn it off.
That matters because this is not a toy demo. It is a compatibility layer for a real graphics application with years of behavior and edge cases behind it.
The trap is to read the story as Claude replacing the maintainer. Brewster’s own account says the opposite: Claude did a huge amount of reverse-engineering work, while he still had to supervise architecture, resource management, and the places where clever code was not correct code.
Treat 180,000 lines as a research result
The number that makes developers stop scrolling is 180,000 lines. Brewster says the new Direct2D implementation is around that size, while the rest of Paint.NET is about 700,000 lines built over more than 20 years.
He also calls much of the new code “vibe coded,” meaning it has not been reviewed with the same depth as the older application code. That phrase lands because it is honest. A generated subsystem can be useful before it is fully trusted.
This is the uncomfortable middle of modern AI pair programming. The agent can produce a mountain of plausible code, including code a human maintainer may never have had time to write, but the maintainer still owns the blast radius.
The trap is to force the story into a yes-or-no argument about AI coding. The interesting part is not whether Claude was brilliant or sloppy. It was both, sometimes in the same project.
Notice where the human work moved
Brewster’s examples are very specific. Claude had to be corrected on COM-style reference counting, including missing the equivalent of AddRef() for reference-counted objects. He also says he had to push back on bad architecture decisions.
That is the part Codex users should keep. When an agent writes a lot of code, the human task moves up a layer: define invariants, spot dangerous ownership mistakes, and decide whether the shape of the subsystem belongs in the codebase.
In a Codex, OpenAI’s coding agent, workflow, this means the prompt is not the control plane. The repo is. AGENTS.md, tests, narrow diffs, and repeatable verification matter more than a heroic chat transcript.
There is a nice parallel in Blume Turns Agent Corrections Into Rules: the best correction is not the one you type once. It is the one you turn into a durable repo rule so the next agent run starts closer to the truth.
Put one boundary around your next agent diff
The practical lesson is small: do not start by asking an agent for a giant subsystem. Start by writing the boundary that would make such a subsystem reviewable.
For Codex users, that boundary can be a local AGENTS.md rule beside the risky package. Keep it short. Make it about invariants, not taste.
# AGENTS.md
Scope: src/graphics/interop/**
When changing graphics interop code:
- Preserve explicit ownership rules for native handles and COM-like objects.
- Add or update a test that fails without the ownership fix.
- Keep generated compatibility shims isolated from application logic.
- Before final response, run the smallest relevant test command and report it.
Then run a verification loop that does not depend on remembering the chat:
codex
# Ask Codex to make one bounded change under src/graphics/interop.
git diff --stat
git diff -- src/graphics/interop
npm test -- graphics-interop
This is the practical shape behind ai coding solutions roi for large teams: not more generated code per hour, but more useful experiments that can be reviewed, tested, and thrown away without drama.
If you connect Codex to outside systems, keep the first Model Context Protocol boundary boring. MCP is a standard way for agents to access external tools and context, such as repositories, docs, issue trackers, and databases. For a risky code path, make the first MCP server read-only unless the write path has its own review step.
For more patterns like this, see the related training topic. The point is not ceremony. It is making sure the repo can say no when the model is confidently wrong.
Copy this fit/not-fit table
Use this table as a quick note before asking an agent for a large generated change. It is not a policy. It is a way to decide whether the Paint.NET story is a useful analogy or a tempting excuse.
| Work type | Fit? | Why | Concrete next step |
|---|---|---|---|
| Compatibility shim behind a stable interface | Good fit | The boundary is narrow, and behavior can be compared against an existing system. | Create a scoped AGENTS.md file and ask for one API surface at a time. |
| Reverse-engineering behavior from examples | Possible fit | Agents can be tireless at exploring cases, but they may invent patterns. | Add golden tests before accepting broad implementation work. |
| Resource ownership and native interop | Risky fit | Small mistakes can leak, crash, or corrupt state. | Require explicit ownership notes in every diff and review them manually. |
| Core product architecture | Poor fit | The cost of a wrong abstraction compounds for years. | Ask for design alternatives, not a full rewrite. |
| Security-sensitive writes through MCP | Poor fit at first | External side effects widen the blast radius. | Start read-only, then add writes behind human review. |
Common questions
-
Does ai coding solutions roi for large teams show up in code volume or shipped capability?
It shows up in shipped capability, not raw code volume. The Paint.NET example is striking because 180,000 generated lines appear to unlock a Wine compatibility path, but Brewster also names the review debt plainly. Count the capability, the tests, the defects found, and the maintenance load together.
-
Should I trust vibe coded code if it passes tests?
No, passing tests is necessary but not enough for vibe coded code. Tests usually prove known expectations, while generated code often fails in ownership, architecture, and edge cases the test suite does not describe. Treat passing tests as permission to review the diff, not as permission to skip review.
-
What should Codex users copy from the Paint.NET story?
Copy the boundary, not the scale. Brewster had a specific compatibility problem, a mature codebase, and enough domain knowledge to catch bad COM-style ownership decisions. In Codex, start with a scoped directory rule, one narrow task, and a verification command you can rerun outside the agent session.
-
Is this a good example of AI software development?
Yes, because it shows both the power and the mess of AI software development in a real codebase. The agent helped produce a large subsystem that may not have happened otherwise, but the maintainer still had to guide design, correct resource handling, and decide what level of risk was acceptable.
Best ways to use this research
- Best for: engineers deciding where agentic coding is safe to try in a mature codebase. Look for isolated compatibility layers, migration helpers, test generation, and reverse-engineering chores.
- Best first artifact: a scoped
AGENTS.mdfile that names ownership rules, test expectations, and the smallest acceptable verification command. - Best comparison angle: compare generated code by review surface, not by model brand. A 500-line change with unclear ownership can be riskier than a 5,000-line shim behind a stable interface.
- Best safety check: map any MCP write access to a human-reviewed step. OWASP’s LLM application risks are a good reminder that agent capability and agent authority are different things.
Further reading
- Simon Willison on Rick Brewster’s Paint.NET note
- OpenAI — Codex
- Model Context Protocol — specification
- OWASP — Top 10 for Large Language Model Applications
Try the small version first
Before you ask Codex for a big rewrite, write the boundary file you wish Brewster had been able to hand Claude on day one. Then let the agent make one change inside that boundary and review the diff like the future maintainer is you.
One methodology lens
One useful way to read this through our methodology is the Plan step: delegate first-pass decomposition and dependency mapping, review the sequencing and assumptions, and keep ownership of scope and priorities. If that split is still fuzzy, the workflow usually is too.
Related training topics
Related research

dmx MCP Server Adds Gated Agent Loops
dmx runs configurable gated loops inside agentic IDEs, helping developers bound coding-agent work before it drifts.

Google AI Adds Search Study Tools
Google AI’s Search study release shows how bounded learning loops can inform safer Codex and MCP workflows.

Codex CLI 0.123.0: workflows that hold up
Codex CLI 0.123.0 workflows that hold up in review: replay recipes in the diff, a pinned model, a connector roster, and a ten-line done checklist.