Summary
The gateway multiplexes nine messaging platforms behind one process, one identity resolver, one delivery router and one session store — but there is no way to reach that running agent from your own terminal as a channel. Every built-in channel is a remote transport (Telegram, Discord, Slack, WhatsApp, Signal, Linear, Email, AgentMail, Webhook). To hold a conversation with your gateway agent you must first register a real remote bot: obtain a provider token, expose a webhook or run a poller, and configure allowlists — even when all you want is to try the agent locally, or run a single-user personal agent on your own box.
praisonai chat is not this: it spins up a separate process with its own session and does not join the gateway's live multiplexed session, identity, memory, delivery or pairing. So there is no supported way to (a) develop and smoke-test the gateway in seconds, or (b) start a conversation at your desk and continue it from your phone within one process and one session. A first-class local (terminal) channel closes both, and completes the "one agent, every surface, shared memory" promise the gateway is otherwise built for.
Current behaviour
The channel registry ships nine remote platforms and no local one:
# src/praisonai-bot/praisonai_bot/bots/_registry.py:60
_BUILTIN_PLATFORMS = {
"telegram": _telegram_loader,
"discord": _discord_loader,
"slack": _slack_loader,
"whatsapp": _whatsapp_loader,
"linear": _linear_loader,
"email": _email_loader,
"agentmail": _agentmail_loader,
"webhook": _webhook_loader,
"signal": _signal_loader,
}
Everything a local channel needs already exists. The core protocol is a clean four-method contract with a declarative capability descriptor — a terminal adapter is a natural fit (live in-place edit in a TTY, no markdown dialect, no rate limit, no webhook):
# src/praisonai-agents/praisonaiagents/bots/base.py:341
class BasePlatformAdapter(ABC):
async def connect(self, *, is_reconnect: bool = False) -> bool: ...
async def disconnect(self) -> None: ...
async def send(self, chat_id, content, *, reply_to=None, metadata=None): ...
async def get_chat_info(self, chat_id) -> Dict[str, Any]: ...
# src/praisonai-bot/praisonai_bot/bots/botos.py:28 (docstring example)
botos = BotOS(agent=agent, platforms=["telegram", "discord"]) # no "local"
The registry is already extensible (register_platform(...) at _registry.py:422, praisonai.channels entry points, and single-file drop-in channels), and the shared machinery a local channel would slot into is fully built: StoreBackedIdentityResolver keys history on a resolved unified id, DeliveryRouter already resolves origin/<platform>/<platform>:<chat> targets, and _mirror.py mirrors cross-channel context. What is missing is simply a concrete terminal adapter and its registry entry — so none of the continuity, delivery or session infrastructure can be reached from the operator's own shell.
Consequence: the minimum viable way to converse with a gateway agent is "create a Telegram bot". There is no zero-setup local surface, and no single-process path for "start locally, continue on a remote channel".
Desired behaviour
A built-in local terminal channel, registered exactly like the others, that:
- reads stdin / writes stdout with a small TTY renderer (in-place edit where the terminal allows, honouring
PlatformCapabilities);
- joins the same
BotOS/gateway session, identity resolver, delivery router and mirror as every other channel, so a conversation begun in the terminal continues seamlessly on Telegram (and vice versa) under one resolved session id;
- is owner-trusted by default (bypasses pairing/allowlists for the local operator), so it needs no tokens or config to work.
Then:
BotOS(agent=agent, platforms=["local"]) # chat in your terminal, no tokens
# gateway.yaml — local channel alongside remote ones
channels:
local: {}
telegram: { token: "..." }
praisonai-bot gateway start # terminal channel live next to Telegram; deliver="local" already resolves
Layer placement
- Primary layer: wrapper (
praisonai-bot) — the gap is a concrete transport adapter plus a registry entry; the heavy I/O (TTY loop, stdin handling) belongs beside the other channel implementations, not in the protocol core.
- Why not core: the core already provides everything needed (
BasePlatformAdapter, PlatformCapabilities, identity/delivery/session protocols); adding a concrete terminal adapter with real I/O to core would violate the protocol-driven-core rule.
- Why not tools: a channel is persistent gateway transport with its own lifecycle, not an agent-callable action taken mid-task.
- Why not plugins: this is a transport, not a lifecycle guardrail, policy or cross-cutting hook.
- Secondary touch (optional): core — only if a
local value needs adding to any default platform enumeration; wrapper CLI onboarding (gateway onboard) to list the local channel; optionally a gateway chat convenience verb that attaches a terminal channel to a running gateway.
- 3-way surface (CLI + YAML + Python): yes — Python
BotOS(platforms=["local"]), YAML channels.local, CLI gateway start (and an optional gateway chat).
Proposed approach
- Extension point: a new built-in channel adapter registered through the existing
BotPlatformRegistry.
# src/praisonai-bot/praisonai_bot/bots/local.py (new)
class LocalBot(BasePlatformAdapter):
"""Terminal (stdin/stdout) channel. Owner-trusted; no tokens.
Joins the same session/identity/delivery as remote channels."""
platform = "local"
capabilities = PlatformCapabilities(
supports_edit=True, supports_typing=False,
markdown_dialect="plain", needs_rate_limit=False,
accepts_webhooks=False,
)
async def connect(self, *, is_reconnect=False) -> bool: ...
async def disconnect(self) -> None: ...
async def send(self, chat_id, content, *, reply_to=None, metadata=None): ...
async def get_chat_info(self, chat_id): ...
# src/praisonai-bot/praisonai_bot/bots/_registry.py
_BUILTIN_PLATFORMS = { ..., "local": _local_loader }
Resolution sketch
# Before (today) — to talk to your gateway agent at all:
# 1. Create a Telegram bot, copy the token
# 2. channels: { telegram: { token: "123:abc" } } + allowlist your user id
# 3. praisonai-bot gateway start
# (praisonai chat exists but is a SEPARATE process/session — no gateway
# continuity, identity, delivery, pairing or cross-channel mirror.)
# After (proposed):
botos = BotOS(agent=agent, platforms=["local"]) # converse immediately, zero setup
# or, alongside remote channels in one process:
# channels: { local: {}, telegram: { token: "..." } }
# Start a thread in the terminal, reply to it later from Telegram — one
# resolved session, shared memory, because the local channel uses the same
# identity resolver + delivery router + mirror as every other channel.
Severity
High — this is a default-path ease-of-use and adoption gap. The lowest-friction way to converse with a gateway agent currently requires standing up an external bot with tokens and allowlists; there is no zero-setup local surface for development or single-user use, and no single-process path for cross-channel continuity between the terminal and a remote platform. It blocks no existing platform, so it is High rather than Critical.
Validation
Confirmed by reading:
src/praisonai-bot/praisonai_bot/bots/_registry.py — _BUILTIN_PLATFORMS (line 60) lists nine remote platforms and no local/terminal/cli; ls bots/ shows no local adapter file. Registration is already extensible (register_platform at line 422; praisonai.channels entry points; single-file drop-in discovery).
src/praisonai-agents/praisonaiagents/bots/base.py:341 — BasePlatformAdapter four-method contract a terminal adapter would implement; PlatformCapabilities (protocols.py:71) already models the flags a TTY needs.
src/praisonai-bot/praisonai_bot/bots/botos.py — BotOS(agent=..., platforms=[...]) shortcut (class at line 77; example at line 28) has no local option.
- Shared continuity infra a local channel would reuse but cannot today:
StoreBackedIdentityResolver (bots/_identity.py), DeliveryRouter origin/<platform> grammar (bots/delivery.py), cross-channel mirror_to_session (bots/_mirror.py).
Summary
The gateway multiplexes nine messaging platforms behind one process, one identity resolver, one delivery router and one session store — but there is no way to reach that running agent from your own terminal as a channel. Every built-in channel is a remote transport (Telegram, Discord, Slack, WhatsApp, Signal, Linear, Email, AgentMail, Webhook). To hold a conversation with your gateway agent you must first register a real remote bot: obtain a provider token, expose a webhook or run a poller, and configure allowlists — even when all you want is to try the agent locally, or run a single-user personal agent on your own box.
praisonai chatis not this: it spins up a separate process with its own session and does not join the gateway's live multiplexed session, identity, memory, delivery or pairing. So there is no supported way to (a) develop and smoke-test the gateway in seconds, or (b) start a conversation at your desk and continue it from your phone within one process and one session. A first-classlocal(terminal) channel closes both, and completes the "one agent, every surface, shared memory" promise the gateway is otherwise built for.Current behaviour
The channel registry ships nine remote platforms and no local one:
Everything a local channel needs already exists. The core protocol is a clean four-method contract with a declarative capability descriptor — a terminal adapter is a natural fit (live in-place edit in a TTY, no markdown dialect, no rate limit, no webhook):
The registry is already extensible (
register_platform(...)at_registry.py:422,praisonai.channelsentry points, and single-file drop-in channels), and the shared machinery alocalchannel would slot into is fully built:StoreBackedIdentityResolverkeys history on a resolved unified id,DeliveryRouteralready resolvesorigin/<platform>/<platform>:<chat>targets, and_mirror.pymirrors cross-channel context. What is missing is simply a concrete terminal adapter and its registry entry — so none of the continuity, delivery or session infrastructure can be reached from the operator's own shell.Consequence: the minimum viable way to converse with a gateway agent is "create a Telegram bot". There is no zero-setup local surface, and no single-process path for "start locally, continue on a remote channel".
Desired behaviour
A built-in
localterminal channel, registered exactly like the others, that:PlatformCapabilities);BotOS/gateway session, identity resolver, delivery router and mirror as every other channel, so a conversation begun in the terminal continues seamlessly on Telegram (and vice versa) under one resolved session id;Then:
praisonai-bot gateway start # terminal channel live next to Telegram; deliver="local" already resolvesLayer placement
praisonai-bot) — the gap is a concrete transport adapter plus a registry entry; the heavy I/O (TTY loop, stdin handling) belongs beside the other channel implementations, not in the protocol core.BasePlatformAdapter,PlatformCapabilities, identity/delivery/session protocols); adding a concrete terminal adapter with real I/O to core would violate the protocol-driven-core rule.localvalue needs adding to any default platform enumeration; wrapper CLI onboarding (gateway onboard) to list the local channel; optionally agateway chatconvenience verb that attaches a terminal channel to a running gateway.BotOS(platforms=["local"]), YAMLchannels.local, CLIgateway start(and an optionalgateway chat).Proposed approach
BotPlatformRegistry.Resolution sketch
Severity
High — this is a default-path ease-of-use and adoption gap. The lowest-friction way to converse with a gateway agent currently requires standing up an external bot with tokens and allowlists; there is no zero-setup local surface for development or single-user use, and no single-process path for cross-channel continuity between the terminal and a remote platform. It blocks no existing platform, so it is High rather than Critical.
Validation
Confirmed by reading:
src/praisonai-bot/praisonai_bot/bots/_registry.py—_BUILTIN_PLATFORMS(line 60) lists nine remote platforms and nolocal/terminal/cli;ls bots/shows no local adapter file. Registration is already extensible (register_platformat line 422;praisonai.channelsentry points; single-file drop-in discovery).src/praisonai-agents/praisonaiagents/bots/base.py:341—BasePlatformAdapterfour-method contract a terminal adapter would implement;PlatformCapabilities(protocols.py:71) already models the flags a TTY needs.src/praisonai-bot/praisonai_bot/bots/botos.py—BotOS(agent=..., platforms=[...])shortcut (class at line 77; example at line 28) has no local option.StoreBackedIdentityResolver(bots/_identity.py),DeliveryRouterorigin/<platform>grammar (bots/delivery.py), cross-channelmirror_to_session(bots/_mirror.py).