# Understanding the Modular Team Architecture in the Agentic-Teams Plugin

> Explore the modular team architecture in the Agentic-Teams plugin. Learn how specialized agents communicate via an async message bus and share state for extensible AI workflows.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: architecture
- Published: 2026-08-25

---

**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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/plugin_entrypoint.py). This file registers the orchestrator's `handle` function in the Claude plugin manifest ([`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.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:

1. **Request Ingestion**: User input arrives at the plugin entry point in [`plugin_entrypoint.py`](https://github.com/anthropics/claude-plugins-community/blob/main/plugin_entrypoint.py), which extracts the query and initializes the orchestrator.

2. **Context Initialization**: The `AgenticOrchestrator` creates a fresh `Context` object and loads the **Team Registry** to determine available capabilities.

3. **Team Selection**: Based on the input and current context, the orchestrator's rule engine selects the appropriate team (e.g., `RetrieverTeam`).

4. **Execution**: The orchestrator instantiates the selected team class and calls its `run(context)` method, passing the shared context.

5. **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.

6. **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`](https://github.com/anthropics/claude-plugins-community/blob/main/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:

```python

# 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

```

```python

# 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

```

```python

# 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"]

```

```python

# 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 **`AgenticOrchestrator`** in [`orchestrator.py`](https://github.com/anthropics/claude-plugins-community/blob/main/orchestrator.py) manages workflow execution by selecting teams based on rules and maintaining state in a shared **`Context`** object.
- Teams implement the **`BaseTeam`** interface defined in [`teams/base.py`](https://github.com/anthropics/claude-plugins-community/blob/main/teams/base.py), ensuring uniform invocation patterns across different capabilities.
- The **[`team_registry.json`](https://github.com/anthropics/claude-plugins-community/blob/main/team_registry.json)** manifest enables dynamic discovery of teams without code changes, supporting pluggable extensibility.
- All components integrate with Claude through **[`plugin_entrypoint.py`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/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.