Engineering

Giving Each Agent Exactly What It Needs

February 25, 2026

Agents used to be a name, a system prompt, and a model choice. Everything else was inherited. Every agent got the same number of tools, no voice identity, and no way to hint to the routing layer what it was actually good at. That worked when I had three agents. With eighteen, it was getting sloppy.

The tool problem

The main orchestrator needs all the allowed tools. It delegates, searches, generates images, sends emails, manages reminders. That's its job. But a Research agent has no business seeing generate_image. A Content Writer shouldn't be considering create_reminder. When every agent sees every tool, the model wastes reasoning cycles on irrelevant options, and sometimes picks the wrong one.

This is just least privilege. A specialist should see exactly what it needs and nothing else. Fewer options means a tighter decision space, which means faster and more accurate tool selection. The difference between "pick from number of tools" and "pick from 8 tools" is real when you're paying per token for the model to reason about it. Luckily I am using chutes which is request based, but there was one more issue - polluting the context which adds to hallucinations. I was literally threatening the agent in the prompt, if you hallucinate - you will be replaced and thrown away. Trust me, I did - out of frustrations.

Per-agent tool allowlists

Each agent now has an optional tool list. When set, the agent only sees those tools during inference. When empty, it falls back to the default set for its type, which is how it always worked, so nothing breaks.

The tool catalogue was already organised into categories (memory, web, media, delegation). The form shows categories with checkboxes. Check the category header to toggle everything in that group. Select all, clear all. The backend validates every tool name against the registered list, so you can't save a tool that doesn't exist.

When the orchestrator builds the tool payload for an API call, it checks the agent's allowlist first. If tools are defined, only those go in. If not, the default scoping applies. Simple intersection, no performance cost.

Voice identity

Each agent can now have its own voice. The voice and voice_provider fields let you assign a specific Kokoro voice. The 28 voices are grouped by accent and gender (British Female, British Male, American Female, American Male), pulled from the backend enum. No hardcoded lists on the frontend.

This is groundwork. When Iris speaks as the Engineer, it should sound different from the Content Writer. The data model is ready. The voice pipeline integration comes next.

Routing keywords

The semantic routing layer blends embedding similarity, keyword matching, performance history, and recency to pick the right agent. Previously, keywords only lived in the capability profile text, influencing the semantic score indirectly. There was no direct keyword signal the scorer could use.

Now each agent has explicit routing keywords. "code", "debug", "refactor" on the Engineer. "draft", "article", "proofread" on the Content Writer. The scorer checks these directly as a binary match signal alongside the semantic similarity. Specific, non-overlapping terms that break ties when semantic scores are close.

I learned this lesson the hard way during the initial routing rollout (covered in post 020). "write" on the Content Writer was catching every "write me a migration" query. "data" on the Researcher collided with "data processing" meant for the Engineer. The fix was domain-specific keywords, and now those keywords are explicitly editable per agent rather than buried in profile text. I know, this statement will change in a month's time or so - as I test Iris more and more and find issues.

Sort order and default status

Two small things that matter in practice. sort_order controls display ordering. is_default marks the fallback agent when routing confidence is low. Both existed on the model already but weren't editable. Now they are. Default agents sort to the top.

What this enables

Each agent is a self-contained unit now. Its own tools, its own voice, its own routing hints, its own priority. The routing layer has sharper signal. The orchestrator sends leaner tool payloads. Voice differentiation is queued up for the next pipeline pass.

Eighteen agents, each with exactly what they need. No more, no less.