Multi-Agent Teams
Teams let you combine multiple NPCs under a coordinator (the forenpc) that routes requests, delegates tasks, and synthesizes results. This guide covers creating teams, orchestrating requests, and understanding the result structure.
Team Concept
A Team is a collection of NPCs with a designated forenpc (short for "foreman NPC") that acts as the coordinator. When you send a request to a team via orchestrate(), the forenpc decides how to handle it -- answering directly, delegating to a team member, or passing work between agents.
Creating a Team
Provide a list of NPCs and a forenpc. The forenpc can be one of the team members or a separate NPC.
from npcpy.npc_compiler import NPC, Team
ggm = NPC(
name='Gabriel Garcia Marquez',
primary_directive='You are Gabriel Garcia Marquez, master of magical realism. '
'Research, analyze, and write with poetic flair.',
model='gemma3:4b',
provider='ollama',
)
isabel = NPC(
name='Isabel Allende',
primary_directive='You are Isabel Allende, weaving stories with emotion '
'and history. Analyze texts and provide insight.',
model='llama3.2',
provider='ollama',
)
borges = NPC(
name='Jorge Luis Borges',
primary_directive='You are Borges, philosopher of labyrinths and libraries. '
'Synthesize findings and create literary puzzles.',
model='qwen3:latest',
provider='ollama',
)
lit_team = Team(
npcs=[ggm, isabel],
forenpc=borges
)
When the Team is initialized:
- Each NPC's
.teamattribute is set to the team instance - The forenpc is determined (either the provided NPC or resolved by name)
- Team-level jinxes are rendered and distributed to NPCs
- A jinx tool catalog is built for the team
Orchestration
Call team.orchestrate(prompt) to send a request through the team. The forenpc receives the request first and decides how to handle it.
Result Structure
orchestrate() returns a dict with two top-level keys: output and result.
result['output']-- the final text output from the orchestrationresult['result']-- the full result dict from the underlyingcheck_llm_commandcall, containingmessages,output, andusagedata
# The text answer
print(result['output'])
# The detailed result from the coordinating NPC
print(result['result'].keys())
# Typical keys: 'messages', 'output', 'usage'
Full Example
from npcpy.npc_compiler import NPC, Team
ggm = NPC(
name='Gabriel Garcia Marquez',
primary_directive='You are Gabriel Garcia Marquez, master of magical realism.',
model='gemma3:4b',
provider='ollama',
)
isabel = NPC(
name='Isabel Allende',
primary_directive='You are Isabel Allende, weaving stories with emotion and history.',
model='llama3.2',
provider='ollama',
)
borges = NPC(
name='Jorge Luis Borges',
primary_directive='You are Borges, philosopher of labyrinths and libraries. '
'Synthesize findings and create literary puzzles.',
model='qwen3:latest',
provider='ollama',
)
lit_team = Team(npcs=[ggm, isabel], forenpc=borges)
result = lit_team.orchestrate(
"Research the topic of magical realism and summarize the findings."
)
# Access the text output
print(result['output'])
# Access the underlying result dict
inner = result['result']
print(inner.get('output', '')[:200])
Agent Passing
During orchestration, the forenpc can delegate work to other team members. This happens automatically when the forenpc mentions another NPC by name (or with @name syntax) in its response.
The orchestration logic:
- The forenpc receives the request and generates a response
- If the response mentions a team member's name, the request is delegated to that NPC
- The delegated NPC processes the request with its own model and directive
- The result is returned through the orchestration pipeline
# The forenpc (Borges) might respond: "Let me ask Gabriel Garcia Marquez about this..."
# This triggers automatic delegation to the ggm NPC
result = lit_team.orchestrate(
"Tell me about the use of time in One Hundred Years of Solitude."
)
print(result['output'])
Agent passing also works explicitly through the handle_agent_pass mechanism when NPCs are used with the check_llm_command pipeline, where the forenpc can choose a pass_to_npc action with a target agent.
Team-Based Jinx Usage
Teams can have jinxes (workflow templates) that are shared across all member NPCs. Pass jinx objects when creating the team.
from npcpy.npc_compiler import NPC, Team, Jinx
literary_research_jinx = Jinx(jinx_data={
"jinx_name": "literary_research",
"description": "Research a literary topic and summarize findings",
"inputs": ["topic"],
"steps": [
{
"name": "gather_info",
"engine": "natural",
"code": "Research the topic: {{ topic }}. "
"Summarize the main themes and historical context."
},
{
"name": "final_summary",
"engine": "natural",
"code": "Based on the research in {{ gather_info }}, "
"write a concise, creative summary."
}
]
})
lit_team = Team(
npcs=[ggm, isabel],
forenpc=borges,
jinxes=[literary_research_jinx]
)
result = lit_team.orchestrate(
"Research the topic of magical realism, analyze it, and summarize the findings."
)
print(result['output'])
Team-level jinxes are distributed to all NPCs during initialization, so any team member can execute them when the forenpc delegates work.
Creating Teams from Directories
For production setups, you can define teams as a directory structure with .npc files and a team.ctx context file:
The directory should contain:
.npcfiles for each agent- A
jinxes/subdirectory with.jinxworkflow files andskills/subfolder - An optional
team.ctxYAML file defining the forenpc and team context
The team.ctx file can also specify SKILLS_DIRECTORY to load skills from an external directory:
Skills loaded this way are merged into the team's jinxes_dict and distributed to all NPCs, just like jinxes in the jinxes/ directory. See the Skills guide for details.
Team Parameters
The Team constructor accepts:
| Parameter | Type | Description |
|---|---|---|
team_path |
str |
Path to team directory |
npcs |
List[NPC] |
List of NPC objects |
forenpc |
NPC or str |
Coordinator NPC or name |
jinxes |
List[Jinx] |
Team-level workflow templates |
db_conn |
connection | Database connection |
model |
str |
Default model for the team |
provider |
str |
Default provider for the team |