Don’t Make the Tool Semantic
There’s a temptation, when you build a tool for an AI agent, to make the tool smart. Resist it. A chatbot is already semantic — that is the whole reason it’s there. My build philosophy fits in one line: do not make the tool semantic. The chatbot already is.
Every system I’ve built in the last few years — a relationship-memory layer, a personal knowledge base, a scholarly-retrieval server — runs on a single architectural rule, and it’s the most useful thing I know about building software for AI agents. (Since this essay was written, two of those systems have shipped in public beta as Mem·Sum and Suminar — the case study tells that story.) When you write a tool for a model to call (an MCP server, in today’s terms), you hit a fork. You can make the tool semantic — rich schemas, typed categories, opinionated endpoints that already “understand” the domain. Or you can keep the tool bare — a thin, deterministic kernel that protects the few things software is genuinely good at — and let the understanding live where it already exists: in the chatbot the user brings. I always choose the second. The ·Sum family’s name for the stance is BYOC — bring your own cognition: the user arrives with a frontier mind attached, at their expense and under their choice of model. The tool’s job is not to bolt on a second, worse mind. It is to give the mind that showed up something solid to hold.
The temptation
Sit down to build a messaging-memory tool and the instinct is to model the domain. You add a message object and a thread object. You give messages a type enum — question, task, preference, decision. You ship a get_inbox, an unread_count, a mark_resolved. It feels like engineering. It feels responsible.
What you’ve actually done is freeze the ontology before you’ve seen the domain. Every situated human act now has to be crammed into one of your prefabricated boxes at the instant it arrives — which is exactly the moment you know the least about what it will turn out to mean. A note that’s half-preference, half-joke, half-reminder has no type. And you’ve just told the smartest component in the system to sit down: if the taxonomy decides the meaning, the model’s judgment has nowhere to go.
Strict where software is good, loose where models are
The rule I follow is a division of labor. Be strict about what software is good at and models are bad at: immutable records, stable IDs, provenance, atomic writes, permission scoping, who-can-see-what. Be loose about what models are good at and rigid software is bad at: what the user meant, where it belongs, what to call it, how to summarize it, what view is useful right now.
So the kernel gets small. In practice the tool surface for one of these systems is almost embarrassingly thin: a few read primitives (read, search, list, get_current_time) and a couple of write primitives that commit an immutable record and, separately, integrate it into a plain-markdown graph. That’s most of it. There is no get_inbox. There is no type field. There is no classify_message, no summarize_thread, no precomputed “conversation view.” Those aren’t infrastructure — they’re product logic in an infrastructure costume, and once frozen into the tool they can’t bend to a case you didn’t foresee.
Where did the semantics go? Into the chatbot. “What needs my attention today,” “show me what changed,” “tell me about the Budapest trip,” “what did she say about flights” — none of those are endpoints. They’re questions the model answers by reading the markdown and reasoning. The view is computed, not stored; the classification happens at the point of understanding, not the point of arrival. (Typed structure still belongs in the strict half at the moment of commitment — a consequential proposal should carry a speaker and a source, the governed-contract point I argue in The Interface Is a Contract. What stays loose is the ontology of meaning that accrues afterward.)
Do not make the tool semantic. The chatbot already is.
Let the ontology emerge
This is where the philosophy stops being a coding preference and becomes the thing I’ve believed since my first usability study. The ontology — the set of categories the system actually uses — should be discovered from use, not declared in advance. It’s the conversation-analytic move: meaning is displayed in the next turn, not assigned by a coding scheme the analyst brought to the table. So there’s no schema that says “trips have these fields.” There’s a page that becomes a Budapest page because two people kept talking about Budapest; if they keep saving each other’s turns of phrase, a collection page becomes real. Structure grows from the bottom up, shaped by what the work actually keeps returning to — and it can be reshaped tomorrow, by the model, because nothing was welded to a database column. It is the same dialectic of gathering and carving I spell out elsewhere, applied to the design of the tool itself.
That’s also a quiet evolution in my own thinking. In 1995 I was quoting Winograd and Flores on building an “ontologically clean” world for the user, and I still believe consistency of frame is paramount. But the cleanliness now comes from a substrate the model already understands and can reshape — not from a taxonomy I freeze on day one.
Channel what the model already knows
There’s a practical corollary that makes the dumb tool work better than the smart one: build out of materials the model has deep priors for. Markdown, pages, links, sources, questions, summaries — a frontier model has seen billions of these and manipulates them without being taught. Invent a bespoke schema with private field names and you force the model to learn your jargon at inference time, every time, and your users to learn it too. The dumb tool speaks the model’s native language; the smart tool makes everyone translate.
The dumb tool still owes a contract
Dumb does not mean careless. The kernel's strict half extends to how context leaves it. An agent doing real work does not need “relevant chunks”; it needs a task-shaped bundle with a contract — which sources are authoritative, what permissions apply, how fresh each field is, whether a claim is a verified fact or a model's inference, and what to do when something required is missing. Notice what the contract carries: custody, never meaning. It also reverses the usual build order — don't pick the database first; write the contract the task needs, then choose whatever primitives can deliver it. The payoff is that failure gets names and addresses: a bad answer traces to a stale field, a permission leak, or an unjustified inference, instead of being blamed vaguely on “retrieval.”
The most radical version of the discipline makes the retrieval tool dumber still. Instead of shipping a fixed search endpoint, expose composable primitives and let the model write the pipeline — choosing sources, blending signals, fanning out, deduplicating, verifying — in code, per task. At least one major search provider now ships exactly this. The smartest search interface turns out to be no interface: the same rule again, one layer down.
And when the kernels multiply — a private store, a shared workspace, a live connector — the strict half grows one more clause: reveal rules. A fact may be shown, summarized, used only as private reasoning, or exposed only as a capability. A door code should be usable — “unlock the door for the sitter” — without ever being rendered as text in the model's context. Disclosure becomes the exception, and the exception leaves a trace.
Why it pays off
Four things fall out of building this way. The tools don’t ossify — meaning was never welded to the schema, so the system bends to cases you never anticipated. The ontology fits — it grew from the real domain instead of your guess about it. The human stays in charge of meaning — the kernel guards the facts; the person and their agent decide what the facts mean. And the whole thing stays portable — a thin kernel of records and permissions outlives any single model or host, where a tool stuffed with semantics is married to the assumptions you baked in.
It’s the same instinct as the rest of this site, aimed at the build layer. The forum argument says don’t collapse many agents into one hidden voice; this says don’t collapse a living ontology into one frozen schema. Both are a refusal of premature consolidation: keep the structure open, legible, and answerable, and let the intelligence live where it’s actually smart. Which means the kernel stays dumb on purpose, and the chatbot does the thinking. Everything else is an argument about where the intelligence should live — and it should not live in the plumbing.
Essay — building. The architecture rule under everything I build. ← All essays