Skip to content
Ben is currently available for contract work for 3D & web solutions — reach out.

Back to Blog Listing

Coding Agents Underestimate the Cost of Code They Own

Your coding agent just rebuilt a library you could have installed. Now every future change has to pay for that decision.

Ben Houston • • 6 min read

Coding agents make code cheap to write. They can also leave you with far more code to maintain than the task required.

While building Land of Assets, an enterprise 3D content management platform, with Claude, I repeatedly had to replace custom implementations with established libraries:

  • Data fetching: pages full of loading flags, effects and cleanup guards became a handful of TanStack Query calls.
  • 3D previews: a buggy custom viewer, built over several rounds of feedback, was replaced by <model-viewer>.
  • Forms: hundreds of lines of field checks and state management gave way to TanStack Form.

Each time, I had to suggest the library.

These are observations from my projects, not a controlled study. But they point to something worth measuring: how much does an agent's code cost to change over the next hundred tasks?

You pay for custom code four times#

A dependency creates an obvious maintenance obligation. Custom code creates one too, but it arrives a few lines at a time, each apparently justified by the current task.

1. Writing it. More generated code generally means more output tokens and more review. Replacing handwritten fetch state with a few library calls saves work immediately.

2. Testing it. You still need integration tests with a library. But write your own fetching layer and you also take responsibility for retries, cancellation, race conditions and cache invalidation. Your test surface now includes the plumbing as well as the product.

3. Understanding it again. A familiar API compresses meaning. An agent that knows useQuery can often work from the call site and consult the documentation. A custom useFetchWithRetry has to be understood from its implementation and tests. That work returns when a new agent takes over or a change challenges the original assumptions. Context caching can reduce the token bill; it doesn't eliminate the need to understand the code.

4. Extending its design. A mature library may encode years of decisions about edge cases and API boundaries. A first-pass implementation often encodes one screen's requirements. The second screen needs something different, so the patches begin. The next feature inherits those patches.

Cheap generation reduces the first cost. The other three accumulate across the life of the application. With usage-based agents, some of that maintenance effort appears directly in the bill. With flat-rate access, it still consumes time and context.

A wheel assembled from many bolted metal parts beside a simple precision-made wheel.

Adding a dependency looks risky; adding code doesn't#

I don't know what caused Claude's choices in my projects. My working hypothesis is that several incentives make custom code look safer than it is.

“Follow existing patterns” can favour extending handwritten plumbing. “Avoid scope creep” can make a dependency seem like an architectural decision requiring permission, while another hundred lines feels like completing the request.

Package recommendations also have a real failure mode: models invent plausible names. Researchers have documented package hallucinations and their supply-chain implications. Caution about an unverified package makes sense. It doesn't settle whether an established implementation is preferable to a custom one.

The evaluation setup matters too. SWE-bench measures agents on real repository issues. Resolving one issue is useful evidence of capability, but it doesn't tell us whether the design makes the next fifty issues easier or harder.

A custom implementation can pass today's tests while creating tomorrow's maintenance burden. An evaluation that ends at today's tests never sees that cost.

“Use these libraries” only helps when you know them#

I can put preferred libraries in CLAUDE.md or AGENTS.md. That helps when I already know the answer.

One reason to use an agent is that it may know a useful tool I've never encountered. If I have to name every library, I'm supplying the architectural judgment as well as the requirements.

Developers with less experience may have no reason to recognize that their agent is rebuilding a form library. Offering three unfamiliar packages doesn't necessarily help them decide. The useful behaviour is to investigate, make a defensible recommendation, and explain the trade-off briefly.

Popular libraries also provide a vocabulary people and agents can share. A contributor can recognize a query or form field without reconstructing a private framework. An allowlist might reduce installation friction, but it won't make the agent think of the appropriate library in the first place.

Measure the next hundred changes#

I'd like to see a benchmark built around the total cost of repeatedly changing an application, with dependency decisions available to the agent. Call it LongHaul.

Research already addresses parts of this problem:

  • SlopCodeBench asks agents to extend their earlier solutions and tracks verbosity and structural erosion.
  • SWE-EVO uses release-note-driven evolution tasks from real projects.
  • SWE-Chain makes each release-level upgrade inherit the agent's previous codebase.
  • MaintainCoder examines maintainability under changing requirements.

LongHaul would put lifetime cost at the centre of the scorecard. Each application would receive roughly a hundred sequential change requests: new features, revised assumptions, removals, and changes that force refactoring.

Two tracks: build an application from scratch, or inherit a working application with awkward design decisions. The takeover track resembles much of the software work I've done.

Continuous ownership: each task starts from the agent's previous output. Save checkpoints for inspection and reproducibility, but don't reset to a clean reference implementation. That would erase the consequences we're trying to measure.

Equal access: give runs the same package registry snapshot and documentation access. Package choices should be reproducible, and a failed download shouldn't decide the result.

The scorecard would track:

MeasureWhat counts
CorrectnessAcceptance tests at every stage, regressions, and completion of the sequence.
Total costInput and output tokens, tool costs, elapsed time, and human intervention.
Code ownedApplication and test code the agent maintains, including copied or vendored implementations.
Design indicatorsDuplication, complexity hotspots, and dependency health.

Record usage as well as dollars so pricing changes don't obscure comparisons. Correctness must be a prerequisite for any efficiency claim: an agent that gives up halfway through shouldn't win because it used fewer tokens.

Code metrics would be supporting evidence. Short code can be unreadable, and low cyclomatic complexity can hide a bad design behind dozens of tiny functions. The decisive measure is whether the application keeps meeting requirements at a reasonable cost as changes accumulate.

LongHaul wouldn't award points for installing TanStack Query. It would give an agent the opportunity to benefit from that decision over the next hundred tasks. If a custom implementation proves cheaper, clearer and just as reliable, it should win.