Multi-agent teams
Goal: stand up a supervisor agent that summons a governed roster of sub-agents on demand — each delegation runs as a durable sub-run under the invoking user’s identity.
Prerequisites: the platform installed; an AgentRegistry whose
members include your supervisor and every roster agent; each of those agents already
deployed and Ready. The supervisor’s spec.role should be orchestrator.
How a team works
Section titled “How a team works”An AgentTeam is three things: a supervisor (the orchestrating agent), a roster (a governed set
of summonable sub-agents), and a spawn budget (the ceiling on delegation). At runtime the supervisor’s
model calls the injected delegate_to tool — the platform starts the chosen roster member as a durable
sub-run that inherits the invoking user’s on-behalf-of grant (no re-consent), the conversation, and the
trace. The supervisor suspends while its delegations run (holding no worker slot) and resumes when they
finish. Every roster member is a standing AgentDeployment — you deploy and govern each one normally; the
team just makes them summonable.
registryRef is the trust boundary. The team references (never generates) an AgentRegistry. The
supervisor and every roster member must be members of it — that same registry scopes the sub-runs’ OBO,
the NetworkPolicy, and shared memory. A member that isn’t in the registry holds the team Ready=False.
1. Author the team
Section titled “1. Author the team”The minimum is a registryRef, a supervisor, and at least one roster entry. Each roster entry has a
roster-local name (what the supervisor summons), an agentRef (the standing agent it runs), and an
optional description surfaced to the supervisor’s model so it can choose whom to delegate to.
apiVersion: agents.ctxmesh.ai/v1beta1kind: AgentTeammetadata: name: support-team namespace: my-teamspec: registryRef: support # the trust boundary — an existing AgentRegistry supervisor: agentRef: triage-agent # role: orchestrator; a member of `support` roster: - name: billing agentRef: billing-agent description: Invoices, refunds, and payment questions. - name: technical agentRef: tech-agent description: Product troubleshooting and how-to. spawnBudget: maxFanOut: 4 # sub-runs one supervisor step may start maxSpawnDepth: 3 # supervisor → sub-agent → … depth maxTotalSpawns: 20 # sub-runs across the whole spawn treeApply it:
kubectl apply -f support-team.yaml2. Watch it resolve
Section titled “2. Watch it resolve”The controller validates the supervisor and every roster member against registryRef, then reports
readiness and the resolved members:
kubectl get agentteam support-team -n my-team -w# Ready transitions to True once every member resolves and is a registry member.kubectl get agentteam support-team -n my-team \ -o jsonpath='{.status.conditions[?(@.type=="Ready")].status} {.status.members}{"\n"}'# → True [triage-agent billing-agent tech-agent]Ready=True means registryRef, the supervisor, and every roster member resolved and all are
members of the registry. status.members lists them.
3. Delegate at runtime
Section titled “3. Delegate at runtime”When the supervisor is a team supervisor, the controller injects the synthetic delegate_to tool.
The supervisor’s model calls it by the roster name:
delegate_to(sub_agent="billing", task="Refund the duplicate charge on invoice INV-4021.")The platform starts billing-agent as a durable sub-run — inheriting the caller’s OBO, the conversation,
and the trace — and returns its terminal result to the supervisor as the tool result. Open the run in the
console to see the spawn tree: the supervisor run with each delegation nested beneath it, each a real agent
run with its own steps, tools, model calls, and cost. Bounded parallel fan-out runs concurrent
delegate_to calls in one step, admitting up to maxFanOut and denying the rest fail-closed.
When to use / when not
Section titled “When to use / when not”- Use for open-ended, model-chosen delegation — the supervisor decides at runtime which specialist to summon based on the request.
- Use a
Workflowinstead when the routing is fixed and you want it evaluated deterministically (author decides the graph, not the model). - Not for a single-loop agent with no delegation — just deploy the agent.
Defaults
Section titled “Defaults”spawnBudgetdefaults tomaxFanOut: 4,maxSpawnDepth: 3,maxTotalSpawns: 20. A nil block resolves to all three defaults.maxFanOut+maxTotalSpawnsare aggregate ceilings enforced fail-closed across the whole spawn tree;maxSpawnDepthbounds the tree depth (distinct from AMP hop depth).- Platform ceilings clamp any client-supplied budget (fan-out 128 / depth 32 / total 1024) so a compromised pod can’t request an unbounded budget — these kill abuse, not legitimate config.
rosterrequires at least one entry (max 64);nameandagentRefare DNS labels (1–63 chars).
Failure modes
Section titled “Failure modes”Roster validation is fail-closed — a team with an unresolvable member is held Ready=False rather than
serving a broken roster. The Ready condition carries the reason:
RegistryNotFound—registryRefnames anAgentRegistrythat doesn’t exist. Create it (or fix the name), and make the supervisor + roster agents members.MemberNotFound— the supervisor or a rosteragentRefnames anAgentDeploymentthat doesn’t exist in the namespace. Deploy it (or fix the ref).NotARegistryMember— the agent exists but isn’t inregistryRef. Add the registry’s member label to itsAgentDeployment(see AgentRegistry).
At runtime, a budget denial or a sub-run failure is returned to the supervisor as an honest tool result (text the model can act on — try another sub-agent, or answer directly) — never a supervisor crash. If the spawn-guard store is unreachable, delegation fails closed (denied) — a runaway supervisor is a cost and resource risk.