11 KiB
Channels Reference
This document is the canonical reference for channel configuration in ZeroClaw.
For encrypted Matrix rooms, also read the dedicated runbook:
Quick Paths
- Need a full config reference by channel: jump to Per-Channel Config Examples.
- Need a no-response diagnosis flow: jump to Troubleshooting Checklist.
- Need Matrix encrypted-room help: use Matrix E2EE Guide.
- Need deployment/network assumptions (polling vs webhook): use Network Deployment.
FAQ: Matrix setup passes but no reply
This is the most common symptom (same class as issue #499). Check these in order:
- Allowlist mismatch:
allowed_usersdoes not include the sender (or is empty). - Wrong room target: bot is not joined to the configured
room_id/ alias target room. - Token/account mismatch: token is valid but belongs to another Matrix account.
- E2EE device identity gap:
whoamidoes not returndevice_idand config does not provide one. - Key sharing/trust gap: room keys were not shared to the bot device, so encrypted events cannot be decrypted.
- Stale runtime state: config changed but
zeroclaw daemonwas not restarted.
1. Configuration Namespace
All channel settings live under channels_config in ~/.zeroclaw/config.toml.
[channels_config]
cli = true
Each channel is enabled by creating its sub-table (for example, [channels_config.telegram]).
In-Chat Runtime Model Switching (Telegram / Discord)
When running zeroclaw channel start (or daemon mode), Telegram and Discord now support sender-scoped runtime switching:
/models— show available providers and current selection/models <provider>— switch provider for the current sender session/model— show current model and cached model IDs (if available)/model <model-id>— switch model for the current sender session
Notes:
- Switching clears only that sender's in-memory conversation history to avoid cross-model context contamination.
- Model cache previews come from
zeroclaw models refresh --provider <ID>. - These are runtime chat commands, not CLI subcommands.
Channel Matrix
2. Delivery Modes at a Glance
| Channel | Receive mode | Public inbound port required? |
|---|---|---|
| CLI | local stdin/stdout | No |
| Telegram | polling | No |
| Discord | gateway/websocket | No |
| Slack | events API | No (token-based channel flow) |
| Mattermost | polling | No |
| Matrix | sync API (supports E2EE) | No |
| Signal | signal-cli HTTP bridge | No (local bridge endpoint) |
| webhook | Yes (public HTTPS callback) | |
| Webhook | gateway endpoint (/webhook) |
Usually yes |
| IMAP polling + SMTP send | No | |
| IRC | IRC socket | No |
| Lark/Feishu | websocket (default) or webhook | Webhook mode only |
| DingTalk | stream mode | No |
| bot gateway | No | |
| iMessage | local integration | No |
3. Allowlist Semantics
For channels with inbound sender allowlists:
- Empty allowlist: deny all inbound messages.
"*": allow all inbound senders (use for temporary verification only).- Explicit list: allow only listed senders.
Field names differ by channel:
allowed_users(Telegram/Discord/Slack/Mattermost/Matrix/IRC/Lark/DingTalk/QQ)allowed_from(Signal)allowed_numbers(WhatsApp)allowed_senders(Email)allowed_contacts(iMessage)
4. Per-Channel Config Examples
4.1 Telegram
[channels_config.telegram]
bot_token = "123456:telegram-token"
allowed_users = ["*"]
4.2 Discord
[channels_config.discord]
bot_token = "discord-bot-token"
guild_id = "123456789012345678" # optional
allowed_users = ["*"]
listen_to_bots = false
mention_only = false
4.3 Slack
[channels_config.slack]
bot_token = "xoxb-..."
app_token = "xapp-..." # optional
channel_id = "C1234567890" # optional
allowed_users = ["*"]
4.4 Mattermost
[channels_config.mattermost]
url = "https://mm.example.com"
bot_token = "mattermost-token"
channel_id = "channel-id" # required for listening
allowed_users = ["*"]
4.5 Matrix
[channels_config.matrix]
homeserver = "https://matrix.example.com"
access_token = "syt_..."
user_id = "@zeroclaw:matrix.example.com" # optional, recommended for E2EE
device_id = "DEVICEID123" # optional, recommended for E2EE
room_id = "!room:matrix.example.com" # or room alias (#ops:matrix.example.com)
allowed_users = ["*"]
See Matrix E2EE Guide for encrypted-room troubleshooting.
4.6 Signal
[channels_config.signal]
http_url = "http://127.0.0.1:8686"
account = "+1234567890"
group_id = "dm" # optional: "dm" / group id / omitted
allowed_from = ["*"]
ignore_attachments = false
ignore_stories = true
4.7 WhatsApp
[channels_config.whatsapp]
access_token = "EAAB..."
phone_number_id = "123456789012345"
verify_token = "your-verify-token"
app_secret = "your-app-secret" # optional but recommended
allowed_numbers = ["*"]
4.8 Webhook Channel Config (Gateway)
channels_config.webhook enables webhook-specific gateway behavior.
[channels_config.webhook]
port = 8080
secret = "optional-shared-secret"
Run with gateway/daemon and verify /health.
4.9 Email
[channels_config.email]
imap_host = "imap.example.com"
imap_port = 993
imap_folder = "INBOX"
smtp_host = "smtp.example.com"
smtp_port = 465
smtp_tls = true
username = "bot@example.com"
password = "email-password"
from_address = "bot@example.com"
poll_interval_secs = 60
allowed_senders = ["*"]
4.10 IRC
[channels_config.irc]
server = "irc.libera.chat"
port = 6697
nickname = "zeroclaw-bot"
username = "zeroclaw" # optional
channels = ["#zeroclaw"]
allowed_users = ["*"]
server_password = "" # optional
nickserv_password = "" # optional
sasl_password = "" # optional
verify_tls = true
4.11 Lark / Feishu
[channels_config.lark]
app_id = "cli_xxx"
app_secret = "xxx"
encrypt_key = "" # optional
verification_token = "" # optional
allowed_users = ["*"]
use_feishu = false
receive_mode = "websocket" # or "webhook"
port = 8081 # required for webhook mode
4.12 DingTalk
[channels_config.dingtalk]
client_id = "ding-app-key"
client_secret = "ding-app-secret"
allowed_users = ["*"]
4.13 QQ
[channels_config.qq]
app_id = "qq-app-id"
app_secret = "qq-app-secret"
allowed_users = ["*"]
4.14 iMessage
[channels_config.imessage]
allowed_contacts = ["*"]
5. Validation Workflow
- Configure one channel with permissive allowlist (
"*") for initial verification. - Run:
zeroclaw onboard --channels-only
zeroclaw daemon
- Send a message from an expected sender.
- Confirm a reply arrives.
- Tighten allowlist from
"*"to explicit IDs.
6. Troubleshooting Checklist
If a channel appears connected but does not respond:
- Confirm the sender identity is allowed by the correct allowlist field.
- Confirm bot account membership/permissions in target room/channel.
- Confirm tokens/secrets are valid (and not expired/revoked).
- Confirm transport mode assumptions:
- polling/websocket channels do not need public inbound HTTP
- webhook channels do need reachable HTTPS callback
- Restart
zeroclaw daemonafter config changes.
For Matrix encrypted rooms specifically, use:
7. Operations Appendix: Log Keywords Matrix
Use this appendix for fast triage. Match log keywords first, then follow the troubleshooting steps above.
7.1 Recommended capture command
RUST_LOG=info zeroclaw daemon 2>&1 | tee /tmp/zeroclaw.log
Then filter channel/gateway events:
rg -n "Matrix|Telegram|Discord|Slack|Mattermost|Signal|WhatsApp|Email|IRC|Lark|DingTalk|QQ|iMessage|Webhook|Channel" /tmp/zeroclaw.log
7.2 Keyword table
| Component | Startup / healthy signal | Authorization / policy signal | Transport / failure signal |
|---|---|---|---|
| Telegram | Telegram channel listening for messages... |
Telegram: ignoring message from unauthorized user: |
Telegram poll error: / Telegram parse error: / Telegram polling conflict (409): |
| Discord | Discord: connected and identified |
Discord: ignoring message from unauthorized user: |
Discord: received Reconnect (op 7) / Discord: received Invalid Session (op 9) |
| Slack | Slack channel listening on # |
Slack: ignoring message from unauthorized user: |
Slack poll error: / Slack parse error: |
| Mattermost | Mattermost channel listening on |
Mattermost: ignoring message from unauthorized user: |
Mattermost poll error: / Mattermost parse error: |
| Matrix | Matrix channel listening on room / Matrix room ... is encrypted; E2EE decryption is enabled via matrix-sdk. |
Matrix whoami failed; falling back to configured session hints for E2EE session restore: / Matrix whoami failed while resolving listener user_id; using configured user_id hint: |
Matrix sync error: ... retrying... |
| Signal | Signal channel listening via SSE on |
(allowlist checks are enforced by allowed_from) |
Signal SSE returned ... / Signal SSE connect error: |
| WhatsApp (channel) | WhatsApp channel active (webhook mode). |
WhatsApp: ignoring message from unauthorized number: |
WhatsApp send failed: |
| Webhook / WhatsApp (gateway) | WhatsApp webhook verified successfully |
Webhook: rejected — not paired / invalid bearer token / Webhook: rejected request — invalid or missing X-Webhook-Secret / WhatsApp webhook verification failed — token mismatch |
Webhook JSON parse error: |
Email polling every ... / Email sent to ... |
Blocked email from ... |
Email poll failed: / Email poll task panicked: |
|
| IRC | IRC channel connecting to ... / IRC registered as ... |
(allowlist checks are enforced by allowed_users) |
IRC SASL authentication failed (...) / IRC server does not support SASL... / IRC nickname ... is in use, trying ... |
| Lark / Feishu | Lark: WS connected / Lark event callback server listening on |
Lark WS: ignoring ... (not in allowed_users) / Lark: ignoring message from unauthorized user: |
Lark: ping failed, reconnecting / Lark: heartbeat timeout, reconnecting / Lark: WS read error: |
| DingTalk | DingTalk: connected and listening for messages... |
DingTalk: ignoring message from unauthorized user: |
DingTalk WebSocket error: / DingTalk: message channel closed |
QQ: connected and identified |
QQ: ignoring C2C message from unauthorized user: / QQ: ignoring group message from unauthorized user: |
QQ: received Reconnect (op 7) / QQ: received Invalid Session (op 9) / QQ: message channel closed |
|
| iMessage | iMessage channel listening (AppleScript bridge)... |
(contact allowlist enforced by allowed_contacts) |
iMessage poll error: |
7.3 Runtime supervisor keywords
If a specific channel task crashes or exits, the channel supervisor in channels/mod.rs emits:
Channel <name> exited unexpectedly; restartingChannel <name> error: ...; restartingChannel message worker crashed:
These messages indicate automatic restart behavior is active, and you should inspect preceding logs for root cause.