A simple philosophy: Claude handles the code; I verify the outputs.
Introduction
I’ve spent the last couple of years using LLMs as my primary method of building
software. Part of this is practice and education; the goal is less to build universally
useful software and more to show what an LLM-centric workflow can accomplish today. As a
bonus, it’s a great chance to build a bunch of little utility apps that help my day to
day tasks.
This site is an archive of that journey: short write-ups of each project, what it does,
how it was built, and where the code and the running version live. Some of it is for
tabletop gaming, some is developer tooling, some is infrastructure. All of it is real,
deployed, and in use.
The number one lesson I’ve learned is that being a good developer now looks a lot like
being good at Quality Assurance - you need to be comfortable testing the flow of the
code, and finding the unhappy paths that the unit tests miss. You also need the patience to
slog through 99% of the features working to find the 1% that went wrong.
Programming experience still matters, though - I can immediately get a feel for a lot
of errors in the code simply based on the behavior. These two numbers don’t match, which
means there’s a DRY (Don’t Repeat Yourself) violation in there somewhere. Knowing
when a build has gotten complex and messy, and pushing the LLM to do an architectural review.
Getting a feel for when technical debt is building, and running a debugging session.
In the end, I think Agile is the most important principle. Writing a quick prototype with
disposable code to test a concept is exactly where LLMs are ideal. They’re great for
rapid iteration and playing around with ideas. Test, iterate, repeat. For example, when
building TurnipText, I could easily try out all sorts of wild ideas, spend a few minutes
seeing if I liked it, and either reverting or iterating forward.
LLMs drop the cost of exploration to near-zero, and I think that’s one of the most
overlooked benefits. Once you’ve proven the concept works, it’s a lot easier to
fine-tune performance, or even start over entirely with a performance-centered rewrite.
Past Projects
TurnipText is a text editor shaped around how I personally work
A small, opinionated writing tool with exactly the features I use and nothing I don’t.
What I learned: It’s ugly but it works exceptionally well for me. It feels a bit
clumsy any time I have to use a non-bespoke Text Editor now. I think in a few years, this
sort of bespoke customization will be normal for a wide range of applications - I can
ask Claude for a new feature and be using it 5 minutes later.
A collection of basic tools like word count, text diff, and some surprisingly capable
image manipulation tools. Plenty of similar collections exist, but this one has everything
I need and nothing I don’t.
What I learned: it’s remarkably easy to build simple single-purpose image
manipulation websites, and they work much faster than a dedicated multi-purpose
application.
WebArcade: a weekend of classic games in the browser
A small arcade of browser games with sound effects, music, and gamepad support. Built
in a weekend to see how far Claude could get with minimal one-shot prompts like
“create Tetris”, “add support for my XBox controller” and “compose some music and
SFX”.
What I learned: with minimal specification, it usually took me a second prompt to
actually be fully satisfied with the output, but only Tetris had a bug (a race condition
where rotation should allow falling to continue, but it had already “locked” into place
- solved by prompting it solely with a description of the behavior). In short, these
tools have a surprisingly good sense of context, and understand what sort of features each
game should have - high scores, etc.
Dice rollers, a SQLite-backed name generator, and digital character sheets for Blades in
the Dark, FATE, and a homebrew system - built to solve real friction at our actual
game table.
What I learned: I’ve built these in a few different languages over the year, so
I know the perils well. I was quite impressed with the LLM’s accuracy here, and
especially their ability to build unit tests around random number generators - which
tends to require both stubbing the Random function AND being willing to run technically
“unreliable” statistical tests. For my personal code base, a one in a million
“flaky test” is quite acceptable to ensure everything really does work when a
non-mocked Random is plugged in.
Bonus: LLMs are also a pretty solid source for populating a database of random names, and
the database / variety helps shake them out of their otherwise slightly eccentric naming
tendencies.