Ewan’s Blog

There Is Nuance, Nae a Binary

March 06, 2026

ewan's avatar
ewan
1mo

i think a lot of people don't realise that malachite was coded with help from Claude Sonnet. It's why I have quick turnaround. yes, i am not forgetting the bugs it snuck in, but that's also why you unit test! or just test edge cases!

Malachite

Import your Last.fm and Spotify listening history into Teal on ATProto. Free, open-source, runs in your browser.


https://malachite.croft.click

You can see the post above. Not a manifesto, not a hot take designed to perform – just a fact I'd been sitting on and finally decided to say out loud, with a quote attached that felt relevant.

surfdude29 had been saying the same thing elsewhere – that writing code with an LLM does not equal slop coding – and getting blocked for it. Both replies eaten before they could land. Two for two, they said, screenshot in hand.

So here I am, a few hours on, with something more than 280 characters' worth of thoughts.


What Malachite Actually Is

For context, because I realise not everyone follows me closely enough to know: Malachite is a tool that imports your Last.fm and Spotify listening history into Teal.fm via ATProto. Free, open-source, runs entirely in your browser. I built it because I was sick of waiting for something like it to exist.

It runs 90,000 scrobbles through just fine. I know this because I tested it on my own account before releasing it. I do not release things I haven't actually tried to break first.

If you want a cleaner picture of what "built with LLM assistance" actually looks like in practice, the commit history is right there. It's 100-odd commits going back to November 2025. The project started as a JavaScript prototype, got a full TypeScript rewrite the same day I wasn't satisfied with it, and has been iterated on steadily ever since.

Some of what's in there: a rate limiter that started simple and grew – across about a dozen commits in early February – into something with a headroom-based model, a sliding window recovery mode for when the PDS quota gets critically low, proactive dynamic batching that learns from server responses, and cache rehydration so state survives between runs. SHA-512 credential storage. A full refactor on 4th March that extracted a shared environment-agnostic core into a pnpm workspace, touching 34 files in one go. The CAR file export that replaced listRecords for all sync and dedup reads, landed on 2nd March – that's the one that made 90,000 scrobbles actually reliable at scale. There's also a commit message from somewhere in the middle that reads fix: why was this not working, which is, at minimum, honest.

The web interface went from first commit on 26th February to full ATProto OAuth support the following morning – about 13 hours. I also extracted the TID generation logic into its own package, @ewanc26/tid, published to npm on 4th March, because it was useful enough to stand alone and other ATProto developers might want it.

And two other people have contributed to it: karitham added a missing dependency in January, and Martín Aguilar Tello fixed PDS resolution using Slingshot on New Year's Day. Real contributors, real PRs. People don't submit pull requests to slop.

That is not the commit history of someone who typed a prompt and shipped whatever came back. That's the commit history of someone iterating, breaking things, fixing them, and making considered decisions about architecture along the way.

It was coded with assistance from Claude Sonnet. This is not a confession. It's just true.

The Binary That Doesn't Exist

There's a version of the LLM discourse that goes like this: either you write every character yourself, with your hands, from first principles, or you are producing slop and you should be ashamed of yourself. The middle ground – using an LLM as a tool, in the same way you might use Stack Overflow, a linter, or any other piece of scaffolding that exists to help you think – apparently doesn't compute.

And I get why that binary exists, even if I think it's wrong.

The thing is, the slop problem is real. Godot's maintainers have been quite open recently about how demoralising it is to wade through AI-generated pull requests from people who clearly haven't read what they submitted. GitHub is exploring ways to deal with the volume of low-quality contributions that are burning out open-source maintainers. Ars Technica published an article with entirely fabricated quotes because someone fed the source material to an LLM and called it journalism. The damage is real, and the frustration behind the anti-LLM sentiment is not coming from nowhere.

But the conflation – treating any LLM use as equivalent to the fire-and-forget shovelware – is where the argument loses me.

There's a phrase that stuck with me from the GamingOnLinux coverage of the Godot situation: a human used a tool vs. a tool used a human. I think that's exactly the right distinction. The problem isn't that LLMs exist or that developers use them. The problem is when the LLM is the one nominally in charge, when the human in the loop has essentially absented themselves from the process, when the output goes out the door without being read, understood, or tested.

That is not what I do.

What I Actually Do With It

When I'm working on Malachite and I ask Claude for help, here is roughly what happens: I explain the problem I'm trying to solve. I get code back. I read it. I question bits of it. I often argue with it. I run it. I check the edge cases – the ones that will actually bite users, not the happy path. Sometimes Claude introduces a bug. This is not a disaster; it's just... part of using any tool. You catch bugs. That's what testing is for.

The bugs Claude sneaks in are not some unique horror – they're the same category of mistake you'd make yourself when tired, when your brain has convinced you the logic is right before you've run it. The difference is I know to look for them, because I know the model doesn't understand my codebase the way I do.

The quick turnaround I've been able to maintain on Malachite – from v1 to the CAR file import/export in v0.10.0, from the CLI to the web interface with OAuth – is partly because I'm not doing everything the hard way. I'm doing it with the best available tools, which currently include LLMs.

I still understand every piece of it. I still own every decision. I still dogfood it before I ship it. The provenance of any given line of code doesn't change that.

Why This Matters (To Me, Specifically)

I'm 20. I have a Ko-fi and not much else. I build things because I want them to exist and because it turns out building things is the part of this I love most, even when it's annoying.

I'm not a company. I'm not a team. I'm one person with a Mac mini, a self-hosted PDS running on a repurposed laptop, and a list of things I want to build before I get bored of them. The resources available to me are not the resources available to a funded dev team, and the tools I reach for reflect that.

LLMs are, for me, the difference between "this takes a weekend" and "this takes a month" on certain classes of problem. I would be a fool not to use them. I would also be a fool to use them without actually reading what they produce – and I'm not that, either.

The Slop Is Real. The Binary Isn't.

I want to say clearly, again: the frustration is valid. AI slop is a genuine problem in open-source communities, in journalism, and especially – and I feel this one personally – in creative spaces. Poetry. Visual art. Writing. The stuff that is supposed to come from somewhere. I write poetry. I have done since I was 14. I find AI-generated creative work genuinely depressing: content for content's sake, pumped out like an amalgamous blob of scrap foodstuffs fed to pigs in troughs. It carries no trace of the person who nominally made it, because there was no person – just a prompt and a publish button. That is the true slop, to my mind. Not a rate limiter written with Claude's help. A gallery wall full of images no human chose to make.

The people burning out trying to triage AI submissions – whether in open-source repos or literary magazines or art communities – have every right to be angry. If you're a project maintainer spending your evenings reviewing PRs from people who didn't read what they submitted, I have nothing but sympathy for you.

But blocking someone on Bluesky because they said writing code with an LLM ≠ slop coding – twice, calmly, presumably accurately – isn't fighting slop. It's just pattern-matching on a keyword and calling it a position.

Anti-LLM Bluesky users were even harassing the core Bluesky team on this, prompting this response.

Paul Frazee's avatar
Paul Frazee
1mo

I do want to make sure we're being clear about this: The Bluesky team maintains the same review, red-teaming, and QA processes that we always have. AI coding tools have been proving useful, but haven't changed the fundamental practices of good engineering. Human review and direction remain key.

The nuance is: how are you using it? Are you reading the output? Do you understand what you're shipping? Are you testing the things that will actually fail in production? Have you made a decision, or did you outsource the decision entirely?

Those are the questions that matter. Not whether an LLM was in the room.

I built Malachite with Claude's help. It imports 90,000 scrobbles without a problem. I tested it until I was confident enough to put my name on it, and I'm confident enough to put my name on it now.

Nae a binary.

Subscribe to Ewan’s Blog
to get updates in Reader, RSS, or via Bluesky Feed
Life Update: Controlled Chaos and March
Silver Fire – Commissions Are Open (and Half Off)

artificial intelligence
llm
coding
vibe coding
slop