Bot platform adapters now ship in the
praisonai-bot package. praisonai bot serve still works exactly as documented here; for a standalone install see praisonai-bot Migration.register_platform()) and two zero-code paths (YAML adapter: ref and .praisonai/channels/ drop-in files). See Custom Gateway Channel (Zero-Code) for the full zero-code story.
Quick Start
1
Programmatic Registration
Register a bot platform directly in your code:
2
Entry-point Plugin
Create a pip-installable plugin using After installation, use the bot platform:
pyproject.toml:Zero-Code Paths
Two paths register a channel with no packaging and no bootstrap Python — both self-register the adapter before startup. YAMLadapter: import ref. Point a channel at a dotted "module:Class" string; the gateway imports, validates, and registers it.
BasePlatformAdapter subclass in ./.praisonai/channels/*.py (project, gated by PRAISONAI_ALLOW_PROJECT_PLUGINS=true) or ~/.praisonai/channels/*.py (user-global, trusted) registers under its platform_name.
How It Works
The bot platform registry provides a central point for managing bot implementations:Configuration
The bot platform registry supports both programmatic and entry-point registration:Built-in Platforms
PraisonAI includes these built-in bot platforms:telegram- Telegram bot integrationdiscord- Discord bot integrationslack- Slack bot integrationwhatsapp- WhatsApp bot integrationlinear- Linear issues integrationemail- Email bot integrationagentmail- AgentMail integrationwebhook- Generic HTTP webhook trigger (declarative routes) — see Webhook Channel
Entry-point Groups
Both groups are scanned by
BotPlatformRegistry on startup. A connector that would shadow a built-in platform is skipped with a warning.
Discovery via entry points (praisonai.channels)
Plugin channels on
praisonai gateway start (from PR #3579, merged 2026-08-01):
the gateway’s _create_bot path now delegates to the same resolve_adapter() seam that Bot() and probe_channels use, so channels registered via register_platform() or a praisonai.channels entry point are launched by the gateway exactly like a built-in. Older gateway builds hardcoded seven built-in platforms and silently skipped everything else with a single WARNING — plugin channels never actually started under the gateway even though Bot() could construct them. Update to the post-#3579 wrapper if you rely on plugin channels in gateway.yaml.praisonai.channels entry-point group is the idiomatic way to distribute a bot connector as a pip-installable package. Once installed, the platform is available with no extra Python code:
pip install praisonai-irc:
list_platforms() also returns anything registered by register_platform() in the current process. The entry-point group is loaded lazily on first registry access, so a plugin that is installed but never imported still appears after the first resolve_adapter() call.
praisonai.channels is preferred over praisonai.bots for new packages. Both entry-point groups continue to work.Plugin channel on the gateway runtime
Register a plugin platform, then reference it ingateway.yaml:
self._mark_degraded_owner("channel", "mattermost", reason="unresolved_platform") instead of raising — the channel is skipped but stays visible in health / doctor.
How the gateway constructs a plugin channel
The gateway builds every channel adapter through one resolution seam and a three-step kwarg assembly. Adapter resolution.resolve_adapter(channel_type) is the single lookup, resolved in ladder order: a registered platform (built-in / entry point / register_platform) wins, then a YAML adapter: import ref, then a .praisonai/channels/ drop-in file. Only when none resolve does the gateway mark the channel unresolved_platform.
Kwarg assembly. The gateway layers three sources in order; later sources override earlier ones:
The gateway then calls
adapter_cls(**init_kwargs). ch_cfg wins over env backfill, and platform / token are stripped so they never double up. This mirrors probe_channels and Bot._build_adapter.
Token env-var fallback. When the token from channels: YAML is falsy, the gateway consults _TOKEN_FALLBACK_ENV — the first non-empty value wins:
Other platforms have no token fallback here — Slack’s app-token env still comes from step 2 (
_EXTRA_ENV_MAP), not this map.
Where a plugin author sets each value:
Degraded channels: what happens when a plugin fails
A channel that cannot resolve or construct is recorded as degraded, not silently dropped. Two exactreason strings surface via _mark_degraded_owner("channel", <channel_type>, reason=...):
Both paths return
None from _create_bot, so the two call sites (start_channels and hot-reload) keep their existing None contract. The failure is queryable via the degraded-owner surface (health / doctor) — see Gateway Degraded Channels — instead of vanishing into logs.
Common Patterns
Declare Platform Capabilities
Register a Native Presentation Renderer
Channel plugins that ship aPresentationRenderer should call register_presentation_renderer(platform, MyRenderer) from praisonaiagents.bots at setup time, so interactive UI (buttons, selects, approvals) renders natively instead of degrading to plain text.
Use the Canonical Admission Primitive
Reuseresolve_ingress_admission() in your adapter’s message handler so your custom channel inherits the same allowlist / blocklist / group-policy semantics as every built-in — and drops become inspectable (reason_code) instead of silent logger.debug lines.
group_policy defaults to mention_only — the live BotConfig default — so a forwarded unset policy fails safe rather than replying to everything in a group.
Reason codes an operator can grep for: allowed, blocked, not_in_allowlist, pairing_required, group_mention_only, command_only, observe.
IngressDecision fields:
The primitive is pure and dependency-free — same inputs, same verdict. That means built-in and plugin channels cannot drift, and adopting it does not couple your adapter to any transport, config-loading, or session module.
Override a Built-in Platform
Registry uses last-write-wins with lower-cased keys:Lazy Heavy Imports
Follow the pattern used by built-ins to avoid import-time failures:Multi-tenant Isolation
Construct your ownBotPlatformRegistry to avoid leaking between tenants:
Best Practices
Use Lazy Imports
Use Lazy Imports
Never import heavy networking SDKs at module top level:
Implement Proper Protocol
Implement Proper Protocol
Follow the expected bot lifecycle pattern:
Handle Errors Gracefully
Handle Errors Gracefully
Use logging instead of raising on initialization:
Delivery lifecycle
Bot plugin authors are the primary consumers of the enriched message identity —platform and channel_id on inbound messages, plus successful and failed delivery signals on outbound. Override message_sent and message_undelivered in a Plugin subclass to add delivery telemetry or dead-letter escalation without patching adapters.
See Plugins → Message-Lifecycle Plugins for the enriched payload keys and runnable per-user, per-channel, and dead-letter examples.
Related
Custom Gateway Channel (Zero-Code)
Add a channel from YAML
adapter: or a .praisonai/channels/ drop-in fileMessage-Lifecycle Plugins
React to inbound, outbound, delivered, and undelivered messages
Bot Platform Capabilities
Declare streaming, chunking, and rate-limit behaviour
Bot Gateway
See how
group_policy, allowed_users, and pairing are configured in YAMLGateway Degraded Channels
See where
unresolved_platform and adapter_construction_failed surface in health/doctorPresentation Renderers
Register a native renderer so buttons, selects, and approvals render natively
Framework Adapter Plugins
Learn about extending PraisonAI with custom execution frameworks
Messaging Channels Strategy
See our roadmap for supported messaging platforms

