Sunday, 31 May 2026

Batteries InClauded

Breaking into my homelab series to gather my thoughts on everyone's hot topic - LLM-driven coding aka AI Agents aka Vibe Coding. I've been doing this blog now for (gulp) 16 years so there's a pretty decent chance that at least some of my sentiments, and certainly some code snippets, have been slurped up and thrown into the giant soup pot full of [weights](https://maxleiter.com/blog/weights). I don't use any LLM assistance when writing posts, and I'm sure things are going to get extremely weird when future generations of LLMs have to deal with their own slop all over the web *as inputs*... It's absolutely been the case for a while that my work VSCode instance (with Copilot) will autocomplete a function given its TypeScript arguments and return type, basically character-for-character how I would have done it. "Coding" as the masses call it, has become a succession of [Tab] [Tab] [Tab] hits, followed by a careful inspection, reflection, then a shrug and a wry smile. __Very, very impressive autocomplete__ was the only way I'd been using LLMs up until *this month*. This month, *everyone* in my company got given unlimited Claude access. Yes, the CEO is one of those [AI maximalists](https://www.youtube.com/watch?v=DmU9uovmT2A). We also we given an "AI Hackday" to use said Claude access to do ... *anything* (as long as it somehow benefits the company). I decided (as did many others) to use Claude Code to build me a dashboard. But unlike most of the non-techies doing these things, I had *Opinions* about *how* Claude should do it. Namely, I wanted a server-side rendered SvelteKit app. Claude rolled up its sleeves and had Version 1.0 up-and-running in __7 minutes__. It worked flawlessly. We iterated on several additional features (mainly view filtering, state retention through URL parameters and rendering nested items). We had it feature-complete, bug-free and *precisely* what I'd been wanting in __just over 1.5 hours__. This included encountering 3 different classes of bugs - one that it spotted all by itself (a permissions problem in the `~/.npm` directory which meant it couldn't cache anything - it worked around it by using an explicit [writable] path for the cache in every `npm` command), one that it did not (it introduced a bug in client state that meant expanding and contracting container rows caused a full page reload), and one that we discovered "together" and fixed in a way that I can only describe as hyper-productive pair programming (it prepared three potential fixes, in parallel, and asked me to evaluate which one fixed the problem). All this would have taken me, starting from a bare-bones `npx sv create myapp` [blank slate](https://svelte.dev/docs/svelte/getting-started), 2-3 working days. I won't lie, I was extremely impressed. I still had an hour of coding time left though, so quit the Claude session and took a *really good look* at the code it had generated, in order to put a few finishing touches on. Styling and what-have you. __Ugh__. Firstly, I hadn't realised, but it had created an app based on __Svelte 4__ - a codebase that [hasn't been touched in a year](https://github.com/sveltejs/svelte/releases/tag/svelte%404.2.20). Clearly (and a general web search will confirm this) the majority of Svelte content out there is based on Svelte <5, and when I asked for a Svelte[Kit] app it went with what it "knew" best. I, on the other hand *do not know* Svelte 4, I picked it up at v5 specifically because I'd heard it was so much nicer to use (and it is - it's been my preferred web dev framework now for a couple of years). Secondly, the code was room-full-of-monkeys-writing-Shakespeare messy. Heaps of things being recalculated all over the place instead of done once in a nice function. CSS that "worked" but would break at the slightest change (which takes real effort in a Svelte app, I can tell you). Thirdly, the function that it wrote (hey, at least it encapsulated *something*) to work out how to find and nest (potentially infinitely deep) child items was, well, I think `O(n^3)` *might* cover the *computational* complexity, but in terms of human intelligibility it was __bonkers__. So it did the job __fast__, __cheap__ (in terms of how much it cost in tokens compared to the time it would have taken me at my hourly rate) and __good-enough__, as long as you didn't need to change it *in any way at all in the future*. I guess in a future Claude Code session I could get it to generate a battery of unit tests for the child-nesting function and then refactor it myself while ensuring all the tests pass. Whether anyone *cares* enough about __good-eough__ remains to be seen.