Teams
A Team is a set of agents (or other teams) plus a strategy that decides who runs next. The strategy is what turns a list of agents into a coordinated workflow — sequential pipeline, AI-chosen speaker, or a graph of allowed transitions.
The full schema reference (every field, every option) lives at Reference → Team. This page walks you through creating teams, the strategies you can pick, querying them, and what’s only configurable via YAML.
Minimum viable team
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: sequential-team
spec:
strategy: sequential
members:
- name: researcher
type: agent
- name: writer
type: agentThat’s enough to apply, given two existing agents named researcher and writer. The team runs researcher first, hands its output to writer, and returns the final response.
Strategies at a glance
| Strategy | What it does | When you’d pick it |
|---|---|---|
sequential | Members run in array order, one pass. | Fixed pipeline (researcher → analyst → writer). |
sequential + loops: true | Members cycle through members repeatedly until maxTurns or a member calls the terminate tool. | Back-and-forth between a small set of agents (e.g. critic + writer iterating). |
selector | An LLM-powered selector agent picks the next member each turn. Required maxTurns. | Free-form coordination where the next speaker depends on context. |
selector + graph | Selector still chooses, but only from members the graph says are reachable. | Workflows that need structure (researcher must come before writer) but allow AI flexibility within those rails. |
round-robin and standalone graph are deprecated and migrated automatically by the mutating webhook when you apply them — round-robin becomes sequential + loops: true; graph becomes sequential (the graph edges are discarded). Both stamp a ark.mckinsey.com/migration-warning-<key> annotation on the Team (e.g. migration-warning-round-robin, migration-warning-graph). New configs should use the strategies in the table.
Create a team
Via Dashboard
- Launch the dashboard:
ark dashboard. - Go to Agent Builder → Teams in the left nav and click Create Team.
- Fill the form:
| Section | Field | Notes |
|---|---|---|
| Basic Information | Name | Required. Lowercase, k8s name rules. |
| Description | Optional. Shown in team lists and surfaced in selector prompts as part of {{.Roles}}. | |
| Strategy Configuration | Strategy | Sequential or Selector. (Deprecated strategies aren’t offered.) |
| Enable loops | Only shown for Sequential. Toggles cycling through members. | |
| Max Turns | Required when strategy is Selector, or when Sequential + Enable loops is on. Caps the number of turns. | |
| Members | Agent checklist | Pick agents to include. Order in the list is execution order for Sequential. |
Selector Configuration (only for Selector) | Selector Agent | Required. The LLM-powered agent that decides who speaks next via the select-next-speaker tool. |
| Selector Prompt | Optional override of the default prompt. Has {{.Roles}}, {{.Participants}}, and {{.History}} template variables. The form has a Reset to Default Prompt button. | |
| Enable Terminate Tool | When on, the selector agent can call terminate to end the conversation early. | |
| Terminate Prompt | Optional override of the prompt that explains when to terminate. | |
Graph (only for Selector) | Add edges | Optional. Constrains the selector to picking from members reachable by from → to edges. |
- Hit Create Team.
Via kubectl
cat <<'EOF' | kubectl apply -f -
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: sequential-team
spec:
strategy: sequential
members:
- name: researcher
type: agent
- name: writer
type: agent
EOFWait for the team to reach Available:
kubectl wait --for=condition=Available team/sequential-team --timeout=60s
kubectl get team sequential-teamThe controller validates that every member resolves, that the strategy’s cross-field rules hold (more on those below), and that the team isn’t “mixed” — i.e. you can’t combine agents whose execution engines are external (Claude Agent SDK, LangChain, …) with built-in completion agents in one team.
Strategy walkthroughs
Sequential — one pass
The simplest workflow. Apply once, each member runs once.
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: pipeline-team
spec:
strategy: sequential
members:
- name: researcher
type: agent
- name: analyst
type: agent
- name: writer
type: agentRules enforced by the admission webhook:
loopsdefaults tofalse.maxTurnsmust not be set whenloopsisfalse. (A single pass is bounded by the member list.)
Sequential with loops — cycling until done
The loops: true flag turns the same pipeline into a loop that cycles through members until maxTurns is reached or a member calls the built-in terminate tool.
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: critic-writer-loop
spec:
strategy: sequential
loops: true
maxTurns: 10
members:
- name: writer
type: agent
- name: critic
type: agentRules:
maxTurnsis required whenloops: true. The admission webhook rejects the team otherwise.- Give at least one member the
terminatebuilt-in tool so the loop can exit early when the conversation is done.
This is the migration target for the old round-robin strategy.
Selector — LLM picks the next speaker
The team includes a separate selector agent. Each turn the selector is given the conversation, the list of participants, and a select-next-speaker tool. Whatever name it returns becomes the next speaker.
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: consulting-team
spec:
strategy: selector
description: Consulting team with AI-driven turn-taking
maxTurns: 10
members:
- name: research-analyst
type: agent
- name: strategy-consultant
type: agent
- name: technical-expert
type: agent
selector:
agent: project-manager
enableTerminateTool: trueRules:
selector.agentis required and must reference an existing agent.maxTurnsis required (selector strategies have no built-in stop condition).loopscannot be set on a selector team. The “loop” comes from the selector picking again each turn.- The selector agent calls a generated tool named
select-next-speakerwhosenameparameter is an enum of valid candidates. If the agent picks something not in the enum, or doesn’t call the tool at all, the conversation ends with a warning event. - When
selector.enableTerminateTool: true(the default in the dashboard form), the selector agent also gets aterminatetool it can call to end the conversation early.
Customising the selector prompt
The selector’s prompt has three template variables. The default looks like this:
You are in a role play game. The following roles are available:
{{.Roles}}.
Read the following conversation, then use the select-next-speaker tool to select the next role from {{.Participants}} to play.
{{.History}}
Read the above conversation, then use the select-next-speaker tool to select the next role from {{.Participants}} to play.If you override selector.selectorPrompt, include an instruction to use the select-next-speaker tool. The mutating webhook will stamp a migration warning on the team if your custom prompt doesn’t mention it, because without that instruction the model will return free-form text and the selector will time out.
selector:
agent: project-manager
selectorPrompt: |
You are coordinating a consulting team. Pick the next speaker.
Roles available: {{.Roles}}
Conversation so far: {{.History}}
Choose from: {{.Participants}}
Use the select-next-speaker tool to make your selection.Selector with graph — structure + flexibility
Adding graph.edges to a selector team turns it into a constrained selector. The selector still chooses each turn, but only from the members reachable by the graph from the current member. If only one outgoing edge exists, the runtime takes it without calling the selector (a cheap optimisation).
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: constrained-research-team
spec:
strategy: selector
maxTurns: 10
selector:
agent: coordinator
members:
- name: researcher
type: agent
- name: analyzer
type: agent
- name: writer
type: agent
graph:
edges:
- from: researcher
to: analyzer
- from: analyzer
to: writerRules:
- Every
fromandtoingraph.edgesmust be a team member name. The admission webhook rejects edges that reference unknown members. graphrequires at least one edge.- The standalone
strategy: graphis deprecated. If you apply it, the mutating webhook rewrites the team tostrategy: sequentialand discards your edges, so re-author asstrategy: selector+graph.edgesinstead.
Member types
members:
- name: researcher
type: agent
- name: review-subteam
type: teamagent— references an Agent in the same namespace. Standard case.team— references another Team. The nested team runs as a single “member”; its own strategy and members are isolated. Useful for composing larger workflows. (Nested teams are YAML-only — the dashboard’s Create Team form does not surface team members.)
A team cannot reference itself, and you can’t mix internal (default completions executor) and external (e.g. Claude Agent SDK, LangChain) agents in the same team — the webhook will reject the apply with mixed teams are not allowed.
Query a team
Send a one-off query without creating a Query resource:
ark query team/sequential-team "Summarise the latest on EV battery chemistries."
# Or via the teams subcommand
ark teams query sequential-team "Summarise the latest on EV battery chemistries."Or apply a Query resource if you want it persisted, want streaming, or want to pass parameters:
cat <<'EOF' | kubectl apply -f -
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: team-q1
spec:
input: "Summarise the latest on EV battery chemistries."
target:
type: team
name: sequential-team
EOF
kubectl get query team-q1 -w
kubectl get query team-q1 -o jsonpath='{.status.response.content}' # final assistant message
kubectl get query team-q1 -o jsonpath='{.status.response.raw}' # full conversation (JSON array)In the dashboard, opening a team also opens an embedded chat panel on the right — type into it to query the team interactively. While a turn is in flight the Send button becomes a Stop button that cancels the conversation. The panel also surfaces selector decisions inline (<selector-agent> chose <speaker>) and a Maximum turns reached (N) badge when maxTurns is hit.
The team form’s Strategy section also shows live warnings about configuration choices that may cause runtime issues — for example, “Neither the agents nor the selector have access to the terminate tool, which may prevent the conversation from terminating gracefully” when nothing on the team can call terminate.
Modify a team
Edit interactively
kubectl edit team sequential-teamPatch a single field
# Switch strategy
kubectl patch team sequential-team --type='merge' \
-p='{"spec":{"strategy":"sequential","loops":true,"maxTurns":10}}'
# Replace members (merge patches REPLACE the whole array)
kubectl patch team sequential-team --type='merge' \
-p='{"spec":{"members":[{"name":"researcher","type":"agent"},{"name":"writer","type":"agent"}]}}'
# Append one member with a JSON patch
kubectl patch team sequential-team --type='json' \
-p='[{"op":"add","path":"/spec/members/-","value":{"name":"reviewer","type":"agent"}}]'Re-apply the YAML
If the team lives in a file, kubectl apply -f again — the controller reconciles the diff.
List, inspect, delete
ark teams list # quick list
kubectl get teams # full kubectl view (shows strategy + Available)
kubectl describe team consulting-team
kubectl get team consulting-team -o yaml
# Delete
kubectl delete team consulting-team
kubectl delete teams team-a team-b
kubectl delete teams --allThe Available condition flips to False when the team is misconfigured — kubectl describe shows the underlying admission error (missing member, missing selector agent, missing maxTurns, mixed engines, etc.).
Team as a tool
A Team can be wired into an agent via the Tool CRD — create a Tool of type: team pointing at the team, then reference that Tool from the agent’s spec.tools:
# 1. The bridge: a Tool of type team that references the team.
apiVersion: ark.mckinsey.com/v1alpha1
kind: Tool
metadata:
name: consulting-team # the Tool's name — this is what the agent references
spec:
type: team
description: AI consulting team — research, strategy, and technical review
team:
name: consulting-team # the Team to delegate to (same namespace)
---
# 2. The agent references the Tool by name (not the Team directly).
apiVersion: ark.mckinsey.com/v1alpha1
kind: Agent
metadata:
name: orchestrator
spec:
prompt: |
You are an orchestrator. Delegate research tasks to the consulting-team tool.
tools:
- type: team
name: consulting-team # resolves to the Tool above, which routes to the TeamWhen the agent calls the tool, the team executes a normal run and returns its final message back to the agent. The Tool’s description is what the LLM sees when deciding whether to call the team — keep it task-oriented.
Features only available in YAML
The dashboard’s Create Team form covers name, description, strategy (sequential or selector), loops, max-turns, member-as-agent selection, and the selector configuration. These features are only configurable via the Team YAML for now:
- Nested teams (
members[].type: team) — the form’s member picker only lists agents. To compose teams, write the YAML. spec.selector.enableTerminateTool/terminatePrompt— actually surfaced in the form’s Advanced Settings, but the same Selector section is the only place to customise these; if you create the team without opening the Advanced section the defaults stick.- Graph edges on selector teams — the dashboard form does have a Graph section, but it’s only visible when
strategy: selector, and many teams using graph constraints today were authored in YAML. If you want aSelector + Graphworkflow with many edges, YAML is far easier.
For any of these, write the Team YAML directly. You can still inspect, edit, and delete it from the dashboard afterwards.
Troubleshooting
kubectl apply rejected by the admission webhook. Failures from the validation webhook happen before the team exists, so the error comes back in the apply output rather than the Available condition. The exact messages and how to fix them:
selector strategy requires maxTurns to prevent infinite execution— addspec.maxTurns: <n>(e.g. 10).selector strategy requires selector.agent to be specified— every selector team needs aselector.agentpointing at an existing Agent in the same namespace.selector agent 'X' not found in namespace Y— the agent name inselector.agentdoesn’t exist; apply it first.maxTurns is required when loops is enabled— sequential + loops needs an upper bound.maxTurns can only be set when loops is enabled— dropmaxTurnsif you don’t want a loop, or setloops: true.loops can only be used with the 'sequential' strategy— selector teams loop via the selector’s choices, not vialoops.graph constraint requires at least one edge— drop thegraph:block entirely or add edges.graph edge N: 'from'/'to' member 'X' not found in team members— every endpoint ingraph.edgesmust reference a member of the team.mixed teams are not allowed— one or more members use an external execution engine while others use the built-in completions engine; split into two teams.team member N references agent: agent 'X' does not exist in namespace 'Y'— apply the referenced Agent first.team 'X' cannot reference itself—members[].namecannot equalmetadata.namewhentype: team.
AVAILABLE: False after the team was accepted. The webhook passed but a runtime dependency is unavailable. Read the condition:
kubectl get team my-team -o jsonpath='{.status.conditions[?(@.type=="Available")].message}'Most common cause is Agent member 'X' is not available — the team’s Available rolls up the Available status of its members, so fix the member first (often a model that can’t reach its provider).
Selector team terminates immediately with no response. The selector agent returned text instead of calling the select-next-speaker tool. Either reset the prompt (the dashboard has a button) or make sure your custom prompt instructs the agent to use the tool. The mutating webhook also stamps an ark.mckinsey.com/migration-warning-selector-prompt annotation when your custom prompt doesn’t reference the tool — check for that on the team.
Conversation hit maxTurns but the work isn’t done. The team appends a system message Team conversation reached maximum turns limit (N) to the conversation, the query still completes with phase: done, and the dashboard chat panel shows a Maximum turns reached (N) badge. To detect this case in YAML/kubectl flows, grep .status.response.raw for maximum turns limit. To fix: increase maxTurns, or give a member (or the selector) the terminate built-in tool so the team can exit cleanly earlier.
Ready for the next step? Move on to Queries for parameter passing, streaming, and session management.