> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Channel Descriptor

> Let a channel plugin declare its config, prompt hint, and setup wizard in one place.

A channel plugin declares — in one place — everything the gateway needs to treat it as first-class: its own config keys, a system-prompt hint, and an optional setup wizard.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    D[📇 ChannelDescriptor] --> S[⚙️ Config Schema]
    D --> W[🧙 Onboarding Wizard]
    D --> P[🤖 Agent Prompt]

    classDef input fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef consumer fill:#189AB4,stroke:#7C90A0,color:#fff

    class D input
    class S,W,P consumer
```

## Quick Start

<Steps>
  <Step title="Declare a descriptor">
    List your channel's config fields and a prompt hint on a small descriptor class:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents.bots import ChannelField

    class IRCDescriptor:
        config_fields = [
            ChannelField("server", required=True, prompt="IRC server host"),
            ChannelField("nickserv_password", secret=True, env="IRC_NICKSERV_PASSWORD"),
        ]
        system_prompt_hint = (
            "You are replying on IRC: plain text only, one short line."
        )
    ```

    <Note>
      **Availability.** Before [PraisonAI PR #3622](https://github.com/MervinPraison/PraisonAI/pull/3622), `system_prompt_hint` was *declared but not delivered* to the model on the gateway path — the resolver existed, but nothing called it. As of PR #3622 the gateway auto-injects the hint at per-channel bot construction (and again on hot-reload), so a plugin's declared hint now actually reaches the agent.
    </Note>
  </Step>

  <Step title="Register the platform">
    Pass the descriptor when you register the adapter — the gateway wires config, onboarding, and prompt for you:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonai.bots._registry import register_platform

    register_platform("irc", IRCBot, descriptor=IRCDescriptor())
    ```
  </Step>
</Steps>

<Note>
  Without a descriptor, a plugin channel's own keys (like IRC's `server`) are silently dropped by the fixed `ChannelConfigSchema`. The descriptor keeps them.
</Note>

***

## How It Works

One declaration feeds three consumers when the channel is active.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Plugin
    participant Registry
    participant Schema as Config Schema
    participant Wizard as Onboarding Wizard
    participant Prompt as Agent Prompt

    participant Gateway as Gateway (_create_bot)
    participant Agent

    Plugin->>Registry: register_platform("irc", IRCBot, descriptor=...)
    Schema->>Registry: read config_fields → keep plugin keys
    Wizard->>Registry: list_platforms() → prompt for each field
    Gateway->>Registry: get_channel_system_prompt_hint("irc")
    Registry-->>Gateway: "You are replying on IRC: plain text only, one short line."
    Gateway->>Agent: append hint to backstory + rebuild system_prompt
```

| Consumer          | Reads                                | Effect                                                                                              |
| ----------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------- |
| Config schema     | `config_fields`                      | Plugin keys validate instead of being dropped                                                       |
| Onboarding wizard | `config_fields` (+ optional `setup`) | Prompts for each field, using `env` as fallback                                                     |
| Agent prompt      | `system_prompt_hint`                 | Appended to the agent's `backstory` and the rebuilt `system_prompt` at per-channel bot construction |

<Info>
  **Guarantees.** The auto-injection is:

  * **Bounded** — a single trailing append.
  * **Idempotent** — won't double-append across hot-reload or re-clone if the hint is already present.
  * **Deterministic** — one ordered append keeps the prompt prefix cache-stable.
  * **No-op** for built-in channels that declare no hint.
  * **Opt-in** — only affects third-party channels that declare a `system_prompt_hint`.

  The hint lands on `backstory` (and the rebuilt `system_prompt`) — the fields the runtime prompt builder actually reads — not `instructions`, which is a construction-only attribute.
</Info>

<Note>
  **Issue #3621:** Prior to this release the hint field existed on the descriptor but was never read by the runtime. Third-party channels that shipped a `system_prompt_hint` before that release should verify their hint now reaches the model.
</Note>

### How the hint reaches the model

The gateway resolves the descriptor's hint and appends it to the cloned agent's `backstory`, then rebuilds `system_prompt` — the runtime prompt builder reads those, not the construction-only `instructions`.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Gateway
    participant Registry as _registry
    participant Agent
    Gateway->>Registry: get_channel_system_prompt_hint("irc")
    Registry-->>Gateway: "plain text only, one short line."
    Gateway->>Agent: append to backstory, rebuild system_prompt
    Agent-->>Gateway: hint now on every turn
```

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.bots import ChannelField
from praisonai.bots._registry import register_platform

class IRCDescriptor:
    config_fields = [
        ChannelField("server", required=True, prompt="IRC server host"),
    ]
    # This hint now actually reaches the model on every turn.
    system_prompt_hint = "You are replying on IRC: plain text only, one short line."

register_platform("irc", IRCBot, descriptor=IRCDescriptor())
```

***

## ChannelField Options

Each `ChannelField` describes one config key the channel needs.

| Field      | Type            | Default | Description                                                 |
| ---------- | --------------- | ------- | ----------------------------------------------------------- |
| `name`     | `str`           | —       | Config key name (as it appears under `channels.<platform>`) |
| `required` | `bool`          | `False` | Whether the field must be provided                          |
| `secret`   | `bool`          | `False` | Whether the value is sensitive (masked in prompts/logs)     |
| `prompt`   | `str`           | `""`    | Human-friendly prompt shown by the onboarding wizard        |
| `env`      | `Optional[str]` | `None`  | Environment-variable name used as a fallback source         |

***

## Interactive Setup

Add an optional `setup(io)` hook for multi-step flows that a flat field list can't express — the wizard calls it when present and merges the returned values.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.bots import ChannelField
from praisonai.bots._registry import register_platform

class IRCDescriptor:
    config_fields = [
        ChannelField("server", required=True, prompt="IRC server host"),
    ]
    system_prompt_hint = "You are replying on IRC: plain text only, one short line."

    def setup(self, io) -> dict:
        channels = io.prompt("Which channels to join? (comma-separated)")
        return {"channels": [c.strip() for c in channels.split(",") if c.strip()]}

register_platform("irc", IRCBot, descriptor=IRCDescriptor())
```

<Note>
  `setup` is optional. A descriptor that only needs declarative `config_fields` omits it entirely.
</Note>

***

## Best Practices

<AccordionGroup>
  <Accordion title="Mark secrets with secret=True">
    Set `secret=True` on tokens and passwords so the wizard masks them and logs never print the value.
  </Accordion>

  <Accordion title="Provide an env fallback for secrets">
    Add `env="IRC_NICKSERV_PASSWORD"` so operators can supply credentials via environment variables instead of prompts.
  </Accordion>

  <Accordion title="Keep the prompt hint short and concrete">
    State the platform and its constraints in one line — for example plain text only, one short line — so the agent adapts its replies.
  </Accordion>

  <Accordion title="Use setup only when fields aren't enough">
    Reach for `setup(io)` for bespoke, multi-step flows. Declarative `config_fields` cover the common case with no code.
  </Accordion>

  <Accordion title="Idempotency & prompt-cache safety">
    The gateway appends the hint as a single trailing line, so injection is deterministic and the prompt prefix stays cache-stable across turns. A hint already present on the agent's `backstory` is a no-op on hot-reload, so re-clones never duplicate it.
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Messaging Bots" icon="robot" href="/docs/features/messaging-bots">
    Connect agents to Telegram, Slack, Discord, and more
  </Card>

  <Card title="Bot Platform Capabilities" icon="sliders" href="/docs/features/bot-platform-capabilities">
    How platform capabilities drive channel behaviour
  </Card>

  <Card title="Gateway" icon="tower-broadcast" href="/docs/features/gateway">
    Multi-agent coordination across channels
  </Card>

  <Card title="Plugins" icon="puzzle-piece" href="/docs/features/plugins">
    Ship channels and tools as pip packages
  </Card>

  <Card title="Channel Directory" icon="list" href="/docs/features/gateway-channel-directory">
    How an adapter enumerates the channels it can see
  </Card>

  <Card title="Visible-Outcome Guarantee" icon="eye" href="/docs/features/visible-outcome-guarantee">
    Every inbound turn ends in a visible reply or a deliberate silence
  </Card>
</CardGroup>

<Note>
  Prompt-hint auto-injection introduced in [PraisonAI PR #3622](https://github.com/MervinPraison/PraisonAI/pull/3622) (fixes [#3621](https://github.com/MervinPraison/PraisonAI/issues/3621)).
</Note>
