Stop an AI Coding Agent From Reinventing Existing Code

Your AI coding agent isn't lazy, it just can't see the helper function you already wrote. Here is the mechanism, a duplicated-helper example, and the AGENTS.md fix.

Steve Jefferson
Steve Jefferson
Developer Advocate
25 August 20261 min read

If your AI coding agent just wrote a second formatCurrency or slugify function when your codebase already had one, you have run into the real reason people search for how to stop an AI coding agent from reinventing code that already exists: the agent never saw your version. Its working context is assembled from the files it opened for the current task, not a map of your whole repository, so when it needs a helper it writes a new one instead of finding yours. This guide breaks down the mechanism, walks through a duplicated-helper example end to end, and gives you the AGENTS.md instructions and prompt pattern that make the agent search before it writes.

Why this happens: your codebase has no map in the agent's head

An AI coding agent does not carry a mental map of your repository between tasks. Its context is rebuilt from whatever it reads during the current session: the file you pointed it at, the files its own reads and greps happened to pull in, and the conversation so far. If your existing formatCurrency, retryWithBackoff, or parseAddress helper is not in that set of files, it does not exist as far as the model is concerned at the moment it starts generating code.

This is a generation problem, not a laziness problem. When a model needs logic to satisfy a task and has no evidence of an existing implementation, it does not answer "I am not sure this exists, let me check." It produces the most plausible continuation given what it has seen, which is a brand new function that looks reasonable in isolation. In practice, the model's search radius quietly stops at the files the current task already pulled in, not the ones sitting three folders over in your utils directory.

The result compounds. Every session that misses your existing helper writes its own near-duplicate, so a codebase that started with one formatCurrency function accumulates three or four, each with slightly different rounding or currency handling, and nobody notices until a bug shows up in only one of them. It is the same underlying context limitation covered in our guide on how an agent loses track of a task partway through, just pointed at a different symptom: there the agent forgets what it already decided, here it fails to notice what already exists.

Not the same problem as an agent adding unneeded dependencies

It is worth separating this from a related failure covered in stop an AI coding agent from adding unnecessary dependencies: that post is about an agent reaching outward, pulling in an external npm or pip package to solve something a few lines of code would have handled. This is the opposite-shaped problem. Here the agent is not reaching outward for something new, it is failing to reach inward for something that already exists in your own codebase.

One failure adds an external dependency you did not need. The other adds an internal duplicate you already had. The fix for one will not fix the other, because the missing piece in each case is different: dependency sprawl needs a rule about when to reach for a package, duplicate helpers need a rule about searching your own code first.

A worked example: the duplicated formatCurrency helper

Here is a case that plays out in most JavaScript and TypeScript codebases within the first few weeks of agent-assisted development.

The codebase already has this in src/lib/format.ts:

export function formatCurrency(amountCents: number, currency = 'USD'): string { return new Intl.NumberFormat('en-US', { style: 'currency', currency, }).format(amountCents / 100) }

Asked to add a price line to a new CheckoutSummary component, the agent opens CheckoutSummary.tsx and the checkout API response type. It never opens src/lib/format.ts, because nothing in the task pointed it there. It writes this instead:

function formatPrice(cents: number) { return '$' + (cents / 100).toFixed(2) }

It compiles, the price displays correctly for US dollars, and the pull request looks fine on review because nobody is diffing it against a helper three directories away. The bug shows up months later: this local formatPrice ignores currency entirely, so a customer paying in EUR sees a dollar sign, while every other screen in the app correctly uses formatCurrency and shows the right symbol.

Same task, with the agent required to search first:

import { formatCurrency } from '@/lib/format' // in CheckoutSummary.tsx <span>{formatCurrency(total.cents, total.currency)}</span>

Same component, one extra step: the agent searched for existing formatting helpers before writing one, found formatCurrency, and imported it instead of reinventing it.

How to tell you already have this problem

Before writing any AGENTS.md rules, it helps to know how much duplication already exists. Run a quick search for repeated function name patterns across your utils and lib directories, and look specifically for functions that do similar work under different names, formatPrice next to formatCurrency, slugifyTitle next to slugify, retryFetch next to retryWithBackoff. A grep for common verbs plus a skim of the results usually surfaces two or three pairs within minutes.

Two signals are worth flagging on their own. First, a helper defined inside a component or route file instead of a shared lib directory is a strong hint it was written on the spot rather than found. Second, two functions with near-identical bodies but different edge-case handling, one that trims whitespace and one that does not, one that handles a null input and one that throws, are usually the same intended behavior implemented twice by two different sessions that never saw each other's work.

The fix: make search-before-write an explicit instruction, not an assumption

An agent does not skip searching your codebase out of laziness. It skips searching because nothing in its instructions told it that searching is a required step, so it optimizes for the fastest path to a working answer, which is writing new code. Fix this by making the search step explicit and by making your existing utilities easy to find once the agent does look.

  1. Add a "reuse before you write" rule to your AGENTS.md. State it as a requirement, not a suggestion: before writing any new function, search the repository for an existing one that does the same thing, and prefer extending or importing it over duplicating it.

  2. List the real locations, not just the concept. "Formatting helpers live in src/lib/format.ts, date helpers in src/lib/dates.ts, validation in src/lib/validate.ts" is something the agent can act on. "Reuse existing code" by itself is not, because the agent still has to guess where to look.

  3. Require a named search action in the instructions, for example: grep the repository for the function name or a close synonym before creating one. Naming the action, grep, search, read the utils directory, gets followed more reliably than a general reminder to check first.

  4. Add a lightweight review check, human or automated, that flags a new file introducing a function whose name or signature closely matches something already in a utils or lib directory. Catching a near-duplicate at review time is far cheaper than catching it after it ships with different behavior.

  5. Keep the utility list current. An AGENTS.md that lists helpers from six months ago sends the agent looking in the wrong place, which produces the same duplication you were trying to prevent.

A prompt pattern to paste before any coding task

Standing instructions in AGENTS.md cover most sessions, but for a task you know touches shared logic, add this to the prompt directly:

"Before writing any new function, search src/lib and src/utils for an existing implementation that does the same thing. If one exists, import and use it. If you extend it instead of replacing it, explain why in a comment. Only write a new function if nothing close already exists."

This works because it does three things a general "reuse code" reminder does not: it names the folders to check, it gives the agent a decision rule for the case where a near-match exists, and it asks for a one-line justification when it decides not to reuse something, which makes that decision visible in code review instead of silent. Saving a pattern like this in a reusable prompt library means every teammate pastes the same instruction instead of reinventing their own version of it.

Frequently asked questions

Why does the agent duplicate a function instead of asking whether one exists?

Most agent setups do not treat "ask before assuming" as a required behavior, and stopping to ask slows down a task the agent is optimizing to finish. Unless your instructions explicitly require a search step, writing a plausible new function is the faster path, so that is what gets generated.

Does a bigger context window fix this?

Not by itself. A larger context window lets the agent hold more files at once, but it still only reads what the current task pulls in. Without an explicit instruction to search for existing implementations, a bigger window just means more room for files it never opens.

Will an AGENTS.md file alone stop every duplicate?

No single file catches everything, but a maintained list of utility locations combined with an explicit search-first rule removes the most common cause, which is the agent simply never seeing that a helper exists. Pair it with a review check for near-duplicate names as a backstop.

What is the difference between this and an agent adding unnecessary dependencies?

They are opposite-shaped failures. Reinventing existing code is the agent failing to look inward at your own codebase. Adding unnecessary dependencies is the agent reaching outward for an external package it did not need. See stop an AI coding agent from adding unnecessary dependencies for that failure mode specifically.

Where should reuse instructions live if I use more than one coding agent?

In AGENTS.md at the repository root. It is the shared convention most coding agents read automatically, so instructions there apply regardless of which specific tool a given session uses, instead of duplicating the same rule across several tool-specific config files. For a broader look at getting reliable output from these tools, see our AI coding tools guide.

Reinvented utility functions are an annoyance. A related risk with real teeth is letting an agent handle AI coding agent database migrations unsupervised.

How did this land?

About the author

Steve Jefferson
Steve Jefferson

Developer Advocate

Steve builds something with Swarmz every week and writes up what worked, what broke, and what he'd do differently. Tutorials and hands-on guides are his lane.

Share

Get the next post in your inbox

One email a month. Product updates, engineering posts, and the best of Built with Swarmz.

I agree to receive emails about AI building tips and Swarmz product news. Unsubscribe any time.