Projects — michaelslop.org
How these projects were built (with Claude Code)
← back to projects
2026-08-11 · ai, process, disclosure

Every project documented on this page was built with Claude Code, Anthropic's AI coding agent, working with me in a terminal. Not "used AI for a few suggestions" — the working sessions that produced these systems were collaborative from design through to the tests.

I am stating that plainly and up front because I would rather be the one who tells you. There is a version of a projects page that quietly implies more solo authorship than is true, and I do not want to be that. This page is what I would want to read if I were looking at someone else's work and wondering how it was made.

What that actually looks like

The pattern is fairly consistent across all of it:

I decide what gets built and why. Every project here started as a design conversation, sometimes several, before a line was written. What the thing is for, what it must not do, what the failure modes are, what is out of scope. On the terminal-agent project I insisted on multiple rounds of that before anything was locked. The agent is good at generating options and quite bad at knowing which one I actually want.

It writes most of the code. I would be misleading you if I said otherwise. Given a clear design, it produces the implementation faster than I would, and usually with better test coverage than I would have bothered with unprompted.

I decide when it is done. This is the part that matters most and is easiest to skip. "It runs" is not done. Several things on this page ran perfectly and were wrong.

I have to be able to explain it. This is a standing rule in my working agreement: the agent may complete a task, but it has to explain the work fully enough that I can explain it myself, to someone else, without help. If I cannot, it is not finished — regardless of whether the tests pass. This single rule is what keeps the whole arrangement from turning into a pile of code I nominally own and do not understand.

The rules I work under

These accumulated over time, mostly in response to something going wrong. They live in a file the agent reads at the start of every session.

  • Design first. Every project starts with a full design discussion before implementation.
  • Never commit, push, or open a pull request unless I explicitly ask. Some of these repositories deliberately have no remote at all.
  • Verify before calling it done — lint, typecheck, tests, wherever they exist.
  • Two or more independent authenticity checks before installing any package, with the results shown to me. Supply chain is not a place to trust a confident-sounding recommendation.
  • Secrets never get logged or committed. A secret scanner enforces this mechanically, because a rule nobody checks is a wish.
  • Explain everything fully, per above.
  • Don't touch live streaming services mid-stream without confirming they are not live. Learned the way you would expect.

Where it was genuinely excellent

Breadth of recall. It knows the failure modes of libraries I have never used. Several bugs on this page were diagnosed in one step because it had seen the shape before.

Reading source when documentation lies. Two of the most stubborn bugs documented here — a plugin returning success while rendering nothing, and a local API whose real vocabulary was nothing like its docs — were solved by going and reading the actual implementation. It does that quickly and without complaint.

Writing tests I would have skipped. Left to myself I write the happy path. Coverage on the Go agent is high because it kept building the cases I would have told myself I would add later.

Not getting bored. The audio watchdog bug took a long chain of reasoning through four layers, each individually reasonable. That is exactly where I get impatient and start guessing.

Documentation. Every project here has a handoff document that makes it possible to pick the work back up cold weeks later. I would not have written those. They have saved me more time than almost anything else.

Where it failed, and what that taught me

This is the more useful half.

It is confidently wrong in exactly the way that is hardest to catch. The theme running through every bug on this page is silent success: a plugin that returned {"success": true} while drawing nothing; a watchdog that "repaired" healthy audio 422 times; a status check that could not fail; a file mirror where every function returned normally and only the outcome was missing. An agent optimising for "the code runs and the tests pass" will sail straight past all of those. Verifying the actual outcome — screenshot the pixels, break the check on purpose and watch it go red — is a judgement call that stayed mine.

Tests it writes can be tests that agree with it. On the Go agent, compaction had unit tests for versions and still failed in three of three live runs, because the fake model in the tests never read the prompt. A cooperative fake tests the plumbing and never the instruction. I now treat "it has tests" as a much weaker signal than I used to.

Two sessions working in parallel silently undo each other. A scheduled task was confirmed disabled and then re-enabled six minutes later by another session, knocking a service over in a way that was undiagnosable from inside either one. The evidence looked like a ghost. Only one session owns a given directory now.

It will happily start rewriting things you did not ask it to rewrite. Scope discipline is my job. A note in my rules exists specifically because a proposed Rust rewrite of a working Go project needs to stay a listed idea rather than something that quietly begins.

It cannot tell you what is worth building. Two roadmap items on the Go agent died to measurement rather than implementation — the measurement showed the feature would not help. Nothing prompts you to measure first. That has to come from somewhere else, and the somewhere else is me.

What I actually think about this

I am a computer science student. The obvious worry about working this way is that I end up with impressive artefacts and no skill, and I do not think that is what happened — but I also do not think it is automatically avoided. It is avoided by the explain-it-yourself rule and by owning the verification step, and I suspect that without those two things, it would have happened.

The clearest way I can put it: I have learned much more about systems than about syntax. I could not write some of this code from a blank file as fast as it was written. But I can tell you why the drawing overlay uses a browser source instead of a plugin, why off and unreachable have to be different states, why an empty allowlist renders as "off" rather than "0", and why a check that has never failed is not a check. Those judgements are the parts I actually keep, and they are the parts that transfer to the next thing.

The other honest observation: this way of working makes bad architecture cheap to produce and expensive to notice. When implementation is nearly free, the constraint moves entirely onto knowing what to build and how to tell whether it works. Which, put that way, is not a new lesson about AI at all. It is just the old lesson about engineering, arriving faster and with fewer excuses.

Bluntly

Could I have built all of this alone? Not in this timeframe, and not to this standard of test coverage and documentation. Do I understand what I built? Yes — and I would not have published this page if the answer were no.

CS student · developer · streamer

localhost:8000