Custom Gateway Channel (Zero-Code)

Add a custom chat channel from YAML or a drop-in file — no packaging, no bootstrap Python

Point a channel at your adapter class from YAML, or drop a .py file into .praisonai/channels/, and praisonai gateway start picks it up — no pip install, no register_platform() call.

Diagram

📝 YAML adapter: ref

📚 BotPlatformRegistry

📁 ./.praisonai/channels/*.py

🏠 ~/.praisonai/channels/*.py

✅ Running Gateway

Your agent replies on the custom channel the same way it does on a built-in one — the channel is just a new door into the same agent.

python
from praisonaiagents import Agent

agent = Agent(
    name="support",
    instructions="Answer questions on our intranet chat.",
)
agent.start("Reply to intranet messages using our knowledge base.")

Quick Start

  1. YAML adapter: import string

    Point a channel at your adapter class with a dotted "module:Class" string. The gateway imports, validates, and self-registers it before startup.

    yaml
    # gateway.yaml
    channels:
      my_intranet_chat:
        adapter: "my_company.adapters:IntranetBot"
        token: ${INTRANET_TOKEN}
        routes:
          default: support
    bash
    praisonai gateway start
  2. Drop-in file

    Copy a single-file adapter into ~/.praisonai/channels/ and start — no packaging, no config edit.

    bash
    mkdir -p ~/.praisonai/channels
    cp adapters.py ~/.praisonai/channels/
    praisonai gateway start

    Any BasePlatformAdapter subclass in the file registers under its platform_name.


How It Works

The gateway resolves a channel’s adapter class from three inputs, self-registers it, then starts it like any built-in.

Diagram
Gatewayregister_platformnormalize_and_validate / BotPlatformRegistrygateway.yaml / drop-inUserGatewayregister_platformnormalize_and_validate / BotPlatformRegistrygateway.yaml / drop-inUserpraisonai gateway startadapter: ref or channels/*.pyimport + validate BasePlatformAdapterself-register under channel keyadapter class readychannel live, agent replies

A single-file adapter needs only the four abstract methods:

python
# ~/.praisonai/channels/intranet.py
from praisonaiagents.bots import BasePlatformAdapter


class IntranetBot(BasePlatformAdapter):
    platform_name = "my_intranet_chat"

    async def connect(self, *, is_reconnect: bool = False) -> bool:
        return True

    async def disconnect(self) -> None:
        return None

    async def send(self, chat_id, content, *, reply_to=None, metadata=None):
        ...

    async def get_chat_info(self, chat_id):
        return {}

Choosing Between the Surfaces

Five registration paths reach the same adapter class — pick the one that matches your packaging.

Diagram

Yes

No

Yes

No

Yes

✏️ Add a channel

Already have
a pip package?

praisonai.channels
entry point

One file,
no install?

YAML adapter: ref
or drop-in file

Need it in code
before startup?

register_platform


Precedence Ladder

The first surface that resolves a channel key wins — a registered platform is never shadowed.

OrderSurfaceWins When
1Registered platform (built-in / entry point / register_platform)The platform name is already registered
2YAML adapter: import refplatform is not registered and adapter: is set
3Filesystem drop-in (project or user)An adapter file declares the platform_name
4Error: Unknown channel typeNothing above resolves the key

Trust Model

User-global drop-ins are trusted; project-local drop-ins require an explicit opt-in.

bash
# Allow project-local channel files for this run
PRAISONAI_ALLOW_PROJECT_PLUGINS=true praisonai gateway start

The trust check is scoped to the channels directory, so a symlinked channels dir is still recognised while a symlinked file cannot slip the gate.


Configuration Options

The adapter field is the only new YAML key — it is a loader-only hint and is never passed to the adapter’s __init__.

OptionTypeDefaultDescription
adapterstrNoneDotted "module.path:ClassName" import string. Class must subclass BasePlatformAdapter. Ignored if platform is already registered.

If the adapter class exposes a channel_descriptor (attribute or callable), that descriptor is used at registration; otherwise the channel registers with descriptor=None.


Common Patterns

Enterprise intranet chat (YAML adapter:)

Point a channel at a packaged internal adapter and pull the token from the environment.

yaml
# gateway.yaml
channels:
  my_intranet_chat:
    adapter: "my_company.adapters:IntranetBot"
    token: ${INTRANET_TOKEN}
    routes:
      default: support
bash
praisonai gateway start

Prototype in one file (drop-in)

Skip packaging entirely — drop a single file into the user-global directory.

bash
mkdir -p ~/.praisonai/channels
cp intranet.py ~/.praisonai/channels/
praisonai gateway start

Overriding a built-in

You cannot silently override a built-in from adapter: — a registered platform always wins. To swap a built-in, register in code before startup.

python
from praisonai.bots._registry import register_platform
from my_company.adapters import CustomSlackBot

register_platform("slack", CustomSlackBot)

Error Surface

Malformed refs fail fast with a clear ValueError so a typo never starts a silent, broken channel.

TriggerExampleError
No colon in ref"my_company.adapters.IntranetBot"ValueError — ref must be "module:Class"
Empty module or class":IntranetBot" / "my_company.adapters:"ValueError — empty module/class
Unimportable module"missing_pkg.adapters:IntranetBot"ValueError — module import failed
Missing class attribute"my_company.adapters:NoSuchBot"ValueError — class not found in module
Not a BasePlatformAdapterclass that does not subclass the baseValueError — not a BasePlatformAdapter

Best Practices

Keep adapters in a versioned repo path

Store the adapter file in a checked-in project path and copy it into ~/.praisonai/channels/ at deploy time, so the running channel is reproducible from source control.

Pin secrets via ${ENV} refs, never inline

Reference tokens as ${INTRANET_TOKEN} in gateway.yaml. Never inline a secret in the YAML or the drop-in file — both are easy to leak.

Keep the drop-in file dependency-free

A single-file adapter should import only BasePlatformAdapter and stdlib. Do heavy SDK imports lazily inside connect() so a missing dependency never breaks gateway startup.

Package once the adapter is stable

When an adapter is shared across teams, promote it to a praisonai.channels entry point. Packaging gives you versioning and dependency pinning that a drop-in file cannot.


Related