<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: swift</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/swift.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-03-27T20:59:53+00:00</updated><author><name>Simon Willison</name></author><entry><title>Vibe coding SwiftUI apps is a lot of fun</title><link href="https://simonwillison.net/2026/Mar/27/vibe-coding-swiftui/#atom-tag" rel="alternate"/><published>2026-03-27T20:59:53+00:00</published><updated>2026-03-27T20:59:53+00:00</updated><id>https://simonwillison.net/2026/Mar/27/vibe-coding-swiftui/#atom-tag</id><summary type="html">
    &lt;p&gt;I have a new laptop - a 128GB M5 MacBook Pro, which early impressions show to be &lt;em&gt;very&lt;/em&gt; capable for running good local LLMs. I got frustrated with Activity Monitor and decided to vibe code up some alternative tools for monitoring performance and I'm very happy with the results.&lt;/p&gt;
&lt;p&gt;This is my second experiment with vibe coding macOS apps - the first was &lt;a href="https://simonwillison.net/2026/Feb/25/present/"&gt;this presentation app a few weeks ago&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turns out Claude Opus 4.6 and GPT-5.4 are both very competent at SwiftUI - and a full SwiftUI app can fit in a single text file, which means I can use them to spin something up without even opening Xcode.&lt;/p&gt;
&lt;p&gt;I’ve built two apps so far: Bandwidther shows me what apps are using network bandwidth and Gpuer to show me what’s going on with the GPU. At Claude’s suggestion both of these are now menu bar icons that open a panel full of information.&lt;/p&gt;
&lt;h4 id="bandwidther"&gt;Bandwidther&lt;/h4&gt;
&lt;p&gt;I built this app first, because I wanted to see what Dropbox was doing. It looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" rel="noopener noreferrer" href="https://github.com/simonw/bandwidther/raw/main/screenshot.png"&gt;&lt;img src="https://github.com/simonw/bandwidther/raw/main/screenshot.png" alt="Screenshot of Bandwidther macOS app showing two columns: left side displays overall download/upload speeds, a bandwidth graph over the last 60 seconds, cumulative totals, internet and LAN connection counts, and internet destinations; right side shows per-process bandwidth usage sorted by rate with processes like nsurlsessiond, apsd, rapportd, mDNSResponder, Dropbox, and others listed with their individual download/upload speeds and progress bars." style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’ve shared &lt;a href="https://gisthost.github.io/?6e06d4724c64c10d1fc3fbe19d9c8575/index.html"&gt;the full transcript&lt;/a&gt; I used to build the first version of the app. My prompts were pretty minimal:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Show me how much network bandwidth is in use from this machine to the internet as opposed to local LAN&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(My initial curiosity was to see if Dropbox was transferring files via the LAN from my old computer or was downloading from the internet.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;mkdir /tmp/bandwidther and write a native Swift UI app in there that shows me these details on a live ongoing basis&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This got me the first version, which proved to me this was worth pursuing further.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;git init and git commit what you have so far&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since I was about to start adding new features.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now suggest features we could add to that app, the goal is to provide as much detail as possible concerning network usage including by different apps&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The nice thing about having Claude suggest features is that it has a much better idea for what’s possible than I do.&lt;/p&gt;
&lt;p&gt;We had a bit of back and forth fixing some bugs, then I sent a few more prompts to get to the two column layout shown above:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;add Per-Process Bandwidth, relaunch the app once that is done&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;now add the reverse DNS feature but make sure original IP addresses are still visible too, albeit in smaller typeface&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;redesign the app so that it is wider, I want two columns - the per-process one on the left and the rest on the right&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;OK make it a task bar icon thing, when I click the icon I want the app to appear, the icon itself should be a neat minimal little thing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The source code and build instructions are available in &lt;a href="https://github.com/simonw/bandwidther"&gt;simonw/bandwidther&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="gpuer"&gt;Gpuer&lt;/h4&gt;
&lt;p&gt;While I was building Bandwidther in one session I had another session running to build a similar tool for seeing what the GPU was doing. Here’s what I ended up with:&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" rel="noopener noreferrer" href="https://github.com/simonw/gpuer/raw/main/screenshot.png"&gt;&lt;img src="https://github.com/simonw/gpuer/raw/main/screenshot.png" alt="Screenshot of the Gpuer app on macOS showing memory usage for an Apple M5 Max with 40 GPU cores. Left panel: a large orange &amp;quot;38 GB Available&amp;quot; readout showing usage of 128.0 GB unified memory, &amp;quot;Room for ~18 more large apps before pressure&amp;quot;, a warning banner reading &amp;quot;1.5 GB pushed to disk — system was under pressure recently&amp;quot;, a horizontal segmented bar chart labeled &amp;quot;Where your memory is going&amp;quot; with green, blue, and grey segments and a legend, an explanatory note about GPU unified memory, a GPU Utilization section showing 0%, and a History graph showing Available and GPU Utilization over time as line charts. Right panel: a Memory Footprint list sorted by Memory, showing process names with horizontal pink/purple usage bars and CPU percentage labels beside each entry, covering processes including Dropbox, WebKit, Virtualization, node, Claude Helper, Safari, LM Studio, WindowServer, Finder, and others." style="max-width: 100%;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://gisthost.github.io/?71ffe216ceca8d7da59a07c478d17529"&gt;the transcript&lt;/a&gt;. This one took even less prompting because I could use the in-progress Bandwidther as an example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I want to know how much RAM and GPU this computer is using, which is hard because stuff on the GPU and RAM does not seem to show up in Activity Monitor&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This collected information using &lt;code&gt;system_profiler&lt;/code&gt; and &lt;code&gt;memory_pressure&lt;/code&gt; and gave me &lt;a href="https://gisthost.github.io/?71ffe216ceca8d7da59a07c478d17529/page-001.html#msg-2026-03-24T22-13-26-614Z"&gt;an answer&lt;/a&gt; - more importantly it showed me this was possible, so I said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Look at /tmp/bandwidther and then create a similar app in /tmp/gpuer which shows the information from above on an ongoing basis, or maybe does it better&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After a few more changes to the Bandwidther app I told it to catch up:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now take a look at recent changes in /tmp/bandwidther - that app now uses a sys tray icon, imitate that&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This remains one of my favorite tricks for using coding agents: having them &lt;a href="https://simonwillison.net/guides/agentic-engineering-patterns/hoard-things-you-know-how-to-do/#recombining-things-from-your-hoard"&gt;recombine elements&lt;/a&gt; from other projects.&lt;/p&gt;
&lt;p&gt;The code for Gpuer can be found in &lt;a href="https://github.com/simonw/gpuer"&gt;simonw/gpuer&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;h4 id="you-shouldn-t-trust-these-apps"&gt;You shouldn't trust these apps&lt;/h4&gt;
&lt;p&gt;These two apps are classic vibe coding: I don't know Swift and I hardly glanced at the code they were writing.&lt;/p&gt;
&lt;p&gt;More importantly though, I have very little experience with macOS internals such as the values these tools are measuring. I am completely unqualified to evaluate if the numbers and charts being spat out by these tools are credible or accurate!&lt;/p&gt;
&lt;p&gt;I've added warnings to both GitHub repositories to that effect.&lt;/p&gt;
&lt;p&gt;This morning I caught Gpuer reporting that I had just 5GB of memory left when that clearly wasn't the case (according to Activity Monitor). I &lt;a href="https://gisthost.github.io/?9ae12fff0fecc9a4482c9b02e8599c70/page-001.html#msg-2026-03-27T19-35-35-866Z"&gt;pasted a screenshot into Claude Code&lt;/a&gt; and it &lt;a href="https://github.com/simonw/gpuer/commit/a3cd655f5ccb274d3561e4cbfcc771b0bb7e256a"&gt;adjusted the calculations&lt;/a&gt; and the new numbers &lt;em&gt;look&lt;/em&gt; right, but I'm still not confident that it's reporting things correctly.&lt;/p&gt;
&lt;p&gt;I only shared them on GitHub because I think they're interesting as an example of what Claude can do with SwiftUI.&lt;/p&gt;
&lt;p&gt;Despite my lack of confidence in the apps themselves, I did learn some useful things from these projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A SwiftUI app can get a whole lot done with a single file of code - here's &lt;a href="https://github.com/simonw/gpuer/blob/main/GpuerApp.swift"&gt;GpuerApp.swift&lt;/a&gt; (880 lines) and &lt;a href="https://github.com/simonw/bandwidther/blob/main/BandwidtherApp.swift"&gt;BandwidtherApp.swift&lt;/a&gt; (1063 lines).&lt;/li&gt;
&lt;li&gt;Wrapping various terminal commands in a neat UI with Swift is easily achieved.&lt;/li&gt;
&lt;li&gt;Claude has surprisingly good design taste when it comes to SwiftUI applications.&lt;/li&gt;
&lt;li&gt;Turning an app into a menu bar app is just a few lines of extra code as well.&lt;/li&gt;
&lt;li&gt;You don't need to open Xcode to build this kind of application!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These two apps took very little time to build and have convinced me that building macOS apps in SwiftUI is a new capability I should consider for future projects.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/macos"&gt;macos&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/vibe-coding"&gt;vibe-coding&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/swift"&gt;swift&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="macos"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="vibe-coding"/><category term="coding-agents"/><category term="swift"/><category term="claude-code"/></entry><entry><title>I vibe coded my dream macOS presentation app</title><link href="https://simonwillison.net/2026/Feb/25/present/#atom-tag" rel="alternate"/><published>2026-02-25T16:46:19+00:00</published><updated>2026-02-25T16:46:19+00:00</updated><id>https://simonwillison.net/2026/Feb/25/present/#atom-tag</id><summary type="html">
    &lt;p&gt;I gave a talk this weekend at Social Science FOO Camp in Mountain View. The event was a classic unconference format where anyone could present a talk without needing to propose it in advance. I grabbed a slot for a talk I titled "The State of LLMs, February 2026 edition", subtitle "It's all changed since November!". I vibe coded a custom macOS app for the presentation the night before.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/state-of-llms.jpg" alt="A sticky note on a board at FOO Camp. It reads: The state of LLMs, Feb 2026 edition - it's all changed since November! Simon Willison - the card is littered with names of new models: Qwen 3.5, DeepSeek 3.2, Sonnet 4.6, Kimi K2.5, GLM5, Opus 4.5/4.6, Gemini 3.1 Pro, Codex 5.3. The card next to it says Why do Social Scientists think they need genetics? Bill January (it's not all because of AI)" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;I've written about the last twelve months of development in LLMs in &lt;a href="https://simonwillison.net/2023/Dec/31/ai-in-2023/"&gt;December 2023&lt;/a&gt;, &lt;a href="https://simonwillison.net/2024/Dec/31/llms-in-2024/"&gt;December 2024&lt;/a&gt; and &lt;a href="https://simonwillison.net/2025/Dec/31/the-year-in-llms/"&gt;December 2025&lt;/a&gt;. I also presented &lt;a href="https://simonwillison.net/2025/Jun/6/six-months-in-llms/"&gt;The last six months in LLMs, illustrated by pelicans on bicycles&lt;/a&gt; at the AI Engineer World’s Fair in June 2025. This was my first time dropping the time covered to just three months, which neatly illustrates how much the space keeps accelerating and felt appropriate given the &lt;a href="https://simonwillison.net/2026/Jan/4/inflection/"&gt;November 2025 inflection point&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(I further illustrated this acceleration by wearing a Gemini 3 sweater to the talk, which I was given a couple of weeks ago and is already out-of-date &lt;a href="https://simonwillison.net/2026/Feb/19/gemini-31-pro/"&gt;thanks to Gemini 3.1&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;I always like to have at least one gimmick in any talk I give, based on the STAR moment principle I &lt;a href="https://simonwillison.net/2019/Dec/10/better-presentations/"&gt;learned at Stanford&lt;/a&gt; - include Something They'll Always Remember to try and help your talk stand out.&lt;/p&gt;
&lt;p&gt;For this talk I had two gimmicks. I built the first part of the talk around coding agent assisted data analysis of Kākāpō breeding season (which meant I got to &lt;a href="https://simonwillison.net/2026/Feb/8/kakapo-mug/"&gt;show off my mug&lt;/a&gt;), then did a quick tour of some new pelicans riding bicycles before ending with the reveal that the entire presentation had been presented using a new macOS app I had vibe coded in ~45 minutes the night before the talk.&lt;/p&gt;
&lt;h4 id="present-app"&gt;Present.app&lt;/h4&gt;
&lt;p&gt;The app is called &lt;strong&gt;Present&lt;/strong&gt; - literally the first name I thought of. It's built using Swift and SwiftUI and weighs in at 355KB, or &lt;a href="https://github.com/simonw/present/releases/tag/0.1a0"&gt;76KB compressed&lt;/a&gt;. Swift apps are tiny!&lt;/p&gt;
&lt;p&gt;It may have been quick to build but the combined set of features is something I've wanted for &lt;em&gt;years&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I usually use Keynote for presentations, but sometimes I like to mix things up by presenting using a sequence of web pages. I do this by loading up a browser window with a tab for each page, then clicking through those tabs in turn while I talk.&lt;/p&gt;
&lt;p&gt;This works great, but comes with a very scary disadvantage: if the browser crashes I've just lost my entire deck!&lt;/p&gt;
&lt;p&gt;I always have the URLs in a notes file, so I can click back to that and launch them all manually if I need to, but it's not something I'd like to deal with in the middle of a talk.&lt;/p&gt;
&lt;p&gt;This was &lt;a href="https://gisthost.github.io/?639d3c16dcece275af50f028b32480c7/page-001.html#msg-2026-02-21T05-53-43-395Z"&gt;my starting prompt&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Build a SwiftUI app for giving presentations where every slide is a URL. The app starts as a window with a webview on the right and a UI on the left for adding, removing and reordering the sequence of URLs. Then you click Play in a menu and the app goes full screen and the left and right keys switch between URLs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That produced a plan. You can see &lt;a href="https://gisthost.github.io/?bfbc338977ceb71e298e4d4d5ac7d63c"&gt;the transcript that implemented that plan here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Present a talk is an ordered sequence of URLs, with a sidebar UI for adding, removing and reordering those URLs. That's the entirety of the editing experience.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/present.jpg" alt="Screenshot of a macOS app window titled &amp;quot;Present&amp;quot; showing Google Image search results for &amp;quot;kakapo&amp;quot;. A web view shows a Google image search with thumbnail photos of kākāpō parrots with captions. A sidebar on the left shows a numbered list of URLs, mostly from simonwillison.net and static.simonwillison.net, with item 4 (https://www.google.com/search?...) highlighted in blue." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;When you select the "Play" option in the menu (or hit Cmd+Shift+P) the app switches to full screen mode. Left and right arrow keys navigate back and forth, and you can bump the font size up and down or scroll the page if you need to. Hit Escape when you're done.&lt;/p&gt;
&lt;p&gt;Crucially, Present saves your URLs automatically any time you make a change. If the app crashes you can start it back up again and restore your presentation state.&lt;/p&gt;
&lt;p&gt;You can also save presentations as a &lt;code&gt;.txt&lt;/code&gt; file (literally a newline-delimited sequence of URLs) and load them back up again later.&lt;/p&gt;
&lt;h4 id="remote-controlled-via-my-phone"&gt;Remote controlled via my phone&lt;/h4&gt;
&lt;p&gt;Getting the initial app working took so little time that I decided to get more ambitious.&lt;/p&gt;
&lt;p&gt;It's neat having a remote control for a presentation...&lt;/p&gt;
&lt;p&gt;So I prompted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Add a web server which listens on 0.0.0.0:9123 - the web server serves a single mobile-friendly page with prominent left and right buttons - clicking those buttons switches the slide left and right - there is also a button to start presentation mode or stop depending on the mode it is in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have &lt;a href="https://tailscale.com/"&gt;Tailscale&lt;/a&gt; on my laptop and my phone, which means I don't have to worry about Wi-Fi networks blocking access between the two devices. My phone can access &lt;code&gt;http://100.122.231.116:9123/&lt;/code&gt; directly from anywhere in the world and control the presentation running on my laptop.&lt;/p&gt;
&lt;p&gt;It took a few more iterative prompts to get to the final interface, which looked like this:&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;img src="https://static.simonwillison.net/static/2026/present-mobile.jpg" alt="Mobile phone web browser app with large buttons, Slide 4/31 at the top, Prev, Next and Start buttons, a thin bar with a up/down scroll icon and text size + and - buttons and the current slide URL at the bottom." style="max-width: 80%;" /&gt;&lt;/p&gt;
&lt;p&gt;There's a slide indicator at the top, prev and next buttons, a nice big "Start" button and buttons for adjusting the font size.&lt;/p&gt;
&lt;p&gt;The most complex feature is that thin bar next to the start button. That's a touch-enabled scroll bar - you can slide your finger up and down on it to scroll the currently visible web page up and down on the screen.&lt;/p&gt;
&lt;p&gt;It's &lt;em&gt;very&lt;/em&gt; clunky but it works just well enough to solve the problem of a page loading with most interesting content below the fold.&lt;/p&gt;
&lt;h4 id="learning-from-the-code"&gt;Learning from the code&lt;/h4&gt;
&lt;p&gt;I'd already &lt;a href="https://github.com/simonw/present"&gt;pushed the code to GitHub&lt;/a&gt; (with a big "This app was vibe coded [...] I make no promises other than it worked on my machine!" disclaimer) when I realized I should probably take a look at the code.&lt;/p&gt;
&lt;p&gt;I used this as an opportunity to document a recent pattern I've been using: asking the model to present a linear walkthrough of the entire codebase. Here's the resulting &lt;a href="https://simonwillison.net/guides/agentic-engineering-patterns/linear-walkthroughs/"&gt;Linear walkthroughs&lt;/a&gt; pattern in my ongoing &lt;a href="https://simonwillison.net/2026/Feb/23/agentic-engineering-patterns/"&gt;Agentic Engineering Patterns guide&lt;/a&gt;, including the prompt I used.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/simonw/present/blob/main/walkthrough.md"&gt;resulting walkthrough document&lt;/a&gt; is genuinely useful. It turns out Claude Code decided to implement the web server for the remote control feature &lt;a href="https://github.com/simonw/present/blob/main/walkthrough.md#request-routing"&gt;using socket programming without a library&lt;/a&gt;! Here's the minimal HTTP parser it used for routing:&lt;/p&gt;
&lt;div class="highlight highlight-source-swift"&gt;&lt;pre&gt;    &lt;span class="pl-k"&gt;private&lt;/span&gt; &lt;span class="pl-en"&gt;func&lt;/span&gt; route&lt;span class="pl-kos"&gt;(&lt;/span&gt;_ raw&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-smi"&gt;String&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pl-smi"&gt;String&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;firstLine&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; raw&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;components&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;separatedBy&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;\r&lt;/span&gt;&lt;span class="pl-s"&gt;\n&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;first &lt;span class="pl-c1"&gt;??&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;
        &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;parts&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; firstLine&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;split&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;separator&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt; &lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
        &lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;path&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; parts&lt;span class="pl-kos"&gt;.&lt;/span&gt;count &lt;span class="pl-c1"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;2&lt;/span&gt; &lt;span class="pl-c1"&gt;?&lt;/span&gt; &lt;span class="pl-en"&gt;String&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-en"&gt;parts&lt;/span&gt;&lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-c1"&gt;1&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-k"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;/&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;

        &lt;span class="pl-k"&gt;switch&lt;/span&gt; path &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-k"&gt;case&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;/next&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;
            state&lt;span class="pl-c1"&gt;&lt;span class="pl-c1"&gt;?&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;goToNext&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
            &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;jsonResponse&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;ok&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
        &lt;span class="pl-k"&gt;case&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;/prev&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;
            state&lt;span class="pl-c1"&gt;&lt;span class="pl-c1"&gt;?&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;goToPrevious&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
            &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;jsonResponse&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;ok&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-kos"&gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using GET requests for state changes like that opens up some fun CSRF vulnerabilities. For this particular application I don't really care.&lt;/p&gt;
&lt;h4 id="expanding-our-horizons"&gt;Expanding our horizons&lt;/h4&gt;
&lt;p&gt;Vibe coding stories like this are ten a penny these days. I think this one is worth sharing for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swift, a language I don't know, was absolutely the right choice here. I wanted a full screen app that embedded web content and could be controlled over the network. Swift had everything I needed.&lt;/li&gt;
&lt;li&gt;When I finally did look at the code it was simple, straightforward and did exactly what I needed and not an inch more.&lt;/li&gt;
&lt;li&gt;This solved a real problem for me. I've always wanted a good way to serve a presentation as a sequence of pages, and now I have exactly that.&lt;/li&gt;
&lt;li&gt;I didn't have to open Xcode even once!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn't mean native Mac developers are obsolete. I still used a whole bunch of my own accumulated technical knowledge (and the fact that I'd already installed Xcode and the like) to get this result, and someone who knew what they were doing could have built a far better solution in the same amount of time.&lt;/p&gt;
&lt;p&gt;It's a neat illustration of how those of us with software engineering experience can expand our horizons in fun and interesting directions. I'm no longer afraid of Swift! Next time I need a small, personal macOS app I know that it's achievable with our existing set of tools.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/macos"&gt;macos&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/vibe-coding"&gt;vibe-coding&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/swift"&gt;swift&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/november-2025-inflection"&gt;november-2025-inflection&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="macos"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="vibe-coding"/><category term="swift"/><category term="agentic-engineering"/><category term="november-2025-inflection"/></entry><entry><title>Linear walkthroughs</title><link href="https://simonwillison.net/guides/agentic-engineering-patterns/linear-walkthroughs/#atom-tag" rel="alternate"/><published>2026-02-25T01:07:10+00:00</published><updated>2026-02-25T01:07:10+00:00</updated><id>https://simonwillison.net/guides/agentic-engineering-patterns/linear-walkthroughs/#atom-tag</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;Sometimes it's useful to have a coding agent give you a structured walkthrough of a codebase. &lt;/p&gt;
&lt;p&gt;Maybe it's existing code you need to get up to speed on, maybe it's your own code that you've forgotten the details of, or maybe you vibe coded the whole thing and need to understand how it actually works.&lt;/p&gt;
&lt;p&gt;Frontier models with the right agent harness can construct a detailed walkthrough to help you understand how code works.&lt;/p&gt;
&lt;h2 id="an-example-using-showboat-and-present"&gt;An example using Showboat and Present&lt;/h2&gt;
&lt;p&gt;I recently &lt;a href="https://simonwillison.net/2026/Feb/25/present/"&gt;vibe coded a SwiftUI slide presentation app&lt;/a&gt; on my Mac using Claude Code and Opus 4.6.&lt;/p&gt;
&lt;p&gt;I was speaking about the advances in frontier models between November 2025 and February 2026, and I like to include at least one gimmick in my talks (a &lt;a href="https://simonwillison.net/2019/Dec/10/better-presentations/"&gt;STAR moment&lt;/a&gt; - Something They'll Always Remember). In this case I decided the gimmick would be revealing at the end of the presentation that the slide mechanism itself was an example of what vibe coding could do.&lt;/p&gt;
&lt;p&gt;I released the code &lt;a href="https://github.com/simonw/present"&gt;to GitHub&lt;/a&gt; and then realized I didn't know anything about how it actually worked - I had prompted the whole thing into existence (&lt;a href="https://gisthost.github.io/?bfbc338977ceb71e298e4d4d5ac7d63c"&gt;partial transcript here&lt;/a&gt;) without paying any attention to the code it was writing.&lt;/p&gt;
&lt;p&gt;So I fired up a new instance of Claude Code for web, pointed it at my repo and prompted:
&lt;pre&gt;Read the source and then plan a linear walkthrough of the code that explains how it all works in detail

Then run “uvx showboat –help” to learn showboat - use showboat to create a walkthrough.md file in the repo and build the walkthrough in there, using showboat note for commentary and showboat exec plus sed or grep or cat or whatever you need to include snippets of code you are talking about&lt;/pre&gt;
&lt;a href="https://github.com/simonw/showboat"&gt;Showboat&lt;/a&gt; is a tool I built to help coding agents write documents that demonstrate their work. You can see the &lt;a href="https://github.com/simonw/showboat/blob/main/help.txt"&gt;showboat --help output here&lt;/a&gt;, which is designed to give the model everything it needs to know in order to use the tool.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;showboat note&lt;/code&gt; command adds Markdown to the document. The &lt;code&gt;showboat exec&lt;/code&gt; command accepts a shell command, executes it and then adds both the command and its output to the document.&lt;/p&gt;
&lt;p&gt;By telling it to use "sed or grep or cat or whatever you need to include snippets of code you are talking about" I ensured that Claude Code would not manually copy snippets of code into the document, since that could introduce a risk of hallucinations or mistakes.&lt;/p&gt;
&lt;p&gt;This worked extremely well. Here's the &lt;a href="https://github.com/simonw/present/blob/main/walkthrough.md"&gt;document Claude Code created with Showboat&lt;/a&gt;, which talks through all six &lt;code&gt;.swift&lt;/code&gt; files in detail and provides a clear and actionable explanation about how the code works.&lt;/p&gt;
&lt;p&gt;I learned a great deal about how SwiftUI apps are structured and absorbed some solid details about the Swift language itself just from reading this document.&lt;/p&gt;
&lt;p&gt;If you are concerned that LLMs might reduce the speed at which you learn new skills I strongly recommend adopting patterns like this one.  Even a ~40 minute vibe coded toy project can become an opportunity to explore new ecosystems and pick up some interesting new tricks.&lt;/p&gt;
    
        &lt;p&gt;Tags: &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;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&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/swift"&gt;swift&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/showboat"&gt;showboat&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="agentic-engineering"/><category term="ai"/><category term="llms"/><category term="vibe-coding"/><category term="coding-agents"/><category term="ai-assisted-programming"/><category term="swift"/><category term="generative-ai"/><category term="showboat"/></entry><entry><title>Ladybird adopts Rust, with help from AI</title><link href="https://simonwillison.net/2026/Feb/23/ladybird-adopts-rust/#atom-tag" rel="alternate"/><published>2026-02-23T18:52:53+00:00</published><updated>2026-02-23T18:52:53+00:00</updated><id>https://simonwillison.net/2026/Feb/23/ladybird-adopts-rust/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://ladybird.org/posts/adopting-rust/"&gt;Ladybird adopts Rust, with help from AI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Really interesting case-study from Andreas Kling on advanced, sophisticated use of coding agents for ambitious coding projects with critical code. After a few years hoping Swift's platform support outside of the Apple ecosystem would mature they switched tracks to Rust their memory-safe language of choice, starting with an AI-assisted port of a critical library:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Our first target was &lt;strong&gt;LibJS&lt;/strong&gt; , Ladybird's JavaScript engine. The lexer, parser, AST, and bytecode generator are relatively self-contained and have extensive test coverage through &lt;a href="https://github.com/tc39/test262"&gt;test262&lt;/a&gt;, which made them a natural starting point.&lt;/p&gt;
&lt;p&gt;I used &lt;a href="https://docs.anthropic.com/en/docs/claude-code"&gt;Claude Code&lt;/a&gt; and &lt;a href="https://openai.com/codex/"&gt;Codex&lt;/a&gt; for the translation. This was human-directed, not autonomous code generation. I decided what to port, in what order, and what the Rust code should look like. It was hundreds of small prompts, steering the agents where things needed to go. [...]&lt;/p&gt;
&lt;p&gt;The requirement from the start was byte-for-byte identical output from both pipelines. The result was about 25,000 lines of Rust, and the entire port took about two weeks. The same work would have taken me multiple months to do by hand. We’ve verified that every AST produced by the Rust parser is identical to the C++ one, and all bytecode generated by the Rust compiler is identical to the C++ compiler’s output. Zero regressions across the board.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Having an existing conformance testing suite of the quality of &lt;code&gt;test262&lt;/code&gt; is a huge unlock for projects of this magnitude, and the ability to compare output with an existing trusted implementation makes agentic engineering much more of a safe bet.

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


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/browsers"&gt;browsers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&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/andreas-kling"&gt;andreas-kling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ladybird"&gt;ladybird&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/swift"&gt;swift&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/conformance-suites"&gt;conformance-suites&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/agentic-engineering"&gt;agentic-engineering&lt;/a&gt;&lt;/p&gt;



</summary><category term="browsers"/><category term="javascript"/><category term="ai"/><category term="rust"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="andreas-kling"/><category term="ladybird"/><category term="coding-agents"/><category term="swift"/><category term="conformance-suites"/><category term="agentic-engineering"/></entry><entry><title>LadybirdBrowser/ladybird: Abandon Swift adoption</title><link href="https://simonwillison.net/2026/Feb/19/ladybird/#atom-tag" rel="alternate"/><published>2026-02-19T01:25:33+00:00</published><updated>2026-02-19T01:25:33+00:00</updated><id>https://simonwillison.net/2026/Feb/19/ladybird/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/LadybirdBrowser/ladybird/commit/e87f889e31afbb5fa32c910603c7f5e781c97afd"&gt;LadybirdBrowser/ladybird: Abandon Swift adoption&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Back &lt;a href="https://simonwillison.net/2024/Aug/11/ladybird-set-to-adopt-swift/"&gt;in August 2024&lt;/a&gt; the Ladybird browser project announced an intention to adopt Swift as their memory-safe language of choice.&lt;/p&gt;
&lt;p&gt;As of &lt;a href="https://github.com/LadybirdBrowser/ladybird/commit/e87f889e31afbb5fa32c910603c7f5e781c97afd"&gt;this commit&lt;/a&gt; it looks like they've changed their mind:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Everywhere: Abandon Swift adoption&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After making no progress on this for a very long time, let's acknowledge it's not going anywhere and remove it from the codebase.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update 23rd February 2025&lt;/strong&gt;: They've &lt;a href="https://ladybird.org/posts/adopting-rust/"&gt;adopted Rust&lt;/a&gt; instead.

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


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/browsers"&gt;browsers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ladybird"&gt;ladybird&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/swift"&gt;swift&lt;/a&gt;&lt;/p&gt;



</summary><category term="browsers"/><category term="rust"/><category term="ladybird"/><category term="swift"/></entry><entry><title>swift-justhtml</title><link href="https://simonwillison.net/2025/Dec/18/swift-justhtml/#atom-tag" rel="alternate"/><published>2025-12-18T23:57:58+00:00</published><updated>2025-12-18T23:57:58+00:00</updated><id>https://simonwillison.net/2025/Dec/18/swift-justhtml/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/kylehowells/swift-justhtml"&gt;swift-justhtml&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
First there was Emil Stenström's &lt;a href="https://simonwillison.net/2025/Dec/14/justhtml/"&gt;JustHTML in Python&lt;/a&gt;, then my &lt;a href="https://simonwillison.net/2025/Dec/15/porting-justhtml/"&gt;justjshtml in JavaScript&lt;/a&gt;, then Anil Madhavapeddy's &lt;a href="https://simonwillison.net/2025/Dec/17/vibespiling/"&gt;html5rw in OCaml&lt;/a&gt;, and now Kyle Howells has built a vibespiled dependency-free HTML5 parser for Swift using the same coding agent tricks against the &lt;a href="https://github.com/html5lib/html5lib-tests"&gt;html5lib-tests&lt;/a&gt; test suite.&lt;/p&gt;
&lt;p&gt;Kyle ran &lt;a href="https://github.com/kylehowells/swift-justhtml/blob/master/Benchmarks/BENCHMARK_RESULTS.md#performance-comparison"&gt;some benchmarks&lt;/a&gt; to compare the different implementations:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rust (html5ever)&lt;/strong&gt; total parse time: 303 ms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swift&lt;/strong&gt; total parse time: 1313 ms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript&lt;/strong&gt; total parse time: 1035 ms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; total parse time: 4189 ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/html5"&gt;html5&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/vibe-coding"&gt;vibe-coding&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/swift"&gt;swift&lt;/a&gt;&lt;/p&gt;



</summary><category term="html5"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="vibe-coding"/><category term="swift"/></entry><entry><title>Vibing a Non-Trivial Ghostty Feature</title><link href="https://simonwillison.net/2025/Oct/11/vibing-a-non-trivial-ghostty-feature/#atom-tag" rel="alternate"/><published>2025-10-11T16:33:59+00:00</published><updated>2025-10-11T16:33:59+00:00</updated><id>https://simonwillison.net/2025/Oct/11/vibing-a-non-trivial-ghostty-feature/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://mitchellh.com/writing/non-trivial-vibing"&gt;Vibing a Non-Trivial Ghostty Feature&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Mitchell Hashimoto provides a comprehensive answer to the &lt;em&gt;frequent&lt;/em&gt; demand for a detailed description of shipping a non-trivial production feature to an existing project using AI-assistance. In this case it's a slick unobtrusive auto-update UI for his &lt;a href="https://ghostty.org/"&gt;Ghostty&lt;/a&gt; terminal emulator, written in Swift.&lt;/p&gt;
&lt;p&gt;Mitchell shares full transcripts of the 16 coding sessions he carried out using &lt;a href="https://ampcode.com/"&gt;Amp Code&lt;/a&gt; across 2 days and around 8 hours of computer time, at a token cost of $15.98.&lt;/p&gt;
&lt;p&gt;Amp has the nicest shared transcript feature of any of the coding agent tools, as seen &lt;a href="https://ampcode.com/threads/T-9fc3eb88-5aa2-45e4-8f6d-03697f53102d"&gt;in this example&lt;/a&gt;. I'd love to see Claude Code and Codex CLI and Gemini CLI and friends imitate this.&lt;/p&gt;
&lt;p&gt;There are plenty of useful tips in here. I like this note about the importance of a cleanup step:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The cleanup step is really important. To cleanup effectively you have to have a pretty good understanding of the code, so this forces me to not blindly accept AI-written code. Subsequently, better organized and documented code helps future agentic sessions perform better.&lt;/p&gt;
&lt;p&gt;I sometimes tongue-in-cheek refer to this as the "anti-slop session".&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And this on how sometimes you can write manual code in a way that puts the agent the right track:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I spent some time manually restructured the view model. This involved switching to a tagged union rather than the struct with a bunch of optionals. I renamed some types, moved stuff around.&lt;/p&gt;
&lt;p&gt;I knew from experience that this small bit of manual work in the middle would set the agents up for success in future sessions for both the frontend and backend. After completing it, I continued with a marathon set of cleanup sessions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's one of those refactoring prompts:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Turn each @macos/Sources/Features/Update/UpdatePopoverView.swift case into a dedicated fileprivate Swift view that takes the typed value as its parameter so that we can remove the guards.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mitchell advises ending every session with a prompt like this one, asking the agent about any obvious omissions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Are there any other improvements you can see to be made with the @macos/Sources/Features/Update feature? Don't write any code. Consult the oracle. Consider parts of the code that can also get more unit tests added.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;("Consult the oracle" is an Amp-specific pattern for running a task through a more expensive, more capable model.)&lt;/p&gt;
&lt;p&gt;Is this all worthwhile? Mitchell thinks so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many people on the internet argue whether AI enables you to work faster or not. In this case, I think I shipped this faster than I would have if I had done it all myself, in particular because iterating on minor SwiftUI styling is so tedious and time consuming for me personally and AI does it so well.&lt;/p&gt;
&lt;p&gt;I think the faster/slower argument for me personally is missing the thing I like the most: the AI can work for me while I step away to do other things.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's &lt;a href="https://github.com/ghostty-org/ghostty/pull/9116/files"&gt;the resulting PR&lt;/a&gt;, which touches 21 files.

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


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&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/mitchell-hashimoto"&gt;mitchell-hashimoto&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/swift"&gt;swift&lt;/a&gt;&lt;/p&gt;



</summary><category term="testing"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="mitchell-hashimoto"/><category term="coding-agents"/><category term="swift"/></entry><entry><title>I Shipped a macOS App Built Entirely by Claude Code</title><link href="https://simonwillison.net/2025/Jul/6/macos-app-built-entirely-by-claude-code/#atom-tag" rel="alternate"/><published>2025-07-06T22:47:51+00:00</published><updated>2025-07-06T22:47:51+00:00</updated><id>https://simonwillison.net/2025/Jul/6/macos-app-built-entirely-by-claude-code/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.indragie.com/blog/i-shipped-a-macos-app-built-entirely-by-claude-code"&gt;I Shipped a macOS App Built Entirely by Claude Code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Indragie Karunaratne has "been building software for the Mac since 2008", but recently decided to try Claude Code to build a side project: &lt;a href="https://github.com/indragiek/Context"&gt;Context&lt;/a&gt;, a native Mac app for debugging MCP servers:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is still skill and iteration involved in helping Claude build software, but of the 20,000 lines of code in this project, I estimate that I wrote less than 1,000 lines by hand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's a good looking native app:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot of a native macOS app for debugging MCP servers. Left sidebar shows connected servers including sentry, github, linear and others with green status indicators. Main panel displays get_issue_details API function with parameters for retrieving Swift app crash data. Right side shows detailed Sentry example - an error information for an EXC_BREAKPOINT crash in ContextCore/StdioTransport.swift, including timestamps, occurrence count, affected users, and event details. Clean modern interface with blue accent colors and organized navigation tabs." src="https://static.simonwillison.net/static/2025/claude-code-context.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This is a useful, detailed write-up. A few notes on things I picked up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude is great at SwiftUI and mostly good at Swift, but gets confused by the newer Swift Concurrency mechanisms.&lt;/li&gt;
&lt;li&gt;Claude occasionally triggers “The compiler is unable to type-check this expression in reasonable time” errors, but is able to recover by refactoring view bodies into smaller expressions.&lt;/li&gt;
&lt;li&gt;Telling Claude to make native macOS interfaces “more beautiful/elegant/usable” works surprisingly well. I’ve seen the same with web frontend code.&lt;/li&gt;
&lt;li&gt;Claude Code’s build/test/debug agentic coding loop works great for Swift apps, but there isn’t a good equivalent to Playwright yet so you need to manually take over to interact with the UI and drop in screenshots of any problems.&lt;/li&gt;
&lt;li&gt;Claude is &lt;em&gt;great&lt;/em&gt; at creating mock data:&lt;blockquote&gt;
&lt;p&gt;The first screenshots of the app that I shared with friends as I dialed in the UI were backed by mock data, but it looked real enough that you could get a good sense of how the app would look when rendering data from real MCP servers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Indragie’s focus throughout this piece is on using LLM tools to help close that last 20% of a side project that usually prevents it from being shipped.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The most exciting thing about this entire journey for me is not the app I built, but that I am now able to scratch my coding itch and ship polished side projects again. It's like I found an extra 5 hours every day, and all it cost me was $200 a month.&lt;/p&gt;
&lt;/blockquote&gt;

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


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/macos"&gt;macos&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/model-context-protocol"&gt;model-context-protocol&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/swift"&gt;swift&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="macos"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="model-context-protocol"/><category term="coding-agents"/><category term="swift"/><category term="claude-code"/></entry><entry><title>WWDC: Apple supercharges its tools and technologies for developers</title><link href="https://simonwillison.net/2025/Jun/9/apple-wwdc/#atom-tag" rel="alternate"/><published>2025-06-09T19:42:10+00:00</published><updated>2025-06-09T19:42:10+00:00</updated><id>https://simonwillison.net/2025/Jun/9/apple-wwdc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.apple.com/newsroom/2025/06/apple-supercharges-its-tools-and-technologies-for-developers/"&gt;WWDC: Apple supercharges its tools and technologies for developers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Here's the Apple press release for today's WWDC announcements. Two things that stood out to me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Foundation Models Framework&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With the Foundation Models framework, developers will be able to build on Apple Intelligence to bring users new experiences that are intelligent, available when they’re offline, and that protect their privacy, using AI inference that is free of cost.
The framework has native support for Swift, so developers can easily access the Apple Intelligence model with as few as three lines of code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's new documentation on &lt;a href="https://developer.apple.com/documentation/FoundationModels/generating-content-and-performing-tasks-with-foundation-models"&gt;Generating content and performing tasks with Foundation Models&lt;/a&gt; - the Swift code looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;session&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;LanguageModelSession&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
    instructions&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;Reply with step by step instructions&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;
&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;prompt&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;Rum old fashioned cocktail&lt;/span&gt;&lt;span class="pl-s"&gt;"&lt;/span&gt;
&lt;span class="pl-k"&gt;let&lt;/span&gt; &lt;span class="pl-s1"&gt;response&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;&lt;span class="pl-k"&gt;try&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; session&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;respond&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;
    to&lt;span class="pl-kos"&gt;:&lt;/span&gt; prompt&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    options&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-en"&gt;GenerationOptions&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;temperature&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-c1"&gt;2.0&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;There's also a &lt;a href="https://developer.apple.com/videos/play/wwdc2025/286/"&gt;23 minute Meet the Foundation Models framework&lt;/a&gt; video from the conference, which clarifies that this is a 3 billion parameter model with 2 bit quantization. The model is trained for both tool-calling and structured output, which they call "guided generation" and describe as taking advantage of constrained decoding.&lt;/p&gt;
&lt;p&gt;I'm also &lt;em&gt;very&lt;/em&gt; excited about this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Containerization Framework&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Containerization framework enables developers to create, download, or run Linux container images directly on Mac. It’s built on an open-source framework optimized for Apple silicon and provides secure isolation between container images. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I continue to seek the ideal sandboxing solution for running untrusted code - both from other humans and written for me by LLMs - on my own machines. This looks like it could be a really great option for that going forward.&lt;/p&gt;
&lt;p&gt;It looks like &lt;a href="https://github.com/apple/container"&gt;apple/container&lt;/a&gt; on GitHub is part of this new feature. From the &lt;a href="https://github.com/apple/container/blob/main/docs/technical-overview.md"&gt;technical overview&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On macOS, the typical way to run Linux containers is to launch a Linux virtual machine (VM) that hosts all of your containers.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;container&lt;/code&gt; runs containers differently. Using the open source &lt;a href="https://github.com/apple/containerization"&gt;Containerization&lt;/a&gt; package, it runs a lightweight VM for each container that you create. [...]&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;container&lt;/code&gt; consumes and produces standard OCI images, you can easily build with and run images produced by other container applications, and the images that you build will run everywhere.&lt;/p&gt;
&lt;/blockquote&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/macos"&gt;macos&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sandboxing"&gt;sandboxing&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/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/swift"&gt;swift&lt;/a&gt;&lt;/p&gt;



</summary><category term="apple"/><category term="macos"/><category term="sandboxing"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="llm-release"/><category term="swift"/></entry><entry><title>How we think about Threads’ iOS performance</title><link href="https://simonwillison.net/2024/Dec/29/threads-ios-performance/#atom-tag" rel="alternate"/><published>2024-12-29T21:45:14+00:00</published><updated>2024-12-29T21:45:14+00:00</updated><id>https://simonwillison.net/2024/Dec/29/threads-ios-performance/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://engineering.fb.com/2024/12/18/ios/how-we-think-about-threads-ios-performance/"&gt;How we think about Threads’ iOS performance&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This article by Dave LaMacchia and Jason Patterson provides an incredibly deep insight into what effective performance engineering looks like for an app with 100s of millions of users.&lt;/p&gt;
&lt;p&gt;I always like hearing about custom performance metrics with their own acronyms. Here we are introduced to &lt;strong&gt;%FIRE&lt;/strong&gt; - the portion of people who experience a &lt;em&gt;frustrating image-render experience&lt;/em&gt; (based on how long an image takes to load after the user scrolls it into the viewport), &lt;strong&gt;TTNC&lt;/strong&gt; (&lt;em&gt;time-to-network content&lt;/em&gt;) measuring time from app launch to fresh content visible in the feed and &lt;strong&gt;cPSR&lt;/strong&gt; (&lt;em&gt;creation-publish success rate&lt;/em&gt;) for how often a user manages to post content that they started to create.&lt;/p&gt;
&lt;p&gt;This article introduced me to the concept of a &lt;strong&gt;boundary test&lt;/strong&gt;, described like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A boundary test is one where we measure extreme ends of a boundary to learn what the effect is. In our case, we introduced a slight bit of latency when a small percentage of our users would navigate to a user profile, to the conversion view for a post, or to their activity feed. &lt;/p&gt;
&lt;p&gt;This latency would allow us to extrapolate what the effect would be if we similarly &lt;em&gt;improved&lt;/em&gt; how we delivered content to those views.&lt;/p&gt;
&lt;p&gt;[...]&lt;/p&gt;
&lt;p&gt;We learned that iOS users don’t tolerate a lot of latency. The more we added, the less often they would launch the app and the less time they would stay in it. With the smallest latency injection, the impact was small or negligible for some views, but the largest injections had negative effects across the board. People would read fewer posts, post less often themselves, and in general interact less with the app. Remember, we weren’t injecting latency into the core feed, either; just into the profile, permalink, and activity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There's a whole lot more in there, including details of their custom internal performance logger (SLATE, the “Systemic LATEncy” logger) and several case studies of surprising performance improvements made with the assistance of their metrics and tools, plus some closing notes on how Swift concurrency is being adopted throughout Meta.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://bsky.app/profile/raf.eco/post/3lehpzyipic2c"&gt;Rafe Colburn&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/threads"&gt;threads&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ios"&gt;ios&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/meta"&gt;meta&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/swift"&gt;swift&lt;/a&gt;&lt;/p&gt;



</summary><category term="performance"/><category term="threads"/><category term="ios"/><category term="meta"/><category term="swift"/></entry><entry><title>Ladybird set to adopt Swift</title><link href="https://simonwillison.net/2024/Aug/11/ladybird-set-to-adopt-swift/#atom-tag" rel="alternate"/><published>2024-08-11T18:38:57+00:00</published><updated>2024-08-11T18:38:57+00:00</updated><id>https://simonwillison.net/2024/Aug/11/ladybird-set-to-adopt-swift/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://twitter.com/awesomekling/status/1822236888188498031"&gt;Ladybird set to adopt Swift&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Andreas Kling on the Ladybird browser project's search for a memory-safe language to use in conjunction with their existing C++ codebase:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Over the last few months, I've asked a bunch of folks to pick some little part of our project and try rewriting it in the different languages we were evaluating. The feedback was very clear: everyone preferred Swift!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Andreas previously worked for Apple on Safari, but this was still a surprising result given the current relative lack of widely adopted open source Swift projects outside of the Apple ecosystem.&lt;/p&gt;
&lt;p&gt;This change is currently blocked on the upcoming Swift 6 release:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We aren't able to start using it just yet, as the current release of Swift ships with a version of Clang that's too old to grok our existing C++ codebase. But when Swift 6 comes out of beta this fall, we will begin using it!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update 18th February 2026&lt;/strong&gt;: Ladybird decided &lt;a href="https://simonwillison.net/2026/Feb/19/ladybird/"&gt;to abandon Swift&lt;/a&gt;.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/browsers"&gt;browsers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/c-plus-plus"&gt;c-plus-plus&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/andreas-kling"&gt;andreas-kling&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ladybird"&gt;ladybird&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/swift"&gt;swift&lt;/a&gt;&lt;/p&gt;



</summary><category term="browsers"/><category term="c-plus-plus"/><category term="andreas-kling"/><category term="ladybird"/><category term="swift"/></entry></feed>