td204

Web development, one post per year since 2002

2025 in review: from autocomplete to something that does the work

I had been writing code with AI assistance for a couple of years already, and gave a conference talk about it in 2023. So this is not the year AI arrived. It is the year it stopped being autocomplete.

On 5 June I committed a CLAUDE.md to a project repository for the first time: a short document describing the stack, the conventions, and how to run things, written for an AI coding assistant rather than for a person. By December that file existed in eight repositories, and the biggest project I have ever worked on was built with Claude Code open the whole time.

The difference from Copilot is not incremental and it is worth being precise about it. Copilot completed the line I was already writing. This reads the repository, plans across files, runs the tests, reads the failure, and tries again. The unit of work went from a line to a task, and every one of my habits had been built around the assumption that I was the only thing capable of holding the whole project in mind.

Game changer is an overused phrase and it is the correct one here. This is the honest version of how it went, including the parts that did not work.

The tooling around it aged faster than the tool

Early on I ran Claude Flow, an orchestration layer that added agent swarms, memory and workflow scaffolding on top. Here is one I ran in August:

npx claude-flow@alpha hive-mind spawn "Review the current code and seeders, clean up the
ones that are no longer used. Check if every page type has a template. Review the URL
structure and make sure every controller action has a view. Document the URL structure.
Check the current texts for clarity and SEO."   --agents devops-engineer,cms-developer,analyst,researcher,tester,seo-content-auditor,architect,optimizer,documenter   --claude

Nine named agents for one cleanup task. It felt like the future, and it worked, and it was genuinely useful for about a quarter.

Then it was not, because the underlying model kept absorbing what the plugin was doing: the planning, the multi-step decomposition, the deciding-what-to-read-next. By autumn the scaffolding was mostly overhead. Handing the same paragraph to the plain tool, without nine declared roles, produced better output and took less setup.

That is worth remembering the next time I bolt a framework onto a fast-moving tool. If a plugin exists to compensate for a limitation, its lifespan is however long that limitation lasts. Write the thin version and expect to throw it away.

The prompt itself, though, aged fine. Look at what it actually asks for: dead code removed, every page type has a template, every action has a view, the URL structure documented, the copy checked. That is a maintenance checklist I would hand a new colleague, and writing it down was the valuable part. The orchestration around it was not.

The number, and what it does not prove

2025 is comfortably my highest-output year on record: about 2,400 commits, against 700 in 2024 and a previous best of 1,700 back in 2019.

The chart at the bottom of this post makes the shape obvious, and the shape is more interesting than the total. January through April come to 140 commits between them, roughly 35 a month, which is not a normal year for me. It is a quarter of my usual rate.

That is not a slow start. That is a big project in its requirements phase. Most of those four months went into meetings, working through what the thing actually had to do before anyone wrote code for it. Nothing about that shows up in a commit graph, which is worth remembering every time somebody reaches for one as a measure of productivity. The most valuable weeks of my year are invisible on it.

Then the build started, and the line goes up and does not come down. The CLAUDE.md commit that opens this post is dated 5 June.

Which means the two things are tangled together, and I should say so rather than take credit for the wrong one. May is when a large project moved from talking to building. June is when the AI arrived. Both would have raised the numbers on their own, and I cannot separate them from this chart.

What I am confident about is narrower: commit count measures activity, not value. A meaningful share of the increase is exactly the work I describe below as the thing AI is good at, which is mechanical and produces a lot of commits and was never the hard part of the job. The deciding, the design and the reviewing did not get three times faster, and those are still the parts that determine whether the software is any good.

What it is good at

Reading a codebase I do not know. Dropping into a project after eighteen months and asking "where does the invoice total get calculated" is worth the subscription on its own.

The boring middle of a task. Once the approach is decided, generating the migration, the model, the form request and the test scaffolding is minutes instead of an hour.

Mechanical migrations at scale. Converting hundreds of tests from one runner's syntax to another, or updating a deprecated call across a large codebase. Repetitive, well-specified, verifiable.

Explaining an error I have not seen before, without the ritual of finding the right search terms.

What it is bad at

Deciding anything. Ask which of two approaches is better and you get a balanced summary of both, weighted towards whatever you mentioned last. The decision is still yours, and pretending otherwise produces architecture nobody chose.

Anything where being subtly wrong looks like being right. Generated code compiles and reads well and is occasionally just incorrect in a way that a plausible-looking test also fails to catch. Business logic with money in it gets read line by line, every time.

Knowing your project's history. It cannot know that this column is nullable because of a data migration in 2019 and that removing the guard will break the import.

The instructions file is the real trick

The single highest-value thing I did all year is short and boring:

# Project notes

## Stack
PHP 8.3, framework X, server-driven components, Vite, Tailwind.
Local environment: containerised, run everything through it, never bare `php`.

## Conventions
- Money is stored in cents, as integers. Never floats.
- All dates are stored UTC, displayed in Europe/Amsterdam.
- Tests live next to the feature. Run: `<container> test`.
- Never edit generated files under `public/build`.

## Gotchas
- The import runs before the nightly sync; ordering matters.
- Two tables are shared with an external system and must not be migrated.

Every one of those lines exists because I explained it twice. The file is not for the AI, really. It is documentation I finally had a reason to write, and the new colleague who benefits most from it is the human one.

The rule I ended up with

I review generated code exactly as strictly as code from a capable contractor I have not worked with before. Which is: read all of it, question anything clever, and never merge something I could not have written myself. The moment that rule slips is the moment the speed becomes a loan rather than a gain.

Elsewhere: deleting the modal library

Non-AI note, because it was satisfying. <dialog> and the popover attribute are in every browser I support, so a dependency I had carried since the jQuery UI days came out of two projects.

<button onclick="signup.showModal()">Sign up</button>

<dialog id="signup">
    <h2>Sign up</h2>
    <form method="dialog">
        <label>Email <input type="email" name="email" required></label>
        <button value="cancel">Cancel</button>
        <button value="ok">Send</button>
    </form>
</dialog>

Rendering in the top layer so z-index stops mattering, a stylable ::backdrop, focus moved in and returned on close, Escape to dismiss, the rest of the page inert. That list is the entire reason those libraries existed.

showModal() and show() are not the same: only showModal() gives you the backdrop, the inert page and Escape-to-close. I have never wanted show().

In short

AI went from autocomplete to doing whole tasks. Claude Code became part of the daily workflow, tried Claude Flow and dropped it when the tool caught up, and deleted a modal library I had carried since jQuery UI.

The year in commits

Commits by month in 2025: 2413 in total, peaking at 614 in Dec.
Jan 2025: 28 commits J Feb 2025: 28 commits F Mar 2025: 41 commits M Apr 2025: 43 commits A May 2025: 189 commits M Jun 2025: 193 commits J Jul 2025: 286 commits J Aug 2025: 102 commits A Sep 2025: 302 commits S Oct 2025: 302 commits O Nov 2025: 285 commits N Dec 2025: 614 commits 614 D