Most AI coding mistakes don't look like mistakes.
They compile. The tests pass. CI is green. The diff reads fine at 6pm on a Friday. Sometimes it's a bug that surfaces two weeks later when money moves where it shouldn't. And sometimes it's not a bug at all — the agent quietly rebuilds something you already had, and you don't notice until you're maintaining two versions of the same thing.
Same root cause both times. The agent couldn't see. It had my prompt. It didn't have the codebase.
I'm the CTO of a payments company. We're FCA-authorised, we move real money for real merchants, and we've leaned on AI agents hard for over a year. So I've watched this happen enough to stop blaming the model for it. Let me show you exactly what I mean, because it happened to me last week.
The report that didn't need to exist
We were adding multi-business support to payouts. One parent account, several businesses underneath it, each needing its own slice of the flow.
The agent did the core work well. I want to be clear about that. On the multi-business payout logic itself, the code was correct. No complaints.
Then I asked for a small follow-on: add callback parameters and a few dynamic fields into the payout report.
The agent went and built a new reporting service. New repo, fresh scaffolding, a whole new report pipeline. It worked. It compiled, it ran, it produced exactly the report I'd asked for.
One problem. We already had a payout report — the single-business one, live in production, tested against real settlements for months. The right move was to extend it to handle multiple businesses and the new fields. Instead I now had two report implementations for the same domain. One battle-tested, one freshly minted. And every future change to payout reporting would either be made twice or silently drift apart.
That's not a bug. Nothing broke. It's worse in a quieter way. It's code-quality debt the agent created because it couldn't see that the thing it was building already existed.
This is the part I keep coming back to. It's not only about bugs. It's about code quality. A blind agent doesn't just get logic wrong. It reinvents, it duplicates, it walks past the shared helper and writes a fourth one. Every instance of that is a small tax you pay forever.
Why a senior wouldn't have done this
A coding agent is the best junior developer money can buy. Tireless, cheap, no ego, near-zero mistakes on routine work. An army of them at your terminal.
But juniors write code. They don't ship products.
A senior handed that report task would have opened with a different question. Not "how do I build a report" but "don't we already have one of these?" That instinct isn't in training data. It comes from having maintained a codebase long enough to know that a second implementation of anything is a liability, not a feature.
The agent never asked that question. Not because it's dumb. Because it only had my sentence. It had no way to know the single-business report existed, where it lived, or that extending it was the whole job.
So the problem stopped being "how do I get a smarter agent" and became "how do I put the judgment a senior carries in their bones somewhere the agent can read it — before it writes a line."
That question is why I built Bodhiorchard. It's open source, Apache 2.0, self-hosted. We run it at Atoa now.
We stopped handing agents a prompt. We hand them a BUD.
The unit of work in Bodhiorchard isn't a Jira ticket. It's a BUD — a Business Understanding Document. One living source of truth for a feature: what it is, why it exists, who asked for it, the design, the tech spec, the decisions made along the way. Vector-indexed, full history, no scatter across Confluence and Slack and someone's memory.
The point of a BUD is that the context is attached to the work, not floating around it. And crucially, Bodhiorchard traces a feature down to the actual code that implements it. A feature isn't a paragraph. It's a paragraph wired to the files, services, and procedures that make it real.
Work moves through seven phases, each its own tab on the BUD:
Requirements → Design → Tech Spec → Development → Code Review → Testing → Prod
Every phase has an agent. Every phase also has a toggle. Flip the agents off and it says "you're driving this BUD" — human in the loop, by design. This was never meant to run while you sleep.
The same task, inside Bodhiorchard
So I gave it the same job. Add callback params and dynamic fields to the payout report. Same class of model. Same one-line request.
This time it didn't start blind. The request came in against the payout feature's BUD, and because the BUD is wired to code, the agent pulled the context over MCP and found the existing single-business report — the real procedure, in the real repo — before it wrote anything.
# The agent reads context before writing — and finds what already exists
POST /mcp → get_bud_context(bud_id: "PAYOUTS-217")
{
"feature": "Payouts — multi-business support",
"request": "add callback params + dynamic fields to the payout report",
"precedent": {
"report": "services/reporting → PayoutReport (single-business, live in prod)",
"guidance": "extend this. do not stand up a second report pipeline."
},
"domain_rules": [
"One report implementation per domain",
"Reporting reads the ledger projection, never writes to it"
]
}
It extended the existing report. Multi-business, dynamic fields, callback params, added to the code that was already there. No new service. No second pipeline. One report that now does more.
The difference wasn't intelligence. It was sight. One agent could see the codebase and one couldn't.
And notice what the agent gets to do versus what it doesn't. The MCP write tools are bounded to the creative phases — it can create and update a BUD, draft the spec, propose the code. Nothing that moves money is a tool an agent can call directly. Read and propose across everything. Execute nothing with a blast radius. That line is drawn on purpose.
Behind the context sits a mechanical gate. Design-pattern lints run in CI, and if an agent reaches for a banned pattern or stands up a duplicate where an ADR says there should be one, the build fails. Not "a reviewer might catch it." The gate fails, every time. And the test suite leans hard on the negative cases agents love to skip — the illegal state transition, the duplicate event, the report that should have been an extension.
The scoreboard is pointed at the thing AI is worst at
Bodhiorchard has a scoreboard, and it does not reward output. It rewards shipped, working value.
You earn points when a BUD reaches production and when your code-review quality holds above a threshold. You lose a point for a bug caught in testing, and more for one that reaches production. The payout only lands when the feature is closed end-to-end, not when the PR merges.
Read that incentive again. It pays for correctness that survives production and for quality that holds up in review — exactly the things a fast, blind agent erodes when it's optimising for a green checkmark. Volume of code earns you nothing. A duplicate report that passes its own tests earns you nothing. Shipping the right thing does.
The honest status
I'm not going to tell you the agents run the whole SDLC while we sleep. They don't. The platform, the BUD lifecycle, the MCP context path, the feature-to-code indexing, the skill profiling — that's live and we use it daily. A fully autonomous execution loop is still being built. Today it's agent-assisted with a human in the loop at the phases that carry weight, and for anything touching payments that's exactly where I want it.
Where do agents own a boundary? Reading context, finding precedent, proposing a spec, drafting code, linting against recorded decisions. Where do they never own one? Anything where the failure mode is money in the wrong account. That's not a limitation I'm apologising for. That's the design.
So, back to blindness
The new report was never a model failure. Neither was the duplicate-refund class of bug before it. Both came from the same place: handing something a blank prompt and hoping it would guess the code you'd already written and the decisions you'd already made.
Give it the context a senior would carry into the review — the domain rules, the precedent, the boundaries, the code that already exists — and put a mechanical gate behind that context so nobody, human or agent, ships past it. The agent stops reinventing your codebase and starts extending it. It stops being a liability and starts being the army your seniors always wanted.
The 80% was already solved. This is how you stop the other 20% from shipping bugs — and from quietly rotting your code quality — while you're not looking.
What's the last thing an agent rebuilt in your codebase that already existed — and where was the context it needed to find it?
I'm Arun, CTO and co-founder at Atoa, building open banking payments for the UK. I built Bodhiorchard, it's open source, and we run it in our workflow. Repo's here if you want to poke at it — feedback over stars: github.com/mickyarun/bodhiorchard. Find me on X @mickyarun.
Top comments (1)
The BUD-to-code link is the important leap here. I’d make its freshness visible to the agent, because stale context can be worse than no context: it produces a confident extension of something that moved three commits ago.
Each context response could carry the indexed commit SHA, branch/ref, generation time, coverage boundaries, and the ADR/policy versions used. If the working tree is newer than the index, the workflow should refresh or explicitly degrade to “context incomplete” instead of silently continuing.
There is also a hard asymmetry in duplicate prevention: finding an existing implementation is evidence; not finding one is not evidence that none exists. Before creating a service, I’d require a broader architecture-inventory/semantic-code search and record what repositories, symbols, owners, and ADRs were checked.
A useful evaluation suite would replay the same feature requests before and after renames, repo moves, refactors, and stale-index conditions, then measure duplicate-service rate—not just test pass rate. That turns “the agent can see” into a claim you can continuously verify.