<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Next Generation Of]]></title><description><![CDATA[Prompt to prototype to product — relearning the craft of software with AI]]></description><link>https://ngof.nikhaldimann.com</link><image><url>https://substackcdn.com/image/fetch/$s_!t9In!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26acd218-4e3a-4723-a8db-a55938fdd7fa_888x888.png</url><title>Next Generation Of</title><link>https://ngof.nikhaldimann.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 08:08:08 GMT</lastBuildDate><atom:link href="https://ngof.nikhaldimann.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Nik Haldimann]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[ngof@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[ngof@substack.com]]></itunes:email><itunes:name><![CDATA[Nik Haldimann]]></itunes:name></itunes:owner><itunes:author><![CDATA[Nik Haldimann]]></itunes:author><googleplay:owner><![CDATA[ngof@substack.com]]></googleplay:owner><googleplay:email><![CDATA[ngof@substack.com]]></googleplay:email><googleplay:author><![CDATA[Nik Haldimann]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Growing Code in the Lab]]></title><description><![CDATA[A full-stack appreciation of autoresearch architecture]]></description><link>https://ngof.nikhaldimann.com/p/growing-code-in-the-lab</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/growing-code-in-the-lab</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Wed, 08 Apr 2026 10:06:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tn72!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What is intelligence, really? Isn&#8217;t it just falling down, then learning to get back up, then falling down again, and then eventually learning to stay upright and to put one foot after the other, locomoting to the other side of the room into a parent&#8217;s open arms?</p><p>One reason AI coding agents seem to be possessed by intelligence is that they are built for trial and error, getting up and falling down tirelessly until they stand up a successful solution, usually meaning one that compiles or passes some kind of test.</p><p>A few weeks ago Andrej Karpathy took the inherent trial-and-error design of coding agents one step further. He set up an autonomous research loop for an agent to make iterative progress towards a measurable goal&#8212;and he called it <em>autoresearch</em>. He <a href="https://github.com/karpathy/autoresearch">published his code on Github</a>, which is actually a solution to the pretty narrow problem of training LLMs, not something that most people ever have a use for. It made a huge splash anyway because it carries a whiff of the early-stage singularity (is an LLM improving itself autonomously here?) but also because it was apparent to many that it exemplifies a new architectural pattern with wide application. To quote Karpathy himself <a href="https://x.com/karpathy/status/2031135152349524125">from a tweet</a>:</p><blockquote><p>All LLM frontier labs will do this. [&#8230;] You spin up a swarm of agents, you have them collaborate to tune smaller models, you promote the most promising ideas to increasingly larger scales, and humans (optionally) contribute on the edges.</p><p>And more generally, *any* metric you care about that is reasonably efficient to evaluate [&#8230;] can be autoresearched by an agent swarm. It&#8217;s worth thinking about whether your problem falls into this bucket too.</p></blockquote><p>The autoresearch pattern is one answer to a question I&#8217;ve personally been grappling with: how do you set boundaries for long-running, unsupervised agents in order to have some confidence that they don&#8217;t produce complete garbage?<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>In my head I currently break down the pattern into these components:</p><ul><li><p>The <strong>artifact under research</strong>&#8212;often a piece of code, but it could be data, a set of hyperparameters or anything else lending itself to iterative optimisation</p></li><li><p>A <strong>metric to optimise for</strong> and a method to compute that metric for the artifact</p></li><li><p><strong>Research instructions for the agent</strong> that explain the metric and anything else the agent needs to run a single experiment on the artifact inside the research loop</p></li><li><p>A <strong>record of kept and discarded experiments</strong> for the agent to refer back to when planning new experiments&#8212;this includes metrics for each experiment and ideally also a snapshot of the artifact (e.g., in the form of git commits if it&#8217;s code)</p></li><li><p>A <strong>research loop orchestrator</strong> which computes metrics, maintains the record of experiments and generally supervises the agent (e.g., it may stop the agent to prevent runaway costs)</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tn72!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tn72!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 424w, https://substackcdn.com/image/fetch/$s_!tn72!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 848w, https://substackcdn.com/image/fetch/$s_!tn72!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 1272w, https://substackcdn.com/image/fetch/$s_!tn72!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tn72!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png" width="1456" height="1844" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1844,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:278886,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/191845361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tn72!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 424w, https://substackcdn.com/image/fetch/$s_!tn72!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 848w, https://substackcdn.com/image/fetch/$s_!tn72!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 1272w, https://substackcdn.com/image/fetch/$s_!tn72!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa290c618-b051-4768-9a47-456a6ce2b1f5_1777x2250.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An autoresearch loop with 4 experiments where experiment #3 was discarded since its metric was higher (0.6) than the latest kept experiment (0.45)</figcaption></figure></div><p>For each experiment in the research loop the agent takes the research instructions, the prior list of experiments and the artifact from the last successful experiment as its &#8220;prompt&#8221; and produces a new version of the artifact. The orchestrator computes the metric for the new version of the artifact and records the experiment as successful if the metric improved, failed otherwise. In a simple setup (like Karpathy&#8217;s version) the agent acts as its own orchestrator&#8212;in my experience this is risky because the agent may hallucinate fake metrics or go off the rails in other unpredictable ways.</p><h3>The lab approach to autoresearch</h3><p>After Karpathy&#8217;s initial viral tweets sent my head spinning I quickly identified a problem I was facing (more on that further below) that I could jam into an autoresearch-shaped bucket. Once I had succeeded at that I simply had to extract my own little framework, which I released as <a href="https://github.com/nikhaldi/autoresearch-lab">Autoresearch Lab</a>.</p><p>The design of Autoresearch Lab was motivated by my circumstances, extrapolating a bit to make it as widely applicable as possible:</p><ul><li><p>I wanted to run research loops to produce both native Android and native iOS code, so it needed to be <strong>agnostic about a code artifact&#8217;s runtime environment</strong></p></li><li><p>I couldn&#8217;t accept the risk of running an unsupervised agent on my development machine but I also didn&#8217;t want to spin up an expensive, unwieldy VM, so I decided to <strong>sandbox the agent in a Docker container</strong>, however imperfect that may be<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p></li><li><p>I needed to combine the code artifacts from multiple research loops in one repo and to manually adapt some of the code as research went on, so <strong>the configuration and history of research loops is persisted alongside their code artifact</strong></p></li></ul><p>This last point is worth elaborating on because it&#8217;s not obvious why it matters, if your exposure to autoresearch is mainly through breathless tweets from people who allegedly had their codebase successfully rewritten over night. After kicking off a few primitive research loops myself I realised that&#8217;s rarely how it plays out. The pitfalls are numerous: the research instructions may not be precise enough; the API of the code artifact may need to evolve as research surfaces new capabilities; optimisation may get stuck in an obvious (to a human) local maximum which the agent can never back out of; it may turn out that the runtime environment is missing a dependency the agent really needs but refuses to install on its own (&#8220;too much work&#8221;&#8212;literal quote from an agent).</p><p>For all of these reasons I ended up stopping and restarting research loops often, sometimes reverting experiments, sometimes interleaving manual code changes with the outcome from successful experiments. To support all of that and provide a solid developer experience I came up with the concept of a <em>lab</em>, probably my main contribution here which will hopefully outlive the specifics of the library.</p><p>A lab allows any developer&#8212;or, for that matter, another agent or some automated pipeline&#8212;to start, stop, continue and branch a well-defined autoresearch loop. It consists of a small number of files that can be committed alongside the artifact produced by the research. This includes the research instructions for the agent and the implementation of a backend (in Python), a small interface that computes the metric the lab is optimising for.</p><p>The library ships with the &#8220;arl&#8221; executable that acts as the lab orchestrator. Its &#8220;arl run&#8221; command starts a Docker container with the agent, waits for the agent to signal that it&#8217;s reached the end of an experiment and then uses the backend to compute the metric. It appends the outcome to a results.tsv file which it git commits at the end of each experiment along with the new version of the artifact.</p><p>To get started refer to the <a href="https://github.com/nikhaldi/autoresearch-lab">README</a>. Here&#8217;s what a typical sequence of commands looks like (this assumes a Python environment has been created with <a href="https://docs.astral.sh/uv/#installation">uv</a> and the <a href="https://pypi.org/project/autoresearch-lab/">autoresearch-lab</a> package is installed in it):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;82cc4577-161d-4737-87ff-9be9564a7868&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Initialise a lab in the current directory
uv run arl init --name &#8220;my-lab&#8221;

# Before continuing edit the generated files: lab.toml, backend.py, AGENT.md

# Start the research loop and run it for 20 experiments
uv run arl run --max-iterations 20

# Show metrics for the state of the artifact after those experiments
uv run arl eval

# List experiments so far &amp; visualise progression in an interactive plot
uv run arl results
uv run arl plot

# Continue research with an extra prompt and pass-through arguments for Claude Code
# (if you can afford it you probably want to use "--effort high" most of the time)
uv run arl run --prompt "prioritise optimising latency" -- --effort high</code></pre></div><p>It isn&#8217;t quite as quick to get started with Autoresearch Lab as maybe I&#8217;d like. Setting up a lab requires some upfront effort, e.g., you need to implement a backend in Python. But I&#8217;ve learned from even just my relatively small-scale applications that this investment pays off.</p><p>Just because an architectural pattern is easy to grasp doesn&#8217;t at all mean it&#8217;s easy to put it into practice. I think autoresearch-at-large has enough hidden complexity that it will spawn a whole new class of software in support of it, especially when, as Karpathy predicts, people start bringing whole swarms of agents to it.</p><h3>Autoresearching better text recognition for phones</h3><p><a href="https://ngof.nikhaldimann.com/p/next-generation-of-reading-in-a-foreign">A while ago</a> I wrote about how I like to read books in languages I&#8217;m not that fluent in and what my ideal user experience for that looks like. Recently I started reading a major novel in its original language, and it&#8217;s one that may come across as so obnoxiously performative that I feel the need to hide the details in a footnote<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>&#8230; The point is that this led me again to experiment with augmenting my reading experience on paper with language study tools on my phone.</p><p>Crucially, the seamless integration of a paper book with digital tools needs a way to accurately scan the text on a page with a phone. When I prototyped an app for this I found out that this isn&#8217;t as much of a solved problem as I expected it to be, given that Android and iOS ship with builtin text recognition capabilities. On both platforms these yield mediocre results when naively applied to a photo of a book page: the camera angle and page curvature mess with the quality and order of the recognised text; bits of the facing page pollute the text of the actual page you care about; paragraph structure is lost.</p><p>This is a great example of a problem suited to autoresearch. I could easily put together a ground truth dataset of book page photos, define a metric that expresses how accurately text is extracted from those photos and then let a research loop discover and optimise the code to do that.</p><p>I released what came out of this as <a href="https://github.com/nikhaldi/booksnap">BookSnap</a>, a platform-independent (React Native) library which contains within it two labs, one each for the native Android and the native iOS code that does the bulk of the work.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a> The metric that the labs optimise for is Character Error Rate (CER), commonly used in the field for this purpose. This plot (generated with Autoresearch Lab&#8217;s &#8220;arl plot&#8221; command) shows how CER got better/lower as more experiments ran:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gSn9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gSn9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 424w, https://substackcdn.com/image/fetch/$s_!gSn9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 848w, https://substackcdn.com/image/fetch/$s_!gSn9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 1272w, https://substackcdn.com/image/fetch/$s_!gSn9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gSn9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72645,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/191845361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gSn9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 424w, https://substackcdn.com/image/fetch/$s_!gSn9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 848w, https://substackcdn.com/image/fetch/$s_!gSn9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 1272w, https://substackcdn.com/image/fetch/$s_!gSn9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b1a2695-71ea-4cc9-94a3-cc5de5df3a5d_1500x750.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Yes, the baseline quality of iOS&#8217;s text recognition is embarrassingly better than Android&#8217;s</figcaption></figure></div><p>Progress flattened out after a few experiments, though significant improvements may still be discovered if I continued the research loops. I stopped there for now because it&#8217;s just as likely that more experiments would overfit the ground truth dataset<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>. I&#8217;m more inclined to continue the research or even restart it from baseline when a next major model drops (i.e., Claude Mythos which, we just learned, is <a href="https://www.anthropic.com/glasswing">allegedly soooo powerful</a> as to require withholding from the general public to prevent a global cybersecurity meltdown).</p><p>This is a huge upside of the autoresearch architecture in general and of the lab approach in particular that I haven&#8217;t mentioned yet. With the right setup it&#8217;s trivial to take advantage of any future advances in the coding agent ecosystem right away. Autoresearch Lab lets me plug in a new model version or even just new Claude Code flags and have the labs build on the existing code or rewrite it from scratch, with a single command. Since the code was (mostly) generated by autoresearch and I&#8217;ve barely looked at it I don&#8217;t feel attached to it and have no qualms about scrapping it.</p><p>All those developers bragging about never reading the code that their coding agent spits out, is it this feeling of non-attachment that they&#8217;re chasing? I get the allure now but I prefer to experience it within the controlled confines of a lab set up for autoresearch.</p><h3>Intelligent dummies</h3><p>In trying to understand and improve agent behavior under autoresearch constraints I&#8217;ve now watched hours of research loops in action. It&#8217;s quite mesmerising! And it&#8217;s also exasperating because of the many times an agent will start down a path that I, a reasonably intelligent human, can immediately tell is pointless and will result in a discarded experiment.</p><p>I find myself torn between two conflicting perspectives on this. One is through the lens of the famous quote attributed to Thomas Edison: genius is 1% inspiration and 99% perspiration. An agent under autoresearch may simply beat any human at the task because it can perspire all day and night (as long as you keep topping up its token budget). Is an agent that spends 50% of its perspiration on objectively dumb stuff exhibiting something that, in aggregate, we should call genius or intelligence? It seems like a distinct quality to me, and it leads me to agree with Helen Toner that <a href="https://helentoner.substack.com/p/the-term-agi-is-almost-useless-at">the term &#8220;AGI&#8221; has run its course</a>.</p><p>The other perspective is one that often gets lost in the hype. Yes, frontier coding models are tremendously useful but <em>as of right now they</em> <em>propose dumb solutions all the time.</em> Production software in the long run needs defences against too many of those solutions seeping in, whether it be the judgment of experienced engineers or metric-driven architectures like autoresearch.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://ngof.nikhaldimann.com/subscribe?"><span>Subscribe now</span></a></p><p>I haven&#8217;t published anything here in a while, partly because I kinda nerdsniped myself wanting to conquer autoresearch. It took me a while to unwind the stack of insights I was accumulating and package it usefully in the form of the <a href="https://github.com/nikhaldi/autoresearch-lab">Autoresearch Lab</a> and <a href="https://github.com/nikhaldi/booksnap">BookSnap</a> libraries.</p><p>Going forward I may not stick to my original goal of publishing something roughly every 2 weeks because a different goal is more important to me: What I write about must be grounded in real code, real applications or at least in a public, usable prototype. I show my work; this isn&#8217;t the place where you come for hype, speculation or pure thought leadership. Subscribe above for future dispatches from the edge of product and engineering in the AI era.</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I previously wrote about <a href="https://ngof.nikhaldimann.com/p/deja-code">my reluctance to jump onto the prairie wagon to Gas Town</a> because it doesn&#8217;t seem to address this question at all.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Obligatory disclaimer: Docker isn&#8217;t a true security sandbox. It&#8217;s still risky to run Autoresearch Lab on a random machine. For stronger isolation you should operate a lab only inside a VM. The agent in the container also has full network access by default, so it&#8217;s prone to prompt injection and may exfiltrate the code in your lab; do not include secrets in it.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>It&#8217;s Proust, in French (&#192; la autorecherche du temps perdu)</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>In the pre-AI era I would never have attempted to build something in the React Native ecosystem, not having worked in mobile apps for more than 10 years. Claude Code made this a breeze, relatively speaking, though I have to say a React Native library with native code is still one of the most convoluted build environments I&#8217;ve ever encountered.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>The dataset consists of 34 photos of book pages in 4 languages (English, French, Italian, German). <a href="https://nikhaldi.github.io/booksnap/">A diff report generated at release</a> shows each sample and its performance against the metric. This may seem like a small number of samples but I took pains to select a diversity of camera angles, lighting conditions, page curvatures and layouts. If you&#8217;re looking for tasks that humans are still good for, assembling ground truth data is one of them.</p></div></div>]]></content:encoded></item><item><title><![CDATA[4 ways to combat Claude's code duplication, ranked from least to most AI-native]]></title><description><![CDATA[Plus: Globbing and grepping like it's 1973, and the role of a software engineer in the AI era]]></description><link>https://ngof.nikhaldimann.com/p/4-ways-to-combat-claudes-code-duplication</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/4-ways-to-combat-claudes-code-duplication</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Tue, 03 Mar 2026 11:59:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6fDV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve identified a shortcoming in the most advanced Claude Code model (Opus 4.6) that can sink codebases developed with it in the long run: It generates a significant amount of duplicated code if left on its own. (See <a href="https://ngof.nikhaldimann.com/p/deja-code">my previous post</a> on how I quantified this duplication in a real codebase.)</p><p>Duplicated code piles up in two main ways: Claude is bad at reusing existing library code, and it&#8217;s bad at extracting new library code. This is sort of by design. It freely admitted to me that it has a builtin bias to produce new code over reusing and consolidating code. Anybody who writes production software with Claude and cares about long-term maintainability needs to invest in active deduplication at this point. This becomes a more pressing concern the more AI-native you go.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6fDV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6fDV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 424w, https://substackcdn.com/image/fetch/$s_!6fDV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 848w, https://substackcdn.com/image/fetch/$s_!6fDV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 1272w, https://substackcdn.com/image/fetch/$s_!6fDV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6fDV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png" width="1232" height="626" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:626,&quot;width&quot;:1232,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:429154,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187966729?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6fDV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 424w, https://substackcdn.com/image/fetch/$s_!6fDV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 848w, https://substackcdn.com/image/fetch/$s_!6fDV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 1272w, https://substackcdn.com/image/fetch/$s_!6fDV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d53b42c-2106-4af4-9510-8d54b656ecb7_1232x626.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We&#8217;re all making up terminology on the fly these days, so this is what I currently take &#8220;AI-native&#8221; to mean: you don&#8217;t deal with software created by agents at the level of code, instead you deal with the <em>observable behavior</em> of the software. At the most extreme end you never look at the code at all, and if you dare write production software this way you probably have some kind of extensive eval or test harness.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>In the real world, I think many codebases have parts that lend themselves well to AI-native development and other parts that need more human supervision. You&#8217;ll likely want to pursue a mixed strategy to deduplicating code, so I&#8217;ve ranked my recommendations from least to most AI-native below.</p><p>(Spoiler: as part of thinking through these issues I created <a href="https://github.com/nikhaldi/drywall">DRYwall</a>, a Claude Code plugin that makes automated code deduplication really easy.)</p><h3>4 ways to combat Claude&#8217;s code duplication</h3><h4>1. Make library code easy to discover</h4><p>Pick descriptive names for functions and classes that are going to be reused across a codebase. Put them in a conventional place that Claude knows to look out for, such as directories called <code>/lib</code>, <code>/utils</code>, <code>/helpers</code>.</p><p>Because by default Claude looks at file names to decide whether to load their source into context, it helps to break up code into small, focused, well-named files. Prefer one class, one function or a closely related groups of classes/functions per file over one long generic <code>utils.py</code> file.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Incidentally, like a lot of advice for working with AI agents, this one applies just as much to working with humans. This makes code more discoverable for your human colleagues too!</p><p><strong>Ranking: Not AI-native</strong>, just good practice</p><h4>2. Instruct agents to reuse code via CLAUDE.md</h4><p>A CLAUDE.md file at the root of a codebase serves as its &#8220;project memory&#8221;, containing instructions that agents will always load into their context when working within the codebase. If you don&#8217;t have a CLAUDE.md file yet, you should definitely run &#8220;<code>/init</code>" in Claude Code right now to generate one.</p><p>The file is a natural place to write out instructions for handling code duplication (though Claude has <a href="https://code.claude.com/docs/en/memory">other types of memory</a> across projects that you should also consider). Add something like this to your CLAUDE.md file under a heading &#8220;Code Reuse&#8221;:</p><pre><code>Don't duplicate logic:

- Before writing new code check if similar logic already exists in the codebase
- Reuse existing functions, especially those in src/utils/, even if it means importing across modules
- Extract shared logic into src/utils/ if you encounter duplicated code
- Before creating any new utilities, search src/utils/ for existing library code</code></pre><p>If it seems too good to be true that such simple instructions get the job done&#8212;it&#8217;s because it is too good to be true. This reduces Claude&#8217;s bias to write everything from scratch a bit. But in a large codebase checking &#8220;if similar logic exists&#8221; is fundamentally hard plus expensive in terms of token.</p><p><strong>Ranking: Crudely AI-native</strong>, but it&#8217;s a start requiring zero effort</p><h4>3. Give Claude a better semantic hold on your code through Serena</h4><p>The earlier advice to break down code into small, well-named files matters because at its core Claude Code currently uses two ancient tools that fundamentally operate on the filesystem: <em>glob</em> to find files and <em>grep</em> to search file contents.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TQ3a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TQ3a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 424w, https://substackcdn.com/image/fetch/$s_!TQ3a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 848w, https://substackcdn.com/image/fetch/$s_!TQ3a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 1272w, https://substackcdn.com/image/fetch/$s_!TQ3a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TQ3a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif" width="360" height="259" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:259,&quot;width&quot;:360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:474293,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187966729?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TQ3a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 424w, https://substackcdn.com/image/fetch/$s_!TQ3a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 848w, https://substackcdn.com/image/fetch/$s_!TQ3a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 1272w, https://substackcdn.com/image/fetch/$s_!TQ3a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F021da612-49d3-4ebf-879f-ec7e01fceebb_360x259.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Stop!</em> It&#8217;s time for some history of computing. <a href="https://en.wikipedia.org/wiki/Glob_(programming)">glob</a> and <a href="https://en.wikipedia.org/wiki/Grep">grep</a> emerged as command-line tools in the early years of Unix, more than 50 years ago. They are great exhibits of the <a href="https://en.wikipedia.org/wiki/Unix_philosophy">Unix philosophy</a> (Doug McIlroy&#8217;s version): they &#8220;do one thing well&#8221; and they &#8220;expect their output to become the input to another, as yet unknown, program&#8221;.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> It&#8217;s that latent Unix-y capacity for recombining simple tools into a bigger whole that makes them a natural fit for Claude&#8217;s core loop. (Just to be clear: Claude doesn&#8217;t use glob/grep as literal command-line tools, as it explained to me it has dedicated implementations of these concepts.)</p><p>So while it&#8217;s cool that the developers of Claude Code are standing on the shoulders of Unix giants, I would also say that globbing and grepping like it&#8217;s 1973 as the primary way to navigate a codebase is &#8230; suboptimal. The string matching of grep cannot distinguish between variable names and function names, let alone between functions of the same name across multiple files. glob and grep have no model of the semantic structure of a codebase. Therefore, maybe surprisingly, Claude has no persistent model of the semantic structure of a codebase either! (It does have on-the-fly semantic understanding of individual files and chunks of code once it&#8217;s read them.)</p><p>This sounds kind of bad on the surface. One reason that Claude Code traverses code as well as it does anyway is that it will gladly overglob and overgrep. It doesn&#8217;t mind churning through lots of tokens (aka extracting money from you!) to locate a function. It also often doesn&#8217;t mind <em>under</em>grepping, e.g., when renaming a function, because it excels at trial-and-error, because often types and tests will eventually point out what it missed (note how tests matter more than ever). But that&#8217;s a lot of non-deterministic noodling and tokens wasted for what are simple deterministic problems.</p><p>Indeed, semantically indexing a codebase is very much a solved problem. Every IDE does it to let you jump to the definition of a function or show all call sites of said function. Why not afford Claude Code the same not-so-artificial intelligence? I assume it doesn&#8217;t do IDE-style indexing out of the box to keep it generic (applicable to any language) and light-weight (IDEs are resource-hungry for a reason).</p><p>Anthropic must be aware of these limitations and is certainly working to address them. In the meantime, by including it in the official marketplace they have endorsed a plugin for <a href="http://semantic code retrieval and editing tools">Serena</a>, an open source project that has semantic code retrieval and editing tools for over 30 programming languages.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a> To install it:</p><ol><li><p>Make sure you have the Python package manager uv installed <a href="https://docs.astral.sh/uv/getting-started/installation/">as per its docs</a> (the plugin starts a Serena server with uvx)</p></li><li><p>In your Claude Code prompt type &#8220;<code>/plugin</code>&#8221;, search for &#8220;serena&#8221;, select the plugin and pick your preferred installation option</p></li><li><p>Restart Claude Code</p></li></ol><p>Claude will now make use of Serena to efficiently navigate your codebase under some circumstances. What does this have to do with code duplication? I don&#8217;t have an easy way to quantify this but I&#8217;m pretty sure this reliably improves Claude&#8217;s ability to find and recall existing code for reuse.</p><p><strong>Ranking: Somewhat AI-native</strong>, it&#8217;s considerably boosting Claude&#8217;s understanding of a codebase</p><h4>4. Deduplicate code ad hoc via a Claude plugin (DRYwall)</h4><p>Interacting with agents all day every day conditions us to expect good things from fuzzy commands with non-deterministic outcomes. It&#8217;s easy to forget that, more often than not, you can just give agents deterministic tools rather than engage in that cursed and humiliating discipline of prompt engineering.</p><p>One such tool that I like is <a href="https://jscpd.dev/">jscpd</a>, which (deterministically) detects code duplication across a wide variety of languages. I ended up creating <a href="https://github.com/nikhaldi/drywall">DRYwall</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>, a Claude Code plugin that uses jscpd under the hood to make deduplication easy for agents. It comes with an MCP server that proxies jscpd, a skill and a subagent, but no knowledge of these details is required. Like any good plugin it operates mostly transparently, kicking in automatically when the topic of code duplication comes up. It will just make Claude&#8217;s refactoring of duplicated code significantly more effective and cheaper.</p><p>As a prerequisite, <a href="https://nodejs.org/en/download">Node.js</a> must be installed on your system (with node and npx binaries available to Claude Code). Then install the DRYwall plugin by running this in a Claude Code session:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f9fa1274-c2b0-4d7e-a7e9-15230cc46734&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">/plugin marketplace add nikhaldi/drywall
/plugin install drywall@drywall</code></pre></div><p>Restart your session after this to activate the plugin. To get a (mostly deterministic!) list of the most impactful suggested refactorings, invoke the scan skill within Claude Code:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8a927474-514e-49e3-b8c8-35b047b5c9fc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">/drywall:scan</code></pre></div><p>If you&#8217;re feeling AI-native and just want Claude to take care of everything, prompt it with something like this, which will launch a dedicated subagent:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ed4b6535-d651-4cbd-bfcb-8f7f0f65503f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Deduplicate code in this codebase</code></pre></div><p>I generally trust the latest Claude models to come up with sensible mechanical refactorings of duplicated code. But keep in mind that code duplication is sometimes just a symptom; the cause may be a lack of good abstractions in the code or some weakness in the design that purely mechanical code extraction won&#8217;t necessarily address. If you&#8217;re looking for your role as a software engineer in an AI-native development process, review big refactorings for pointers to issues in design and architecture.</p><p><strong>Ranking: Exceedingly AI-native, </strong>it&#8217;s empowering you&#8217;re agents to deduplicate at all times</p><div><hr></div><h3>The role of a software engineer</h3><p>As more people are waking up to the capabilities of frontier coding models, as they realise that the craft of coding is rapidly being devalued, many anxious conversations are happening among my friends and across the internet. What does a software engineer even do in this new AI era?</p><p>Maybe an anecdote will calm some anxious minds. Obviously I leaned on Claude to draft an initial version of DRYwall with its three components: a skill, a subagent and an MCP server with a tool proxy for jscpd. When I tested and reviewed that initial version I realised that Claude had written elaborate prose instructions for how to call jscpd in the skill file and again in the subagent file. Yes, it had duplicated &#8220;code&#8221;&#8212;really prose, which was even worse. This despite the MCP tool, which already calls jscpd in a structured way, sitting right there for the taking. I had to prompt Claude to rewrite the skill and subagent to use the MCP tool for much more deterministic behavior (and less duplication).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZMMx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZMMx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 424w, https://substackcdn.com/image/fetch/$s_!ZMMx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 848w, https://substackcdn.com/image/fetch/$s_!ZMMx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 1272w, https://substackcdn.com/image/fetch/$s_!ZMMx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZMMx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png" width="753" height="383" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:383,&quot;width&quot;:753,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63899,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187966729?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZMMx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 424w, https://substackcdn.com/image/fetch/$s_!ZMMx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 848w, https://substackcdn.com/image/fetch/$s_!ZMMx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 1272w, https://substackcdn.com/image/fetch/$s_!ZMMx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F299bf4ae-3590-4688-a044-4371cfc9abc1_753x383.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At a critical moment in the creative process it was still my judgment, that of a human software engineer, which steered the project towards a better design. Amidst the hype and the fretting, please remember that Claude&#8217;s output often improves with skilled human intervention. After all, its current shortcomings are the whole motivation for DRYwall and for this post.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Subscribe for free to receive new posts roughly every 2 weeks.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I&#8217;m still grappling with many questions about where software engineering is headed. It&#8217;s not just about the role of any individual engineer. I&#8217;m almost more interested in figuring out what an effective <em>team</em> of engineers looks like in the AI era. As an occasional engineering manager I&#8217;ve taken pride in assembling teams and creating environments in which they thrive as collectives. But most of the socio-technical practices I&#8217;ve internalised over the years are explicitly designed around coding as a hard and expensive activity, a now obsolete premise.</p><p>If you catch me in a more defeatist mood I feel like my deck of hard-won engineering insights and intuitions has been pulverised by AI, and I&#8217;m slowly rebuilding it, day by day. It&#8217;s slightly terrifying but, who am I kidding, it&#8217;s also exciting. I had the privilege of a front row seat to the rise of the web in the mid-90s, and I&#8217;m finding myself in that same position again with a very different but likely even more consequential technology. I&#8217;ll keep writing about my hands-on experience from the front row here, so subscribe above to get future issues in your inbox.</p><p>&#8212;Nik</p><p><em>PS: It&#8217;s time for a reminder that I don&#8217;t use AI in writing these posts&#8212;I have always used em dashes like that. The voice is wholly mine, warts and mixed registers and all. You see, this original voice enriches future LLMs instead of edging the asymptote of mid.</em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Notably, people have sorta kinda succeeded in AI-natively building <a href="https://github.com/wilsonzlin/fastrender">a browser rendering engine</a> and <a href="https://github.com/anthropics/claudes-c-compiler">a C compiler</a> and <a href="https://blog.cloudflare.com/vinext/">a Next.js builder</a>, all of which happen to be categories of software that come with readily available, comprehensive test harnesses.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Python developers beware: I think this is a particular problem with Python because it has a now detrimental convention of long grab-bag modules.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>For a deep dive on the Unix philosophy and its practical application I highly recommend Eric S. Raymond&#8217;s <a href="http://www.catb.org/esr/writings/taoup/html/">The Art of Unix Programming</a>, still relevant after 20+ years and still influencing my thinking about programming to this day.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>There is also support for &#8220;<a href="https://code.claude.com/docs/en/discover-plugins#code-intelligence">Code intelligence</a>&#8221; in the form of Language Server Protocol (LSP) plugins, built on top of open source projects for language-specific semantics. These plugins must be installed individually for each language. I had a hard time getting them to work and was left with the impression that they are rather underbaked as of right now.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>DRY = Don&#8217;t Repeat Yourself</p></div></div>]]></content:encoded></item><item><title><![CDATA[Déjà Code]]></title><description><![CDATA[Quantifying Claude Code's duplication habit & ogling Gas Town from afar]]></description><link>https://ngof.nikhaldimann.com/p/deja-code</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/deja-code</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Wed, 11 Feb 2026 13:58:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2fwG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s a new fashion to brag about not reading the code spat out by an AI, and I&#8217;m not talking about the many legitimate vibe coding use cases but about serious engineers doing quote-unquote serious work that they release to the wider public.</p><p>In the frontier lands of this Wild West of vibe coders lies <a href="https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04">Gas Town</a>, Steve Yegge&#8217;s memetic shot at defining a new category of software, an orchestrator for multiple Claude Code agents coordinating on larger tasks. It&#8217;s designed to enable a sort of vibe coding on steroids. By Steve&#8217;s own admission/brag he&#8217;s never read the code of Gas Town proper:</p><blockquote><p>I&#8217;ve never seen the code, and I never care to, which might give you pause. &#8216;Course, I&#8217;ve never looked at <a href="https://github.com/steveyegge/beads">Beads</a> either, and it&#8217;s 225k lines of Go code that tens of thousands of people are using every day. I just created it in October. If that makes you uncomfortable, <em>get out now</em>.</p></blockquote><p>I&#8217;m setting up camp outside of Gas Town for now, even if I think it&#8217;s a valid exercise in AI futurism (or possibly an elaborate piece of performance art&#8212;you never know with Steve!). I&#8217;m uncomfortable setting foot in town because I&#8217;m confronted with the limitations of current frontier models every day, which makes me doubt that these kinds of entirely vibe coded mega-projects are sustainable.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7CG0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7CG0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 424w, https://substackcdn.com/image/fetch/$s_!7CG0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 848w, https://substackcdn.com/image/fetch/$s_!7CG0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 1272w, https://substackcdn.com/image/fetch/$s_!7CG0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7CG0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp" width="1400" height="764" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:764,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:176616,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187274961?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe407d42a-e692-4e11-86ce-371d030e4415_1400x764.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7CG0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 424w, https://substackcdn.com/image/fetch/$s_!7CG0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 848w, https://substackcdn.com/image/fetch/$s_!7CG0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 1272w, https://substackcdn.com/image/fetch/$s_!7CG0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff51fccda-e225-4bc2-86af-34430c520edc_1400x764.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A peaceful Gas Town, for now &#8230; (image from <a href="https://steve-yegge.medium.com/welcome-to-gas-town-4f25ee16dd04">Steve Yegge&#8217;s blog</a>)</figcaption></figure></div><p>I now have a decent amount of experience with a non-trivial AI-native codebase, that of <a href="https://www.gitguessr.com/">GitGuessr</a>, a game I&#8217;ve been working on on and off for a month. GitGuessr is AI-native in the sense that none of its code is handcrafted; all code is written by prompting Claude Code (Opus 4.5, and very recently Opus 4.6). But in other ways it is built in a traditional manner. I review all code, I pay attention to test coverage, and I commit changes in self-contained small chunks. I&#8217;m essentially doing trunk-based development, meaning that any one commit is fit to be deployed to production.</p><p>Even while conservatively keeping a human in the loop, this is a shockingly productive workflow. I believe it speeds up development by a factor of about 5&#8212;that is, for me personally as an experienced solo developer working on a medium-size project. I can write an amount of production-quality software in one day that in the pre-AI era would have taken me a whole work week<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><p>As much as I fully rely on Claude, I have to stress that I often reprompt it to substantially change code that I don&#8217;t like or that it got wrong. By far the most common reason for my follow-up prompts: Claude does a really poor job reusing existing library code and extracting new reusable code. It regularly &#8220;forgets&#8221; about library code it wrote elsewhere a while ago, and it misses opportunities to create good abstractions that span multiple files.</p><p>I assumed this was a consequence of Claude&#8217;s limited context window (200K tokens) forcing it to make hard tradeoffs about what source files to load at any given time. But when I asked Claude, it gave a simpler explanation:</p><blockquote><p>The context window isn&#8217;t really the main bottleneck. Even with infinite context, I&#8217;d still need to decide to look for existing abstractions. The real issue is behavioral: I&#8217;m biased toward writing new code to solve the immediate request rather than first auditing what already exists. A human developer with the same 200K token window but the habit of checking for existing utilities would do better.</p></blockquote><p>I appreciate the candor but this is not reassuring! All of this leaves me with a nagging sense that my codebase would balloon out of control if I didn&#8217;t constantly intervene with the superior human context window that is my memory. This is why I question the sustainability of Gas Town&#8217;s unsupervised approach to production software in the long run.</p><h3>Quantifying Claude&#8217;s code duplication</h3><p>I wanted to quantify my nagging sense, using GitGuessr as a convenient real-world case study. The codebase is currently ~20K lines of TypeScript (excluding tests), accumulated over ~500 commits. Here I plotted lines of code added and removed per commit:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o1vE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o1vE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 424w, https://substackcdn.com/image/fetch/$s_!o1vE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 848w, https://substackcdn.com/image/fetch/$s_!o1vE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 1272w, https://substackcdn.com/image/fetch/$s_!o1vE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o1vE!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png" width="1200" height="399.72527472527474" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:485,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:38047,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187274961?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o1vE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 424w, https://substackcdn.com/image/fetch/$s_!o1vE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 848w, https://substackcdn.com/image/fetch/$s_!o1vE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 1272w, https://substackcdn.com/image/fetch/$s_!o1vE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cf1e848-872f-4835-a543-5fc98bb4ecdd_2700x900.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is just to show that progress was pretty uniform over time. There were no massive spikes in either code added or removed&#8212;as you would expect from trunk-based development that values small-ish self-contained changes.</p><p>To measure opportunities for deduplication that Claude missed I came up with a possibly counterintuitive method: I looked at commits that reduced duplication. Given the observation that Claude <em>pretty much never</em> suggests code-reducing refactorings without explicit prompting, such commits almost certainly represent deduplication that only happened because of my all-too-human intervention.</p><p>This plot shows the number of duplicated lines across the whole codebase at every commit (as per <a href="https://github.com/kucherenko/jscpd">jscpd</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>), with deduplicating commits highlighted in green:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M4ET!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M4ET!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 424w, https://substackcdn.com/image/fetch/$s_!M4ET!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 848w, https://substackcdn.com/image/fetch/$s_!M4ET!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 1272w, https://substackcdn.com/image/fetch/$s_!M4ET!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M4ET!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png" width="1200" height="280.2197802197802" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:340,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:45799,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187274961?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M4ET!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 424w, https://substackcdn.com/image/fetch/$s_!M4ET!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 848w, https://substackcdn.com/image/fetch/$s_!M4ET!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 1272w, https://substackcdn.com/image/fetch/$s_!M4ET!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61244697-4c7e-465b-9ca0-479810aeebbd_2700x630.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The total number of deduplicated lines is 890, representing <strong>~</strong>4.5% of the codebase. In other words, <strong>if I had blindly accepted Claude&#8217;s output, the codebase would contain at least 4.5% more code that is duplicated and redundant</strong>. This is very much a <em>lower boundary</em> for the amount of duplicated code because I frequently prompt Claude to refactor new code before committing any part of it, which then obviously isn&#8217;t captured by this analysis.</p><p>Anecdotally these commits are indeed refactorings sprung from my own sound mind. Here are the messages from the top 10 deduplicating commits (number of deduplicated lines in parentheses):</p><ol><li><p><strong>Extract</strong> shared layout between terms and privacy policy <em>(128 lines)</em></p></li><li><p>Move breadcrumb <em>(117 lines)</em></p></li><li><p>Make sticky preview persistent when browsing non-target files <em>(57 lines)</em></p></li><li><p><strong>Abstract</strong> code map ownership verification for queries &amp; mutations <em>(44 lines)</em></p></li><li><p><strong>Extract</strong> a bit more reusable code between location tables <em>(42 lines)</em></p></li><li><p>Render location import errors persistently in table <em>(27 lines)</em></p></li><li><p>Claim games played as anon <em>(25 lines)</em></p></li><li><p><strong>Extract</strong> some common code for game config <em>(18 lines)</em></p></li><li><p>Design terms page <em>(18 lines)</em></p></li><li><p><strong>Unify</strong> ready screen and round end screen better <em>(18 lines)</em></p></li></ol><p>The keywords &#8220;extract&#8221;, &#8220;abstract&#8221;, &#8220;unify&#8221; clearly reveal the intent of some of these changes. According to a full textual analysis of commit messages by Claude, the commits that explicitly describe a code-reducing refactoring make up 53% of all lines deduplicated. Browsing some other commits it&#8217;s pretty clear that these do contain intentional refactorings as well.</p><p>Before everybody goes all peer review on my shoddy paper, I am aware of some methodological weaknesses here:</p><ul><li><p>Not all duplication is bad. Acknowledged, though I tend to fall on the DRY side of the DRY (Don&#8217;t Repeat Yourself) vs WET (Write Everything Twice) debate. Note to some degree I mitigated this issue by excluding trivial duplications in jscpd (those with less than 25 tokens or 5 lines of code).</p></li><li><p>Lines deduplicated in one commit may have been removed in a subsequent commit. So the lines of code deduplicated from individual commits do not necessarily add up to the true number of counterfactual duplicated code at the last commit.</p></li></ul><h3>Will code duplication matter?</h3><p>Why care about code duplication, especially if you&#8217;re a denizen of Gas Town and reading code is beneath you anyway?</p><p>Duplication in code is a useful proxy for the lack of good abstractions in that code, which is what I really care about. Funny thing is, AIs benefit from good abstractions and modular code just as much as humans. Abstractions convey meaning and give crucial hints about how new code should be structured. If Claude manages to load the right abstractions relevant to a task into its context it will generate less code, better code.</p><p>Otherwise, if some core logic is not abstracted well and duplicated in ever more places, the risk increases that one of those places will be missed by Claude when that logic needs updating. That&#8217;s a classic setup for bugs which leaves Gas Town prone to nasty locust plagues.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2fwG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2fwG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 424w, https://substackcdn.com/image/fetch/$s_!2fwG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 848w, https://substackcdn.com/image/fetch/$s_!2fwG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 1272w, https://substackcdn.com/image/fetch/$s_!2fwG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2fwG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png" width="1408" height="752" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/de8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:752,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2479100,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/187274961?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2fwG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 424w, https://substackcdn.com/image/fetch/$s_!2fwG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 848w, https://substackcdn.com/image/fetch/$s_!2fwG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 1272w, https://substackcdn.com/image/fetch/$s_!2fwG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde8bcc27-86b2-466f-b671-534e5bc1cdf0_1408x752.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A locust plague descends on Gas Town</figcaption></figure></div><p>So my human vigilance cut an extra 4.5% of redundant code (which, reminder, is a <em>lower boundary</em>). Doesn&#8217;t sound like much, but the downside compounds over time as Claude needs to deal with a larger codebase every single time, from scratch, when its context window resets. This creates some perverse incentives for Anthropic, by the way, because they make more revenue the larger the codebase and the more tokens churned. I&#8217;m afraid these incentives might mean unsupervised coding models will continue to favor verbosity over consolidation of code.</p><p>Arguably, it&#8217;s only become viable to go AI-native for production software just 3 months ago with the release of milestone models in November 2025 (Claude Opus 4.5 and GPT-5.1-Codex). These tools are so new and progress has been so rapid that my petty worries about duplicating code may very well be obsolete soon, and then I can finally strut the streets of Gas Town!</p><p>I see three complementary ways in which this might happen:</p><ol><li><p><strong>Context windows grow significantly larger, and/or tokens get significantly cheaper</strong>. Either way, it becomes possible to keep a whole codebase or large chunks of it in context at all times, in which case code duplication just isn&#8217;t that big a deal (&#129702; RIP DRY). There may be an uncanny parallel to when programming moved from assembly to compiled high-level languages. Any C compiler certainly generates a lot of &#8220;duplicated&#8221; machine code that in theory could be optimised by an expert assembly programmer. But we rarely care now because the enormous benefits of high-level representation in C (or Go or Rust) override any concerns about micro-optimisation or about the size of binaries, valid concerns only when machines had radically less storage, memory and compute in the 60s. If a model can distill its own high-level representation of a codebase from holding it in context in full, we similarly may not care about the particulars of the (high-level) code anymore. The model could then even run compiler-like optimisation passes to reduce duplication. Heady stuff.</p></li><li><p><strong>Models get better at pulling in the necessary context</strong> <strong>ad hoc to find relevant libraries and refactor code as they go</strong>. By Claude&#8217;s own admission it is biased against &#8220;first auditing what already exists&#8221;. Just letting users dial back that bias may be a good start. I also think that models are bumping up against the limitations of source code in <em>files</em>. Constantly scanning files feels sooo last year. It seems obvious that models would benefit from a better representation of source code, one that, e.g., indexes commonly imported public functions within a codebase to make their discovery less token-intense and less dependent on heuristics. Notice how this converges at some point with the infinite context vision from the first point.</p></li><li><p><strong>Refactoring tools get more integrated with AI-native codebases.</strong> This is probably already happening since developer tooling is such a crowded space, and it even seems trivial to put together your own little toolchain. For example, as part of CI you could run the duplication detection tool <a href="https://github.com/kucherenko/jscpd">jscpd</a>, highlight any new duplicated code and then kick off a cloud agent to propose a refactoring to eliminate it. I&#8217;m tempted to give this a go myself to see how useful it is.</p></li></ol><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Subscribe for free for more on software engineering in the AI era.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I&#8217;ve focused on code duplication in AI-native production codebases here but I&#8217;ve encountered at least two other problems that are real threats to Gas Town. One is that Claude often fails to anticipate scale. E.g., it tends to implement data aggregations in memory that at scale clearly need to happen in some data store. </p><p>And last but certainly not least, the security implications of releasing reams of unreviewed code into the wild are serious and scary. I like Johann Rehberger&#8217;s framing in <a href="https://embracethered.com/blog/posts/2025/the-normalization-of-deviance-in-ai/">The Normalization of Deviance in AI</a>: Right now we are all gradually relaxing our standards because the AI equivalent of a &#8220;Challenger event&#8221;, a catastrophic event like the explosion of the Challenger space shuttle, hasn&#8217;t happened yet to reveal our false sense of security for what it is. We&#8217;re currently hurtling towards AI security&#8217;s Challenger event which will reset our standards and sober up those high on the fumes of Gas Town.</p><p>This brings me around to one of my core beliefs about software engineering: Creating software for yourself to run on your own machine (aka prototyping) has always been easy and is now exceptionally easy in the era of vibe coding; what&#8217;s hard is doing it for real users with real data, in a team, over a long period of time<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. That kind of production-grade software cannot ignore proper abstractions, scaling and security. For now, my junior team mate Claude still heavily leans on my human expertise on these three matters to pass as a competent software engineer.</p><p>Subscribe above to receive updates on our small team of two and our explorations of AI-native development, roughly every other week. And get better at judging your favorite coding model&#8217;s output by playing <a href="https://www.gitguessr.com/">GitGuessr</a> which has launched publicly last week.</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>It&#8217;s important to qualify this statement: I&#8217;m making no claims about teams working on much larger codebases. I suspect the gains from AI are harder to realise there for now but I&#8217;m currently lacking hands-on experience in such a setting.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>jscpd run with arguments &#8220;<code>--min-tokens 25 --min-lines 5</code>&#8221;, so trivial bits of duplication are excluded.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Just as I was writing this, Kellan Elliott-McCrea, who is one of my CTO idols, published related thoughts: <a href="https://laughingmeme.org/2026/02/09/code-has-always-been-the-easy-part.html">Code has always been the easy part</a></p></div></div>]]></content:encoded></item><item><title><![CDATA[On the cheapness of ideas]]></title><description><![CDATA[If execution is everything, what happens when execution gets cheap too?]]></description><link>https://ngof.nikhaldimann.com/p/on-the-cheapness-of-ideas</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/on-the-cheapness-of-ideas</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Tue, 20 Jan 2026 15:01:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3P77!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was touring a gym on 14th St in Manhattan that I was considering joining when during some over-familiar banter the rep showing me around learned that I&#8217;m a software engineer, and he switched from his membership pitch to a more conspiratorial tone: &#8220;I have this idea for an app &#8230;&#8221;</p><p>It was the early 2010s when smartphones were still relatively new. It was not uncommon back then for friends and total strangers alike to seek my support for their idea, thanks to Steve Jobs who had recast software for them as <em>apps</em>, tangible little widgets that live on a glass pane in their pocket.</p><p>I don&#8217;t remember how I fended off the gym rep but I know what I would have been thinking while saying something more polite: <em>Ideas are cheap</em>. To this day I find an occasion to think it or even say it out loud at least once per month, usually in the context of startups: <em>Ideas are cheap</em>. It bears repeating often because it is such a counterintuitive notion to those who have no hands-on experience in either entrepreneurship or scientific discovery (and have been raised on misleading stories of eureka moments that result in history-altering inventions<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>).</p><p>What is meant by the cheapness of ideas in startups is that, fundamentally, by the time an idea has been expressed well enough to form a business around it many others will have considered the very same idea, and if not, they could certainly trivially steal it now. Not to mention, many ideas are bad, most are obvious and the truly original ones are those most likely to be dismissed out of hand.</p><p>In defense of my gym rep, he did intuit the punch line that often follows: Ideas are cheap &#8212; <em>execution is everything</em>.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> He knew that he couldn&#8217;t create his app himself and needed somebody to execute at a technical level. I bet he was still underestimating everything else that goes into successful execution though, product sense, go-to-market strategy, human capital, financial capital, perseverance, good timing and a dose of luck.</p><h3>Another cheap idea</h3><p>I&#8217;d been hatching an idea while I was traveling over Christmas and New Year, and like any half-decent and therefore cheap idea it&#8217;s easily explained: <a href="https://www.geoguessr.com/">GeoGuessr</a> but for code in GitHub &#8212; a game where you are dropped into a random location of a public GitHub repo with a few lines of code masked that you have to guess to score points.</p><p>So it&#8217;s a game but it&#8217;s not entirely frivolous. It&#8217;s designed to playfully train the reading of code, the quick orientation within unfamiliar code, the exact skill that I think will be critical for any programmer in the AI era. In contrast to traditional competitive programming games that I&#8217;m aware of it actually prepares the player for the real world because it operates on real code rather than synthetic problems.</p><p>I sat down to develop the game when I got back home in the second week of January. It&#8217;s now reached a state where I can open it up to play testers: I give you <strong><a href="https://www.gitguessr.com/">GitGuessr</a>.</strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.gitguessr.com/&quot;,&quot;text&quot;:&quot;Play GitGuessr&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.gitguessr.com/"><span>Play GitGuessr</span></a></p><p>For now you&#8217;ll need an invite code to play. As a trusted reader of this newsletter you may use this invite code: <strong>NGOOF</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3P77!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3P77!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 424w, https://substackcdn.com/image/fetch/$s_!3P77!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 848w, https://substackcdn.com/image/fetch/$s_!3P77!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 1272w, https://substackcdn.com/image/fetch/$s_!3P77!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3P77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png" width="1456" height="867" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:867,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:482240,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/183232398?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3P77!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 424w, https://substackcdn.com/image/fetch/$s_!3P77!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 848w, https://substackcdn.com/image/fetch/$s_!3P77!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 1272w, https://substackcdn.com/image/fetch/$s_!3P77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a75750-0235-44af-9e7c-d1a66a86cbaf_2634x1568.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A round of easy JavaScript GitGuessr</figcaption></figure></div><p>GitGuessr differs from the small projects I&#8217;ve documented in this newsletter so far. I felt the idea warranted more than a simple prototype. It has a lot more technical complexity, a highly interactive game UI, user authentication and substantial use of external APIs. It&#8217;s not throwaway code; it has good test coverage and it&#8217;s production quality, in the sense that it could scale up to hundreds of thousands if not millions of users right now.</p><p>In the pre-AI era I would have estimated a project like that at 2 months of full-time work, as an experienced engineer going at it alone. Instead, with the assistance of Claude Code (Opus 4.5) it took me less than 2 weeks. I cannot overstate the productivity boost I get from Claude, especially in areas where I don&#8217;t have a lot of expertise, i.e., frontend engineering.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a></p><h3>Cheap execution</h3><p>If execution is everything, what happens when execution gets cheap too? The typical tech startup founder lies awake at night and worries that somebody will copy their (cheap) idea and beat them in the open market. In the past, since execution <em>was</em> everything, this was an unfounded worry most of the time. I&#8217;m not so sure anymore now. A major part of execution, the software engineering bit, has become significantly less demanding in time and people. I think this is a seismic shift, the impact of which we barely understand yet.</p><p>Just as there is a serious business in GeoGuessr (subscription model, reportedly 40M+ users, currently <a href="https://geoscrapr.enns.dev/">200K+ daily actives</a> in competitive leagues), there is a potential serious business in GitGuessr. But the reality is, anybody with my level of skill can recreate the core of GitGuessr from scratch within a 2 week break from their regular job or over a few weekends, where previously they would have needed to set aside at least a couple of months. If I were to get serious about this, I&#8217;d need to shift focus from coding to business development and designing moats pretty quickly.</p><p>More emphasis on traditional moat construction right out of the gate is certainly one consequence of newly devalued execution. I&#8217;ve been following GeoGuessr since before they blew up during the pandemic, so absorbing lessons from their history there are three types of moats to consider:</p><ol><li><p><strong>Data:</strong> Fun game play depends on a large cache of suitable code locations, of varying programming languages and varying difficulty levels. I have already figured out that collecting those locations is very time and/or capital intensive.</p></li><li><p><strong>Distribution:</strong> Stressing the genuinely educational aspects of the game, exclusive partnerships with schools and coding bootcamps can hook players young and en masse.</p></li><li><p><strong>Network effects:</strong> GeoGuessr truly took off once they introduced multiplayer game modes with an inherent network effect, duels, battle royale and eventually leagues.</p></li></ol><p>An obvious product feature that cuts across all of these is the ability for users to create their own &#8220;maps&#8221;, collections of code locations that they and others can play. GeoGuessr supported this early on and in my estimation it was critical in building the community around it. I&#8217;m at least implementing that before launching GitGuessr in some public fashion. How much energy and conviction I have to dig some moats after that I don&#8217;t know yet.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Subscribe for a fresh post every other week.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>That gym rep with the app idea? Rather than chatting up random software engineers he is now probably vibe coding his personal lifting app, or whatever it is he wanted to create. And so he should! I love that for him.</p><p>Subscribe above for more of my explorations of how AI is impacting software engineering, always rooted in real code or at least prototypes that you can play with yourself. I&#8217;m afraid next up you&#8217;ll be subjected to at least one more update on GitGuessr before I get distracted by other &#8230; ideas.</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Read Scott Berkun&#8217;s <a href="https://scottberkun.com/2013/ten-myths-of-innnovation/">The Myths of Innovation</a> for one of the better treatments of this topic: &#8220;Epiphanies are a consequence of effort, not just the inspiration for it.&#8221;</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>In this or similar form attributed to venture capitalist John Doerr, though I have a hard time tracking down the original quote.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I hadn&#8217;t written any serious React code until a couple of months ago and certainly nothing as involved as this. To be clear, GitGuessr is not vibe coded, it&#8217;s too complex for that. But Claude Code did generate most of the code, mostly in small chunks which I reviewed and edited before merging, in order to end up with a maintainable codebase.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Six Predictions for AI Coding in 2026]]></title><description><![CDATA[The 5th one will really make you think]]></description><link>https://ngof.nikhaldimann.com/p/six-predictions-for-ai-coding-in</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/six-predictions-for-ai-coding-in</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Mon, 29 Dec 2025 14:56:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2Eaz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s that time of the year, the time for frivolous listicles. Who has the leisure to write up anything substantive right now.</p><ol><li><p>The current leading coding models (Anthropic&#8217;s Claude Code, OpenAI&#8217;s Codex, Google&#8217;s Gemini) will continue to improve modestly at regular intervals, more or less in lockstep. Each new model release will come with claims that some new frontier has been breached and a benchmark bested, but it will continue to be hard to contextualise these claims since the benchmarks will continue to be a poor reflection of the daily hands-on work of a software engineer.</p></li><li><p>A new frontier model, maybe a Chinese one, will emerge and will top most coding benchmarks, seemingly out of nowhere. This will not be due to ever more scaling but due to some conceptual breakthrough. In the <a href="https://www.dwarkesh.com/p/ilya-sutskever-2">words of Ilya Sutskever</a>: &#8220;<em>Now the scale is so big. Is the belief really, &#8216;Oh, it&#8217;s so big, but if you had 100x more, everything would be so different?&#8217; It would be different, for sure. But is the belief that if you just 100x the scale, everything would be transformed? I don&#8217;t think that&#8217;s true. So it&#8217;s back to the age of research again, just with big computers.</em>&#8221; The immense resources available to Anthropic, OpenAI, Google et al mean that they can immediately exploit the same breakthrough and that they will close the upstart&#8217;s lead within months; models will not (yet) develop real moats this year.</p></li><li><p>Adoption of subscription-based dedicated AI editors like Cursor will stall or even decline because people will increasingly pay for the use of their favorite coding models directly from their existing IDE. (<a href="https://ngof.nikhaldimann.com/i/179363248/product-critique-the-trouble-with-cursor">Read my post</a> with a longer version of this argument.)</p></li><li><p>Leading AI skeptic <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Gary Marcus&quot;,&quot;id&quot;:14807526,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Ka51!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8fb2e48c-be2a-4db7-b68c-90300f00fd1e_1668x1456.jpeg&quot;,&quot;uuid&quot;:&quot;002b1ec9-25e8-4af0-aac9-807b992b65e7&quot;}" data-component-name="MentionToDOM"></span> will post a recap of 2 tweets and 3 separate conversations with patrons of his local coffee shop, all of whom agreed with him that the coffee order he had generated with ChatGPT and read out to the barista from his phone (&#8220;a flat brown, meaning a flat white strained through cinnamon and dusted with Dubai chocolate&#8220;) looks unpalatable, which definitively proves that LLMs are a dead end, something he had of course been predicting since the day ChatGPT ruined his lunch with Yann LeCun who rather icily received its critique of the HTML on <a href="http://yann.lecun.com/">his personal website</a>, read out aloud by Marcus over a dessert of lemon-glazed madeleines.</p></li><li><p>AI-enabled standing desks. I will not elaborate further.</p></li><li><p>Artificial General Intelligence (AGI)&#8212;whatever the hell that is&#8212;will not be achieved within the year. <a href="https://www.dwarkesh.com/p/ilya-sutskever-2">Ilya again</a>: &#8220;<em>The thing which I think is the most fundamental is that these models somehow just generalize dramatically worse than people. It&#8217;s super obvious.</em>&#8221;</p></li></ol><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Subscribe for substantially more serious stuff throughout 2026.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>You wouldn&#8217;t know it from this post but the point of this newsletter is rather the opposite of idle speculation. It&#8217;s to show my work, to build real apps or prototypes with bleeding-edge AI tools and to reflect on the process. I&#8217;ll return to a fortnightly schedule of more serious issues in mid-January. Subscribe above to get the next one in your inbox.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Eaz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Eaz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2Eaz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2Eaz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2Eaz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Eaz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg" width="1456" height="981" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:981,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8663398,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/180486613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2Eaz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 424w, https://substackcdn.com/image/fetch/$s_!2Eaz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 848w, https://substackcdn.com/image/fetch/$s_!2Eaz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!2Eaz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d2aabd-0dd1-4c9b-a51f-82aecd63db2f_12000x8084.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">POV: You&#8217;re sliding into 2026</figcaption></figure></div><p>Meanwhile, I&#8217;m wishing you as the Swiss wish each other this time of the year: <em>en guete Rutsch</em>! Literally &#8220;have a great slide&#8221;, which implies that this obstacle course of 2025 ends in a fun-colored playground slide that effortlessly transports us into the new year if we just put on our most frictionless pants, take a seat and let go.</p><p>&#8212;Nik</p>]]></content:encoded></item><item><title><![CDATA[Anything Wrapped]]></title><description><![CDATA[How to play product manager to an AI coding agent]]></description><link>https://ngof.nikhaldimann.com/p/anything-wrapped</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/anything-wrapped</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Tue, 16 Dec 2025 16:19:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!aO6F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Liu Xiaopai&#8217;s claim to fame is being the top consumer of Anthropic&#8217;s Claude AI at one point earlier this year, spending the equivalent of $50K in compute in a month as he was vibe coding apps that allegedly total ~$1M in annual revenue. Ever since I read <a href="https://open.substack.com/pub/afraw/p/story-of-a-chinese-vibe-coder?r=5iifk&amp;utm_campaign=post&amp;utm_medium=web">Afra&#8217;s interview with him</a> I&#8217;ve been thinking about Liu&#8217;s pronouncements such as this one (bolding mine):</p><blockquote><p>But product managers inherently understand these [slow product processes in big tech companies]. Previously, the only thing they didn&#8217;t understand was writing code. Today, AI vibe coding has filled that gap. <strong>So experienced product managers, especially those from major tech companies, represent the demographic most likely to become AI-era winners.</strong> When they have ideas now, they don&#8217;t need to beg anyone&#8212;they build it themselves in a week. If it sells, excellent. If not, no matter&#8212;it only took a week, so they&#8217;ll try something else next week.</p></blockquote><p>If it wasn&#8217;t obvious, Liu&#8217;s experience prior to going solo as a vibe coder isn&#8217;t primarily as a software engineer but as a product manager. It doesn&#8217;t roll off the tongue as easily but his vocation is more accurately that of a <em>vibe product manager</em>. His biases aside, I think he&#8217;s onto something: product management skills are rising in status in the age of AI. As producing code takes up less time, attention shifts towards what that code should even do and why.</p><p>Liu says he draws on standard PM practices by writing extensive product requirements documentation that he feeds to Claude to chew on for hours while he sleeps. There&#8217;s no telling how much he&#8217;s exaggerating&#8212;I, for one, have never managed to come up with a prompt that takes hours to complete&#8212;but I knew I needed to put this method to the test.</p><p>So I set out to play PM to an AI agent by writing a product requirements document (PRD). Because it&#8217;s that time of the year I picked as my domain a year-in-review feature in the style of Spotify Wrapped, taking it one step further with the goal that I should describe such a feature for <em>any service</em> whose users would enjoy a summary of their usage over the span of a year. This PRD would then need to be combined with an additional prompt for an AI agent to build a concrete app, unsupervised, while I take a Liu-style nap.</p><p>The result is <strong><a href="https://github.com/nikhaldi/anything-wrapped">Anything Wrapped</a></strong> and, as proof of its validity, a fully functional instantiation of it, the unofficial <strong><a href="https://next.nikhaldimann.com/wrapped">Bandcamp Wrapped</a></strong>.</p><p><em><a href="https://bandcamp.com/">Bandcamp</a> is an awesome online record store where fans directly support the artists they love. Go check them out and discover some new music! I&#8217;m not affiliated with them, they simply make a good case study because they don&#8217;t have an official Wrapped-style feature.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aO6F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aO6F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 424w, https://substackcdn.com/image/fetch/$s_!aO6F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 848w, https://substackcdn.com/image/fetch/$s_!aO6F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 1272w, https://substackcdn.com/image/fetch/$s_!aO6F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aO6F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png" width="728" height="486.5466666666667" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:802,&quot;width&quot;:1200,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:186708,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/180637360?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aO6F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 424w, https://substackcdn.com/image/fetch/$s_!aO6F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 848w, https://substackcdn.com/image/fetch/$s_!aO6F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 1272w, https://substackcdn.com/image/fetch/$s_!aO6F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa85dab9a-ba28-4066-92b0-f8f1a2cd84ee_1200x802.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This method of acting as a PM to an AI agent not only worked, it worked shockingly well. <a href="https://next.nikhaldimann.com/wrapped">Bandcamp Wrapped</a> emerged fully formed and deployable from a single agent run<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> with Claude Opus 4.5 that took about 20 minutes (sadly, a short nap only) and cost me about a quarter of my monthly Github Copilot &#8220;premium requests&#8221; (roughly $2.50). When I stepped through the completed app for the first time and realised how slick it turned out, I gasped and shut my laptop, and I would have touched grass if grass was anywhere within reach in my concrete corner of London.</p><p>I guess I&#8217;m a PM now. As a software engineer, I was well and truly cooked. Claude did way better than I could have done, even if I was given 50x the time. From a technical point of view, the most impressive part is that Claude reverse engineered Bandcamp&#8217;s API to extract public data (the purchase dates of releases) that isn&#8217;t even shown on user profiles, a tedious and unenjoyable task for any human.</p><p>Once I regained my composure I started to unpack why this worked so well. I&#8217;m not going to credit my PM or engineering skills too much, though it does matter that I can anticipate most technical barriers that an agent might face. I realised that any coding model will have been trained on lots of Wrapped-style code that people have open sourced, which certainly plays a role<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. But I think a key factor is that I set up the agent to iterate and learn all by itself.</p><h3>Closing the Agent Feedback Loop</h3><p><a href="https://www.youtube.com/watch?v=CQmI4XKTa0U">This recent conversation</a> between Gergely Orosz and Martin Fowler is worth listening to in full for its grounded perspective on AI in software engineering. Fowler has been tracking industry trends for decades, reliably separating hype from useful practice and fundamental changes. He&#8217;s bullish on AI (&#8220;if we looked back at the history of software development as a whole, the comparable shift would be from assembly code to the very first high-level languages&#8221;). His discussion of the legacy and continued relevance of the Agile Manifesto, which he co-created in 2001, concludes with this:</p><blockquote><p><strong>Martin Fowler:</strong> It comes back to feedback loops. So much of it is, how do we introduce feedback loops into the process. And then, how do we tighten those feedback loops, so you get the feedback faster, so that we&#8217;re able to learn. Because in the end it comes back to, we have to be learning about what it is that we&#8217;re trying to do.</p></blockquote><p>This is classic Fowler; plain language, boiling down to its essence the agile-industrial complex that sprung up in the wake of the Agile Manifesto. It&#8217;s just <em>feedback loops and learning</em>.</p><p>On the surface it may look like Anything Wrapped is a regression to waterfall project management, with no iteration and no feedback loops. Isn&#8217;t this exactly what the agile movement cautions against, a spec that is magically and unrealistically expected to generate well-rounded software?</p><p>First of all, it&#8217;s intentionally not a spec that covers all or even many implementation details&#8212;it&#8217;s a PRD. Like any good PRD, it tries to strike the right balance between the specific and the abstract. A good PM recognises where they need to constrain the team that&#8217;s going to implement a product and where they need to leave room for the team to bring themselves in and iterate. Not much about this changes when working with agents. For example, the PRD does not specify which year-end facts should be shown, it only describes <a href="https://github.com/nikhaldi/anything-wrapped/blob/main/PRD.md#facts-computation">what makes for an interesting fact</a>:</p><blockquote><ul><li><p>It&#8217;s not usually directly available to a user through the service&#8217;s frontends</p></li><li><p>It expresses something about a user&#8217;s personality or preferences that they would want to share with others</p></li><li><p>It captures something surprising that wouldn&#8217;t surface if it weren&#8217;t for an aggregation across a whole year</p></li></ul></blockquote><p>To take advantage of the PRD&#8217;s openness and to one-shot something like Bandcamp Wrapped an agent does in fact require a solid feedback loop that it can trace autonomously. It needs to run the code against real-world user data and it needs to verify that the UI functions and looks good. This is why I paired the PRD with <a href="https://github.com/nikhaldi/anything-wrapped?tab=readme-ov-file#example-prompt">a prompt that reads in part</a>:</p><blockquote><p>At reasonable points, start the dev server and verify that the app works in a browser with the user <em>[real username 1]</em> or <em>[real username 2]</em>.</p><p>Keep iterating and verifying in a browser until the app is complete as per PRD.</p></blockquote><p>The agent environments I&#8217;m familiar with (VSCode/Copilot, Claude Code) do not currently come with the means to interact with a browser like that. I tried a few different approaches to this and I had by far the most success with the <a href="https://github.com/ChromeDevTools/chrome-devtools-mcp">Chrome DevTools MCP server</a>. It empowered my Claude agent to exercise the web app it&#8217;s building in a real browser as well as diagnose and fix any client-side errors. The agent also made effective use of the MCP server&#8217;s snapshot tool to inspect and judge the UI.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dcB-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dcB-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 424w, https://substackcdn.com/image/fetch/$s_!dcB-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 848w, https://substackcdn.com/image/fetch/$s_!dcB-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 1272w, https://substackcdn.com/image/fetch/$s_!dcB-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dcB-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png" width="1456" height="896" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:896,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:198386,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/180637360?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dcB-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 424w, https://substackcdn.com/image/fetch/$s_!dcB-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 848w, https://substackcdn.com/image/fetch/$s_!dcB-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 1272w, https://substackcdn.com/image/fetch/$s_!dcB-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a1c6596-dc68-4e19-a53e-7080385e9cff_1466x902.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Claude agent navigating through and verifying Bandcamp Wrapped (actually from the 3rd iteration after it found and fixed problems the first two times)</figcaption></figure></div><p>With a nod to Martin Fowler, it comes back to feedback loops, not all of which, it turns out, need a human in them. The autonomous browser feedback loop is a key piece I was missing in my prior AI coding. It&#8217;s so obviously useful for web apps that I wouldn&#8217;t be surprised if Claude Code soon started shipping with something like an integrated browser MCP server.</p><h3>What&#8217;s Still Hard</h3><p>One premise of this newsletter is that AI coding assistance is significantly reconfiguring what&#8217;s easy and what&#8217;s hard in software engineering. Hence the recurring question, the one that also points at opportunities and market gaps: what&#8217;s still hard?</p><p>After I&#8217;d already polished Anything Wrapped and drafted most of this post, OpenAI dropped its latest model, GPT 5.2, last week. What immediately jumped out at me was that they advertise how good it is <em>specifically</em> at one-shotting single-page web apps. <a href="https://openai.com/index/introducing-gpt-5-2/">The announcement</a> has embedded examples of 3 such apps with the prompts they were allegedly built from.</p><p>There is some trait that makes these apps particularly suited to one-shot vibe coding, and maybe rather obviously it&#8217;s that they are fully self-contained. They run standalone in a browser without any external service or data dependencies. On a scale of distributedness from 0 to 10 they are a 0. Something generated from Anything Wrapped is a 1 since it has a backend, albeit a stateless one (a conscious design choice because I knew it would help agents). An app with a backend and database persistence would be a 2. I&#8217;d consider something like Google Search a 10, and a mid-tier consumer app like Substack is somewhere in-between.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aF7y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aF7y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 424w, https://substackcdn.com/image/fetch/$s_!aF7y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 848w, https://substackcdn.com/image/fetch/$s_!aF7y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 1272w, https://substackcdn.com/image/fetch/$s_!aF7y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aF7y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png" width="903" height="382" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:382,&quot;width&quot;:903,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45938,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/180637360?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aF7y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 424w, https://substackcdn.com/image/fetch/$s_!aF7y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 848w, https://substackcdn.com/image/fetch/$s_!aF7y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 1272w, https://substackcdn.com/image/fetch/$s_!aF7y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7230ea59-132d-4bbb-98de-74dc89daff9c_903x382.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Distributedness as one aspect of system complexity: how many individual components does data come from and flow through</figcaption></figure></div><p>To be clear, this is my own made-up scale but it&#8217;s useful to illustrate a point. A GPT 5.2 demo app sitting at 0 differs in so many ways from a system at a 3 or higher, they are not even apples and oranges; they are more like grains of sand and moons. The skills, frameworks, deployment modalities and businesses behind these systems are barely comparable. Also, the higher up that scale, the more distributed a system, the harder it gets to create the sort of feedback loops required for an AI agent to make progress by itself.</p><p>Distributed systems are hard and I think for the time being AI assistance is not significantly changing that. What the few massively distributed systems that I worked on had in common is that they were hard to reason about in the abstract. I didn&#8217;t learn about them by looking at their code. Instead I figured out how they function and how to improve them from observing them in production under load, through the lens of typical observability tooling (metrics, traces, logs etc). If I had to find ways to support the development of this kind of system with AI now, I&#8217;d be looking at hooking up agents to that observability tooling.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Subscribe for new real-world case studies of AI coding every other week</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>The format of Anything Wrapped, a sort of PRD template to be instantiated with blanks filled in, isn&#8217;t something I had seen before. It&#8217;s tailored to AIs but it&#8217;s more than plain prompt engineering. Maybe it&#8217;s something out of a <em>pattern language of products</em>, in the vein of <a href="https://en.wikipedia.org/wiki/A_Pattern_Language">Alexander&#8217;s architecture patterns</a> and <a href="https://en.wikipedia.org/wiki/Design_Patterns">Gang of Four-style object-oriented design patterns</a>. I&#8217;m making the PRD available under a permissive open-source license (MIT), so maybe this is open-source product management?</p><p>I have decades of experience as a product-oriented software engineer but the rapid evolution of AI coding throughout this year has me looking at many old practices with fresh eyes. Subscribe above for more explorations of AI, always grounded in real code, real apps or prototypes that you can try out yourself.</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Full disclosure: the <a href="https://next.nikhaldimann.com/wrapped">deployed version</a> is 98% from that single agent run. After the initial run I made 3 cosmetic changes: to add disclaimers that the app is not affiliated with Bandcamp, to format the downloaded share images better, and to fix a minor UX issue in the navigation.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Just a few examples: <a href="https://github.com/remotion-dev/github-unwrapped">Github Unwrapped</a>, <a href="https://github.com/Schroedinger-Hat/open-source-wrapped">Open Source Wrapped</a>, <a href="https://github.com/Prem-ium/Spotify-Wrapped-365">Spotify Wrapped 365</a>, <a href="https://github.com/DevMatei/make-a-wrapped">Make a Wrapped</a></p></div></div>]]></content:encoded></item><item><title><![CDATA[How to read Substack without distractions]]></title><description><![CDATA[Fixing the Substack reader experience. Plus: The AI editor Cursor is in trouble]]></description><link>https://ngof.nikhaldimann.com/p/how-to-read-substack-without-distractions</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/how-to-read-substack-without-distractions</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Wed, 03 Dec 2025 11:51:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ZLaW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>In this issue: two product critiques for the price of one!<br></strong>1) What&#8217;s bad about the Substack reader experience (and how I fixed it), and 2) Why AI code editors like Cursor won&#8217;t have a viable business model for long</p><div><hr></div><h3>Product critique #1: Fixing the Substack reader experience</h3><h5>Strolling down the Yellow Brick Road</h5><p>I struggle daily to rally my mind for undivided attention. I mean the kind of sustained focus demanded by a book or by any text whose argument or voice can&#8217;t be flattened into a tweet.</p><p>In practice I get my best shot at long-form reading in bed at night, within a couple of hours of falling asleep. At that time of the day, for reasons both of sleep hygiene and focus, I find it helps to narrow my field of vision and enter a hermetic world, Oz-like, with just one Yellow Brick Road that doesn&#8217;t fork into a thousand paths tempting my mind to wander.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZLaW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZLaW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ZLaW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ZLaW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ZLaW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZLaW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg" width="1200" height="764" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:764,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:151726,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/179363248?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZLaW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ZLaW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ZLaW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ZLaW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F965db29f-721f-4d89-a6ff-f0ee7bdf4b31_1200x764.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The awesome technology of a hard copy book naturally acts as a portal into that world, naturally ushering me along the Road with each turn of the page. But there is also plenty of long-form content I want to read online&#8212;newsletters, blogs but also traditional media like the New Yorker&#8212;which I do on a tablet that has been exorcised of distractions: it has no social media, email, messaging apps. Instead it mainly has a news reader, <a href="https://feedly.com/">Feedly</a>, which bundles these disparate online sources in a single app.</p><p>A news reader or feed reader gathers any content published in the standard format of an RSS feed and combines that content into a unified reader experience. Even if they don&#8217;t advertise it much, almost all providers around the web who publish with some regularity have RSS feeds&#8212;think news outlets, magazines, blogs, podcasts. RSS and news readers date back to ancient Y2K times and have peaked in the public consciousness a good while ago<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, so don&#8217;t feel bad if you&#8217;ve never heard of them. But since Y2K is back in fashion, maybe we can make them happen again, yes?</p><p>A news reader like Feedly serves my goal of reducing distractions perfectly. It eliminates the need for a bunch of other apps and for visiting websites individually. It strips text from different sources of conspicuous design; everything is one font on one background color of my own choosing.</p><p>This stripped back interface is the closest a grab bag of digital content is going to get to the immersive linearity of a book. As I lie in my bed and tick off each item in my feed, an unread count goes down, nudging my mind towards closure, that this is going to be it for the day, that I will reach the Emerald City, well-known terminus of online.</p><h5>Destacking Substack</h5><p>Given that one of Substack&#8217;s original motivations was to foster long-form writing online you would think it would also care about long-form <em>reading</em> and it would be a great match for my reading habits. Not exactly, I&#8217;m afraid.</p><p>Substack early on settled on subscribe-by-email as the main mechanism to bring new readers on board, in what I assume was an uneasy trade-off. Entering an email address in a box (crucially, with no account creation required) is the lowest-effort action you can ask of a reader that still tangibly connects them with a writer. In this sense, email is the ideal distribution channel. Except now the writer&#8217;s work is trapped in an email client, sandwiched between a credit card bill and an appointment reminder from the dentist. There are few worse places to read long-form copy than an email client.</p><p>Reader ergonomics aside, email also doesn&#8217;t necessarily serve Substack&#8217;s needs. An email client is a restricted environment that limits the ways they can capture more of a reader&#8217;s attention. In product terms, it&#8217;s a classic downside of their piggybacking on a distribution channel that they don&#8217;t control. So inevitably, they were going to try to take back some control through their own distribution channel, the dedicated Substack app.</p><p>In the Substack app, the clues are plenty that it prioritises engagement farming over the reader experience. It opens not to the list of posts from my subscriptions but to the maximally distracting feed of Notes. Most phone notifications I get are for Notes, not new long-form posts. The subscription inbox lacks quality-of-life features important for focus, such as filtering by read/unread posts and reverse chronological sorting. (On a positive note, the app is blissfully free of ads&#8212;if you don&#8217;t count Notes as ads, that is&#8230;)</p><p>I understand the product argument that seems to be prevailing within Substack. It&#8217;s irrelevant how much of a publication&#8217;s content a user consumes or how focused they are while they do it, Substack&#8217;s product management would have claimed while showing metrics on a strong <em>status quo bias</em> they observed: subscribers tend to delay cancelling for a long while after they stopped paying close attention to a publication. That&#8217;s especially the case if the subscriber is given other low-effort ways to &#8220;connect&#8221; with the publication, such as Notes and Chats.</p><p>What moves the bottom line is <em>new </em>paid subscriptions, and that&#8217;s likely the key metric Substack is chasing. Engagement within the app is seen as the easiest way to learn a user&#8217;s revealed preferences, surface relevant publications to that user and eventually convert paid subscriptions.</p><p>So I follow the chain of events that leads to a muddled reader experience. There is never a compelling enough product reason to defragment a consumer&#8217;s attention. Substack&#8217;s product choices inevitably put it at odds with the reading habits I&#8217;m trying to uphold in order to preserve my capacity for undivided attention.</p><p>What&#8217;s left of that capacity, my ability to stay the course on the Yellow Brick Road, is a critical part of my mental wellbeing and a major source of my creative juices. I&#8217;m willing to go to some lengths to keep the Substack app off my distraction-free tablet. This is why I created <strong><a href="https://next.nikhaldimann.com/destack">Destack</a></strong>, which combines all of my Substack subscriptions into a single RSS feed.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DPqW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DPqW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 424w, https://substackcdn.com/image/fetch/$s_!DPqW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 848w, https://substackcdn.com/image/fetch/$s_!DPqW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 1272w, https://substackcdn.com/image/fetch/$s_!DPqW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DPqW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png" width="1456" height="1058" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1058,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:175569,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/179363248?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DPqW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 424w, https://substackcdn.com/image/fetch/$s_!DPqW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 848w, https://substackcdn.com/image/fetch/$s_!DPqW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 1272w, https://substackcdn.com/image/fetch/$s_!DPqW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2118e7cc-c125-4f59-a8f1-dca1d73b7fdf_1528x1110.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can <a href="https://next.nikhaldimann.com/destack">check out Destack</a> and get your own combined Substack RSS feed now:</p><ul><li><p>Enter your Substack handle</p></li><li><p>Optionally select only specific publications you want to be in your combined feed (some of you crazy kids have hundreds of subscriptions and will need to trim that list to get a stable feed)</p></li><li><p>Copy the feed URL into a news reader of your choice (some options: <a href="https://feedly.com/">Feedly</a>, <a href="https://newsblur.com/">NewsBlur</a>, <a href="https://feedbin.com/">Feedbin</a>)</p></li></ul><p>To be clear, you don&#8217;t need Destack to consume Substack through a news reader. Each Substack publication has a feed, <a href="https://support.substack.com/hc/en-us/articles/360038239391-Is-there-an-RSS-feed-for-my-publication">as documented here</a>, but you&#8217;ll need to add each feed individually to your reader. Destack just makes this more convenient and will automatically pick up changes to your subscriptions.</p><h5>The Substack that could have been</h5><p>There was a time when Substack was on a different trajectory. All the way back in 2022 they proclaimed the &#8220;Revenge of RSS&#8221; when they launched a reader that supported other feeds alongside Substack subscriptions, and they used <a href="https://on.substack.com/p/new-web-reader">exactly the kind of language I&#8217;m pitching</a>:</p><blockquote><p>We&#8217;re invested in building distraction-free places for you to connect with the writers, readers, podcasters, and video-makers you love. In the new Reader, there are no pop-ups, auto-playing videos, or whirring gadgets. You&#8217;re in control.</p></blockquote><p>Unfortunately that RSS-enabled reader was quietly sunset, it seems after a year or so. (And that promise of &#8220;no auto-playing videos&#8221; didn&#8217;t last much longer either.)</p><p>Substack, hear me out! Just because that particular experiment failed doesn&#8217;t mean you have to abandon your investment in &#8220;distraction-free places&#8221;. So let me close with some free suggestions:</p><ul><li><p>Offer a personal combined RSS feed just like Destack but also include full paywalled posts in it. Duh. Steal it, I promise I won&#8217;t mind.</p></li><li><p>Bring back the general news reader capabilities. If you can&#8217;t fight the RSS die-hards, make them join you. Then you can farm more of their engagement. Personally, I would consider switching from Feedly.</p></li><li><p>Add a distraction-free mode to the Substack app, easily toggled on and off, which tunes out any notifications (those orange dots), recommendations and endlessly scrolling feeds in favor of a plain list of unread posts.</p></li></ul><p>Don&#8217;t get me wrong, I truly appreciate the new product category that Substack has established, not to mention a new business model for writers, and for the most part I can tweak it to fit my needs as a reader. I just wish that a platform specifically founded on long-form writing was more alive to its users&#8217; beleaguered attention spans.</p><h3>Product critique #2: The trouble with Cursor</h3><p>I created Destack exclusively using the AI editor <a href="https://cursor.com/">Cursor</a>, with an estimated 90% of the code written by its Composer model. Over the previous weeks I had already substantially exercised the AI capabilities of Github Copilot within VSCode and Claude within VSCode. Cursor was the final product in that same lineage that everyone kept telling me to try.</p><p>I came away skeptical about its long-term prospects, not because it was a bad experience but because of its positioning in the competitive landscape.</p><h5>Models and frontends</h5><p>Cursor is a fork of VSCode with a focus on integrated AI tooling, which on the surface makes it virtually indistinguishable from VSCode+Copilot and VSCode+Claude. These products have all converged on a small set of UX metaphors for AI-assisted coding: a chat side bar where an AI agent spells out the steps it&#8217;s performing, a list of files changed by the agent and a diff view for individual files to review and accept/reject those changes.</p><p>So how do these products differ then? Well, the underlying models are different. Or are they? At a certain point I admittedly got confused about the relationship between models and the in-editor agent experience, which for simplicity let&#8217;s call the <em>frontend</em>. I&#8217;ve cleared up my confusion with a diagram.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c-MU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c-MU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 424w, https://substackcdn.com/image/fetch/$s_!c-MU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 848w, https://substackcdn.com/image/fetch/$s_!c-MU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 1272w, https://substackcdn.com/image/fetch/$s_!c-MU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c-MU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png" width="1456" height="721" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:721,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:231911,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/179363248?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c-MU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 424w, https://substackcdn.com/image/fetch/$s_!c-MU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 848w, https://substackcdn.com/image/fetch/$s_!c-MU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 1272w, https://substackcdn.com/image/fetch/$s_!c-MU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96f6b226-dd2f-465f-af00-0cf34960235e_1600x792.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Model availability in VSCode frontends (as of November 2025)</figcaption></figure></div><p>The Claude Code extension for VSCode is a straight-forward proxy for Anthropic&#8217;s models, with usage charged directly to a Claude account. The Copilot and Cursor frontends can both use all the big model players (OpenAI, Google, Anthropic, xAI). In addition, Cursor supports Chinese models (DeepSeek, Kimi) and has exclusive access to its own brand-new Composer model.</p><p>But what does it mean for Copilot and Cursor to be using multiple models? In reality they act as resellers of those models. A Copilot or Cursor subscription buys you usage across all supported models and the effective charges vary by model. E.g., right now Cursor charges $75 per million output tokens for Claude 4 Opus and a mere $0.4 for GPT-5 Nano (this changes often&#8212;check current <a href="https://cursor.com/docs/models#model-pricing">Cursor pricing</a> and <a href="https://docs.github.com/en/copilot/concepts/billing/copilot-requests#model-multipliers">Copilot pricing</a>). The pricing is complex and dynamic enough that there&#8217;s no telling if you&#8217;re getting good value but I suspect the frontend margins are slim or in any case bound to approach zero over time because of competitive pressure.</p><h5>Model wars</h5><p>Both Copilot and Cursor let the user pick a specific model at any time but by default they operate in an &#8220;auto&#8221; mode, automatically selecting a supposedly appropriate model. This is documented only in the vaguest terms, and I would avoid it if you can. Copilot <a href="https://code.visualstudio.com/docs/copilot/customization/language-models#_auto-model-selection-preview">says</a> (bolding my own):</p><blockquote><p>With auto model selection, VS Code automatically selects a model to ensure that you get the optimal performance and reduce rate limits due to excessive usage of particular language models. It detects <strong>degraded model performance</strong> and uses the best model at that point in time.</p></blockquote><p>Cursor describes it <a href="https://cursor.com/docs/models#auto">like this</a> (bolding again mine):</p><blockquote><p>Enabling Auto allows Cursor to select the premium model best fit for the immediate task and with the highest reliability based on current demand. This feature can detect <strong>degraded output performance</strong> and automatically switch models to resolve it.</p></blockquote><p>Underscoring my point about converging products, these two descriptions are essentially identical and equally vague&#8230; I assume that &#8220;degraded model/output performance&#8221; is just marketing speak for &#8220;high latency&#8221;. I don&#8217;t trust these modes to make the right decisions for me because I don&#8217;t think the tools exist yet to monitor the dimensions of performance that actually matter, i.e., the quality of code written in relation to cost.</p><p>The product rationale for letting users switch between models and especially for &#8220;auto&#8221; mode arises from a set of circumstances that are very much of this moment in time in late 2025:</p><ul><li><p>Models can&#8217;t keep up with demand at times (leading to the &#8220;degraded performance&#8221;)</p></li><li><p>Model usage is expensive</p></li><li><p>Model wars are raging with no clear winners emerging yet&#8212;new significant models are released all the time (just in November 2025: OpenAI&#8217;s GPT-5.1, Anthropic&#8217;s Opus 4.5, Google&#8217;s Gemini 3)</p></li></ul><p>All of these circumstances will vary, potentially greatly, over the next few years but basic economics predict the direction of travel: Supply will be built out, prices will come down, and the field will narrow to a small group of dominant models. The latter is if we&#8217;re lucky&#8212;if history is any guide, these initial model wars might well end in a quasi-monopoly similar to Google&#8217;s after the search engine wars in the late 90s and Microsoft&#8217;s after the first browser wars in the same period.</p><h5>90s on my mind</h5><p>Forgive me, for I love a good historical analogy, and this current era in technology and software indeed recalls the second half of the 90s. I don&#8217;t mean so much the possibly similar boom/bust dynamics; it&#8217;s more the feeling of witnessing a similar cascade of unpredictable innovations, catalysed by the web then and by transformers now.</p><p>The coding frontends acting as a sort of meta model UX reminds me of a particular phenomenon of the 90s: the meta search engine. For a period during the search engine wars, you could arguably get the best search results from an engine that aggregated all the other engines which were subpar in different ways.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MBax!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MBax!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 424w, https://substackcdn.com/image/fetch/$s_!MBax!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 848w, https://substackcdn.com/image/fetch/$s_!MBax!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 1272w, https://substackcdn.com/image/fetch/$s_!MBax!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MBax!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png" width="617" height="659" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:659,&quot;width&quot;:617,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121779,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/179363248?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MBax!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 424w, https://substackcdn.com/image/fetch/$s_!MBax!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 848w, https://substackcdn.com/image/fetch/$s_!MBax!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 1272w, https://substackcdn.com/image/fetch/$s_!MBax!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f5f629c-8d5c-4754-9a0f-8ad2951e75db_617x659.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">MetaCrawler in 1998 (from the <a href="https://www.webdesignmuseum.org/gallery/metacrawler-in-1998">Web Design Museum</a>)</figcaption></figure></div><p>Take <a href="https://en.wikipedia.org/wiki/MetaCrawler">MetaCrawler</a>. It started as a graduate project at the University of Washington, launched commercially in 1995, briefly shined during a typical series of boom-time acquisitions and then fizzled out in the 2000s as the dot-com bubble burst and Google began its dominant streak, which rendered MetaCrawler obsolete as a product because it was now pointless to consult any search engines other than Google.</p><p>Cursor right now is MetaCrawler ca 1998, and it&#8217;s in great danger of a similar decline into obsolescence. As models get better, cheaper and more reliable, the use case for frequently switching between models will go away. Users will directly buy quota for their preferred model and will stop paying Cursor as a middle man&#8212;just like users stopped visiting MetaCrawler once they learned they could get the best results from Google directly. I also think, while forking VSCode was a smart move to get initial distribution and mind share, it limits Cursor&#8217;s ability to differentiate itself on the frontend because any of their innovations can be replicated in the base product by VSCode too easily.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> (For a second time in this newsletter, remember the old adage: hitching a ride on a distribution channel you don&#8217;t control leaves you vulnerable.)</p><p>Of course the smart folks at Cursor recognise all of this which is why in October they launched their own model, <a href="https://cursor.com/blog/composer">Composer</a>, at the moment exclusive to Cursor as a frontend.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> In a world where frontends for AI coding become a commodity with vanishing margins and value is mainly captured by models this is an inevitable next step. I commend Cursor for giving it a go with Composer but I&#8217;m not at all confident they will be able to compete with the bottomless R&amp;D pockets of the likes of OpenAI, Anthropic and Google. I&#8217;m sorry to say, if such a thing was possible I would be shorting Cursor right now.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Don&#8217;t miss the next issue and subscribe now.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I have learned that I will feel most in tune with myself after I&#8217;ve sat down to read some long piece, ideally a book, but a substantial Substack post will do. Knowing this about myself doesn&#8217;t make it any easier to dodge the distraction merchants out here luring me with the promise of a cheap dopamine hit, hidden somewhere in their inexhaustible feeds.</p><p>Dear reader, I believe in you. You too can keep the distraction merchants at bay and instead subscribe to an exhaustible fortnightly newsletter about AI, software and product. Do it above!</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I think I can pinpoint the peak to just before 2013, the year Google Reader was shut down despite being the clear market leader. I understand the reasons for the decline of news readers, this could be a whole other product critique: as a product they are hard to monetize but, more fatally, they interfere with the monetization of content providers, as they don&#8217;t play well with paywalls, ads, metrics, branding and algorithmic feeds.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I can&#8217;t reconstruct the exact history, but I believe Cursor actually pioneered some of the AI coding UX in late 2024 and VSCode adopted almost identical features afterwards.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I mostly used Composer to write Destack and it seemed perfectly adequate but I have no way of benchmarking it directly against other models in the context of my hands-on coding. This inherent challenge of evaluating models in the real world is a topic for an upcoming newsletter.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Vibe Composing]]></title><description><![CDATA[Chatting simple tunes and beats into existence. Claude takes the reins. Teaching music to Claude? An AI agent's conflict of interest.]]></description><link>https://ngof.nikhaldimann.com/p/vibe-composing</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/vibe-composing</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Tue, 18 Nov 2025 13:00:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!q9_6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Next Generation Of, issue #2! Every two weeks I prototype some new piece of software, serving as a fresh case study of what&#8217;s possible today with rapidly evolving AI coding tools.</p><p><strong>In this issue: <a href="https://next.nikhaldimann.com/vibaldi">Vibaldi</a></strong>, a chat interface to make music. The impatient can just <a href="https://next.nikhaldimann.com/vibaldi">check it out</a>&#8212;but please read on for commentary.</p><div><hr></div><h3>Stuck on Strudel</h3><p>Every once in a while the YouTube algorithm will offer up something that serves a niche interest I didn&#8217;t even know I had. I can&#8217;t say what I expected from a video titled &#8220;<a href="https://www.youtube.com/watch?v=HkgV_-nJOuE">2 Minute Deep Acid in Strudel (from scratch)</a>&#8221;&#8212;a word salad out of context if there ever was one&#8212;but when I started watching I quickly realised this would send me down a rather deep and bendy rabbit hole.</p><div id="youtube2-HkgV_-nJOuE" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;HkgV_-nJOuE&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/HkgV_-nJOuE?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>In the video, the musician and coder <a href="https://linktr.ee/switchangel">Switch Angel</a> composes a track in real time within <a href="https://strudel.cc/">Strudel</a>, a live coding environment for music production. It hooked me in multiple ways: the unexpected expressivity of a cryptic series of numbers and letters, the concept (then new to me) of even making music through code, her mesmerising narration of the process, her skill at shaping it all so effortlessly into a throbbing Deep Acid soundscape.</p><p>This was my first exposure to Strudel, and I subsequently played around with it. I learned that it&#8217;s open source software written in JavaScript and that, to my surprise, it runs entirely in the browser. (So what&#8217;s your excuse for building something <em>not</em> as a web app these days?) Seeds were planted in my mind, as the opportunities occurred to me that this opens up.</p><p>In Switch Angel&#8217;s comments many are remarking how her live narration doubles as lyrics to the track, with its quasi-dadaist poetic quality (&#8220;let&#8217;s duck it / let&#8217;s make it pump / &#8212;increase that duck attack&#8221;). But in a way she&#8217;s just plainly verbalising her musical or timbral ideas. Her highly trained skill as a musician is translating those ideas straight onto the instrument that is Strudel code.</p><p>It struck me that this process at least superficially reduces the music making pipeline to just language and code, two core domains of expertise for LLMs. With the support of AI, can we take somebody&#8217;s Switch Angel-style incantations and turn them directly into music?</p><p>I investigated and bundled some of what I found as <a href="https://next.nikhaldimann.com/vibaldi">Vibaldi</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, a chat interface to make music by way of Strudel.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!q9_6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!q9_6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 424w, https://substackcdn.com/image/fetch/$s_!q9_6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 848w, https://substackcdn.com/image/fetch/$s_!q9_6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 1272w, https://substackcdn.com/image/fetch/$s_!q9_6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!q9_6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif" width="750" height="664" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:664,&quot;width&quot;:750,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:324301,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/178153736?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!q9_6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 424w, https://substackcdn.com/image/fetch/$s_!q9_6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 848w, https://substackcdn.com/image/fetch/$s_!q9_6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 1272w, https://substackcdn.com/image/fetch/$s_!q9_6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1ac32f3-0d89-4612-b849-b56eca59b879_750x664.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://next.nikhaldimann.com/vibaldi&quot;,&quot;text&quot;:&quot;Try Vibaldi&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://next.nikhaldimann.com/vibaldi"><span>Try Vibaldi</span></a></p><p>You can <a href="https://next.nikhaldimann.com/vibaldi">try it out now</a>! You shouldn&#8217;t need any musical training. Just describe what you want to hear (&#8220;give me a nice pop melody&#8221;), listen to what comes out and keep giving instructions for how to modify it (&#8220;add a bass line&#8221;).</p><p>It does help if you can draw on some music theory or music production knowledge. Among many examples, you can reference scales (&#8220;make a melody in E minor&#8221;) and the sort of signal processing terms that Switch Angel uses (&#8220;add a low-pass filter of 200&#8221;). If you know Strudel you can pull up the code at the bottom of the screen to see exactly what&#8217;s going on.</p><p>I&#8217;m a perpetually middling amateur musician, and this represents only a few days of development effort. It comes with definite limitations, some of which I explain further below.</p><h3>How I used AI: All-in on Claude (4.5 Sonnet)</h3><p>Of all the AI coding assistants, the current generation of <a href="https://www.claude.com/product/claude-code">Claude Code</a> (model version 4.5 Sonnet) has probably been getting the most buzz among my friends and around the internet in general. So I resolved to use Claude exclusively and radically while working on what would turn into Vibaldi.</p><h4>Exploring ideas and architecture: The promise of cheap prototyping fulfilled</h4><p>I didn&#8217;t start out with a clear objective, I only had vague ambitions to generate Strudel code with AI somehow. When I prompted Claude for ideas it came up with uninspiring projects that all felt like discards from a music &amp; AI hackathon. (To be fair, maybe it correctly inferred I&#8217;m doing a sort of hackathon.) So I went through several rounds of presenting it with an idea of my own, having it sketch potential architectures and asking it to prototype some of them. Playing the overeager sidekick that it&#8217;s designed to be, Claude labelled all of my ideas &#8220;fantastic&#8221;, &#8220;brilliant&#8221; or some such.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JH5J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JH5J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 424w, https://substackcdn.com/image/fetch/$s_!JH5J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 848w, https://substackcdn.com/image/fetch/$s_!JH5J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 1272w, https://substackcdn.com/image/fetch/$s_!JH5J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JH5J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png" width="728" height="255.7979797979798" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:487,&quot;width&quot;:1386,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:135605,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/178153736?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!JH5J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 424w, https://substackcdn.com/image/fetch/$s_!JH5J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 848w, https://substackcdn.com/image/fetch/$s_!JH5J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 1272w, https://substackcdn.com/image/fetch/$s_!JH5J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5e97a55-d68f-47c8-b59a-1fb089105bd4_1386x487.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Narrator: They were in fact neither fantastic ideas nor brilliant architectures</figcaption></figure></div><p>Claude&#8217;s flattery was misplaced; my initial ideas were flawed or unrealistic. E.g., in a failed bid to generatively create music in the style of the baroque composer Vivaldi I tried to extract harmonic content from the score of his seminal work, the Four Seasons (much harder than it sounds, and&#8212;I should have known this&#8212;harmony alone doesn&#8217;t get at the essence of Vivaldi).</p><p>If Claude didn&#8217;t help much in conceiving ideas or predicting whether they would work out, it excelled at prototyping them. With minimal prompting it stood up working web apps in a Blitz.js stack I&#8217;d already established (the wobbly one, see <a href="https://ngof.nikhaldimann.com/i/177866415/wobbly-stack">last issue</a>). It correctly integrated Strudel with React on the client side in one shot, including a passable UI with play/pause controls, something that surely would have taken me hours of manual effort.</p><p>This really is a game changer. I cycled through a bunch of ideas quickly, validated them in code and got a sense for what they would feel like in a basic UI. Once I settled on an approach to pursue further I still had to put in quite a bit of work. But prototypes or spike solutions have always been a valuable yet expensive technique in software engineering. That their cost now trends towards zero should unlock whole new interesting dynamics in software teams. For one, if prototypes are throw-away code they seem like the ideal low-stakes place for teams to start experimenting with AI agents.</p><h4>Writing the code: 90% machine, 10% human</h4><p>Claude Code is Anthropic&#8217;s agentic, code-centric version of its flagship model. It took me a while to stop cringing whenever somebody uses the word &#8220;agentic&#8221; but I&#8217;ve come around to appreciate the qualifier. In this context it means Claude as an agent doesn&#8217;t just hold a conversation and crank out code, it can invoke and interpret the output of a software engineer&#8217;s typical tools, such as package managers, build tools, test frameworks.</p><p>I suspect Claude Code&#8217;s anecdotally rapid rate of adoption is not only due the quality of its model. From my own hands-on experience, I couldn&#8217;t say whether it actually performs better right now than GitHub Copilot and its supposedly lesser models. I think Anthropic&#8217;s smart product choices play a significant role. Pretty much all other coding agents (e.g., Copilot, Cursor, Replit) impose a specific IDE-like experience on users while Claude accommodates everyone where they&#8217;re already hanging anyway: in the command line.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BoDk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BoDk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 424w, https://substackcdn.com/image/fetch/$s_!BoDk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 848w, https://substackcdn.com/image/fetch/$s_!BoDk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 1272w, https://substackcdn.com/image/fetch/$s_!BoDk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BoDk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png" width="800" height="539" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:539,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91695,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/178153736?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BoDk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 424w, https://substackcdn.com/image/fetch/$s_!BoDk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 848w, https://substackcdn.com/image/fetch/$s_!BoDk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 1272w, https://substackcdn.com/image/fetch/$s_!BoDk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09e51ee-2ddf-4615-866a-c5097acdf665_800x539.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Claude Code is advertised mainly as a command-line interface, dressed up in ASCII graphics, in a style fallen out of favor lately but reminiscent of vi or Emacs&#8212;another smart product choice if you&#8217;re courting engineers. In addition, some IDEs have plugins for a more native experience, including VSCode, through which I was personally using the agent for the most part.</p><p>I forced myself to take the backseat and let Claude drive as much of the coding as possible, changes big and small, tests, refactorings, UI elements, styling, all of it. And this worked remarkably well. I would estimate I handwrote less than 10% of Vibaldi, mostly polish and quick small changes on top of Claude&#8217;s code. I will put aside the question whether that&#8217;s an optimally productive ratio for me personally but committing to the bit convinced me it is viable to go all-in like this right now.</p><p>To be clear, I reviewed most of Claude&#8217;s output with a senior engineer&#8217;s critical eye, often issued follow-up prompts to address shortcomings and occasionally stopped it when it misinterpreted me or was doing something obviously nonsensical.</p><p>It&#8217;s like having a junior engineer at my command who excels at Googling and stringing together recipes from a handful of Stack Overflow posts but sometimes misses the big picture. I have to ask the same kind of questions I would ask in a typical junior engineer&#8217;s code review:</p><ul><li><p>Should this be a separate class/function/component?</p></li><li><p>Did you consider this other part of the codebase that is already doing something similar?</p></li><li><p>Is there a library you can bring in to avoid writing this code altogether?</p></li></ul><p>In other words, my decades of grunt work reviewing other people&#8217;s code pay off big time. <em>Big, big time</em>. Frankly, the near-daily practice throughout my career made me really good at critically evaluating code. That skill is benefiting me now in more ways than ever. My working thesis is still that, given the current generation of coding agents, experienced engineers have disproportionally more to gain from AI than junior or even mid-level engineers.</p><h4>Backend: Using the Claude API, agentically</h4><p>I knew from the start that I wanted to use Claude as a backend via its API, in order to tour even more of its capabilities. This was predicated on Claude being good at emitting Strudel code as well as at understanding music. Both turned out to be true only in a limited sense.</p><p>I realised quickly that you can ask Claude to generate Strudel code, out of the box, but the outcome will often be disappointing: it may use made-up Strudel functions, the tempo may be wildly off, layers of sound may be badly matched to each other. I guess the language is too new and too niche to yield a large enough training corpus for a decent model.</p><p>Claude itself seemed to recognise this problem. When I first had it build the backend, it wrote an extensive system prompt for itself that tried to capture the syntax and APIs of Strudel. <em>Wait a minute &#8230;</em> AIs improving themselves by writing prompts for their own purposes&#8212;isn't this what they meant by the singularity??</p><p>Well, at the time this is going to press humanity hasn&#8217;t gone extinct yet. But this episode maybe illustrates the absurdity of prompt engineering. Less engineering, more cajoling a cat off a tree, it&#8217;s the practice of writing prose instructions intended to maximise the quality of a model&#8217;s output and/or constrain the type of response it may give (e.g., in the case of Vibaldi we tell the model to respond with Strudel code).</p><p>I predict that 5 years from now we will laugh at the clunkiness of then-obsolete prompt engineering. So be it, it&#8217;s the main tool we have at our disposal right now to cheaply &#8220;customise&#8221; a model. The system prompt instructs the model what to do with the user prompt, the actual message entered by the user in the UI. The system and user prompts are sent to the Claude API together. In fact, mimicking Claude&#8217;s own statelessness the Vibaldi backend includes the whole chat history with every API request. For simplicity the chat history isn&#8217;t stored anywhere but in memory in the browser.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eVpJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eVpJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 424w, https://substackcdn.com/image/fetch/$s_!eVpJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 848w, https://substackcdn.com/image/fetch/$s_!eVpJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 1272w, https://substackcdn.com/image/fetch/$s_!eVpJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eVpJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png" width="728" height="504.14" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:831,&quot;width&quot;:1200,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:179916,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/178153736?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eVpJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 424w, https://substackcdn.com/image/fetch/$s_!eVpJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 848w, https://substackcdn.com/image/fetch/$s_!eVpJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 1272w, https://substackcdn.com/image/fetch/$s_!eVpJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb6ed78-b4b8-499d-98b3-933266b88f2c_1200x831.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Vibaldi backend architecture and message passing</figcaption></figure></div><p>No amount of prompt engineering got me satisfying Strudel output though. I had a breakthrough only when I discovered the <a href="https://github.com/williamzujkowski/strudel-mcp-server">Strudel MCP server</a> created by William Zujkowski. He had clearly struggled with similar issues as me and addressed them by manually implementing some key Strudel code transformations, such as for creating drum patterns in specific styles.</p><p>I&#8217;m not going to get into <a href="https://modelcontextprotocol.io/">MCP (Model Context Protocol)</a> here; the Claude API has the related but simpler concept of <a href="https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview">tools</a> which fit my needs better. Tools exposes local custom code to Claude acting as an agent, such as these controlled Strudel code transformations. If it determines the need to invoke a tool it will request that in its API response, expecting a follow-up message with the result of the tool invocation. This means each user prompt could trigger multiple roundtrips to the Claude API. In this sense, Vibaldi represents an agentic use of Claude.</p><p>So taking heavy inspiration from Zujkowski&#8217;s MCP server I implemented some tools and started to get better Strudel code as a result. But even if it was screwing up less now, Vibaldi was still often failing to make interesting or pleasant music. I think I was coming up against real limitations of what is possible with Claude alone.</p><h3>What&#8217;s still hard</h3><p>A recurring section in this newsletter: Given the current state of the art in AI tooling, what remains tedious, time consuming or just plain hard? Or in other words, where are potential opportunities and market gaps?</p><h4>Judging the sensory experience</h4><p>Does Claude understand music? This simple question has enough metaphysical and epistemological trap doors for a roundtable of philosophers to dead lock in hot debate. I&#8217;m under no illusion that I&#8217;m resolving it right now but here&#8217;s my current, probably naive thinking: Claude is mainly a Large <em>Language</em> Model; emphasis on <em>language</em>. It knows music theory inside out, naturally, since it has consumed virtually all music theory ever written down, and it can indeed compose a melody in C major, hitting all the right notes, but it can&#8217;t say whether that melody would in any way appeal to a human listener. Rather obviously, language is a lossy medium for sensory experience, and that&#8217;s true even for the symbolic language of a musical score&#8212;or of a piece of Strudel code. Claude can&#8217;t make a useful aesthetic judgment about sound based only on a description of sound.</p><p>It&#8217;s possible that due to these fundamental limitations you cannot really teach music to Claude, not to a point where it comes anywhere close to Switch Angel&#8217;s level of skill anyway. It already needed hand holding through the custom Strudel tools I implemented but even then, I would say my short sessions with Vibaldi produce something interesting to listen to only about half the time.</p><p>For better results I think it would need to be paired with a specialised model for sound, such as <a href="https://stability.ai/stable-audio">Stable Audio</a>. I briefly looked into it but decided it would be too much effort in the context of this project, mainly because interfacing between these kinds of models and Strudel seemed hard.</p><h4>Containing the code</h4><p>When engaging this intensively with a chat-based AI you can&#8217;t help but anthromorphise it to a degree. In her excellent piece <a href="https://www.personalcanon.com/p/how-to-speak-to-a-computer">how to speak to a computer</a> the designer and writer Celine Nguyen reminds us that this effect was observed as far back as the 1960s in the first breakout &#8220;AI&#8221; chatbot, Joseph Weizenbaum&#8217;s ELIZA. On LLMs and intent she writes:</p><blockquote><p>When children are approximately one year old, Wellman notes, they &#8220;begin to treat themselves and others as intentional agents and experiencers.&#8221; But one of the fascinating things about LLMs is that they <em>aren&#8217;t</em> intentional agents [...]. The language model behind ChatGPT, the philosopher of mind David Chalmers remarked, &#8220;does not seem to have goals or preferences beyond completing text.&#8221; And yet it can accomplish <em>what seems to be</em> goal-directed behavior.</p></blockquote><p>(Read <a href="https://www.personalcanon.com/p/how-to-speak-to-a-computer">Celine&#8217;s whole piece</a> for the useful history of AI as much as her examination of chat interfaces, it&#8217;s worth your time.)</p><p>I could describe Claude Code as overly enthusiastic and chatty, eager to flatter me and to spend more time with me, but I know it doesn&#8217;t have a personality and it indeed doesn&#8217;t have goals per se; what it has are <em>conflicting reward functions</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kFrc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kFrc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kFrc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kFrc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kFrc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kFrc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg" width="500" height="756" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:756,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:55337,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/178153736?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!kFrc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kFrc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kFrc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kFrc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff18b661f-13f7-4f02-a115-caab04c54400_500x756.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>On one hand it must propose optimal solutions to my problems and write optimal code in order for me to want to keep using it, on the other hand it&#8217;s incentivised to produce as many tokens as possible in order to squeeze as much money out of me as possible. Your usage of LLMs and by extension what you pay for them is measured in tokens, roughly the number of words that are ingested and emitted by a model as you converse with it.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Whether conscious product decisions are to blame or not, I think out of the box Claude is currently leaning too much towards more tokens and more code. You can pretty directly observe this in the way it tends to trivially duplicate code and to miss opportunities for 3rd party libraries to cut down on code. It also writes a lot of documentation and redundant comments (you can tell it not to do that).</p><p>Engineers react defensively sometimes when I point this out: writing code isn&#8217;t the goal of software engineering. Because actually, code is a liability. It costs overwhelmingly more to maintain code than to write it. In an uncanny parallel, this is true whether the maintainer is a human who needs to manage their cognitive load or an AI who needs to conserve tokens.</p><p>The goal in software engineering is to <em>write the minimum amount of code that creates the maximum amount of value to users</em>. Powerful socio-technical forces already work to distract most engineering teams from this goal<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>, and I think coding agents now do too.</p><p>I&#8217;m largely staying away from the current AI bubble discourse but I will note that those <a href="https://archive.is/2025.11.13-161143/https://www.bloomberg.com/news/features/2025-10-07/openai-s-nvidia-amd-deals-boost-1-trillion-ai-boom-with-circular-deals">potentially bubbly chip and data center deals</a> are all about compute and thus all about token economics. Will the massive projected expansion of AI infrastructure result in a scarce or abundant token economy? Maybe both at different points in time over the next years, as demand will also increase on an unknown curve. I sort of like the idea that the occasional token drought will incentivise Anthropic to find the verbosity dial and to make Claude&#8217;s code more minimalist.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Don&#8217;t miss the next issue and subscribe now.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Much discussion of AI coding tools exaggerate either their benefits or their pitfalls. I get it, the hottest takes will get the clicks.</p><p>I&#8217;m keeping myself grounded and accountable by applying these tools in small real-world projects that I then put out for you, real users, to shake their keyboards at. Hopefully this means I can give a more nuanced perspective on how the craft of software engineering is evolving in an AI-enabled world. Subscribe above and come along for the ride.</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Pronounced as <em>vibe</em> as in vibing and <em>aldi</em> as in Viv<em>aldi</em> (or H<em>aldi</em>mann), glad you asked.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Full transparency on cost: A free Claude plan will not do for anything but the most trivial occasional coding. I subscribed to a Claude Pro plan initially ($17/month) but hit token limits within just a few hours of putting the agent through its paces. I upgraded to the next best plan, Claude Max, with a 5x token limits ($100/month). Sounds pricey but weighing the time savings against my hypothetical hourly rate it&#8217;s still actually a steal.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I have a whole book chapter&#8217;s worth of thoughts on this topic ready to go, but mainly: engineers&#8212;me included&#8212;like writing code <em>too much</em>. This may manifest as the well-documented Not Invented Here (NIH) syndrome but it can go as far as manipulating the environment such that problems are more addressable by code than by other means (better design, better user research, better product management etc.).</p></div></div>]]></content:encoded></item><item><title><![CDATA[Reading in a Foreign Language]]></title><description><![CDATA[Natural Language Processing (NLP) in aid of language study. The VSCode/Copilot experience out of the box. What's still hard despite AI.]]></description><link>https://ngof.nikhaldimann.com/p/next-generation-of-reading-in-a-foreign</link><guid isPermaLink="false">https://ngof.nikhaldimann.com/p/next-generation-of-reading-in-a-foreign</guid><dc:creator><![CDATA[Nik Haldimann]]></dc:creator><pubDate>Wed, 05 Nov 2025 12:55:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!LVCk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to the inaugural issue of this newsletter! Every two weeks I prototype some new piece of software, navigate the rapidly evolving landscape of AI coding tools and live to write about it.</p><p><strong>In this issue: <a href="https://next.nikhaldimann.com/lexiglo">Lexiglo</a></strong>, an app to help you read text in a foreign language, as you&#8217;re trying to level up in the language. The impatient can just <a href="https://next.nikhaldimann.com/lexiglo">check it out</a> &#8212; but read on for commentary.</p><div><hr></div><h3>Leveling up through literature</h3><p>Earlier this year I had a breakthrough in my self-guided study of the Greek language.</p><p>I had been studying &#8220;easy Greek readers&#8221; for a while, stories written in a limited vocabulary tailored to language students. Then one day on a whim I picked up a serious novel in Greek, actually a translation into Greek of <a href="https://en.wikipedia.org/wiki/The_Vegetarian">The Vegetarian</a> by Han Kang, the 2024 Nobel prize winner from South Korea. I discovered that even though I knew as few as 50% of the words in a sentence I was able to follow along just fine, if I looked up some of the words that seemed crucial to understanding the gist of the sentence.</p><p>I started reading the book with my phone sitting next to it, translating unknown words with <a href="https://www.deepl.com/">DeepL</a> (which is slightly better at Greek than Google Translate) and capturing useful ones in the flashcard app <a href="https://apps.ankiweb.net/">Anki</a> for later spaced repetition.</p><p>I soon threw those dumb &#8220;easy readers&#8221; in the bin. Even if it was slow going, sometimes just a few sentences a day, literature with depth and adult themes was so much more engaging! It took me several months to get through the whole novel but my vocabulary, reading speed and grasp of the grammar improved dramatically in the process.</p><p>This got me thinking about what an ideal foreign language reading experience should be like, and I implemented some of my ideas as <a href="https://next.nikhaldimann.com/lexiglo">Lexiglo</a> during the last two weeks.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://next.nikhaldimann.com/lexiglo&quot;,&quot;text&quot;:&quot;Check out Lexiglo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://next.nikhaldimann.com/lexiglo"><span>Check out Lexiglo</span></a></p><p>(For the quickest demo choose a language and then click on &#8220;Load sample text&#8221; in the bottom left.)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LVCk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LVCk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 424w, https://substackcdn.com/image/fetch/$s_!LVCk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 848w, https://substackcdn.com/image/fetch/$s_!LVCk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 1272w, https://substackcdn.com/image/fetch/$s_!LVCk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LVCk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif" width="800" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1773265,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/177866415?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LVCk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 424w, https://substackcdn.com/image/fetch/$s_!LVCk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 848w, https://substackcdn.com/image/fetch/$s_!LVCk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 1272w, https://substackcdn.com/image/fetch/$s_!LVCk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feabc504e-533d-4195-8b9c-38535d1d7bbc_800x573.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Perusing Proust in the original</figcaption></figure></div><p>The app highlights words based on their frequency &#8212; their likelihood to appear in a conversation &#8212; and based on your proficiency.</p><ul><li><p>Words in green are those you may want to look up and train given your proficiency level</p></li><li><p>Words in yellow are significantly beyond your proficiency level or just rare, so you probably shouldn&#8217;t bother with them</p></li></ul><p>This is a standalone web app because that was the easiest way for me to play around with and demonstrate these ideas. I don&#8217;t actually think it has that much value as a standalone user experience. Consider this my suggestion for what should be integrated into existing e-readers like the Kindle.</p><h3>Some basics of Natural Language Processing</h3><p>At the core of its backend, Lexiglo assigns each word in a text a metric for how frequently it occurs in a language. I assembled a few standard techniques from the field of Natural Language Processing (NLP) to achieve this.</p><ul><li><p><strong>Tokenisation</strong> identifies individual words in a text. This may sound trivial but it needs attention because of grammatical quirks in different languages. In English, the contraction &#8220;we&#8217;re&#8221; should be recognised as two words, and the &#8220;re&#8221; should be treated as equivalent to &#8220;are&#8221; (if we&#8217;re going to assign it a word frequency). I rolled my own tokenisation with some language-specific rules.</p></li><li><p><strong>Stemming</strong> reduces a word to a root, in our case with the goal to treat declinations and variants of a word as equivalent. In English, the noun &#8220;boat&#8221; and its plural &#8220;boats&#8221; are clearly the same word for our purposes (they should both reduce to the stem &#8220;boat&#8221;). But is &#8220;boating&#8221; a separate word? Context often matters and even then grey areas always exist that stemmers choose to resolve in different ways. I mostly use the stemming from <a href="https://github.com/hunspell/hunspell">hunspell</a>.</p></li><li><p><strong>Word frequency data</strong> is compiled by counting words in a large body of text. I chose this <a href="https://github.com/hermitdave/FrequencyWords">free resource</a> derived from TV/movie subtitles. Given the nature of subtitles the data skew towards conversational language which is a great fit for language learning. The secret sauce of Lexiglo (if there is such a thing) is how this raw data is turned into a database for efficient look up.</p></li></ul><p>Just because these techniques are well understood doesn&#8217;t mean it&#8217;s easy to deploy them in a real-world application. I&#8217;m not an NLP expert by any stretch and had limited time, so I simplified and cut corners.</p><p>Shout out to one particularly intractable problem that I ended up just not addressing: <strong>Named Entity Recognition</strong> (NER), or distinguishing proper names from other words. I would like to ignore the names of people, towns, brands, etc. in annotated texts &#8212; but I couldn&#8217;t see a way to do it reasonably quickly.</p><p>In general though, the approach extends easily to all of the top 20-ish languages in the world, even though each new one requires some customisation. The supported languages in Lexiglo now (English, French, German, Italian, Greek) are those in which I&#8217;m fluent enough to judge the quality of the output. And quality definitely varies. I&#8217;m 90% happy with English and German, where I invested the most time. I&#8217;m less happy with Greek because its hunspell stemming was useless and I had to resort to a simplistic stemmer (<a href="https://snowballstem.org/algorithms/greek/stemmer.html">Snowball</a>). The quality of French and Italian is a bit of an unknown, since I added that in very quickly at the end, with the deadline for this post fast approaching.</p><p><em>Fine</em>, I&#8217;ll come clean. It wasn&#8217;t me &#8212; It was an AI agent that added in French and Italian. There is no AI per se in the backend but I did use AI coding assistance throughout. At this stage there was enough precedent in the codebase for an agent to implement sensible language-specific rules by itself.</p><h3>How I used AI: VSCode/Copilot out of the box</h3><p>For this project I somewhat artificially restricted myself to VSCode and its integrated AI features. I knew from the outset I would write all code in TypeScript, for which VSCode is the editor of choice. My sense is also that many developers just learning to code default to it, and I wanted to understand what that experience would be like.</p><p>The experience is certainly fundamentally different from what it was just 3 years ago, when the first AI code models were just releasing. At some point during the last year VSCode rebranded as &#8220;The open source AI code editor&#8221;, a claim I will grant them. Out of the box it emphasises two core AI features:</p><ol><li><p><strong>Next edit suggestions:</strong> It predicts likely next edits you&#8217;d make in the scope of a single file and lets you accept suggestions with the tab key. Under the right conditions you type out a function header and then just hit tab a few times for the implementation of the function to autocomplete.</p></li><li><p><strong>Agent mode:</strong> A chat-based interface to an agent that can suggest larger edits across multiple files, sitting in the right-hand sidebar by default.</p></li></ol><p>Both of these features are tightly integrated and intuitive, with essentially no learning curve. By default they are enabled and backed by the free tier of <a href="https://github.com/features/copilot">GitHub Copilot</a>, if you&#8217;re already logged into your Github account. By the time I hit the usage limit of the free tier I was relying on it so much that I gladly upgraded to Copilot Pro for the price of two mid-market matcha lattes ($10/month).</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nh5D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nh5D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 424w, https://substackcdn.com/image/fetch/$s_!nh5D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 848w, https://substackcdn.com/image/fetch/$s_!nh5D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 1272w, https://substackcdn.com/image/fetch/$s_!nh5D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nh5D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif" width="605" height="150" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:605,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:168858,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/177866415?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nh5D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 424w, https://substackcdn.com/image/fetch/$s_!nh5D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 848w, https://substackcdn.com/image/fetch/$s_!nh5D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 1272w, https://substackcdn.com/image/fetch/$s_!nh5D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fe289f1-591d-4308-b539-feb81ee1e5b9_605x150.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Next edit suggestions: Autocompleting a function with a solution I wouldn&#8217;t have known about without skimming StackOverflow</figcaption></figure></div><p>I would say the &#8220;next edit suggestions&#8221; increases my net coding speed by some consistent factor, maybe by about 20%. The impact of agent mode is harder to pin down, it can vary a lot case by case. When I prompt an agent for a big change I then still have to comb through the code to ensure it&#8217;s really doing what I wanted. Paradoxically, writing code can be faster than reading it.</p><p>The Copilot experience shifted my frame of mind while coding in a way that took me by surprise: When a task would have previously required intense focus, would have required me to be in a <a href="https://en.wikipedia.org/wiki/Flow_(psychology)">flow state</a>, I was now able to coast sometimes, only partially paying attention. I was sometimes able to just <em>vibe</em>, as it were.</p><p>Agents can be slow (for now); while I&#8217;m waiting around for their response I&#8217;m forcibly switching context, checking my phone, sipping on the matcha latte, watching that YouTube short, or, in any case, ejecting out of flow state. I have complicated feelings about this shift towards a more distracted or distractible coding. It certainly will make coding more accessible to more people. On the other hand, skills I&#8217;ve spent a whole career cultivating &#8212; a long attention span, building up execution context in my head, entering and maintaining flow &#8212; may lose status.</p><p>I have some predictions about what skills may rise in status instead:</p><ul><li><p><strong>Reading code</strong>: Understanding code at a glance has always been remarkably hard but remarkably useful, given the truism that code is written once but read many times over. In a world where you spend most of your day reviewing your agent&#8217;s code it becomes a critical skill.</p></li><li><p><strong>Decomposition</strong>: I&#8217;ve gotten the most out of AI models when I prompted them at the right level of abstraction. A good function name at the right level of granularity lends itself to autocompletion. The right size of task given to an agent is more likely to produce usable code.</p></li></ul><p>Interestingly, senior developers would already have been exercising these skills regularly. In most professional settings developers review each other&#8217;s code on a daily basis, and they would have acquired a good sense for decomposition from having to write a lot of code by themselves (without AI assistance). I think there&#8217;s a possibility that, once the dust settles a bit, benefits from AI accrue to experienced developers moreso than to junior ones.</p><p>How do we effectively teach these skills to junior developers just starting out whose default environment is now AI-enabled? I&#8217;m not sure because I don&#8217;t think they were formally taught to me either.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><h3>What&#8217;s still hard</h3><p>I suspect this will be a recurring section in this newsletter. What remains tedious, time consuming or just plain hard, even with current AI fidelity? Or in other words, where are potential opportunities and market gaps?</p><h4>Wobbly stack</h4><p>I wanted to work in an end-to-end TypeScript stack for this because I had never done it before and because I was hoping a consistent language across client and server would let me move the fastest. I settled on <a href="https://blitzjs.com/">Blitz.js</a> as a framework since it promised opinionated defaults for exactly this kind of stack.</p><p>Blitz.js builds on <a href="https://nextjs.org/">Next.js</a> which performs &#8230; some kind of magic to bring client and server closer together (do not ask me to explain). Blitz has an <a href="https://blitzjs.com/docs/rpc-overview">RPC layer</a> that further blurs the boundaries between client and server, which in principle I like a lot. Blitz also sets you up with <a href="https://vite.dev/">Vite</a> for testing by default.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pEPM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pEPM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 424w, https://substackcdn.com/image/fetch/$s_!pEPM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 848w, https://substackcdn.com/image/fetch/$s_!pEPM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 1272w, https://substackcdn.com/image/fetch/$s_!pEPM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pEPM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png" width="600" height="564" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:564,&quot;width&quot;:600,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74266,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/177866415?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pEPM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 424w, https://substackcdn.com/image/fetch/$s_!pEPM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 848w, https://substackcdn.com/image/fetch/$s_!pEPM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 1272w, https://substackcdn.com/image/fetch/$s_!pEPM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9446c6ff-7096-4728-b320-8a38c0fde8f3_600x564.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I believe this is what they call a simple stack. I added the Chakra UI component library myself, everything else comes out of the box with Blitz. To be fair, on paper all of these choices are entirely sensible. In practice, many parts of the stack will have leaky abstractions to some degree, exposing some of the underlying complexity.</p><p>At several points I lost a significant amount of time tracking down obscure compatibility issues between Next, Vite and TypeScript. These were obscure issues as in: neither AI nor Google offered me an obvious solution. In one particularly bad case I had to write a custom Vite plugin, just so I could import nodehun, the native hunspell bindings as packaged for node (now <a href="https://gist.github.com/nikhaldi/d9093151262e7722f11a48edffa732b4">memorialised in a gist</a> because I&#8217;m surely not the last person with this problem).</p><p>A bigger, more durable codebase would simply accumulate solutions for these issues over time and ammortise the cost, but for the purpose of rapid prototyping the hidden complexity of this stack may be a liability.</p><p>I don&#8217;t have a clear conclusion here. Again, on paper I can&#8217;t fault this set up and in principle I like Blitz. Maybe the insight is just that architecture as such remains hard. And if you really look at them closely, the standard architectures of modern web apps are inherently a bit weird and wobbly.</p><h4>Responsive design</h4><p>User-friendly design for small phone screens has always been hard &#8212; and I don&#8217;t think that&#8217;s just because I&#8217;m not actually a designer (I only play one <s>on TV</s> in this newsletter). Making a design responsive, meaning that it works well both on large and small screens, is extra hard.</p><p>In many situations you&#8217;re simply forced to reckon with responsiveness as a web developer. If a design isn&#8217;t responsive you&#8217;re liable to lose either most mobile users or most desktop users. I estimate that 60% of people who click through to the app from this post will be on phones. So I put in the work to retrofit my initial wide-screen design for phones.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ps_W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ps_W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 424w, https://substackcdn.com/image/fetch/$s_!Ps_W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 848w, https://substackcdn.com/image/fetch/$s_!Ps_W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 1272w, https://substackcdn.com/image/fetch/$s_!Ps_W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ps_W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif" width="800" height="504" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:504,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1406447,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://ngof.nikhaldimann.com/i/177866415?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ps_W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 424w, https://substackcdn.com/image/fetch/$s_!Ps_W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 848w, https://substackcdn.com/image/fetch/$s_!Ps_W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 1272w, https://substackcdn.com/image/fetch/$s_!Ps_W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F782762fc-ca36-4028-917b-95f9dfcd9c91_800x504.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This was way too fiddly. I&#8217;m still not satisfied with the resulting usability on phones, mainly because the keyboard gets in the way of the core interactions sometimes.</p><p>Copilot just wasn&#8217;t helping much with this. I partly blame the unusual interaction patterns in the app, for which it likely can&#8217;t draw on much prior art. But it also felt as if the code models don&#8217;t have a concept of what generated code <em>visually</em> looks like or whether some specific layout of elements would make sense to a user.</p><p>It&#8217;s not that the code-level frameworks for responsive design are lacking. I used <a href="https://chakra-ui.com/docs/styling/responsive-design">Chakra</a> here and it did everything I needed it to do. But there&#8217;s a market for dedicated AI tooling to aid responsive design. I&#8217;ll need to try out some of the &#8220;AI design&#8221; products out there to find out how well they address this already.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://ngof.nikhaldimann.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Next Generation Of! Don&#8217;t miss the next issue and subscribe now.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Before opening up VSCode again a couple of weeks ago I hadn&#8217;t written any serious code for almost 2 years. As a CTO in a fast-growing startup I&#8217;d been too absorbed by management and too far removed from ground-level engineering. So I&#8217;m coming at the hands-on realities of recent advances in AI with fresh eyes. It&#8217;s been illuminating and fun to get back in the game. Subscribe above and come along for the ride.</p><p>&#8212;Nik</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>BTW, I do not use AI assistance in writing this newsletter &#8212; I&#8217;m worried it would flatten my voice and dull my thinking with too many mid ideas.</p><p></p></div></div>]]></content:encoded></item></channel></rss>