Everyone built the same agent (notes on an org brain)
I set out to build a small thing: a bot that reads an on-call incident, works out the likely cause, and drafts a fix a human can approve. Useful, bounded, a weekend's worth of ambition. What I actually walked into was a bigger, dumber problem — half the team had already built the same shape of thing, and none of us knew about the others.
The agent is easy to describe. An incident comes in; it pulls up similar past ones, walks the codebase to a probable cause, checks its own answer, and opens a draft PR that a person reviews before anything ships. The interesting part wasn't the agent, though. It was the one thing I had to build to make it any good: a map of the code.
An LLM in a big codebase is a new hire with no map
Drop a capable model into a large, unfamiliar codebase and it behaves like a sharp new hire on day one: it greps around, follows a hunch, and sounds completely certain about the wrong file. The fix is the same one you'd give a person — a map. So I built a graph of the code: symbols, who calls what, and the seams where one service hands off to another. The agent locates on the graph first, then reads only the handful of files that actually matter.
I measured this rather than guessing. Letting the agent search raw was expensive and wandered. Giving it only the graph was cheaper but confidently wrong — it would name a service that wasn't even involved, because a graph is a closed world and it can't see what it doesn't contain. The combination — locate on the graph, then read the real source — was the cheapest and the most correct: roughly half the tokens of the naive version, and it stopped blaming the wrong thing.
A code graph is a map, not the territory. It tells the agent where to look; the source tells it what is actually true. Skip the second step and you get fast, fluent, and wrong.
Then I noticed everyone had built a corner of the same thing
I went to reuse a teammate's document-search tool and found it was, structurally, my agent with a different face. Then another one for validating configuration. Then an analytics assistant. Same recipe every time: a model, a set of tools, a chat surface, updates posted back to the team. Four or five of us, in four or five repos, none aware of the others. Two separate knowledge bases. Two of every piece of scaffolding. Zero integration between any of it.
That reframed the whole thing. The bottleneck was never the engineering — every one of those builds was fine. The waste was that nobody had turned their head and compared notes. We'd each paid the cost of building the plumbing and shipped none of the connective tissue. The thing worth building wasn't a sixth agent. It was one seam that let all of them share what they knew.
Two kinds of question, the same parts in opposite order
Once I looked at what people actually asked, there were plainly two modes. One is forensic: why did this specific thing fail for this account, right now. That question wants the incident memory, the code graph, the source, and the live logs — and the prose docs barely help. The other is exploratory: how does this subsystem work, help me onboard. That one wants the docs first, and the code graph is barely a map. Same pillars, ranked in the opposite order.
This is the whole reason one fixed pipeline can't serve everyone. The system has to notice which kind of question it's holding and order the pillars accordingly. A cheap classifier on the way in does most of that. The important discipline: this router only decides what's relevant, never what's allowed. Those are different jobs, and quietly merging them is how you build a security hole.
One front door, not one big box
The obvious move is to pour everything into a single store and search it. It's the wrong move. A call graph, a pile of past incidents, and a wall of documentation are three different data shapes that want three different engines — graph traversal, vector similarity, keyword search. Force them into one and each gets worse. So the merge happens at the interface, not the storage: one gateway that every human and agent talks to, which works out which backends a question needs, asks only those, fuses the answers, and writes down every call. Federate; don't consolidate.
The nice thing about a front door is that the rooms already exist. Most of these pillars were built — they just each had their own doorway. The gateway isn't a rewrite; it's the merge commit nobody had gotten around to.
Give the agent tools, not a database login
There's a tempting shortcut: hand the agent a read-only connection and let it write its own queries. Don't. A named tool — 'get the published menu for this location at this time' — bakes in the correct source of truth, including the sharp edges only the owning team knows about. A raw query bakes in whatever the model guessed, and a well-formed, plausible, wrong answer is worse than an error, because it looks right and ships. So the live surface is a set of intent tools, each declaring exactly what it touches, with a guarded read-only escape hatch for the rare question no tool covers. When that escape hatch gets used for the same thing over and over, that's your backlog for the next tool.
Because every request is a named tool, you get access control almost for free. An engineer's agent can see the code tools; a support-facing assistant sees only the documents it's cleared for and never the codebase — the code tools don't even appear for it. Permission lives on the tool, denied by default. The router picks what's relevant, the gate decides what's allowed, and the two never trade jobs.
Build the chassis once
The instant you have one of these servers you want ten, one per domain. And every one needs the same unglamorous parts: auth, sessions, an audit trail, the permission gate. The mistake — which by this point the team had made four separate times — is hand-rolling that for each new server. So the shared parts became a chassis: a small base a new server is built on, where you write your handful of tools and inherit the rest. The proof it worked was retrofitting the first pillar onto it, deleting all of its bespoke plumbing, and watching nothing break.
Knowledge that pays for itself
The last piece is a loop. Every solved incident is a piece of knowledge, and if it evaporates when the ticket closes, the corpus slowly rots between the sprints where someone finally 'writes the docs.' So a confirmed investigation writes itself back — into the incident memory automatically, and into the documentation as a draft that a human merges. Read on the way in, write on the way out. The corpus gets better as a side effect of the work, which is the only kind of documentation that survives contact with a deadline.
Where it actually is
Honest status, because the fun part of these write-ups is usually oversold: the code maps across the services are built, the on-call agent runs, and the incident memory works. The first retrieval pillar sits on the shared chassis. The gateway and a single sign-in story across the whole fleet are the next real work. And the hardest part left isn't code at all — it's getting several people who each built the same thing to agree to build the next one once, together.
None of this needed much new code. It needed a merge commit, and one conversation we all kept not having.
Built something similar, or want to argue with an approach here?
contact@singhpratap.dev