The last developer to use AI
Blog: 25-Oct-2025
Preface
This is a story of one man's Damascene conversion to AI development tools from a starting point of knowing pretty much nothing about them.
But first, a quick disclaimer: many people now believe that the use of bullet points and em dashes is a sure-fire indicator of AI writing assistance tools. So I just want to state here that this story is 100% fully organic hand-rolled human nonsense—none of it was dropped out of the backside of an AI writing tool.
So here's the story:
- Who isn't using AI?
- Playing with local models
- Coding with local models
- Cross-platform coding with the AI big boys
- Big deal or just hype?
Who isn't using AI?
Even in late 2025, when so many developers are already neck-deep in AI tools, you can still find a good number of devs on Hacker News (and presumably in real life too) who are pretty anti the whole notion, usually on the grounds that:
- they've tried some of the tools but didn't get the results they were hoping for
- they feel uncomfortable farming out important work to as-yet unreliable automation
- they worry about the lethal trifecta in agentic mode
- they work in a niche language where there isn't much AI knowledge out there yet
So are these people just change-resistant, or do they have a point? As a retired software developer, I have no axe to grind. I hadn't taken a dive into AI thus far because I was very happy working in the traditional way. I code hobby stuff for fun with no commercial pressure to deliver anything to anyone by any date—it's a delightful way to code. But the downside of no external pressure is that it can lead to stagnation and a reluctance to change with the times.
Back in the 1880s in Nottingham, the Luddites were also happy working the old-fashioned way with their manual weaving machines, too busy to notice the mechanised future rolling inexorably towards them until it was too late (cue Terminator sound FX).
So was I a Luddite, or just lazy? Either way, it really was about time that I took a proper dive into the world of LLMs before I got too far off the pace. I had taken a brief look at AI coding in Zed (my code editor of choice) but the terminology was largely unexplained, and I felt a bit out of my depth. So I decided to have a good play with some local models before trying to seriously code with any expensive commercial products.
As luck would have it, it was also time to upgrade my daily workhorse. So I bought a Mac mini M4 Pro with 64GB of unified memory to replace my 5-year-old Mac mini M1. The new machine would give me plenty of headroom to play with local LLMs and help me to get up to speed generally with this brave new world.
Playing with local models
A few days later and I'm humming along nicely. I soon discovered that there are several ways to run local LLMs. The easiest way is to install a one-stop shop like LM Studio or Ollama, both of which allow you to download a variety of models and chat with them. Both can also be run as a local server so that other applications can access their models via their APIs. Or, if you know some Python, you can go hardcore and get models directly from Hugging Face. Each model there has some accompanying demo Python code to run its features. Python is a language I knew very little about, but it's not hard to pick up the basics to get some demo code running. The only pain point when playing directly with models in this manner is the need to create Python virtual environments. That's because version incompatibility is a real problem in the Python world, so none of the AI demo code you might want to try out is likely to run on whatever default version of Python you might have on your system. However, uv is your friend here. It can simplify much of this for you by allowing you to easily create a versioned Python virtual environment, activate it, and run the demo code inside it. Then everything works as it should.
Then to tie everything together I installed Open WebUI, a browser-based AI portal which lets you:
- chat with your Ollama, LM Studio, and other local models
- connect to and chat with remote models
- use external search services like Google PSE
- produce images via external generators like ComfyUI
- upload files for context (accepts drag & drop)
- upload a web page for context
- talk into the prompt and have it talk back to you
- maintain your chat and generated image history
So I installed ComfyUI to generate images through Open WebUI. And in order to get the most out of my Mac, I also installed a set of custom ComfyUI image generation nodes called Mflux-ComfyUI. These take advantage of MLX, an Apple-specific machine learning framework which gives a big performance boost by taking full advantage of Apple silicon. The current image model I'm using (black-forest-labs/FLUX.1-schnell-8bit) needs around 18 GB VRAM to run. That’s a lot of words to say that all the images on this page took around 15 seconds each to generate locally using my Open WebUI text-to-image prompt. Making mad images like these is a load of fun if you have a suitably warped mind. The M4 mini Pro is an amazing little machine, I'm loving it.
And as for regular text-to-text models, I can happily run those with up to around 40B parameters at 8-bit quantization alongside my usual variety of running applications. Or push my luck with even larger models if I close some running apps. The larger models do eventually make the (unobtrusive) fan spin up for a few minutes, but it soon stops once the models finish working.
For non-dev stuff (like converting my basic text input into imaginative image prompts) I became a fan of the tiny Google Gemma-3N, an 8B model which pumps out responses at around 45 tokens per second. Super speedy, very low memory use, and surprisingly good for simple general life questions.
You soon find out though that playing with local models is a balancing act between how much VRAM you have and how much model brain-death you can tolerate when running heavily quantized versions. So you have to experiment with different model sizes and quantization levels. I found 30-40B/8bit quant models did a great all-round job; speedy, and fit easily into a 64GB unified memory computer. So I've found my happy medium.
Coding with local models
So how about coding with local LLMs? These days I'm mainly playing with just HTML, CSS, vanilla JS and Rust, with a bit of PHP thrown in from time to time, all of which are inarguably mainstream. I'd assumed that a good model would be able to write new stuff in any of the above without breaking sweat, which is largely true. But I was surprised to find how good the models could be at improving my existing code. That hurt a bit to be honest. However, once my ego had calmed down, I accepted the obvious fact that code distilled from the brains of millions of coders was likely—at least some of the time—to be better than my original stuff. In other words, I could use the AI as a peer review session. My ego coped better with that perspective.
I was also surprised to discover how quickly a good local model could become a Stack Overflow replacement. I found I could ask it how a function worked or to explain aspects of a language I hadn't fully grasped. Back in the day I would have had a handful of tabs open in my browser doing the SO shuffle, trying to sort the wheat from the chaff. But I soon found that my local AI was almost a complete replacement. Tectonic plates really have shifted.
Another advantage of having several models available in Open WebUI is the ability to pose the same question to different models. This lets me shine a cross-pattern of knowledge beams across my shadows of ignorance. Differences in the responses often give me useful different perspectives.
As for the actual models, I was initially quite impressed with Gemma3:27B which responded at
around 12t/s, which is about the lowest speed I could tolerate. I also tried
Marvin Qwen3:32B but found it took forever thinking about life,
the universe and everything, and often got itself caught up in endless loops of self-loathing until I
put it out of its misery. Deepseek-coder:33B was also pretty good. The issue for me though is
that those "thinking" models take forever to make their minds up, and the wait soon becomes intolerable
for live coding assistance.
But the arrival of speedy active parameter models changed the picture in a big way. I'm currently testing an 8-bit quantization of Qwen3-coder-30b-a3b-instruct-mlx in Zed via LM Studio which is running at around 50t/s. That's bonkers fast when compared with older models of a similar size. You still need to load up the whole 30B in memory, but it runs at the speed of a 3B model. I'm loving it so far, especially for code Q&A—it's like having a polyglot automated Jon Skeet sat next to you whispering into your ear. But the model landscape is literally changing by the week, so my model comparisons will age about as well as a fax machine review.
So what worked and what didn’t in my local models? I found that if I gave a good LLM clean and clear instructions in short bursts, it could work miracles. But blindly returning all the previous context for fixes was often counter-productive. Re-tuning by shortening the context and adding just a few files generally gave me me much better results than saying, "dude, write me a new Facebook".
However, there’s no getting away from the fact that local models are not (yet) as good as the big commercial offerings. Kimi K2 is the most recent commercial offering from Moonshot AI as I write this. It has 1,000B parameters. Compare that to my local models running about 40B. Now it's certainly true to say that that a trillion-parameter model is not 25 times better than a 40 billion model as the numbers might suggest, but it will certainly be measurably better. And it will run fast due to the big boy hardware it's running on. The problem is that most of the commercial models are all just too pricey for me to use for hobby use—until Kimi K2 arrived, that is. Kimi K2 is currently an order of magnitude less expensive than the other top-end models like Claude and is almost as good, depending on whether you believe benchmarks. And even better, I can call it directly in Zed because most models now have an OpenAI-compatible API, which Zed can call for both basic text assistance and agentic mode for tool use.
But no-one likes the AI cost meter running constantly in the background, especially if you're just fooling around. It feels like ordering a taxi to go to the airport, then having it wait outside your door with the engine running while you take a long relaxing shower before leaving. But I can happily live with paying cents rather than dollars while I play with Kimi K2. So I was now off to the races with the big boys…
Quick aside: I'm very well aware of the irony of complaining about the cost of commercial LLMs having just purchased a 64GB Mac mini Pro. But the Mac is a one-off purchase that will last me for five years of constant daily use, and I already have financial death by a thousand cuts with TV and many other non-essential life subscriptions. So getting LLMs for hobby use for free (or really cheaply) is a very attractive proposition. It would be a different story if I was still working—I would expect my employer to be paying for Claude or whatever is the current SOTA (that's state of the art for those who don't frequent LLM-related social media platforms, where the term appears in every second post).
Cross-platform coding with the AI big boys
But what to use all this power on? I decided to try it out on a small cross-platform Mac and PC project. Writing cross-platform native desktop apps has long been like sticking a screwdriver into your own eyes; you can do it if you really want to, but it will be exceptionally painful.
Various cross-platform tools exist which all claim to help take away the pain, but their output often results in enormous file sizes, and you are inevitably tied into vendor lock-in. Fine for a big project perhaps, but overkill for the kind of utility applications I like to mess around with.
I had an existing tiny Rust project called Media File Date Fixer (mfdf) which started life as a CLI utility. It fixes up common image and video file dates which often get overwritten during copying across devices, like from an SD card to an iPad to a computer. It reads the files' metadata, finds any dates within, and uses them to update the OS Created and Modified dates so that you can then view or edit a mix of copied media files from different devices in shot date order. Conceptually very simple, and something an LLM could write for you in 30 seconds. I had written the core code library and the command line app to run it by hand several months ago just for my own use. But I always quite fancied making a simple Mac and Windows version of it because sometimes normal humans just can't be arsed with CLI stuff.
I decided to convert it to a Rust code library (DLL on Windows, dylib on MacOS) which could then be loaded up by an appropriate native front-end app. The idea was that the library has all the brains, and the front-end apps would just display controls for getting user input and displaying the output returned from the library. Rust makes this easy to do in principle: you just compile your library code on a Mac and it spits out a dylib, then compile the exact same code on a PC and it spits out a DLL. Any platform-specific differences can easily be handled by conditional compilation directives.
But native desktop development generally requires working in a full platform-specific IDE. On the Windows side, I knew Visual Studio and C# pretty well from ASP.NET MVC web work back in the day. But I hadn't done desktop stuff for very many years, not since the glory days of Delphi, which had its own IDE. So I knew nothing about WinUI3 or any of the myriad older Windows desktop frameworks which seem to hang around in a zombified state of quasi-deprecation. And Mac dev was a whole new world to me, which would mean working with Xcode for the very first time to produce a SwiftUI app written in Swift.
Another reason to put off this project was the extra work required to get an app written in one language to talk to a library written in another. Both must use code at the calling and receiving points which adheres to a common calling convention, usually based on the C language. The trouble is that C is a language written before our ancestors had crawled out of the primordial swamps, and it has some nasty low-down features queuing up to bite you.
So most modern languages have a set of features under the banner of the Foreign Function Interface (FFI) to enable communication across language boundaries. The FFI essentially provides wrapper code around the underlying nastiness of adhering to a C-based calling convention. But there's a cost to this: Your regular Rust code can be very beautiful, but if you've ever looked at Rust FFI code, you'll know that it looks like your embarrassing old uncle who has stains on his clothes, the origins of which you avoid thinking about. It works by passing C-style pointers to raw byte collections and converting UTF8 strings to horrible null-terminated C strings. And you have to remember to free the memory after use like a goddam Neanderthal. So I wondered how Kimi K2 would handle all that.
I wasn't yet brave enough for the full agentic mode in Zed where the AI and Zed work together to create new
files and amend existing ones. So I got my feet wet by trying Kimi K2 in coward text mode which
allows you to prompt the model in a side panel and insert the results into your code. I began by asking it
to write a Rust FFI function to expose the main library function for external use by the Mac and
Windows apps. I attached the current library functions for context. I was closely checking as it did its
work, but I could fault none of it. So far, so good.
Then I moved up a league and prompted it with this in Open WebUI for use in Visual Studio on my PC:
Write a minimal WinUI3 application with C# code which accesses a Rust DLL. The DLL has
an exported function called make_report() which takes a directory path (string) as input
and returns a report as a long string. The application will have an introductory text panel
with a single button underneath to open up a directory picker. On selecting a directory,
the code will hide the intro text panel, pass the directory path as the parameter to
make_report() and receive back the report to be displayed in a scrollable text viewer
under the button.
And it just went off and bloody well wrote it for me. Complete with a dummy Rust FFI make_report()
function to ensure I got the Rust side exporting correctly. Plus it wrote a function to free the
memory afterwards. Plus all the C# DLL calling code, plus the UI as described, with a directory picker,
text panel, and button. And it told me which files names to create and where to copy the code into.
All it got wrong was a couple of hallucinated non-existent properties in the UI XAML file which made
the build fail. So I chopped them out and suddenly it was built and running. I nearly fell over.
A working Windows WinUI desktop app calling a Rust DLL. In minutes.
The last time I got an IT jolt of this magnitude was when I got my first response from a modem back in the early 90s. I plugged it into the phone socket, hit the connect button in whatever software was controlling it, and listened with anticipation as it squeaked and howled into life, dialling out for the very first time. Then, as I watched it slowly print some remotely generated text across the screen, I realised that my computer was no longer an island; the world and I could now talk to each other, and nothing would ever be the same again. It felt like a giant step into the future. Like I was communicating with Uhura on the Enterprise. It was thrilling.
And that's exactly how my AI-assisted coding experiment felt when I saw it working for the first time. A properly jaw-dropping, WTAF moment. The world has moved up a notch and I'm here to observe it. People must have felt like this when they saw Stephenson's Rocket puffing past them.
So then I switched to the Mac and used the same prompt, just changing "WinUI" to "SwiftUI", "C#" to Swift, and "DLL" to "Dylib". After a little rumination, Kimi K2 told me the various incantations I had to type into the Xcode project settings to talk to the Rust dylib, all of which were entirely new and alien to me, plus all the code and the files into which I should place it, just like the Windows version. It almost worked first time, but it spat out perms errors when trying to change file dates. So I asked Kimi K2:
The code now builds and runs; it can scan and traverse the directory contents OK but cannot
change file dates. Is there a permission problem somewhere? Each attempt by the library code to
amend file dates in the chosen directory fails with the error "Operation not permitted (os error 1)
on 'filename'.
And it responded with a detailed explanation of the issue and suggested some code
changes which fixed the problem. It turned out I needed an .entitlements file and some
security scoping code wrapped around the directory chooser code. There is no equivalent to this
on the Windows side, so this was all foreign territory to me. Then it worked just like the Windows
version. Pick me up from the floor. Not only my first ever Mac desktop app, but one that talked to
a Rust dylib. In minutes.
In the event that someone who doesn't code reads this piece, I cannot overstate what a game changer this is. Given my first-time use of a FFI in any language, my very out-of-date knowledge of Windows desktop development, and my zero knowledge of Mac desktop development, writing both of the above lttle apps without AI might reasonably have taken me a couple of days to research, experiment, and fail to build dozens of times over.
After that, I spent far too much time getting both apps to look like not-crap. The non-existent artist in me struggles with stick men, let alone UI design. That was the least enjoyable part by far, but Kimi K2 even helped there, but not much to be honest. Desktop UI design has regressed mightily since the drag-and-drop days of VB and Delphi. Today, it's all about coding your UI in SwiftUI, or fighting with XAML on Windows. If you thought CSS was hard work, then desktops UIs will have you opening a vein with your fingernails, hanging heavy chains round your neck, and going for a long walk down a short pier. To be fair though, Microsoft has published the WinUI 3 Gallery which is pretty good at showing you how it all hangs together, but it's still a lot of tiresome, ugly XAML.
And I found the SwiftUI coding experience to be even worse. It just wasn't well documented, or maybe Google just couldn't find it for me. It was an exercise in frustration. So once I had got both front ends looking half-decent, I called it a day, mission accomplished!
So it was happy days for me, and the Windows and Mac apps together had cost me under a dollar in my Moonshot AI account! The Rust, Mac and Windows versions are all up at https://github.com/bobosola/media-file-date-fixer if anyone wants to play with them.
Big deal or just hype?
Of course, critics could rightly argue that this is just a small toy project written in mainstream languages, so not much of a challenge. Which is a fair criticism. I can imagine someone on Hacker News saying "Huh, not impressed. I bet you can't do that in Haskell or Zig". Maybe, maybe not, I really can't say because I don't have a Scooby-Doo about either of them. Exotic languages aside though, doing something like this was pretty much science fiction even just a couple of years ago. But I'm not yet convinced about vibe coding.
What exactly is vibe coding?
The original meaning of vibe coding was letting the AI do 100% of the work. You just fed the build errors back into the prompt until it sort-of worked. You wrote no actual code yourself at all, in fact you were supposed to act as if the code didn't even exist, rather like how you might instruct a builder to extend your house—lots of detailed instruction, but no getting your hands dirty yourself. However, the phrase has since been watered down as it spread around the internet and is now often used to merely mean "coding with AI assistance", much to Simon Willison's disgust. But it's already a lost battle.
At the time of writing, could someone who doesn't code at all vibe code the desktop apps and Rust library? I very much doubt it. The thing is, for cross-platform desktop apps, you need to have enough experience in at least one language and its dev environment such that you can pick up another in a reasonably short time, or at least feel comfortable in the landscape even if the geography is unfamiliar. It's rather like driving abroad on the other side of the road—it feels weird for a while but you eventually tune in, even if it never feels completely natural. But it would be a lot harder if you didn't know how to drive at all.
It's not so much that a modern LLM couldn't vibe code such a small project (after all, Kimi K2 almost did it for me), it's more that you need the domain knowledge to feed it the right prompts to get you there. But I'm not sure I like the current fashion for calling this prompt engineering— that phrase seems a little overblown to me. The word engineering implies formal training with rules and standards. But there's none of that with prompting. It's a bit like playing darts—sometimes you play like a champ, and you start to believe you might actually have some talent for it. But on the next go you miss the board completely.
The truth is, it's really all about domain knowledge, clarity of intent and clear concise instruction. Plus a little perseverance.
But the doubters will say "don't these models hallucinate and get things wrong?". Well, yes, sometimes. But avoiding these tools because they get things wrong occasionally is looking through the wrong end of the telescope. They also get a hell of a lot of things right! So turn the telescope around and embrace what they can do rather than worry about what they can't. Your work colleagues get things wrong sometimes too, but that's no reason to fire them. I'm convinced that once all the mad hype dies down about vibe-coding teenage millionaires, AGI being just around the corner etc., good developers will all still be employed, and—thanks to these tools—they'll be writing better code more efficiently than they did before.
In my first career, over time, I saw many of the skills I learned in nautical college disappear into a circuit board: GPS for navigation, electronic charts instead of paper, computers to calculate a ship's stability, automated radar collision detection instead of manual plotting, and satellite comms instead of morse code. And I'm seeing it again now in software development. But here's the thing: if I was still working, I wouldn't be worried at all about being replaced by LLMs. Because you still need significant experience built up over time by the school of hard knocks to make AI output coherent, safe, extensible, and maintainable. The difference is that with AI, I feel like I'm in charge of driving a quirky, fun sports car through the landscape as opposed to just dragging my heels through on foot.
But that description doesn't quite cover it. There's a lot of talk about how using AI is like having a junior engineer at your beck and call 24/7. But that doesn't quite fully pigeonhole it either, because AIs can get things wrong in ways that even the most junior human would not—that's just anthropomorphization creeping in. The AI is not human; it's spitting out a non-deterministic simulacrum of code learned from millions of examples of other people's code from all round the internet. It doesn't arrive pre-compiled and tested, it just looks good with a very high probability of actually being good. The model neither knows nor cares whether it compiles, unless you run it in agentic mode and allow it to access tools and do a build. And that nearly always fails on the first run, initiating a debug and rebuild loop which involves throwing more good-looking code at the problem. But it seems to me that you can't really call that intelligence. Very clever design? Certainly. But it's not applying intellect to fix build failures, it's just doing brute force loops until it builds, or the AI gives up, runs out of context, or hangs.
The best I can come up with is that coding with AI is like chatting with a smart stranger in a bar. You're enjoying the conversation and there is a feel-good buzz in the air. The stranger is witty and fluent and sounds like they know their stuff (they are certainly super-confident). But sometimes your own knowledge and experience make you realise that your new friend is very occasionally talking shite. Does that make the entire conversation worthless? No, not at all, because you may well have learnt something interesting and useful along the way. You just have to keep your shite detector batteries fully charged.
For the average mid-range developer (like me) working for an average mid-range employer (like I used to), these tools have helped me to:
- quickly pick up the basics of a new language
- become more idiomatic and fluent in my mid-skill-level languages by asking the tool for suggestions for improving my code
- take the pain out of an unfamiliar IDE
- answer all manner of code questions in popular languages with good working examples (i.e. Stack Overflow but without zero-rated comments and mean moderators)
- write the shell of a new website or desktop app
- find logic holes and bugs in existing code
- tidy up messy legacy code
- write the boring boilerplate stuff, like tests
- add good quality comments to new and existing code
- get me past file->new brain freeze
- try out new techniques without losing too much time
- get stuff done much faster, so long as I check it thoroughly
If you're a real top-end domain or language expert, then perhaps these tools can do very little for you. But I don't kid myself. I'm very comfortable knowing that I'm down there with the average Joes—I'll never be a 10x developer. Some days I even struggle to be a 0.75x developer. So I'll accept all the help I can get. Take me AI, I'm yours.