Rebuilt something that already existed
重新造了一个早已存在的轮子
Instead of finding the existing function, component or service, the agent writes a second one, and now there are two to keep in sync.
Applies to: Claude Code · Cursor · Codex · Copilot agent
Symptom
A new `formatCurrency`, `useDebounce` or `apiClient` next to the one the codebase already uses, with slightly different behavior.
Why it happens
Writing new code is faster than searching for old code, and the agent's context rarely includes the whole repo. Kaplira's first step is to "check whether the agent found the existing implementation", noting that a second implementation can widen the task without fixing its cause. Over time, this is what developertoolkit.ai calls erosion.
Example
Illustrative.
textexisting: src/lib/money.ts export function formatCurrency(cents, locale)
new: src/cart/utils.ts export const fmtPrice = (n) => "$" + n.toFixed(2)
Copy-paste fixes
Pick the files for the agents you use. Snippets are in English so they work in any repo.
Claude Code: add to CLAUDE.md
CLAUDE.md## Reuse before you write
- Before writing a helper, hook, component or client, search the repo for an existing one
(`rg -n "format.*currency|useDebounce|apiClient" src`) and report what you found.
- Use the existing implementation. If it doesn't fit, say why, and extend it rather than writing a parallel one.
- Keep a short "Where things live" section in this file for common utilities.
Codex, Copilot coding agent and others: add to AGENTS.md
AGENTS.md## Reuse before you write
- Before writing a helper, hook, component or client, search the repo for an existing one
(`rg -n "format.*currency|useDebounce|apiClient" src`) and report what you found.
- Use the existing implementation. If it doesn't fit, say why, and extend it rather than writing a parallel one.
- Keep a short "Where things live" section in this file for common utilities.
Cursor: project rule
.cursor/rules/duplicate-implementation.mdc---
description: "AgentFails: Rebuilt something that already existed"
alwaysApply: true
---
## Reuse before you write
- Before writing a helper, hook, component or client, search the repo for an existing one
(`rg -n "format.*currency|useDebounce|apiClient" src`) and report what you found.
- Use the existing implementation. If it doesn't fit, say why, and extend it rather than writing a parallel one.
- Keep a short "Where things live" section in this file for common utilities.
"Where things live" section for CLAUDE.md / AGENTS.md
CLAUDE.md## Where things live (use these, don't recreate them)
- Money/currency formatting: src/lib/money.ts
- HTTP client (auth, retries): src/lib/api.ts
- Date helpers: src/lib/dates.ts
- Shared UI components: src/components/ui/
Sources and credit
- Kaplira: When an AI agent changes unrelated files (investigate the cause first)
- developertoolkit.ai: failure taxonomy (erosion)
- @octavianslash on X: a cookie middleware with a bespoke dispatch layer duplicating the existing middleware system
- @paolocargnin on X: rejected code often reimplements something that already exists in the codebase
- @triskweline on X: preventing a third notion of "is this invoice paid"