How do you stop AI coding agents from silently duplicating code?
Something I keep running into with vibe coding: the agent loses context mid-task and rebuilds a helper that already exists, under a new name, a couple of folders away.
Everything compiles and tests pass. But now half the app uses version A and half uses version B, and the two slowly drift apart. Each version passes review on its own, so nothing looks broken.
The symptoms can be small, like inconsistent date formatting across pages. They can also be serious. If only one copy got the auth check or input validation, part of your app is protected and part isn’t, with no visible sign.
One cheap guardrail I’ve seen: at the end of each session, ask the agent to list every new function it created, then check for near-duplicates before release.
I’d love to hear how you handle this:
Have you hit this? How did you first notice, through a bug report, code review, or something else?
What’s in your workflow to prevent it (rules files, a shared utilities index, linters, duplicate detectors)?
Do you review new files and functions specifically, or mostly trust tests?
Any tools that reliably catch near-duplicate code?
Practical setups over theory, please. Thanks!
Replies
What helped me most was writing the "only one way to do this" rules down in a file the agent reads at the start of every session. Mine says things like: every tap target goes through one Pressable widget, every vibration through one Haptic class, all database access through one manager file, never call the SDK directly from a screen. Some of those rules exist because a second version had already crept in and the two drifted apart, exactly like your date formatting example. Once it's written down, the agent goes looking for the existing helper instead of inventing one, and a quick grep for the forbidden direct call catches what slips through. Your end of session list is a nice extra check, I might borrow it.
Yes. In my case it's handled by rules in CLAUDE.md, and I'm pretty strict about it. Telling the agent after the fact never fixed it, the same mistake just came back under a different name, so the rule itself goes in there where every session reads it. The ones that really can't be broken are hooks that reject the tool call. On top of that I've got a refactoring command I run regularly to clean things up.
I usually do a quick git diff --stat at the end of each vibe coding session just to inspect newly created files and utility folders.
I have been using a simple AST-based duplicate detector in our pre-commit hook that flags functions with similar logic before PRs get merged.
On larger codebases this gets much worse, because nobody holds the whole map in their head anymore, and the agent doesn’t either. The fix that mattered most for us was structural. Auth and validation live in middleware, so a duplicated helper can’t quietly skip a security check. Beyond that, a shared-utils index in the rules file, jscpd in CI, and a PR step that lists every new exported function catch most of the drift before it ships. Tools catch copy-paste. A renamed rewrite still takes a reviewer who knows the code.
I set up a rule asking the agent: Check if a similar helper exists in @/utils before writing new code. simple prompt tweak but super effective.