Building Teams

Define team members, roles, and structure for multi-agent coordination.

Start simple: a model, team members, and instructions. Add functionality as needed.

Minimal Example

1from kern.team import Team
2from kern.agent import Agent
3from kern.models.openai import OpenAIResponses
4from kern.tools.hackernews import HackerNewsTools
5from kern.tools.yfinance import YFinanceTools
6
7news_agent = Agent(
8 name="News Agent",
9 role="Get trending tech news from HackerNews",
10 tools=[HackerNewsTools()]
11)
12
13finance_agent = Agent(
14 name="Finance Agent",
15 role="Get stock prices and financial data",
16 tools=[YFinanceTools()]
17)
18
19team = Team(
20 name="Research Team",
21 members=[news_agent, finance_agent],
22 model=OpenAIResponses(id="gpt-4o"),
23 instructions="Delegate to the appropriate agent based on the request."
24)
25
26team.print_response("What are the trending AI stories and how is NVDA stock doing?", stream=True)

Team Modes

Teams default to coordinate mode (leader delegates and synthesizes). Set mode to change how the leader collaborates with members.

1from kern.team.mode import TeamMode
2from kern.models.openai import OpenAIResponses
3
4team = Team(
5 name="Language Router",
6 members=[...],
7 model=OpenAIResponses(id="gpt-4o"),
8 mode=TeamMode.route
9)
ModeConfigurationUse case
Coordinatemode=TeamMode.coordinate (default)Decompose work, delegate to members, synthesize results
Routemode=TeamMode.routeRoute to a single specialist and return their response directly
Broadcastmode=TeamMode.broadcastDelegate the same task to all members and synthesize
Tasksmode=TeamMode.tasksRun a task list loop until the goal is complete

Tasks mode runs an iterative task loop. Use max_iterations to cap how many cycles the leader can run.

1from kern.models.openai import OpenAIResponses
2
3team = Team(
4 name="Ops Team",
5 members=[...],
6 model=OpenAIResponses(id="gpt-4o"),
7 mode=TeamMode.tasks,
8 max_iterations=6
9)

Team Members

Each member should have a name and role. The team leader uses these to decide who handles what.

1news_agent = Agent(
2 name="News Agent", # Identifies the agent
3 role="Get trending tech news from HackerNews", # Tells the leader what this agent does
4 tools=[HackerNewsTools()]
5)

For better tracing, also set an id:

1news_agent = Agent(
2 id="news-agent",
3 name="News Agent",
4 role="Get trending tech news from HackerNews",
5 tools=[HackerNewsTools()]
6)

When both id and name are set on a member, team delegation uses id as the member identifier.

Note

Members must be native Kern Agent or Team instances. External-framework adapters (ClaudeAgent, LangGraphAgent, DSPyAgent) can be served by AgentOS as standalone agents but cannot be a member agent of an Kern Team or an agent of a Workflow Step yet. See Multi-Framework Support.

Nested Teams

Teams can contain other teams. The top-level leader delegates to sub-team leaders, who delegate to their members.

1from kern.team import Team
2from kern.agent import Agent
3
4team = Team(
5 name="Language Team",
6 members=[
7 Agent(name="English Agent", role="Answer in English"),
8 Agent(name="Chinese Agent", role="Answer in Chinese"),
9 Team(
10 name="Germanic Team",
11 role="Handle German and Dutch questions",
12 members=[
13 Agent(name="German Agent", role="Answer in German"),
14 Agent(name="Dutch Agent", role="Answer in Dutch"),
15 ],
16 ),
17 ],
18)

Model Inheritance

Team members inherit the model from their parent team if not explicitly set.

1from kern.team import Team
2from kern.agent import Agent
3from kern.models.openai import OpenAIResponses
4from kern.models.anthropic import Claude
5
6# This agent uses its own model (Claude)
7agent_with_model = Agent(
8 name="Claude Agent",
9 model=Claude(id="claude-sonnet-4-5"),
10 role="Research with Claude"
11)
12
13# This agent inherits gpt-4o from the team
14agent_without_model = Agent(
15 name="Inherited Agent",
16 role="Research with inherited model"
17)
18
19team = Team(
20 name="Research Team",
21 model=OpenAIResponses(id="gpt-4o"), # Default for team and members without a model
22 members=[agent_with_model, agent_without_model]
23)

Callable Factories

Pass a function instead of a static list for members, tools, or knowledge. The function is called at the start of each run, so the composition can vary per user or session.

1from kern.agent import Agent
2from kern.models.openai import OpenAIResponses
3from kern.team import Team
4
5writer = Agent(
6 name="Writer",
7 role="Content writer",
8 model=OpenAIResponses(id="gpt-5-mini"),
9 instructions=["Write clear, concise content."],
10)
11
12researcher = Agent(
13 name="Researcher",
14 role="Research analyst",
15 model=OpenAIResponses(id="gpt-5-mini"),
16 instructions=["Research topics and summarize findings."],
17)
18
19
20def pick_members(session_state: dict):
21 if session_state.get("needs_research", False):
22 return [researcher, writer]
23 return [writer]
24
25
26team = Team(
27 name="Content Team",
28 model=OpenAIResponses(id="gpt-5-mini"),
29 members=pick_members,
30 cache_callables=False,
31)
32
33team.print_response(
34 "Write a haiku about Python",
35 session_state={"needs_research": False},
36 stream=True,
37)
38
39team.print_response(
40 "Research the history of Python and write a short summary",
41 session_state={"needs_research": True},
42 stream=True,
43)

The same pattern works for tools and knowledge. Agents also support callable factories for tools and knowledge.

Injected Parameters

Name your factory function parameters to receive context automatically:

ParameterTypeDescription
agentAgentThe current Agent instance
teamTeamThe current Team instance
run_contextRunContextRun context with user_id, session_id, session_state
session_statedictSession state dict directly (defaults to {} if None)

Use any combination. A zero-argument factory also works.

add_tool and set_tools

add_tool() raises RuntimeError when tools is a callable factory. Use set_tools() to replace the factory entirely:

1team = Team(tools=tools_for_user, ...)
2
3team.add_tool(some_tool) # raises RuntimeError
4
5team.set_tools(new_factory) # replace with a new factory
6team.set_tools([DuckDuckGoTools()]) # replace with a static list

Callable Caching Settings

Factory results are cached by default. The cache key is resolved in this order: custom key function > user_id > session_id. If none are available, caching is skipped and the factory runs every time.

SettingDefaultDescription
cache_callablesTrueEnable or disable caching for all callable factories
callable_tools_cache_keyNoneCustom cache key function for tools factory
callable_knowledge_cache_keyNoneCustom cache key function for knowledge factory
callable_members_cache_keyNoneCustom cache key function for members factory (Team only)

Set cache_callables=False when session_state changes between runs and the factory should re-evaluate each time.

Clear cached results programmatically:

1from kern.utils.callables import clear_callable_cache
2
3clear_callable_cache(team) # Clear all caches
4clear_callable_cache(team, kind="tools") # Clear tools cache only
5clear_callable_cache(team, kind="tools", close=True) # Clear and call .close() on cached resources

Use aclear_callable_cache() in async code.

Team Features

Teams support the same features as agents:

FeatureDescription
InstructionsGuide the team leader on how to coordinate
ModeChoose the coordination strategy (coordinate, route, broadcast, tasks)
DatabasePersist session history and state
ReasoningEnable the leader to plan before delegating
KnowledgeGive the leader access to a knowledge base
MemoryStore and recall information across sessions
ToolsGive the leader tools to use directly
SkillsGive the leader domain expertise via instructions, scripts, and references

See the guides below to add these features.

Next Steps

TaskGuide
Run teamsRunning Teams
Control delegationDelegation
Add skillsTeam Skills
Add chat historyChat History
Manage sessionsSessions
Handle input/outputInput and Output
Add knowledgeKnowledge
Add guardrailsGuardrails

Developer Resources