The three layers every agent needs.
Okay, here is what happened. In the last two days I built three new AI agents. One is an accountant. One is an IT admin. One reviews our contracts. I thought I was fixing three different problems. I was not. I was fixing the same problem three times. And the fact that it felt the same each time is the whole story.
The problem I thought I had
I run a small business. I'm the founder, the bookkeeper, the sysadmin, the junior lawyer reviewing my own contracts before sending them to a real one. Every one of those roles has a different texture. Bookkeeping is receipts and HST and QuickBooks. IT is DNS records and TLS certs and alerts. Legal is clauses and disclaimers and the Law Society of Ontario. They look like three different jobs, because they are.
So I sat down to build "my AI accountant." I thought the code would look nothing like the IT agent's code. I thought both would look nothing like the contract reviewer. New domain, new tools, new everything. That was my guess.
That turned out to be wrong in a useful way.
What I actually built. Three times
Each of the three agents ended up with exactly the same three files, named differently but doing the same job at the same level of abstraction. If you renamed the files, you couldn't tell one agent from another by its structure.
Here's the pattern:
Layer 1: the tool file. A TypeScript file that knows how to do things. For the accountant, it's AccountantAgent.ts . It knows how to call the QuickBooks Online API, create a draft expense, list the chart of accounts. For the IT admin, it's ITAgent.ts . It knows how to talk to GoDaddy, DigitalOcean, Twilio, Telegram. For the contract reviewer, it's ContractReview.ts . It knows how to read a markdown contract, scan it for missing clauses, and return a structured review. Each tool file is a CLI with actions like --action health, --action dry-run, --action list-dns. None of them touches an LLM directly. They're plumbing.
Layer 2: the rulebook. A JSON file that knows what the agent should and shouldn't do. The accountant's rulebook has vendor-to-GL-account mappings, HST rules, escalation triggers, and a hard "draft-only" guardrail. The IT agent's rulebook has alert routing by severity, reserved subdomains, backup policies, and a list of destructive operations that require a confirmation flag. The contract reviewer's rulebook is a library of ten approved Ontario B2B clauses, each tagged with a risk level and review notes. The rulebooks are the part that changes when the business changes. They're configuration, not code.
Layer 3: the agent definition. A markdown file that describes why the agent exists . Its role, its workflow, its hard refusals, its escalation paths, and the story of its own build. This is the file a human reads to understand what the agent is for. It's also the file a model reads when you point it at the agent's persona. The accountant's definition says "I'm the CFO role; I handle cash flow and expense reconciliation; I never post transactions directly." The IT admin's definition says "I'm the CTO role; I never auto-delete DNS records; I escalate unknowns via Telegram." The contract reviewer's definition says "I'm internal-use only; I never answer 'should I sign this'; every output carries a mandatory disclaimer."
Three files per agent. Same three, in that order. By the third one, I caught myself copying the last agent and swapping out the domain bits. That was the tell. I wasn't building three things. I was stamping out the same shape three times.
Why the separation matters
Here's why this pattern works. I want to say it out loud. I've watched myself skip this. I've watched others skip it too. We all paid for it later. The reason is simple. Each layer runs on its own clock.
The tool file changes when you add a new capability. New action, new integration, new API endpoint. These changes are rare and structural. Weeks between edits, once you've got the basics wired.
The rulebook changes when the business changes. New vendor shows up on an invoice. You decide HST treatment for a reverse-charge case. You add a new subdomain to the reserved list. These changes are frequent and tactical. Days or hours between edits.
The agent definition changes when the agent's role changes. Rarely. When you decide to broaden the refuse-line. When you move an agent from internal-only to client-facing. These are quarterly-scale decisions.
If you cram all three concerns into one file, you end up editing the same file for three different reasons on three different timescales. That's how agent codebases rot. That's how you end up with a single 2,000-line agent.ts file that you're afraid to touch because it contains both "the vendor mapping for Stripe" and "the hard rule about never posting directly to QuickBooks." You're afraid to touch it because the tactical changes and the structural rules live in the same blast radius.
Three files solves it. Tool is code. Rulebook is config. Definition is prose. Each has its own change cadence, its own review criteria, and its own failure mode.
Where MCP fits. The glue nobody notices
One thing I didn't expect, but should have: none of the three tool files had to re-implement access to Gmail, Obsidian, Google Drive, or the filesystem. All of that work was already done by the MCP servers we've been running for weeks.
MCP is short for Model Context Protocol. It fixes a pain. Without it, each agent needs its own Gmail tool. With it, they all share one. They don't have to know how it works. The inbox triage agent already uses an MCP server for Gmail. The accountant agent will use that same server. It will read labeled receipts. The law advisor uses the Obsidian local-REST-API MCP tool. It reads my clause library. The IT admin agent will use that same tool. It will write an incident log to my vault. One tool. Many agents.
This is what the agent-framework crowd keeps missing. The win is not the LLM. The win is that the LLM can grab a dozen ready-made tools and chain them into a workflow. Nobody has to write a new Gmail client. MCP is the boring part that makes the cool parts work.
The fractal I didn't plan
Here is the part I saw this morning. I had to sit with it for a minute.
At the business level, I sell a thing called the three-agent executive team: a CEO agent, a CTO agent, and a CFO agent, organized the way a real executive team is organized. It's the mental model I use in every pitch. Three specialists. One team. Never sleeps.
At the implementation level, each of those specialists is itself built out of three layers: tool, rulebook, definition. It's the same "three specialized pieces working together" shape, at a different scale.
That's a fractal. I didn't design it to be one. But it turns out that the mental model I'm selling on the outside is the same mental model I'm using on the inside. That's probably not an accident. Patterns that work at one level tend to work at others, because the underlying principle. separate concerns that change at different clocks . Is domain-independent.
Here's the good part. I tell a client about a CEO, CTO, and CFO agent team. That same talk shows what good design looks like. I don't have to say so. I tell a coder about the split of tools, rulebooks, and definitions. That same talk makes the case for a team of pros over a jack of all trades. Same point. Two crowds.
What I'd change next
Two things. Biggest cost first if I left them alone.
Shared infrastructure for the rulebooks. Right now each rulebook is a hand-maintained JSON file. That's fine for three agents. It stops being fine at ten. The next evolution is a small shared schema and a validator. Probably another TypeScript file that knows how to load any rulebook, check it against the schema for that agent type, and warn on mismatches. Cheap to build, expensive to skip.
A generator. By the time I build the fourth agent, I should be running a small CLI command that scaffolds the three files from templates. I copy-pasted the first three by hand because I didn't know yet that it was a pattern. The fourth one is when I'll know I should have a tool for it. Writing that scaffolder will take 20 minutes and save hours over the next year.
Why this matters if you're building agents
Building one agent? Put it all in one file. It works fine. Building two? You feel some pain. You can still ignore it. Building three or more? You hit this pattern. You hit it whether you plan or not. So plan for it.
Here are the three things to take away. Just three bullets.
- Separate your concerns by change cadence. Code that changes rarely, config that changes often, prose that almost never changes. Three files minimum per agent.
- Let MCP handle the shared plumbing. Don't re-write Gmail access, Drive access, or filesystem access in every agent. Use the shared tools. That's what they're for.
- Watch for the fractal. The shape of your team structure and the shape of your code are often the same shape, because they're governed by the same principle. If the two shapes diverge, one of them is wrong.
This is the part of the job I like. Three problems look unrelated. Then you see they are the same problem. The pattern that fixed the first one fixes the other two for free.
Build three things. Notice what's the same. That's your architecture.
← Back to all posts