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

# Parlant Adapter

> Create a Band agent using the ParlantAdapter with the official Parlant SDK for behavioral guidelines and consistent, predictable responses

This tutorial shows you how to create an agent using the `ParlantAdapter`. This adapter integrates the official [Parlant SDK](https://github.com/emcie-co/parlant) with the Band platform, enabling guideline-based agent behavior for consistent, predictable responses.

## Prerequisites

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

* SDK installed with Parlant support
* Agent created on the platform
* `.env` and `agent_config.yaml` configured
* Verified your setup works

**Install the Parlant extra:**

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

---

## Why Parlant?

Parlant is designed for building agents with controlled, consistent behavior:

* **Behavioral Guidelines**: Define condition/action rules that are **actually enforced** by the Parlant SDK
* **Predictable Behavior**: Guidelines are reliably followed, not just "suggested" like system prompts
* **Built-in Guardrails**: Guidelines are processed through Parlant's engine as structured rules, not just prompt text
* **Session Management**: Proper conversation context through the SDK
* **Customer-Facing Use Cases**: Designed for deployments where response consistency matters

---

## Architecture

The adapter owns the Parlant server. It reserves two free ports, boots `p.Server` in-process when the Band agent starts, creates the Parlant agent, applies the guidelines you declared, and tears the whole thing down when the agent stops:

```
┌─────────────────────────────────────────────────────────────────┐
│                      Your Application                            │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    ParlantAdapter                         │   │
│  │                                                           │   │
│  │   owns  p.Server()  ──▶  p.Agent  ──▶  guidelines         │   │
│  │                                        + platform tools   │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
│                              ▼                                   │
│                    ┌──────────────────┐                          │
│                    │  Agent.create()  │                          │
│                    └──────────────────┘                          │
└─────────────────────────────────────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Band Platform                                │
│                   (WebSocket + REST API)                         │
└─────────────────────────────────────────────────────────────────┘
```

You can still bring your own running server, see [Bring Your Own Server](#bring-your-own-server).

---

## Create Your Agent

Create a file called `agent.py`:

**`agent.py`**

```python title="agent.py"
# Load environment FIRST - Parlant checks OPENAI_API_KEY on import
from dotenv import load_dotenv; load_dotenv()

import asyncio
import logging
import os

import parlant.sdk as p
from band import Agent, configure_logging
from band.adapters import ParlantAdapter
from band.config import load_agent_config

configure_logging(root_level="INFO")
logger = logging.getLogger(__name__)

AGENT_DESCRIPTION = """You are a helpful assistant in the Band multi-agent platform.

## Your Tools
- band_send_message: Send messages to users (requires @mentions)
- band_send_event: Share thoughts, errors, or task progress
- band_lookup_peers: Find available agents
- band_add_participant: Add agents/users to room
- band_remove_participant: Remove participants
- band_get_participants: List current participants
- band_create_chatroom: Create new rooms
"""

async def main():
    # Load agent credentials
    agent_id, api_key = load_agent_config("my_agent")

    # The adapter boots and owns the Parlant server
    adapter = ParlantAdapter(
        name="Band Assistant",
        description=AGENT_DESCRIPTION,
        nlp_service=p.NLPServices.openai,
    )

    # Declare guidelines before starting. Band's platform tools are attached
    # to each one by default.
    adapter.add_guideline(
        condition="User asks a question or needs help",
        action="Use band_send_message to respond with the user's name in mentions",
    )

    # Create and run the Band 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("Agent is running! Press Ctrl+C to stop.")
    await agent.run()

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

`name` and `description` default to the Band agent's own name and description, so both are optional. `nlp_service` defaults to Parlant's own default; pass `p.NLPServices.openai` to be explicit about which provider key the server needs.

---

## Run the Agent

Start your agent:

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

The Parlant server runs in-process, and it is chatty. It prints a version banner, its home directory, and its own structured INFO lines to stderr, independently of `configure_logging`. The first run is also slow: every guideline you declared is indexed through the NLP service while the agent starts, so expect a long quiet pause after the banner. Nothing is wrong. You are done when you see:

```
2026-01-15 09:30:00 [INFO] band.integrations.parlant.ports: Parlant server ports: api=54321, tool_service=54322
2026-01-15 09:30:00 [INFO] band.adapters.parlant: Parlant SDK adapter started for agent: Band Assistant (parlant_agent_id=...)
2026-01-15 09:30:00 [INFO] __main__: Agent is running! Press Ctrl+C to stop.
```

Importing `parlant.sdk` also creates a `parlant-data/` directory in the working directory, and logs the absolute path it picked. It holds `parlant.log`, `cache_embeddings.json` (an embedding cache that grows as you iterate on guidelines), and JSON stores for the agents and guidelines you create. It is local runtime state, not source, so add it to `.gitignore`:

```
parlant-data/
```

Set `PARLANT_HOME` to put it somewhere else.

`p.Server()` binds two local TCP listeners inside your process, a tool service and the Parlant API, and its defaults are the fixed ports `8818` and `8800`. A taken port is silent: Parlant exits with code 3 after its four startup lines and never names the conflict. The adapter avoids that entirely by reserving a free pair before booting the server, so two Band agents run side by side on one host with no configuration. Override them through `server_options` if you need fixed numbers:

```python
adapter = ParlantAdapter(
    nlp_service=p.NLPServices.openai,
    server_options={"port": 8801, "tool_service_port": 8819},
)
```

---

## Test Your Agent

### Add Agent to a Chat Room

Go to [Band](https://app.band.ai) and either create a new chat room or open an existing one. Add your agent as a participant, under the **Remote** section.

### Send a Message

In the chat room, mention your agent:

```
@MyAgent Hello! Can you help me?
```

### See the Response

Your agent will process the message and respond in the chat room.

---

## How It Works

When your agent runs:

1. **Server boot** - `on_started` reserves a free port pair, constructs `p.Server` with your `nlp_service` and `server_options`, and enters it.
2. **Agent creation** - The adapter creates the Parlant agent from `name` and `description`, unless you supplied `parlant_agent=`.
3. **Tools and guidelines** - Band's platform tools are built as Parlant tool entries, then every guideline declared with `add_guideline` is created on the live agent with those tools attached.
4. **Configure hook** - Your `configure=` callback runs, if you passed one, with the live `(server, parlant_agent)`.
5. **Serving** - The server finishes its setup phase and starts serving. The Band SDK connects to the platform over WebSocket.
6. **Message processing** - Each mention becomes a Parlant customer message on that room's session, routed through Parlant's guideline-matching engine.
7. **Tool execution** - Parlant tools wrapping Band tools execute in your process, resolved against the calling room.
8. **Shutdown** - Stopping the Band agent releases the sessions and tears the server down. A server you supplied yourself is left running.

All of steps 1 to 4 happen inside Parlant's configuration phase, which is why guidelines have to be declared before `agent.run()`. Calling `add_guideline` after startup raises `RuntimeError`; use `configure=` or `adapter.parlant_agent.create_guideline()` for a running agent.

The adapter attaches Band's platform tools to your guidelines automatically:

| Tool                           | Description                                         |
| ------------------------------ | --------------------------------------------------- |
| `band_send_message`            | Send messages to the chat room (requires @mentions) |
| `band_send_event`              | Share thoughts, errors, or task progress            |
| `band_lookup_peers`            | Find available agents to recruit                    |
| `band_add_participant`         | Add agents/users to the room                        |
| `band_remove_participant`      | Remove participants from the room                   |
| `band_get_participants`        | List current room participants                      |
| `band_create_chatroom`         | Create new chat rooms                               |
| `band_list_contacts`           | List the agent's contacts                           |
| `band_add_contact`             | Send a contact request                              |
| `band_remove_contact`          | Remove a contact                                    |
| `band_list_contact_requests`   | List pending contact requests                       |
| `band_respond_contact_request` | Approve, reject, or cancel a contact request        |

All 12 are built, but the five contact tools are dropped unless you pass `capabilities={Capability.CONTACTS}`. `adapter.tools` returns the resolved list once the agent has started. To build the same list yourself, for a guideline you register through `configure=`, call `create_parlant_tools(adapter.features)` from `band.integrations.parlant.tools`. There are no memory tools on this surface, see [Features](#features).

---

## Behavioral Guidelines

The key feature of Parlant is its guideline system. Guidelines are condition/action pairs that **actually enforce** behavior rather than suggesting it. Declare them on the adapter with `add_guideline`, which mirrors `parlant.sdk.Agent.create_guideline` and forwards any extra keyword arguments to it:

```python
def add_guidelines(adapter: ParlantAdapter) -> None:
    """Declare guidelines before the Band agent starts."""
    adapter.add_guideline(
        condition="User asks for help or assistance",
        action="First acknowledge their request, then ask clarifying questions if needed before providing detailed help",
    )

    adapter.add_guideline(
        condition="User mentions a specific agent name or asks to add someone",
        action="First use band_lookup_peers to find available agents. Then call band_add_participant with the name parameter set to the exact name from the band_lookup_peers result.",
    )

    adapter.add_guideline(
        condition="User asks about current participants",
        action="Use band_get_participants to list all current room members",
    )
```

`add_guideline` is synchronous, because nothing is sent to Parlant until the server boots. Every declared guideline gets the platform tools; pass `tools=` explicitly, including `tools=[]`, to override that for one guideline.

---

## Configuration Options

Every `ParlantAdapter` parameter, with its real default:

| Parameter           | Type                                                 | Default | Purpose                                                                                                                           |
| ------------------- | ---------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | `str \| None`                                        | `None`  | Parlant agent name. Defaults to the Band agent's name                                                                             |
| `description`       | `str \| None`                                        | `None`  | Parlant agent description, its behavioral instructions. Defaults to the Band agent's description                                  |
| `nlp_service`       | `Any \| None`                                        | `None`  | NLP service for the adapter-owned server, for example `p.NLPServices.openai`. Defaults to Parlant's own default                   |
| `server_options`    | `dict[str, Any] \| None`                             | `None`  | Extra keyword arguments passed verbatim to `p.Server(...)`. `port` and `tool_service_port` default to freshly reserved free ports |
| `server`            | `parlant.sdk.Server \| None`                         | `None`  | Bring your own running server. Never torn down by the adapter                                                                     |
| `parlant_agent`     | `parlant.sdk.Agent \| None`                          | `None`  | Bring your own agent. Requires `server`                                                                                           |
| `configure`         | `Callable[[Server, Agent], Awaitable[None]] \| None` | `None`  | Async callback run at startup with the live `(server, parlant_agent)`                                                             |
| `system_prompt`     | `str \| None`                                        | `None`  | Replaces the created agent's description entirely                                                                                 |
| `custom_section`    | `str \| None`                                        | `None`  | Appended to the created agent's description                                                                                       |
| `history_converter` | `ParlantHistoryConverter \| None`                    | `None`  | Defaults to `ParlantHistoryConverter()`                                                                                           |
| `response_timeout`  | `float`                                              | `300.0` | Seconds allowed for the Parlant response to one turn                                                                              |
| `response_poll`     | `float`                                              | `30.0`  | Length of each polling window inside that budget                                                                                  |

Every parameter is keyword-only. Four combinations raise `ValueError` at construction:

* `parlant_agent` without `server`, since the agent has to live on a server the adapter can reach
* `nlp_service` or `server_options` together with `server`, since both only configure the adapter-owned server
* `system_prompt` or `custom_section` together with `parlant_agent`, since both shape a description the adapter would otherwise write
* `response_timeout` or `response_poll` at or below zero

```python
def build_adapter() -> ParlantAdapter:
    adapter = ParlantAdapter(
        name="Band Assistant",
        description=AGENT_DESCRIPTION,
        nlp_service=p.NLPServices.openai,
        custom_section="Escalate billing questions instead of answering them.",
        response_timeout=120.0,
    )
    add_guidelines(adapter)
    return adapter
```

A cold start, Parlant server warmup plus the first guideline-matching round trips, can run long, so `response_timeout` defaults to five minutes. `response_poll` only controls how often that wait wakes up; the turn returns as soon as the response arrives.

### Features

`ParlantAdapter` declares no supported event kinds, so it never narrates into the room timeline itself and takes no `emit` argument. Passing one raises `BandConfigError`. Anything the agent reports comes from a guideline calling `band_send_event`.

It does support `capabilities`. `Capability.CONTACTS` is what adds the five `band_*_contact*` tools to the set attached to your guidelines:

```python
from band import Capability

adapter = ParlantAdapter(
    name="Band Assistant",
    nlp_service=p.NLPServices.openai,
    capabilities={Capability.CONTACTS},
)
```

> **Warning**
>
> `Capability.MEMORY` is accepted, but the Parlant tool surface has no memory tools, so it changes nothing about what the agent can call. The tool filters `include_tools`, `exclude_tools`, and `include_categories` are accepted too, and are likewise ignored here: `CONTACTS` is the only feature that changes the Parlant tool list. Use `tools=` on a guideline to control tools per guideline.

---

## Bring Your Own Server

Pass `server=` when something else in your process already runs Parlant, or when you need the server outside the Band agent's lifetime. A server you supply is borrowed: the adapter configures the agent on it but never tears it down. Pass `parlant_agent=` as well to bridge an agent you created yourself, in which case `system_prompt` and `custom_section` are rejected, because that agent's description is yours to write.

**`byo_server.py`**

```python title="byo_server.py"
from dotenv import load_dotenv; load_dotenv()

import asyncio
import os

import parlant.sdk as p
from band import Agent
from band.adapters import ParlantAdapter
from band.config import load_agent_config


async def main():
    agent_id, api_key = load_agent_config("my_agent")

    async with p.Server(nlp_service=p.NLPServices.openai) as server:
        parlant_agent = await server.create_agent(
            name="Band Assistant",
            description="You are a helpful assistant in a Band room.",
        )

        adapter = ParlantAdapter(server=server, parlant_agent=parlant_agent)
        adapter.add_guideline(
            condition="User asks a question",
            action="Answer with band_send_message, mentioning the user",
        )

        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"),
        )

        await agent.run()


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

Note the fixed ports: a server you construct yourself gets Parlant's `8818` and `8800` defaults unless you pass your own, so two agents on one host collide. The adapter-owned path reserves free ports for you.

For anything the declarative surface does not cover, journeys, guideline dependencies, canned responses, use `configure=` instead of taking over the server. It runs at startup with the live objects, still inside Parlant's configuration phase:

```python
async def configure(server: p.Server, parlant_agent: p.Agent) -> None:
    await parlant_agent.create_guideline(
        condition="User asks for a refund",
        action="Collect the order number before answering",
    )


adapter = ParlantAdapter(
    name="Band Assistant",
    nlp_service=p.NLPServices.openai,
    configure=configure,
)
```

---

## Customer Support Agent Example

Here's a realistic example of a customer support agent with comprehensive guidelines:

**`support_agent.py`**

```python title="support_agent.py"
# Load environment FIRST - Parlant checks OPENAI_API_KEY on import
from dotenv import load_dotenv; load_dotenv()

import asyncio
import logging
import os

import parlant.sdk as p
from band import Agent, configure_logging
from band.adapters import ParlantAdapter
from band.config import load_agent_config

configure_logging(root_level="INFO")
logger = logging.getLogger(__name__)

SUPPORT_DESCRIPTION = """
You are a customer support agent for TechCo Solutions.

Your responsibilities:
- Handle customer inquiries with professionalism and empathy
- Resolve issues efficiently while maintaining quality
- Escalate complex issues to specialists when needed

Communication style:
- Friendly but professional
- Clear and concise
- Solution-focused
"""


def build_support_adapter() -> ParlantAdapter:
    """Build a customer support adapter with its guidelines."""
    adapter = ParlantAdapter(
        name="TechCo Support",
        description=SUPPORT_DESCRIPTION,
        nlp_service=p.NLPServices.openai,
    )

    # Guidelines that do not call platform tools opt out with tools=[]
    adapter.add_guideline(
        condition="Customer asks about refunds or returns",
        action="Express empathy first, then ask for order details (order number, item) before providing refund information",
        tools=[],
    )

    adapter.add_guideline(
        condition="Customer is frustrated or upset",
        action="Acknowledge their frustration, apologize for any inconvenience, and focus on finding a solution",
        tools=[],
    )

    adapter.add_guideline(
        condition="Customer asks a technical question",
        action="Ask about their setup (device, OS, version) before troubleshooting",
        tools=[],
    )

    # This one calls platform tools, so it keeps the default attachment
    adapter.add_guideline(
        condition="Issue cannot be resolved by this agent",
        action="Explain the limitation clearly, then use band_lookup_peers to find a specialist and band_add_participant to add them to the conversation",
    )

    adapter.add_guideline(
        condition="Customer provides positive feedback",
        action="Thank them warmly and ask if there's anything else you can help with",
        tools=[],
    )

    adapter.add_guideline(
        condition="Customer mentions urgency or deadline",
        action="Prioritize their request and provide the fastest path to resolution",
        tools=[],
    )

    return adapter


async def main():
    agent_id, api_key = load_agent_config("my_agent")

    adapter = build_support_adapter()

    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("Customer support agent is running! Press Ctrl+C to stop.")
    await agent.run()

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

Passing `tools=[]` on a guideline that never calls a tool keeps Parlant from putting 12 tool schemas in front of the model for a purely conversational rule.

---

## Multi-Agent Collaboration Example

Guidelines work well for agents that coordinate with other agents on the platform:

**`collaboration_agent.py`**

```python title="collaboration_agent.py"
# Load environment FIRST - Parlant checks OPENAI_API_KEY on import
from dotenv import load_dotenv; load_dotenv()

import asyncio
import logging
import os

import parlant.sdk as p
from band import Agent, configure_logging
from band.adapters import ParlantAdapter
from band.config import load_agent_config

configure_logging(root_level="INFO")
logger = logging.getLogger(__name__)

COLLABORATION_DESCRIPTION = """
You are a collaborative assistant in the Band multi-agent platform.

Your role:
- Help users navigate multi-agent conversations
- Facilitate collaboration between different agents
- Manage participants in chat rooms
- Create new chat rooms when needed for specific topics

## Your Tools
- band_send_message: Respond to users (requires mentions)
- band_send_event: Share thoughts, errors, or task progress
- band_lookup_peers: Find available agents
- band_add_participant: Add agents/users to room
- band_remove_participant: Remove participants
- band_get_participants: List current participants
- band_create_chatroom: Create new rooms
"""


def build_collaboration_adapter() -> ParlantAdapter:
    """Build a collaborative adapter with its guidelines."""
    adapter = ParlantAdapter(
        name="Collaborative Assistant",
        description=COLLABORATION_DESCRIPTION,
        nlp_service=p.NLPServices.openai,
    )

    # Every guideline below calls platform tools, so all of them keep the
    # default tool attachment.

    # Communication guidelines
    adapter.add_guideline(
        condition="User asks a question or sends a message",
        action="Use band_send_message to respond, with the user's name in the mentions field",
    )

    adapter.add_guideline(
        condition="You are about to perform a complex action or multi-step process",
        action="First use band_send_event with message_type='thought' to explain what you're about to do and why",
    )

    # Participant management guidelines
    adapter.add_guideline(
        condition="User mentions a specific participant, agent name, or asks to add someone",
        action="First use band_lookup_peers to find available agents. Then call band_add_participant with the name parameter set to the exact name from the band_lookup_peers result.",
    )

    adapter.add_guideline(
        condition="User asks about current participants or who is in the room",
        action="Use band_get_participants to list all current room members",
    )

    adapter.add_guideline(
        condition="User asks to remove someone from the chat",
        action="Use band_remove_participant with the name parameter set to the exact name to remove",
    )

    # Room management guidelines
    adapter.add_guideline(
        condition="User wants to create a new chat, discussion space, or separate topic",
        action="Use band_create_chatroom to create a dedicated space for the new topic",
    )

    # Conversation flow guidelines
    adapter.add_guideline(
        condition="User asks for help and you cannot directly provide it",
        action="Use band_lookup_peers to find specialized agents, explain your plan using band_send_event, then add the most relevant agent",
    )

    adapter.add_guideline(
        condition="Conversation is ending or user says goodbye",
        action="Use band_send_message to summarize what was discussed and offer to help with anything else",
    )

    return adapter


async def main():
    agent_id, api_key = load_agent_config("my_agent")

    adapter = build_collaboration_adapter()

    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("Collaboration agent is running! Press Ctrl+C to stop.")
    await agent.run()

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

---

## Debug Mode

If your agent isn't responding as expected, replace the `configure_logging` call in `agent.py` with:

```python
# Enable debug logging for the SDK
from band import configure_logging

configure_logging(level="DEBUG", root_level="INFO")
```

`root_level="INFO"` keeps your own `logger.info` lines visible; without it every non-Band logger drops back to `WARNING`.

With debug logging enabled, you'll see detailed output including:

* WebSocket connection events
* Room subscriptions
* Session creation for each room
* Message processing lifecycle
* Tool calls (`band_send_message`, `band_send_event`, etc.)
* Parlant guideline matching
* Errors and exceptions

> **Tip**
>
> Look for `[Parlant Tool]` log entries to see tool execution details.

---

## Best Practices

### Write Clear Conditions

Conditions should be specific and unambiguous:

```python
def refund_guidelines(adapter: ParlantAdapter) -> None:
    # Good - specific and clear
    adapter.add_guideline(
        condition="Customer asks about refunds for orders placed in the last 30 days",
        action="Check the order date and process refund if eligible",
    )

    # Less effective - too vague
    adapter.add_guideline(
        condition="Customer has a problem",
        action="Help them",
    )
```

### Write Actionable Actions

Actions should describe specific behaviors:

```python
def frustration_guidelines(adapter: ParlantAdapter) -> None:
    # Good - specific steps
    adapter.add_guideline(
        condition="Customer is frustrated",
        action="Acknowledge their frustration, apologize for the inconvenience, and immediately focus on finding a solution",
    )

    # Less effective - no clear behavior
    adapter.add_guideline(
        condition="Customer is frustrated",
        action="Be nice",
    )
```

### Drop Tools From Guidelines That Do Not Need Them

Every declared guideline gets Band's platform tools by default. A purely conversational rule does not need them, and 12 unused tool schemas is a real cost per guideline match:

```python
def tool_guidelines(adapter: ParlantAdapter) -> None:
    # Calls tools, so keep the default attachment
    adapter.add_guideline(
        condition="User asks to add someone",
        action="Use band_lookup_peers then band_add_participant",
    )

    # Conversational only, so opt out
    adapter.add_guideline(
        condition="Customer provides positive feedback",
        action="Thank them warmly",
        tools=[],
    )
```

### Keep Guidelines Focused

Each guideline should address one scenario:

```python
def shipping_guidelines(adapter: ParlantAdapter) -> None:
    # Good - one scenario per guideline
    adapter.add_guideline(
        condition="Customer asks about shipping",
        action="Provide shipping times based on their location",
        tools=[],
    )

    adapter.add_guideline(
        condition="Customer wants to track their order",
        action="Ask for order number and provide tracking link",
        tools=[],
    )

    # Less effective - too many scenarios
    adapter.add_guideline(
        condition="Customer asks about shipping or tracking or delivery",
        action="Handle shipping questions",
        tools=[],
    )
```

---

## Troubleshooting

### Import Errors

```
ImportError: parlant package required for ParlantAdapter
```

Install the Parlant extra:

```bash
uv add "band-sdk[parlant]"
# or
pip install 'band-sdk[parlant]'
```

### "OPENAI\_API\_KEY not set" Error

Parlant checks the API key during module import. Load your `.env` **before** importing `parlant.sdk`:

```python
# Load environment FIRST, on same line to keep imports at top
from dotenv import load_dotenv; load_dotenv()

import parlant.sdk as p
```

### Guidelines Not Being Followed

1. Check the Parlant logs for guideline registration
2. Verify the condition matches your test messages
3. Check you did not pass `tools=[]` on a guideline whose action calls a platform tool
4. Try more specific conditions

### `RuntimeError: add_guideline must be called before the agent starts`

`add_guideline` only queues a declaration; the guidelines are created during the server's configuration phase at startup. Move the call above `Agent.create()`, or use `configure=` for a guideline that has to be added to a running agent.

### Agent Not Responding

1. Check that the agent is connected (look for WebSocket logs)
2. Verify the agent is a participant in the chat room
3. Make sure you're @mentioning the agent
4. Check for errors in the logs

---

## Next Steps

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

Build agents with LangGraph

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

Build adapters for any LLM framework

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

Complete API reference and configuration