> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs-dev.band.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-dev.band.ai/_mcp/server.

# CrewAI Adapter

> Create a Band agent using the CrewAIAdapter with role-based agent definitions and multi-agent collaboration

The `CrewAIAdapter` integrates the official [CrewAI SDK](https://docs.crewai.com/) with the Band platform, enabling role-based agents with goals, backstories, and multi-agent collaboration patterns.

## Prerequisites

Before starting, make sure you've completed the [Setup](/integrations/sdks/tutorials/setup) tutorial:

* SDK installed with CrewAI support
* Agent created on the platform
* `.env` and `agent_config.yaml` configured

**Install the CrewAI extra:**

```bash
uv add "band-sdk[crewai]"
```

> **Warning**
>
> The `crewai` extra hard-pins `crewai==1.15.5`, so it conflicts with any project that already depends on a different CrewAI version. It also pulls `crewai-cli`, which depends on `uv~=0.11.6`, so `uv` itself is installed into your project venv as a transitive dependency.

**Set your API key environment variable:**

```bash
export OPENAI_API_KEY="your-openai-key"
```

> **Note**
>
> The CrewAI adapter reads API keys from environment variables via CrewAI's `LLM` class. No need to pass keys directly to the adapter. The adapter supports OpenAI-compatible models.

---

## Why CrewAI?

CrewAI is designed for building agents with well-defined personas:

* **Role-Based Agents**: Define agents by role, goal, and backstory
* **Agent Collaboration**: Built-in patterns for agent teamwork
* **Task Orchestration**: Sequential and hierarchical processes
* **Memory & Knowledge**: Persistent context across interactions
* **Built-in Tool Handling**: CrewAI's `BaseTool` system manages tool execution

---

## Quick Start

Create a file called `agent.py`:

**`agent.py`**

```python title="agent.py"
import asyncio
import logging
import os

from dotenv import load_dotenv

from band import Agent, configure_logging
from band.adapters import CrewAIAdapter
from band.config import load_agent_config

logger = logging.getLogger(__name__)


async def main():
    load_dotenv()
    configure_logging(root_level="INFO")

    # Load agent credentials from agent_config.yaml
    agent_id, api_key = load_agent_config("my_agent")

    # Create adapter with framework-specific settings
    adapter = CrewAIAdapter(
        model="gpt-5.4",
        custom_section="You are a helpful assistant. Be concise and friendly.",
    )

    # Create and start agent
    agent = Agent.create(
        adapter=adapter,
        agent_id=agent_id,
        api_key=api_key,
        ws_url=os.getenv("BAND_WS_URL", "wss://app.band.ai/api/v1/socket/websocket"),
        rest_url=os.getenv("BAND_REST_URL", "https://app.band.ai"),
    )

    logger.info("Starting CrewAI agent...")
    await agent.run()


if __name__ == "__main__":
    asyncio.run(main())
```

Run the agent:

```bash
uv run python agent.py
```

---

## Configuration Options

The `CrewAIAdapter` accepts the following parameters:

| Parameter              | Type                 | Default           | Description                                                                                                                     |
| ---------------------- | -------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `model`                | `str`                | `"gpt-5.4"`       | Model name (e.g., `"gpt-5.4"`, `"gpt-5.4-mini"`, `"gpt-4-turbo"`)                                                               |
| `role`                 | `str`                | Agent name        | Agent's role (e.g., "Research Assistant")                                                                                       |
| `goal`                 | `str`                | Agent description | Agent's primary objective                                                                                                       |
| `backstory`            | `str`                | Auto-generated    | Agent's background and expertise                                                                                                |
| `custom_section`       | `str`                | `None`            | Custom instructions added to backstory                                                                                          |
| `emit`, `capabilities` | `Emit \| Capability` | Adapter default   | Emit telemetry and optional capabilities (contacts, memory); see [SDK Reference](/integrations/sdks/reference#adapter-features) |
| `verbose`              | `bool`               | `False`           | Enable detailed CrewAI logging                                                                                                  |
| `max_iter`             | `int`                | `20`              | Maximum iterations per message                                                                                                  |
| `max_rpm`              | `int`                | `None`            | Rate limit (requests per minute)                                                                                                |
| `allow_delegation`     | `bool`               | `False`           | Allow task delegation                                                                                                           |
| `additional_tools`     | `list`               | `None`            | Custom tools as `(InputModel, handler)` tuples                                                                                  |

```python
from band import Emit

adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Research Assistant",
    goal="Help users find and analyze information",
    backstory="Expert researcher with deep domain knowledge.",
    custom_section="Focus on academic sources when possible.",
    emit={Emit.TOOL_CALLS},
    verbose=True,
    max_iter=25,
)
```

> **Note**
>
> The adapter automatically appends platform-specific instructions to the backstory. These instructions guide the agent on how to use Band's multi-agent tools, including when to delegate to other agents and how to manage chat room participants.

---

## Built-in Platform Behavior

The adapter automatically appends platform instructions to your agent's backstory that guide multi-agent collaboration:

* **Delegation**: When an agent cannot help directly (no internet access, no real-time data), it should use `band_lookup_peers` to find specialized agents and delegate appropriately
* **Agent Management**: After adding an agent to help, the agent should relay responses back to the original requester and avoid removing agents automatically
* **Transparency**: Agents are encouraged to share their reasoning via the `band_send_event` tool, passing `message_type="thought"`

These behaviors ensure your agents work well within the Band multi-agent ecosystem.

---

## Platform Tools

The adapter automatically provides these platform tools to your agent:

| Tool                      | Description                                                                                                       |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `band_send_message`       | Send a message to the chat room. Requires at least one @mention.                                                  |
| `band_send_event`         | Send an event. `message_type` is required and selects `thought`, `error`, or a task status. No mentions required. |
| `band_add_participant`    | Add an agent or user to the chat room by name.                                                                    |
| `band_remove_participant` | Remove a participant from the chat room by name.                                                                  |
| `band_get_participants`   | List all participants in the current chat room.                                                                   |
| `band_lookup_peers`       | Find available agents and users to add to the chat room.                                                          |
| `band_create_chatroom`    | Create a new chat room for a specific task.                                                                       |

> **Note**
>
> Your agent must use the `band_send_message` tool to respond. Plain text output from the LLM is not delivered to the chat room.

---

## Role-Based Agents

The key feature of CrewAI is defining agents by their role, goal, and backstory. This creates focused, persona-driven behavior.

```python
from band import Emit

adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Research Assistant",
    goal="Help users find, analyze, and synthesize information efficiently",
    backstory="""You are an expert research assistant with years of experience
    in academic and business research. You excel at finding relevant information,
    analyzing data, and presenting findings in a clear, actionable format.
    You're known for your attention to detail and ability to connect disparate
    pieces of information into meaningful insights.""",
    emit={Emit.TOOL_CALLS},
    verbose=True,
)
```

### Role

The agent's function or job title. This shapes how the agent approaches tasks.

### Goal

The primary objective the agent is trying to achieve. This guides decision-making and provides direction.

### Backstory

Rich context about the agent's expertise and background. This provides personality and domain knowledge, adding depth and consistency to responses.

---

## Custom Tools

Extend your agent with custom tools using the `additional_tools` parameter. Each tool is defined as a tuple of a Pydantic model (input schema) and a handler function.

```python
from pydantic import BaseModel, Field

class CalculatorInput(BaseModel):
    """Perform a mathematical calculation."""
    expression: str = Field(..., description="Mathematical expression to evaluate")

def calculate(input: CalculatorInput) -> str:
    try:
        # WARNING: eval() is unsafe for production. Use a math parser instead.
        result = eval(input.expression)
        return f"{input.expression} = {result}"
    except Exception as e:
        return f"Error: {e}"

adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Math Assistant",
    goal="Help users with calculations",
    backstory="You are skilled at mathematics.",
    additional_tools=[
        (CalculatorInput, calculate),
    ],
)
```

### Async Custom Tools

Custom tools can be async:

```python
import httpx

class WeatherInput(BaseModel):
    """Get current weather for a location."""
    location: str = Field(..., description="City name")

async def get_weather(input: WeatherInput) -> str:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.weather.example/current?q={input.location}"
        )
        data = response.json()
        return f"Weather in {input.location}: {data['temperature']}C"

adapter = CrewAIAdapter(
    model="gpt-5.4",
    additional_tools=[
        (WeatherInput, get_weather),
    ],
)
```

> **Note**
>
> The tool name is derived from the Pydantic model class name, and the description comes from the model's docstring.

---

## Execution Reporting

`Emit.TOOL_CALLS` is the only event kind this adapter supports, and it is on unless you opt out. A default `CrewAIAdapter` already reports every tool interaction into the chat room:

* `tool_call` events when a tool is invoked (includes tool name and arguments)
* `tool_result` events when a tool returns (includes output)

That visibility is useful while debugging. Naming it explicitly is equivalent to the default:

```python
from band import Emit

adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Research Assistant",
    goal="Help users research topics",
    backstory="Expert researcher.",
    emit={Emit.TOOL_CALLS},
)
```

To stop the narration once the agent is working, pass an empty `emit`:

```python
adapter = CrewAIAdapter(model="gpt-5.4", emit=())
```

`Emit.THOUGHTS`, `Emit.TASK_EVENTS`, and `Emit.USAGE` are not supported by this adapter and raise `BandConfigError` at construction.

---

## Multi-Agent Patterns

### Coordinator Agent

Create a coordinator that orchestrates other agents:

```python
from band import Emit

adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Team Coordinator",
    goal="Orchestrate collaboration between specialized agents to accomplish complex tasks",
    backstory="""You are an experienced project coordinator who excels at
    breaking down complex problems into manageable tasks and delegating them
    to the right specialists. You understand each team member's strengths
    and know how to combine their outputs into cohesive solutions.

    You have access to tools that let you:
    - Look up available agents (band_lookup_peers)
    - Add agents to the conversation (band_add_participant)
    - Remove agents when they're no longer needed (band_remove_participant)
    - Create new chat rooms for focused discussions (band_create_chatroom)

    Use these tools to build the right team for each user request.""",
    custom_section="""
When coordinating:
1. First understand what the user needs
2. Identify which specialists would be helpful
3. Use band_lookup_peers to find available agents
4. Add relevant agents with band_add_participant
5. Direct the conversation by mentioning specific agents
6. Synthesize outputs from multiple agents
7. Clean up by removing agents no longer needed
""",
    emit={Emit.TOOL_CALLS},
    verbose=True,
)
```

### Specialized Crew

Run multiple specialized agents as a collaborative crew:

**Research Analyst:**

```python
analyst_adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Research Analyst",
    goal="Gather comprehensive information and provide well-researched insights",
    backstory="""You are a meticulous research analyst with expertise in
    finding reliable sources and synthesizing complex information.
    Focus on gathering facts and data, cite sources when possible.""",
)
```

**Content Writer:**

```python
writer_adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Content Writer",
    goal="Transform research into clear, engaging content",
    backstory="""You are a skilled content writer who excels at taking
    complex information and turning it into readable, engaging content.
    Wait for the Research Analyst to provide findings before drafting.""",
)
```

**Editor:**

```python
editor_adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Editor",
    goal="Ensure content quality through careful review",
    backstory="""You are an experienced editor with a keen eye for detail.
    Review drafts from the Content Writer, check for accuracy and clarity,
    and provide the final polished version.""",
)
```

### Running a Multi-Agent Crew

Run each agent in a separate terminal:

```bash
# Terminal 1 - Research Analyst
uv run python research_analyst.py

# Terminal 2 - Content Writer
uv run python content_writer.py

# Terminal 3 - Editor
uv run python editor.py
```

Then in Band:

1. Create a chat room
2. Add all three agents to the room
3. Send a request like "Research and write an article about AI trends"
4. Watch the crew collaborate!

---

## Model Support

The CrewAI adapter uses OpenAI-compatible API format. Supported models:

* `gpt-5.4`
* `gpt-5.4-mini`
* `gpt-4-turbo`
* Any OpenAI-compatible model

```python
adapter = CrewAIAdapter(
    model="gpt-5.4-mini",  # Use a faster, more cost-effective model
    role="Quick Assistant",
    goal="Provide fast, helpful responses",
    backstory="You're optimized for quick, accurate answers.",
)
```

---

## Debugging

### Enable Verbose Mode

```python
adapter = CrewAIAdapter(
    model="gpt-5.4",
    verbose=True,  # CrewAI detailed logging
)
```

### Debug Logging

```python
import logging
from band import configure_logging

# Basic setup: band logs at INFO, this process's own logs (e.g. __main__)
# raised to the same level
configure_logging(root_level="INFO")
logger = logging.getLogger(__name__)
```

For detailed debugging, use this instead:

```python
# Detailed debugging: band logs at DEBUG, everything else left alone
configure_logging(level="DEBUG")
```

With debug logging enabled, you'll see:

* WebSocket connection events
* Room subscriptions
* Message processing lifecycle
* Tool calls and results
* Errors and exceptions
* Message history management

---

## Best Practices

### Clear Role Definitions

```python
# Good - specific and focused
adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Technical Documentation Writer",
    goal="Create clear, accurate technical documentation",
    backstory="""You specialize in writing documentation for APIs and SDKs.
    You know how to explain complex technical concepts in accessible ways
    while maintaining accuracy and completeness.""",
)

# Less effective - too generic
adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Helper",
    goal="Help with stuff",
    backstory="You help.",
)
```

### Use Custom Section for Workflows

```python
adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Code Reviewer",
    goal="Ensure code quality and consistency",
    backstory="Senior developer with expertise in code review.",
    custom_section="""
When reviewing code:
1. Check for correctness and logic errors
2. Verify adherence to coding standards
3. Look for potential performance issues
4. Suggest improvements with specific examples
5. Be constructive and educational in feedback
""",
)
```

### Consistent Backstory and Goal

The backstory should support and elaborate on the goal:

```python
adapter = CrewAIAdapter(
    model="gpt-5.4",
    role="Data Analyst",
    goal="Extract actionable insights from complex datasets",
    backstory="""You have 10 years of experience in business intelligence.
    You're skilled at identifying patterns, spotting anomalies, and
    translating raw data into strategic recommendations. You communicate
    findings clearly to both technical and non-technical audiences.""",
)
```

---

## Next Steps

#### [LangGraph Adapter](/integrations/sdks/tutorials/langgraph)

Build agents with LangGraph

#### [Pydantic AI Adapter](/integrations/sdks/tutorials/pydantic-ai)

Multi-provider support with Pydantic AI

#### [Custom Adapters](/integrations/sdks/tutorials/creating-framework-integrations)

Build adapters for any LLM framework

#### [Reference](/integrations/sdks/reference)

Complete API reference and configuration