One of the versions I published last weekend replied to a perfectly ordinary request with: “I cannot assess urgency.”

The sentence itself was fine. It was true of one of my agents — the one that owns patient records and knows nothing about clinical priority. The problem was who said it. The speaker was the router: the agent above the others whose entire job is to work out who should answer, and get them to answer. It had picked up a specialist’s limitation, worn it as its own, and used it to decline a request it was supposed to pass along.

I have seen that exact failure in schools. A parent asks at the front desk and, instead of “let me get the person who handles that”, hears “I’m afraid I can’t help with that” — true of the person speaking, useless to the person asking.

This post is the design that came out of fixing it. The build is a hospital scenario — a fictional clinic in a real Developer Edition org, written in Agent Script — and none of it is client or production work.

Four agents, one conversation

The shape is one router above three specialists:

  • Records owns patient history.
  • Triage owns urgency.
  • Scheduling owns booking.

The router owns none of those things. It owns the conversation: who is asked, in what order, and what the patient finally hears. The reason to split at all is the reason you split a school into subject teachers — each specialist has a small, well-described job, so its instructions stay short and specific. One agent that does everything hedges in every direction, and ends up reliable at nothing.

Exclusive ownership, and a fixed order

Ownership is exclusive. Exactly one agent owns each capability. Records offers no opinion on urgency. Triage does not look up history for itself. Scheduling does not decide who is seen soonest. If two agents can both do a thing, you cannot say which one did it on a given run — and the moment an answer is wrong, you have no idea where to look.

The order is fixed: Records, then Triage, then Scheduling — not for tidiness, but because each specialist needs what the previous one established. Triage cannot judge urgency without the history; Scheduling cannot book sensibly without the urgency. It is a dependency chain, the same reason you deploy an object before the fields that sit on it.

If two agents can do the same job, you have not designed a team. You have designed an argument, and you will not be in the room when it happens.

Escalation belongs to the router alone

This is the rule I would defend hardest, and it fixes the opening story.

No specialist carries an escalation path. Each specialist’s only tool is its own action. Records reads records, Triage assesses, Scheduling books. None can reach sideways to another agent, and none can decide that a case needs a human. Escalation lives entirely with the router.

The reason is accountability. If any agent can escalate, then when something should have been escalated and was not, the answer to “who decided that?” is a shrug. One owner means exactly one set of instructions to read when the decision was wrong.

It also removes the failure I opened with. A specialist that cannot route has no way to decline on behalf of the whole system. It answers within its remit or reports that it could not, and the router decides what happens next.

Identifiers cannot travel down the channel

Now a platform constraint that shaped the design more than any preference of mine.

When a router involves another agent, you might expect to hand over a neat parcel of context: here is the patient identifier, carry on. In practice, only a target agent’s linked context variables can be bound at that moment. A mutable variable declared on the specialist is not a valid target — it is rejected when you publish. Which means identifiers cannot ride down that channel at all.

The workaround is less clever than the problem, and I have come to prefer it. The router captures the identifiers first and states them in full inside every request it sends. Not “the patient we discussed” — the actual value, spelled out, in the request.

That is good hygiene independently of the constraint. Every request a specialist receives is self-contained, and reading a trace afterwards, I can see exactly what each one was told.

Report results, never narrate steps

One instruction had to be written out explicitly, because earlier versions kept getting it wrong in the friendliest possible way: report results, never narrate steps.

Two sentences that look helpful and are not:

  • “I have retrieved the history.”
  • “An appointment is being booked.”

Neither contains a result. From where the caller sits, “an appointment is being booked” is indistinguishable from nothing happening — no time, no confirmation, just a reassuring noise. If the booking silently failed, that sentence reads exactly the same.

So the instruction is blunt: say what the history is, what the urgency is, what was booked, or say that it could not be done. Narration is not an answer; it is the sound an answer makes on its way past.

Five versions, each one a recorded step

There are five published versions of the orchestrator and five of each specialist. I mention it not as a boast but as the opposite: five is the honest count of how many attempts it took, and each is a recorded step. When version four behaves differently from version three, I have both, and the difference is one change I made on purpose. Rewriting in place until it works leaves you with an agent that works for reasons you cannot name.

One more thing about how the pieces connect: a subagent has to be called, so its answer comes back to the router, rather than handed control of the conversation. That distinction was the difference between a working system and a silent one, and it deserves its own post — Call It, Don’t Hand Off.

What is not proven yet

Let me be precise about the boundary — this is where an author is tempted to round up.

The orchestration runs. The router calls the three specialists in order, and their answers come back to it. What I have not yet proven is that the booking writes a record. That is the next thing to demonstrate, and until a record exists in the org that I can point at, the honest statement is that it has not been shown.

Note the shape of that sentence: saying “an appointment is being booked” would be the precise failure this design forbids — and it is no less a failure when the author says it about his own project.

Your next step

If you are splitting one agent into several, do not start with the prompts. Start with a table: one row per capability, one column for the agent that owns it, no capability appearing twice. Then add a second table with exactly one row — escalation — and put a single agent’s name in it.

If you cannot fill either table without hesitating, the design is not ready, and no amount of instruction-writing will settle a question the architecture left open.

Mustafa Aksu

Salesforce developer & ISV builder focused on Revenue Cloud, Agentforce, and Data Cloud. I write from real, shipped work.