Channels
Channels are how a mono-agent receives input and delivers replies. Core channels use independent JSON sections in mono-agent.config.json; external channel packages are declared under channels.plugins[] and return the same ChannelDriver shape. Most channels opt in through their own enabled flag; the loopback tui operator surface defaults on and can be disabled explicitly. @mono-agent/agent-app composes the resolved drivers into the running host. This page explains the shared lifecycle, how to pick a channel, and links to every per-channel guide. Coverage: config unless a feature is noted otherwise.
Core channels
Section titled “Core channels”| Channel | Transport | Section | Guide |
|---|---|---|---|
| Telegram | Bot long polling | telegram | Telegram |
| Slack | Socket Mode bot | slack | Slack |
| Webhook | HTTP POST, sync or async | webhook | Webhook |
| OpenAI-compatible API | /v1/chat/completions (SSE) | openaiApi | OpenAI-compatible API |
| Cron | Scheduled prompts | cron | Cron |
| Operator stream endpoint | Loopback NDJSON turns for mono-agent tui and mono-agent web | tui | Operator stream endpoint |
External channel packages
Section titled “External channel packages”| Channel | Transport | Plugin package | Guide |
|---|---|---|---|
| Baileys socket (QR login) | @mono-agent/whatsapp-adapter | ||
| Facebook Messenger | Meta webhook + Send API | @mono-agent/messenger-adapter | Messenger |
| A2A | Agent-to-Agent provider/consumer | @mono-agent/a2a-adapter | A2A |
Channels are fully independent: enabling one neither requires nor affects another, and a misconfigured channel never blocks the rest of the host from starting.
Opt-in and the status lifecycle
Section titled “Opt-in and the status lifecycle”Most channels default to off. The deliberate exception is the tui operator stream endpoint, which defaults to on (loopback-only, ephemeral port, so the TUI/web console can chat without a config edit). Set "tui": {"enabled": false} to opt out. You turn other channels on with enabled: true and supply their required settings; external channels also need a channels.plugins[] entry naming the package. Human status output groups communication channels separately from the operator transport, labels the stable tui id as gui (TUI + Web), and folds disabled ids into one compact line. JSON retains stable ids and full reasons. Active entries reflect one of five states:
| State | Meaning |
|---|---|
disabled | The resolved enabled value is false. Omission resolves false for most channels, but tui defaults true and requires an explicit false to reach this state. |
waiting_for_config | enabled: true but a required setting is missing — the line names the exact missing field. |
running | Ready and listening; the line includes endpoint facts (host/port/path, or the bot it connected as). |
degraded | Was running but the live transport connection dropped on a transient failure (e.g. a Telegram poll crash on a network switch, or a Slack Socket Mode disconnect); the responder/harness is kept alive and the adapter is reconnecting, so the channel keeps serving. Rendered degraded: <reason> with a warning badge. Non-fatal and self-recovering — it returns to running automatically once the transport stays up, unlike failed. |
failed | The channel errored on startup; the line includes the reason. |
{ "telegram": { "enabled": true, "allowedChatIds": ["123456789"] }}Put MONO_AGENT_TELEGRAM_BOT_TOKEN=... in the agent’s .env; source-config examples omit credentials even though inline fields remain accepted for compatibility.
Environment variables
Section titled “Environment variables”Fields with a documented mapping can also be set with a MONO_AGENT_<CHANNEL>_* environment variable, which is especially useful for secrets you do not want in the JSON file. Some fields are JSON-only. A .env in the agent folder is loaded automatically (exported shell variables win); use --env-file <path> for an alternate file. Per-channel env var names are listed in each channel’s guide. See Environment variables for the complete mapping.
export MONO_AGENT_TELEGRAM_ENABLED=trueexport MONO_AGENT_TELEGRAM_BOT_TOKEN=REPLACE_WITH_BOT_TOKENWhich channel?
Section titled “Which channel?”Pick by who or what is on the other end:
| You want… | Use | Why |
|---|---|---|
| A human chatting interactively | Telegram, Slack, WhatsApp, or Messenger | Conversational adapters with allowlists, working indicators, and final-answer delivery; WhatsApp and Messenger are loaded as external plugins |
| Programmatic / pipeline invocation | Webhook or A2A | Webhook for plain HTTP POST (sync or async polling); A2A for agent-to-agent calls with Agent Card discovery and is loaded as an external plugin |
| A chat UI (e.g. Open WebUI) | OpenAI-compatible API | Exposes /v1/models + /v1/chat/completions with token-by-token SSE streaming |
| A first-party operator console | Terminal console or web console | Connects through the loopback operator endpoint while keeping transport details out of user-facing chat |
| Scheduled / unattended runs | Cron | Timezone-aware five-field jobs that invoke the responder on a schedule |
You can enable any combination — for example Telegram for your own use plus a webhook for automation and cron for a daily digest.
Concurrency is per-channel
Section titled “Concurrency is per-channel”The app builds one runtime harness per channel, and each harness holds its own concurrency limiter. The concurrency.* bounds therefore apply to each channel independently, not as a single global cap: with N enabled channels the effective ceiling is N× the configured value. See Sessions & concurrency for maxConcurrentRuns / maxPendingRuns and the admission model.
Sending and proactive delivery
Section titled “Sending and proactive delivery”Replies go back over the same channel that received the request. To send outbound messages — proactive notifications from cron/webhook turns, or app-owned send tools like SlackSendMessage and TelegramSendMessage — see Delivery & send tools. Note that these send tools require the target adapter to already be enabled and configured, and the adapter’s own allowlist remains the delivery boundary.
Custom transports
Section titled “Custom transports”For a bespoke transport, implement a ChannelDriver from @mono-agent/agent-contracts and either expose it from a package loaded by channels.plugins[] or pass it via startMonoAgentApp({ drivers }). See Write your own channel adapter.