The right agent for the job
There’s a tendency, when people start working with AI agents, to build one agent that does everything. One system prompt to rule them all. One tool list that covers every possible action the agent might conceivably need. One model that reads files, writes code, runs tests, creates pull requests, searches documentation, sends Slack messages, and probably orders your lunch if you asked nicely enough.
I get it. It feels efficient. One thing to configure, one thing to debug, one thing to explain to the next engineer who inherits it.
It’s also a trap, and it’s one I’ve fallen into myself. The everything-agent sounds powerful in theory and turns out to be mediocre in practice — and the reason why is something every senior engineer already knows from watching teams grow.
What actually happens when one thing does everything
Good teams don’t ask one person to do every job. The person who reviews infrastructure changes is not the same person who writes customer emails. The engineer who owns the database schema is not approving marketing copy. You might think that’s just about skill sets — but it’s really about surface area, accountability, and the cognitive cost of holding too much in your head at once. When someone is responsible for everything, every context switch is legitimate, and there’s never a clean boundary to hide behind.
Agents have all the same problems.
Tool noise is a real thing
Here’s something that doesn’t get talked about enough: giving an agent too many tools makes it worse, not better.
When a model has 50 tools available, it has to reason about which 3 are relevant to the current task — and that reasoning happens silently, in the middle of everything else it’s doing. More tools means a longer context devoted to tool descriptions. More tools means more ways to accidentally pick the wrong one. More tools means the model is spending attention on send_slack_message even when all it needs to do is read_code and write_code.
If you’ve worked with these systems for any length of time you’ve seen it firsthand. It’s the model equivalent of decision fatigue. You wouldn’t hand an intern a keyring with 50 keys and say “find the one that opens the supply closet.” You’d hand them the right key.
The same principle applies here. An agent doing code review doesn’t need write access. An agent that’s gathering research doesn’t need to be able to deploy anything. An agent that’s drafting a PR description doesn’t need shell access to your build environment. Giving them those tools anyway doesn’t make them more capable — it adds surface area for things to go wrong and makes the model work harder to ignore what isn’t relevant.
Prompt clarity compounds
Specialization also makes prompts dramatically better.
When you’re writing a system prompt for an agent that does one well-defined job — “you read code and produce a structured analysis of the blast radius of this change, nothing else” — the prompt is short, precise, and testable. You know exactly what good output looks like. You know exactly what bad output looks like. When the agent drifts, it’s obvious.
When you’re writing a system prompt for the everything-agent, you’re writing a policy document. Every clause you add to cover one capability potentially conflicts with a clause you added for another. “Be conservative with file changes” sounds great for a refactoring task and terrible for a migration task. You end up with hedged, conditional language trying to capture every situation, and the model is left doing interpretive work you didn’t intend.
Narrow prompts are honest about what the agent is supposed to do. They make the model’s job easier and your debugging job easier. When something breaks, you have a much smaller search space.
Permissions aren’t just security theater
There’s a habit of thinking about agent permissions the way we used to think about development environment permissions: a mild inconvenience, mostly theater, something you deal with so that compliance doesn’t complain.
I’ve written before about the Cursor agent that wiped a company’s production database in nine seconds. That wasn’t a model failure. That was a permissions failure. The agent had access it didn’t need, used it in a way that made internal sense given its context, and by the time anyone noticed, there was nothing left to recover.
Minimal permissions aren’t about distrust. They’re about blast radius. An agent that can only read files can’t accidentally delete them. An agent that can only run approved build targets can’t rm -rf its way to an empty repo. An agent that has no network access can’t exfiltrate your API keys even if someone manages to inject a prompt that asks it to.
This is exactly why good organizations separate production access from development access, and development access from read-only auditing. The principle isn’t that your engineers are malicious. It’s that accidents happen, and the right structure limits how bad any individual accident can get.
The composition pattern that actually works
Once you’ve accepted that specialized agents are better than generalist agents, the natural question is: how do you make them work together?
The answer is simpler than it sounds. Agents don’t need to be aware of each other at the model level. They need well-defined inputs and outputs.
A useful pattern I’ve landed on looks roughly like this:
-
A planning agent gets broad context — the goal, the codebase structure, the design constraints — and produces an ordered list of steps. Its job is thinking, not acting. It has read access and maybe the dependency graph, but no write tools. It can’t be tempted to “just fix that quick thing it noticed.”
-
Implementation agents get one step at a time from the plan. Each has a tightly scoped tool set matching the kind of work in that step. A “make this code change” agent has
read_code,write_code, and the dependency graph. A “run the tests” agent hasexecute_build_targetand the right to read test output. A “create the PR” agent has GitHub access and nothing else. -
A review agent (or a human) looks at what was produced before anything merges.
Each agent is short-lived, focused, and auditable. Their context windows aren’t polluted with tools and instructions from six other jobs they might be doing. When one fails, you know where to look.
This isn’t some exotic architecture. It’s just separation of concerns applied to the agent layer — which is exactly how you’d design a reliable system for human workers too.
Don’t optimize for “one thing to configure”
The reason people build everything-agents isn’t laziness. It’s the same instinct that produces monoliths: one thing to configure, one place to look, one team responsible for the whole surface.
Monoliths are great — until they’re not. The codebase grows, the system gets harder to reason about, and the cost of every change goes up because touching one thing risks breaking everything else.
The same lifecycle plays out with agents. The everything-agent is fine for demos and side projects. Under real load, with real stakes, the lack of structure starts to cost you: harder to debug, harder to trust, harder to extend without breaking what already works.
The teams and systems that stay reliable as they grow are the ones that invest early in clear boundaries, narrow responsibilities, and explicit handoffs. That’s as true for software architecture as it is for org design — and it turns out it’s equally true for the agents you’re building today.
Give them the right tools, the right prompts, and the right scope. They’ll do better work. So will you.