A Year of Agents, Measured in the Git Log

October 26, 2026

A commit graph over 2026: human-only commits fading out as agent co-authored commits take over

Everyone who builds with coding agents has an opinion about how much they help. I had one too. Then I realised the answer was sitting in my git history, and that it would be more useful to count than to guess.

So I counted. Every repository I touched in 2026, from the Koppa platform down to a one-page marketing site. This post is what the log says, including the parts I would rather it didn’t.

How I measured

Every commit an agent co-wrote carries a Co-Authored-By trailer. That convention started in February, so January reads as all-human when it was not, and one of the two tools I used never added a trailer at all. The numbers below therefore undercount. I would rather publish a floor than an estimate.

The scope is the 26 repositories in my working directory, January through September 2026, commits authored by me. Automated commits from the CMS bot are excluded. The three that matter are the Koppa web application, its API and the Flutter app, so most of the detail comes from those.

The curve

MonthAgent co-authoredHuman only
January0559
February213481
March161439
April21328
May338249
June763347
July682194
August1,293396
September2590

Those are the three core repositories combined. Across everything, 8,385 commits, of which 5,016 carry the trailer.

Two things stand out. The first is that the pivot is sharp. Until April the agent was a tool I reached for sometimes. From May it was the default, and by September there was not a single commit I wrote alone. The second is the volume. August produced more commits than the first four months of the year together, and that was not a month of trivial changes. It was the month the whole email system moved out of the web app, among other things.

The honest reading of the throughput is “roughly tripled”. I would not defend a more precise number, because commit counts are a loose proxy and the work itself changed shape.

What got better

The commit messages. This surprised me most. A year ago my messages said what changed. Now they say why, name the trap that was avoided, and often carry the date and the production evidence that a change was verified. One from this month explains, in four paragraphs, why six relegated clubs lost their shirts in the fixture list, which earlier change caused it, and when the fix was applied to production. I did not write that. I reviewed it.

Operational knowledge got written down. 110 skill and specification files now sit next to the code, and 320 commits this year touched the instruction files the agent reads at the start of every session. Almost every one of those files encodes something that cost real time. How to run a one-off job against the production database without taking it down. Why a certain index exists. Which Sportmonks status means the ball was kicked and which means it was not. That knowledge used to be in my head, which is a single point of failure with a mortgage.

Dangerous commands grew a convention. Every command that writes to production data now previews by default and needs an explicit flag to execute. One-off jobs print a count before and after, so the log proves what happened rather than that the process exited zero. These are the kind of habits a good team enforces in code review and a solo founder quietly skips. I did not skip them this year, because the agent kept proposing them and I kept saying yes.

I wrote about the mechanism behind this in Recursive Self-Improvement. The agent writes down what it learned, reads it next time, and does the task better. The numbers above are what that loop looks like from the outside.

What did not get better

Self-inflicted regressions are common. I searched the commit bodies for phrases like “got it wrong”, “silently”, and “never ran”. 79 hits in the web app, 67 in the API, 43 in the Flutter app. That is a lot of commits whose purpose is to undo an earlier commit’s mistake.

The reverts cluster around agent work. 25 revert-style commits in the web app this year. The pattern is a feature done in one go, shipped, found wrong, reverted, redone. One change to how language prefixes work in URLs was reverted three times in a row before it stuck.

Incidents happened. 29 commits in the web app mention an outage. Two were directly caused by agent-written code that nobody load-tested: a database join that could not use an index and took the site down on a match day, and a readiness check that kept answering “not ready” for six hours after a restart. Both were the kind of bug that reads correctly and fails under load.

And the git log cannot show you the twelve days in October a content system was down because a registry cleanup policy deleted the image it was running on. Nothing in any repository changed. Nothing alerted. I found it by accident while looking for something else. That one is not an agent story. It is a monitoring story, and I will write it up separately.

The bug that came back three times

One failure shape deserves its own section, because it recurred and because every fix for it was a document.

The platform draws a club’s shirt from a table of colours. The table is filled by a generator that reads the fixture list and dresses every club it finds. The first time this ran, it ran inside a database migration. A migration executes once, at the moment it is applied, and a competition imported the next day gets nothing. 151 of 153 clubs in one competition rendered in the default shirt, and nothing reported it.

The fix was to move the generator into a command that could be re-run. The specification that came out of it says, in bold, never to generate kits in a migration again.

Then it happened again, differently. Six clubs relegated from the top division had their shirts filed under the top division. The lookup fell back to a club’s other leagues when the current one had no entry, which worked until the generator gave the second division its own entries. Now the fallback found the second division first, found no row for those six clubs, and stopped. The generator’s own output broke the fallback.

And a third time, this month. A cup competition with 111 entrants, 86 of them from divisions the platform has never carried. No table row anywhere, blank shirts on every fixture.

Three occurrences of the same shape: a data source that was complete when it was written, and silent about data that arrived later. After the first two, the agent and I wrote careful explanations of the trap. After the third, I know what would have caught all three, and it is not a third explanation: a check that runs after every import and lists the clubs that have no shirt. That is the next thing on the list.

That is the lesson of the year, if there is one. When an agent gets something wrong, the reflex is to document the trap so the next session avoids it. Documentation is cheap and it feels like progress. A test is the only fix that still works when nobody reads the document.

What I would tell a team starting this now

Count from the start. Add the co-author trailer on day one. The numbers are the only way you will ever settle an argument about whether this is working.

Make the judge before the agent. I said this in the self-improvement post and the git log just proved it. Every recurrence above would have been caught by a check that existed before the second attempt.

Treat instruction files as code. They now carry more operational knowledge than any wiki I have maintained. Review changes to them, keep them in the repository, and prune them, because they grow faster than you expect.

Expect the reverts. A tripled throughput with a visible rate of self-correction is still a tripled throughput. The question is whether the correction happens before or after a user sees it, and that is a question about your tests, not about the agent.

Conclusion

A year ago I typed most of the code in these repositories. Now I review most of it. The output roughly tripled, the quality of the record went up, and the failure mode that stayed is the one every engineering team already knows: a change that was right about the data present when it was written. The agent did not invent that bug. It just produced it faster, and then helped me find it.

If you are putting agents into a delivery process and want someone who has run that loop in production for a year, that is what my agentic engineering practice is for. Have a look at my availability and get in touch.

Related reading: Recursive Self-Improvement, Feedback Loops: Keep Them Short and Fast and Vibe Coding.