Understanding the Modular Team Architecture in the Agentic-Teams Plugin
The modular team architecture in the Agentic-Teams plugin implements a component-based design pattern where specialized agent teams communicate via an async message bus and share mutable state through a centralized context object, all orchestrated by a rules-driven core to enable extensible, isolated AI workflows.
The anthropics/claude-plugins-community repository hosts the Agentic-Teams plugin, which demonstrates how to build scalable LLM applications using this modular team architecture. This architecture decouples domain expertise into self-contained units that interact through well-defined interfaces, allowing Claude to orchestrate complex multi-step tasks by delegating to specialized components.
Core Components of the Modular Architecture
Team Registry
The Team Registry acts as a capability catalog that maps team identifiers to their implementation modules. According to the source code, this is implemented as a JSON manifest (team_registry.json) that enables dynamic discovery of available teams without hard-coding dependencies.
Team Interface
Every team must honor the Team Interface defined in teams/base.py. The abstract base class BaseTeam exposes an async run(context) method that serves as the uniform contract for all team implementations, ensuring the orchestrator can invoke any team interchangeably.
Agentic Orchestrator
The Agentic Orchestrator in orchestrator.py serves as the workflow engine. The AgenticOrchestrator class uses a priority-queue and rules engine to select the next appropriate team based on the current state, managing the lifecycle of the shared context throughout the execution loop.
Message Bus
Teams communicate through a lightweight Message Bus implemented in message_bus.py. This in-memory pub-sub system serializes messages as JSON and supports async listeners, enabling loose-coupled communication where teams can broadcast events (e.g., "documents_fetched") without direct knowledge of their consumers.
Shared Context
The Shared Context carries evolving state across team boundaries. Implemented as a mutable Context object in context.py, this dictionary-like structure stores user queries, intermediate results, and provenance timestamps, allowing teams to read and update the collective workflow state.
Plugin Entry Point
The Plugin Glue exposes the architecture to Claude through plugin_entrypoint.py. This file registers the orchestrator's handle function in the Claude plugin manifest (.claude-plugin/plugin.json), creating the bridge between Claude's request format and the modular team system.
Execution Flow in the Modular System
The architecture follows a specific six-step orchestration pattern:
-
Request Ingestion: User input arrives at the plugin entry point in
plugin_entrypoint.py, which extracts the query and initializes the orchestrator. -
Context Initialization: The
AgenticOrchestratorcreates a freshContextobject and loads the Team Registry to determine available capabilities. -
Team Selection: Based on the input and current context, the orchestrator's rule engine selects the appropriate team (e.g.,
RetrieverTeam). -
Execution: The orchestrator instantiates the selected team class and calls its
run(context)method, passing the shared context. -
Event Broadcasting: During execution, teams may publish events to the Message Bus; peer teams subscribed to these events react asynchronously without blocking the primary workflow.
-
Iteration and Termination: The orchestrator evaluates the updated context after each team execution, determining whether to invoke additional teams or return the final answer to Claude.
Key Architectural Benefits
Extensibility: Adding new capabilities requires only implementing a new BaseTeam subclass and registering it in team_registry.json. The orchestrator discovers and invokes new teams automatically without modifying core logic.
Isolation: Each team operates as a self-contained unit with domain-specific logic. This sandboxing reduces side effects, as teams interact only through the message bus and shared context rather than direct method calls.
Reusability: The same team implementation can serve multiple orchestration workflows. For example, a SummarizerTeam can be reused across research, reporting, and data analysis pipelines without code duplication.
Implementation Examples
Here are concrete implementations of the core architectural components from the source code:
# teams/base.py – the abstract interface every team must implement
from abc import ABC, abstractmethod
from .context import Context
class BaseTeam(ABC):
@abstractmethod
async def run(self, ctx: Context) -> Context:
"""Perform the team's work and return the updated context."""
pass
# teams/retriever.py – a concrete team that fetches documents
from .base import BaseTeam
from ..message_bus import bus
class RetrieverTeam(BaseTeam):
async def run(self, ctx):
query = ctx["user_query"]
docs = await fetch_documents(query) # ← custom I/O
ctx["documents"] = docs
await bus.publish("documents_fetched", ctx) # notify peers
return ctx
# orchestrator.py – core of the modular orchestration
from .team_registry import TEAM_REGISTRY
from .message_bus import bus
from .context import Context
class AgenticOrchestrator:
def __init__(self):
self.registry = TEAM_REGISTRY # loads JSON manifest
async def handle(self, user_input: str) -> str:
ctx = Context(user_query=user_input)
while not ctx.get("final_answer"):
team_name = self._select_next_team(ctx) # rule-engine logic
team_cls = self.registry[team_name]
ctx = await team_cls().run(ctx) # invoke team
return ctx["final_answer"]
# plugin_entrypoint.py – Claude's entry point into the system
import json
import asyncio
from .orchestrator import AgenticOrchestrator
orchestrator = AgenticOrchestrator()
def handle(request):
"""Claude calls this function; it forwards the request to the orchestrator."""
user_input = request["messages"][-1]["content"]
answer = asyncio.run(orchestrator.handle(user_input))
return {"response": answer}
Summary
- The modular team architecture in the Agentic-Teams plugin separates concerns into specialized, self-contained teams that communicate through a message bus.
- The
AgenticOrchestratorinorchestrator.pymanages workflow execution by selecting teams based on rules and maintaining state in a sharedContextobject. - Teams implement the
BaseTeaminterface defined inteams/base.py, ensuring uniform invocation patterns across different capabilities. - The
team_registry.jsonmanifest enables dynamic discovery of teams without code changes, supporting pluggable extensibility. - All components integrate with Claude through
plugin_entrypoint.py, which bridges the modular architecture with the Claude plugin protocol.
Frequently Asked Questions
How does the Agentic-Teams plugin handle communication between different teams?
Teams communicate through an in-memory Message Bus implemented in message_bus.py. This pub-sub system allows teams to publish JSON-serialized events (such as "documents_fetched") that other teams can subscribe to, enabling loose coupling where teams react to state changes without direct method invocation or tight integration.
What is the role of the BaseTeam abstract class in the modular architecture?
The BaseTeam abstract class in teams/base.py defines the contract that every team must implement. By requiring an async run(context) method, the orchestrator can treat all teams polymorphically—invoking them uniformly without knowing their specific implementation details, which is essential for the plugin's extensibility and maintainability.
How does the orchestrator decide which team to execute next?
The AgenticOrchestrator uses a rules engine and priority queue to evaluate the current Context state after each team execution. It examines keys in the context (such as user_query or intermediate results) and consults the Team Registry to select the most appropriate team, continuing this loop until a termination condition (like a populated final_answer field) is met.
Can new teams be added to the plugin without modifying existing code?
Yes. The architecture supports hot-swappable teams through the team_registry.json manifest. Developers create a new class inheriting from BaseTeam, place it in the teams/ directory, and add an entry to the registry. The AgenticOrchestrator discovers and loads the new team automatically on the next invocation, requiring no changes to the orchestrator logic or other team implementations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →