diff --git a/CHANGELOG.md b/CHANGELOG.md index 9efbb243d..c3fa749cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2025.1.12 (Unreleased) ### Highlights +- **BREAKING:** rename chat “providers” (Slack/Telegram/WhatsApp/…) to **channels** across CLI/RPC/config; legacy config keys auto-migrate on load (and are written back as `channels.*`). - Memory: add vector search for agent memories (Markdown-only) with SQLite index, chunking, lazy sync + file watch, and per-agent enablement/fallback. - Plugins: restore full voice-call plugin parity (Telnyx/Twilio, streaming, inbound policies, tools/CLI). - Models: add Synthetic provider plus Moonshot Kimi K2 0905 + turbo/thinking variants (with docs). diff --git a/README.md b/README.md index 515c12af1..11d42c690 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@

**Clawdbot** is a *personal AI assistant* you run on your own devices. -It answers you on the providers you already use (WhatsApp, Telegram, Slack, Discord, Signal, iMessage, Microsoft Teams, WebChat), can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant. +It answers you on the channels you already use (WhatsApp, Telegram, Slack, Discord, Signal, iMessage, Microsoft Teams, WebChat), can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant. If you want a personal, single-user assistant that feels local, fast, and always-on, this is it. [Website](https://clawdbot.com) · [Docs](https://docs.clawd.bot) · [Getting Started](https://docs.clawd.bot/start/getting-started) · [Updating](https://docs.clawd.bot/install/updating) · [Showcase](https://docs.clawd.bot/start/showcase) · [FAQ](https://docs.clawd.bot/start/faq) · [Wizard](https://docs.clawd.bot/start/wizard) · [Nix](https://github.com/clawdbot/nix-clawdbot) · [Docker](https://docs.clawd.bot/install/docker) · [Discord](https://discord.gg/clawd) -Preferred setup: run the onboarding wizard (`clawdbot onboard`). It walks through gateway, workspace, providers, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**. +Preferred setup: run the onboarding wizard (`clawdbot onboard`). It walks through gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**. Works with npm, pnpm, or bun. New install? Start here: [Getting started](https://docs.clawd.bot/start/getting-started) @@ -54,7 +54,7 @@ The wizard installs the Gateway daemon (launchd/systemd user service) so it stay Runtime: **Node ≥22**. -Full beginner guide (auth, pairing, providers): [Getting started](https://docs.clawd.bot/start/getting-started) +Full beginner guide (auth, pairing, channels): [Getting started](https://docs.clawd.bot/start/getting-started) ```bash clawdbot onboard --install-daemon @@ -97,17 +97,17 @@ Clawdbot connects to real messaging surfaces. Treat inbound DMs as **untrusted i Full security guide: [Security](https://docs.clawd.bot/gateway/security) Default behavior on Telegram/WhatsApp/Signal/iMessage/Microsoft Teams/Discord/Slack: -- **DM pairing** (`dmPolicy="pairing"` / `discord.dm.policy="pairing"` / `slack.dm.policy="pairing"`): unknown senders receive a short pairing code and the bot does not process their message. -- Approve with: `clawdbot pairing approve ` (then the sender is added to a local allowlist store). -- Public inbound DMs require an explicit opt-in: set `dmPolicy="open"` and include `"*"` in the provider allowlist (`allowFrom` / `discord.dm.allowFrom` / `slack.dm.allowFrom`). +- **DM pairing** (`dmPolicy="pairing"` / `channels.discord.dm.policy="pairing"` / `channels.slack.dm.policy="pairing"`): unknown senders receive a short pairing code and the bot does not process their message. +- Approve with: `clawdbot pairing approve ` (then the sender is added to a local allowlist store). +- Public inbound DMs require an explicit opt-in: set `dmPolicy="open"` and include `"*"` in the channel allowlist (`allowFrom` / `channels.discord.dm.allowFrom` / `channels.slack.dm.allowFrom`). Run `clawdbot doctor` to surface risky/misconfigured DM policies. ## Highlights -- **[Local-first Gateway](https://docs.clawd.bot/gateway)** — single control plane for sessions, providers, tools, and events. -- **[Multi-provider inbox](https://docs.clawd.bot/providers)** — WhatsApp, Telegram, Slack, Discord, Signal, iMessage, Microsoft Teams, WebChat, macOS, iOS/Android. -- **[Multi-agent routing](https://docs.clawd.bot/gateway/configuration)** — route inbound providers/accounts/peers to isolated agents (workspaces + per-agent sessions). +- **[Local-first Gateway](https://docs.clawd.bot/gateway)** — single control plane for sessions, channels, tools, and events. +- **[Multi-channel inbox](https://docs.clawd.bot/channels)** — WhatsApp, Telegram, Slack, Discord, Signal, iMessage, Microsoft Teams, WebChat, macOS, iOS/Android. +- **[Multi-agent routing](https://docs.clawd.bot/gateway/configuration)** — route inbound channels/accounts/peers to isolated agents (workspaces + per-agent sessions). - **[Voice Wake](https://docs.clawd.bot/nodes/voicewake) + [Talk Mode](https://docs.clawd.bot/nodes/talk)** — always-on speech for macOS/iOS/Android with ElevenLabs. - **[Live Canvas](https://docs.clawd.bot/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.clawd.bot/platforms/mac/canvas#canvas-a2ui). - **[First-class tools](https://docs.clawd.bot/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions. @@ -127,9 +127,9 @@ Run `clawdbot doctor` to surface risky/misconfigured DM policies. - [Session model](https://docs.clawd.bot/concepts/session): `main` for direct chats, group isolation, activation modes, queue modes, reply-back. Group rules: [Groups](https://docs.clawd.bot/concepts/groups). - [Media pipeline](https://docs.clawd.bot/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.clawd.bot/nodes/audio). -### Providers -- [Providers](https://docs.clawd.bot/providers): [WhatsApp](https://docs.clawd.bot/providers/whatsapp) (Baileys), [Telegram](https://docs.clawd.bot/providers/telegram) (grammY), [Slack](https://docs.clawd.bot/providers/slack) (Bolt), [Discord](https://docs.clawd.bot/providers/discord) (discord.js), [Signal](https://docs.clawd.bot/providers/signal) (signal-cli), [iMessage](https://docs.clawd.bot/providers/imessage) (imsg), [Microsoft Teams](https://docs.clawd.bot/providers/msteams) (Bot Framework), [WebChat](https://docs.clawd.bot/web/webchat). -- [Group routing](https://docs.clawd.bot/concepts/group-messages): mention gating, reply tags, per-provider chunking and routing. Provider rules: [Providers](https://docs.clawd.bot/providers). +### Channels +- [Channels](https://docs.clawd.bot/channels): [WhatsApp](https://docs.clawd.bot/channels/whatsapp) (Baileys), [Telegram](https://docs.clawd.bot/channels/telegram) (grammY), [Slack](https://docs.clawd.bot/channels/slack) (Bolt), [Discord](https://docs.clawd.bot/channels/discord) (discord.js), [Signal](https://docs.clawd.bot/channels/signal) (signal-cli), [iMessage](https://docs.clawd.bot/channels/imessage) (imsg), [Microsoft Teams](https://docs.clawd.bot/channels/msteams) (Bot Framework), [WebChat](https://docs.clawd.bot/web/webchat). +- [Group routing](https://docs.clawd.bot/concepts/group-messages): mention gating, reply tags, per-channel chunking and routing. Channel rules: [Channels](https://docs.clawd.bot/channels). ### Apps + nodes - [macOS app](https://docs.clawd.bot/platforms/macos): menu bar control plane, [Voice Wake](https://docs.clawd.bot/nodes/voicewake)/PTT, [Talk Mode](https://docs.clawd.bot/nodes/talk) overlay, [WebChat](https://docs.clawd.bot/web/webchat), debug tools, [remote gateway](https://docs.clawd.bot/gateway/remote) control. @@ -145,10 +145,10 @@ Run `clawdbot doctor` to surface risky/misconfigured DM policies. - [Skills platform](https://docs.clawd.bot/tools/skills): bundled, managed, and workspace skills with install gating + UI. ### Runtime + safety -- [Provider routing](https://docs.clawd.bot/concepts/provider-routing), [retry policy](https://docs.clawd.bot/concepts/retry), and [streaming/chunking](https://docs.clawd.bot/concepts/streaming). +- [Channel routing](https://docs.clawd.bot/concepts/channel-routing), [retry policy](https://docs.clawd.bot/concepts/retry), and [streaming/chunking](https://docs.clawd.bot/concepts/streaming). - [Presence](https://docs.clawd.bot/concepts/presence), [typing indicators](https://docs.clawd.bot/concepts/typing-indicators), and [usage tracking](https://docs.clawd.bot/concepts/usage-tracking). - [Models](https://docs.clawd.bot/concepts/models), [model failover](https://docs.clawd.bot/concepts/model-failover), and [session pruning](https://docs.clawd.bot/concepts/session-pruning). -- [Security](https://docs.clawd.bot/gateway/security) and [troubleshooting](https://docs.clawd.bot/providers/troubleshooting). +- [Security](https://docs.clawd.bot/gateway/security) and [troubleshooting](https://docs.clawd.bot/channels/troubleshooting). ### Ops + packaging - [Control UI](https://docs.clawd.bot/web) + [WebChat](https://docs.clawd.bot/web/webchat) served directly from the Gateway. @@ -315,13 +315,13 @@ Minimal `~/.clawdbot/clawdbot.json` (model + defaults): Details: [Security guide](https://docs.clawd.bot/gateway/security) · [Docker + sandboxing](https://docs.clawd.bot/install/docker) · [Sandbox config](https://docs.clawd.bot/gateway/configuration) -### [WhatsApp](https://docs.clawd.bot/providers/whatsapp) +### [WhatsApp](https://docs.clawd.bot/channels/whatsapp) - Link the device: `pnpm clawdbot providers login` (stores creds in `~/.clawdbot/credentials`). - Allowlist who can talk to the assistant via `whatsapp.allowFrom`. - If `whatsapp.groups` is set, it becomes a group allowlist; include `"*"` to allow all. -### [Telegram](https://docs.clawd.bot/providers/telegram) +### [Telegram](https://docs.clawd.bot/channels/telegram) - Set `TELEGRAM_BOT_TOKEN` or `telegram.botToken` (env wins). - Optional: set `telegram.groups` (with `telegram.groups."*".requireMention`); when set, it is a group allowlist (include `"*"` to allow all). Also `telegram.allowFrom` or `telegram.webhookUrl` as needed. @@ -334,11 +334,11 @@ Details: [Security guide](https://docs.clawd.bot/gateway/security) · [Docker + } ``` -### [Slack](https://docs.clawd.bot/providers/slack) +### [Slack](https://docs.clawd.bot/channels/slack) - Set `SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN` (or `slack.botToken` + `slack.appToken`). -### [Discord](https://docs.clawd.bot/providers/discord) +### [Discord](https://docs.clawd.bot/channels/discord) - Set `DISCORD_BOT_TOKEN` or `discord.token` (env wins). - Optional: set `commands.native`, `commands.text`, or `commands.useAccessGroups`, plus `discord.dm.allowFrom`, `discord.guilds`, or `discord.mediaMaxMb` as needed. @@ -351,11 +351,11 @@ Details: [Security guide](https://docs.clawd.bot/gateway/security) · [Docker + } ``` -### [Signal](https://docs.clawd.bot/providers/signal) +### [Signal](https://docs.clawd.bot/channels/signal) - Requires `signal-cli` and a `signal` config section. -### [iMessage](https://docs.clawd.bot/providers/imessage) +### [iMessage](https://docs.clawd.bot/channels/imessage) - macOS only; Messages must be signed in. - If `imessage.groups` is set, it becomes a group allowlist; include `"*"` to allow all. @@ -395,7 +395,7 @@ Use these when you’re past the onboarding flow and want the deeper reference. - [Set up Gmail Pub/Sub triggers.](https://docs.clawd.bot/automation/gmail-pubsub) - [Learn the macOS menu bar companion details.](https://docs.clawd.bot/platforms/mac/menu-bar) - [Platform guides: Windows (WSL2)](https://docs.clawd.bot/platforms/windows), [Linux](https://docs.clawd.bot/platforms/linux), [macOS](https://docs.clawd.bot/platforms/macos), [iOS](https://docs.clawd.bot/platforms/ios), [Android](https://docs.clawd.bot/platforms/android) -- [Debug common failures with the troubleshooting guide.](https://docs.clawd.bot/providers/troubleshooting) +- [Debug common failures with the troubleshooting guide.](https://docs.clawd.bot/channels/troubleshooting) - [Review security guidance before exposing anything.](https://docs.clawd.bot/gateway/security) ## Advanced docs (discovery + control) diff --git a/docs/_config.yml b/docs/_config.yml index 06161b641..13c41bb84 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -41,7 +41,7 @@ nav: - title: "Android App" url: "/platforms/android/" - title: "Telegram" - url: "/providers/telegram/" + url: "/channels/telegram/" - title: "Security" url: "/gateway/security/" - title: "Troubleshooting" diff --git a/docs/broadcast-groups.md b/docs/broadcast-groups.md index 07068d0d3..c2f478a02 100644 --- a/docs/broadcast-groups.md +++ b/docs/broadcast-groups.md @@ -403,5 +403,5 @@ Planned features: ## See Also - [Multi-Agent Configuration](/multi-agent-sandbox-tools) -- [Routing Configuration](/concepts/provider-routing) +- [Routing Configuration](/concepts/channel-routing) - [Session Management](/concepts/sessions) diff --git a/docs/providers/discord.md b/docs/channels/discord.md similarity index 65% rename from docs/providers/discord.md rename to docs/channels/discord.md index 80b118304..f25f0e623 100644 --- a/docs/providers/discord.md +++ b/docs/channels/discord.md @@ -1,7 +1,7 @@ --- summary: "Discord bot support status, capabilities, and configuration" read_when: - - Working on Discord provider features + - Working on Discord channel features --- # Discord (Bot API) @@ -12,7 +12,7 @@ Status: ready for DM and guild text channels via the official Discord bot gatewa 1) Create a Discord bot and copy the bot token. 2) Set the token for Clawdbot: - Env: `DISCORD_BOT_TOKEN=...` - - Or config: `discord.token: "..."`. + - Or config: `channels.discord.token: "..."`. 3) Invite the bot to your server with message permissions. 4) Start the gateway. 5) DM access is pairing by default; approve the pairing code on first contact. @@ -20,9 +20,11 @@ Status: ready for DM and guild text channels via the official Discord bot gatewa Minimal config: ```json5 { - discord: { - enabled: true, - token: "YOUR_BOT_TOKEN" + channels: { + discord: { + enabled: true, + token: "YOUR_BOT_TOKEN" + } } } ``` @@ -30,29 +32,29 @@ Minimal config: ## Goals - Talk to Clawdbot via Discord DMs or guild channels. - Direct chats collapse into the agent's main session (default `agent:main:main`); guild channels stay isolated as `agent::discord:channel:` (display names use `discord:#`). -- Group DMs are ignored by default; enable via `discord.dm.groupEnabled` and optionally restrict by `discord.dm.groupChannels`. -- Keep routing deterministic: replies always go back to the provider they arrived on. +- Group DMs are ignored by default; enable via `channels.discord.dm.groupEnabled` and optionally restrict by `channels.discord.dm.groupChannels`. +- Keep routing deterministic: replies always go back to the channel they arrived on. ## How it works 1. Create a Discord application → Bot, enable the intents you need (DMs + guild messages + message content), and grab the bot token. 2. Invite the bot to your server with the permissions required to read/send messages where you want to use it. -3. Configure Clawdbot with `DISCORD_BOT_TOKEN` (or `discord.token` in `~/.clawdbot/clawdbot.json`). -4. Run the gateway; it auto-starts the Discord provider when a token is available (env or config) and `discord.enabled` is not `false`. +3. Configure Clawdbot with `DISCORD_BOT_TOKEN` (or `channels.discord.token` in `~/.clawdbot/clawdbot.json`). +4. Run the gateway; it auto-starts the Discord channel when a token is available (env or config) and `channels.discord.enabled` is not `false`. - If you prefer env vars, set `DISCORD_BOT_TOKEN` (a config block is optional). 5. Direct chats: use `user:` (or a `<@id>` mention) when delivering; all turns land in the shared `main` session. Bare numeric IDs are ambiguous and rejected. 6. Guild channels: use `channel:` for delivery. Mentions are required by default and can be set per guild or per channel. -7. Direct chats: secure by default via `discord.dm.policy` (default: `"pairing"`). Unknown senders get a pairing code (expires after 1 hour); approve via `clawdbot pairing approve discord `. - - To keep old “open to anyone” behavior: set `discord.dm.policy="open"` and `discord.dm.allowFrom=["*"]`. - - To hard-allowlist: set `discord.dm.policy="allowlist"` and list senders in `discord.dm.allowFrom`. - - To ignore all DMs: set `discord.dm.enabled=false` or `discord.dm.policy="disabled"`. -8. Group DMs are ignored by default; enable via `discord.dm.groupEnabled` and optionally restrict by `discord.dm.groupChannels`. -9. Optional guild rules: set `discord.guilds` keyed by guild id (preferred) or slug, with per-channel rules. -10. Optional native commands: `commands.native` defaults to `"auto"` (on for Discord/Telegram, off for Slack). Override with `discord.commands.native: true|false|"auto"`; `false` clears previously registered commands. Text commands are controlled by `commands.text` and must be sent as standalone `/...` messages. Use `commands.useAccessGroups: false` to bypass access-group checks for commands. +7. Direct chats: secure by default via `channels.discord.dm.policy` (default: `"pairing"`). Unknown senders get a pairing code (expires after 1 hour); approve via `clawdbot pairing approve discord `. + - To keep old “open to anyone” behavior: set `channels.discord.dm.policy="open"` and `channels.discord.dm.allowFrom=["*"]`. + - To hard-allowlist: set `channels.discord.dm.policy="allowlist"` and list senders in `channels.discord.dm.allowFrom`. + - To ignore all DMs: set `channels.discord.dm.enabled=false` or `channels.discord.dm.policy="disabled"`. +8. Group DMs are ignored by default; enable via `channels.discord.dm.groupEnabled` and optionally restrict by `channels.discord.dm.groupChannels`. +9. Optional guild rules: set `channels.discord.guilds` keyed by guild id (preferred) or slug, with per-channel rules. +10. Optional native commands: `commands.native` defaults to `"auto"` (on for Discord/Telegram, off for Slack). Override with `channels.discord.commands.native: true|false|"auto"`; `false` clears previously registered commands. Text commands are controlled by `commands.text` and must be sent as standalone `/...` messages. Use `commands.useAccessGroups: false` to bypass access-group checks for commands. - Full command list + config: [Slash commands](/tools/slash-commands) -11. Optional guild context history: set `discord.historyLimit` (default 20, falls back to `messages.groupChat.historyLimit`) to include the last N guild messages as context when replying to a mention. Set `0` to disable. -12. Reactions: the agent can trigger reactions via the `discord` tool (gated by `discord.actions.*`). +11. Optional guild context history: set `channels.discord.historyLimit` (default 20, falls back to `messages.groupChat.historyLimit`) to include the last N guild messages as context when replying to a mention. Set `0` to disable. +12. Reactions: the agent can trigger reactions via the `discord` tool (gated by `channels.discord.actions.*`). - Reaction removal semantics: see [/tools/reactions](/tools/reactions). - - The `discord` tool is only exposed when the current provider is Discord. + - The `discord` tool is only exposed when the current channel is Discord. 13. Native commands use isolated session keys (`agent::discord:slash:`) rather than the shared `main` session. Note: Discord does not provide a simple username → id lookup without extra guild context, so prefer ids or `<@id>` mentions for DM delivery targets. @@ -117,37 +119,41 @@ Or via config: ```json5 { - discord: { - enabled: true, - token: "YOUR_BOT_TOKEN" + channels: { + discord: { + enabled: true, + token: "YOUR_BOT_TOKEN" + } } } ``` -Multi-account support: use `discord.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. +Multi-account support: use `channels.discord.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. #### Allowlist + channel routing Example “single server, only allow me, only allow #help”: ```json5 { - discord: { - enabled: true, - dm: { enabled: false }, - guilds: { - "YOUR_GUILD_ID": { - users: ["YOUR_USER_ID"], - requireMention: true, - channels: { - help: { allow: true, requireMention: true } + channels: { + discord: { + enabled: true, + dm: { enabled: false }, + guilds: { + "YOUR_GUILD_ID": { + users: ["YOUR_USER_ID"], + requireMention: true, + channels: { + help: { allow: true, requireMention: true } + } } + }, + retry: { + attempts: 3, + minDelayMs: 500, + maxDelayMs: 30000, + jitter: 0.1 } - }, - retry: { - attempts: 3, - minDelayMs: 500, - maxDelayMs: 30000, - jitter: 0.1 } } } @@ -158,8 +164,8 @@ Notes: - `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) also count as mentions for guild messages. - Multi-agent override: set per-agent patterns on `agents.list[].groupChat.mentionPatterns`. - If `channels` is present, any channel not listed is denied by default. -- Bot-authored messages are ignored by default; set `discord.allowBots=true` to allow them (own messages remain filtered). -- Warning: If you allow replies to other bots (`discord.allowBots=true`), prevent bot-to-bot reply loops with `requireMention`, `discord.guilds.*.channels..users` allowlists, and/or clear guardrails in `AGENTS.md` and `SOUL.md`. +- Bot-authored messages are ignored by default; set `channels.discord.allowBots=true` to allow them (own messages remain filtered). +- Warning: If you allow replies to other bots (`channels.discord.allowBots=true`), prevent bot-to-bot reply loops with `requireMention`, `channels.discord.guilds.*.channels..users` allowlists, and/or clear guardrails in `AGENTS.md` and `SOUL.md`. ### 6) Verify it works 1. Start the gateway. @@ -167,7 +173,7 @@ Notes: 3. If nothing happens: check **Troubleshooting** below. ### Troubleshooting -- First: run `clawdbot doctor` and `clawdbot providers status --probe` (actionable warnings + quick audits). +- First: run `clawdbot doctor` and `clawdbot channels status --probe` (actionable warnings + quick audits). - **“Used disallowed intents”**: enable **Message Content Intent** (and likely **Server Members Intent**) in the Developer Portal, then restart the gateway. - **Bot connects but never replies in a guild channel**: - Missing **Message Content Intent**, or @@ -175,78 +181,80 @@ Notes: - Your config requires mentions and you didn’t mention it, or - Your guild/channel allowlist denies the channel/user. - **`requireMention: false` but still no replies**: - - `discord.groupPolicy` defaults to **allowlist**; you must either set it to `"open"` or explicitly list the channel under `discord.guilds..channels`. - - `requireMention` must live under `discord.guilds` (or a specific channel). `discord.requireMention` at the top level is ignored. -- **Permission audits** (`providers status --probe`) only check numeric channel IDs. If you use slugs/names as `discord.guilds.*.channels` keys, the audit can’t verify permissions. -- **DMs don’t work**: `discord.dm.enabled=false`, `discord.dm.policy="disabled"`, or you haven’t been approved yet (`discord.dm.policy="pairing"`). + - `channels.discord.groupPolicy` defaults to **allowlist**; set it to `"open"` or explicitly list channels under `channels.discord.guilds..channels`. + - `requireMention` must live under `channels.discord.guilds` (or a specific channel). `channels.discord.requireMention` at the top level is ignored. +- **Permission audits** (`channels status --probe`) only check numeric channel IDs. If you use slugs/names as `channels.discord.guilds.*.channels` keys, the audit can’t verify permissions. +- **DMs don’t work**: `channels.discord.dm.enabled=false`, `channels.discord.dm.policy="disabled"`, or you haven’t been approved yet (`channels.discord.dm.policy="pairing"`). ## Capabilities & limits - DMs and guild text channels (threads are treated as separate channels; voice not supported). -- Typing indicators sent best-effort; message chunking uses `discord.textChunkLimit` (default 2000) and splits tall replies by line count (`discord.maxLinesPerMessage`, default 17). -- File uploads supported up to the configured `discord.mediaMaxMb` (default 8 MB). +- Typing indicators sent best-effort; message chunking uses `channels.discord.textChunkLimit` (default 2000) and splits tall replies by line count (`channels.discord.maxLinesPerMessage`, default 17). +- File uploads supported up to the configured `channels.discord.mediaMaxMb` (default 8 MB). - Mention-gated guild replies by default to avoid noisy bots. - Reply context is injected when a message references another message (quoted content + ids). -- Native reply threading is **off by default**; enable with `discord.replyToMode` and reply tags. +- Native reply threading is **off by default**; enable with `channels.discord.replyToMode` and reply tags. ## Retry policy -Outbound Discord API calls retry on rate limits (429) using Discord `retry_after` when available, with exponential backoff and jitter. Configure via `discord.retry`. See [Retry policy](/concepts/retry). +Outbound Discord API calls retry on rate limits (429) using Discord `retry_after` when available, with exponential backoff and jitter. Configure via `channels.discord.retry`. See [Retry policy](/concepts/retry). ## Config ```json5 { - discord: { - enabled: true, - token: "abc.123", - groupPolicy: "allowlist", - guilds: { - "*": { - channels: { - general: { allow: true } - } - } - }, - mediaMaxMb: 8, - actions: { - reactions: true, - stickers: true, - polls: true, - permissions: true, - messages: true, - threads: true, - pins: true, - search: true, - memberInfo: true, - roleInfo: true, - roles: false, - channelInfo: true, - voiceStatus: true, - events: true, - moderation: false - }, - replyToMode: "off", - dm: { + channels: { + discord: { enabled: true, - policy: "pairing", // pairing | allowlist | open | disabled - allowFrom: ["123456789012345678", "steipete"], - groupEnabled: false, - groupChannels: ["clawd-dm"] - }, - guilds: { - "*": { requireMention: true }, - "123456789012345678": { - slug: "friends-of-clawd", - requireMention: false, - reactionNotifications: "own", - users: ["987654321098765432", "steipete"], - channels: { - general: { allow: true }, - help: { - allow: true, - requireMention: true, - users: ["987654321098765432"], - skills: ["search", "docs"], - systemPrompt: "Keep answers short." + token: "abc.123", + groupPolicy: "allowlist", + guilds: { + "*": { + channels: { + general: { allow: true } + } + } + }, + mediaMaxMb: 8, + actions: { + reactions: true, + stickers: true, + polls: true, + permissions: true, + messages: true, + threads: true, + pins: true, + search: true, + memberInfo: true, + roleInfo: true, + roles: false, + channelInfo: true, + voiceStatus: true, + events: true, + moderation: false + }, + replyToMode: "off", + dm: { + enabled: true, + policy: "pairing", // pairing | allowlist | open | disabled + allowFrom: ["123456789012345678", "steipete"], + groupEnabled: false, + groupChannels: ["clawd-dm"] + }, + guilds: { + "*": { requireMention: true }, + "123456789012345678": { + slug: "friends-of-clawd", + requireMention: false, + reactionNotifications: "own", + users: ["987654321098765432", "steipete"], + channels: { + general: { allow: true }, + help: { + allow: true, + requireMention: true, + users: ["987654321098765432"], + skills: ["search", "docs"], + systemPrompt: "Keep answers short." + } } } } @@ -323,7 +331,7 @@ To request a threaded reply, the model can include one tag in its output: - `[[reply_to:]]` — reply to a specific message id from context/history. Current message ids are appended to prompts as `[message_id: …]`; history entries already include ids. -Behavior is controlled by `discord.replyToMode`: +Behavior is controlled by `channels.discord.replyToMode`: - `off`: ignore tags. - `first`: only the first outbound chunk/attachment is a reply. - `all`: every outbound chunk/attachment is a reply. @@ -336,7 +344,7 @@ Allowlist matching notes: Native command notes: - The registered commands mirror Clawdbot’s chat commands. -- Native commands honor the same allowlists as DMs/guild messages (`discord.dm.allowFrom`, `discord.guilds`, per-channel rules). +- Native commands honor the same allowlists as DMs/guild messages (`channels.discord.dm.allowFrom`, `channels.discord.guilds`, per-channel rules). ## Tool actions The agent can call `discord` with actions like: diff --git a/docs/providers/grammy.md b/docs/channels/grammy.md similarity index 65% rename from docs/providers/grammy.md rename to docs/channels/grammy.md index 9fa3c30fb..ff0c92c7a 100644 --- a/docs/providers/grammy.md +++ b/docs/channels/grammy.md @@ -14,11 +14,11 @@ read_when: # What we shipped - **Single client path:** fetch-based implementation removed; grammY is now the sole Telegram client (send + gateway) with the grammY throttler enabled by default. - **Gateway:** `monitorTelegramProvider` builds a grammY `Bot`, wires mention/allowlist gating, media download via `getFile`/`download`, and delivers replies with `sendMessage/sendPhoto/sendVideo/sendAudio/sendDocument`. Supports long-poll or webhook via `webhookCallback`. -- **Proxy:** optional `telegram.proxy` uses `undici.ProxyAgent` through grammY’s `client.baseFetch`. -- **Webhook support:** `webhook-set.ts` wraps `setWebhook/deleteWebhook`; `webhook.ts` hosts the callback with health + graceful shutdown. Gateway enables webhook mode when `telegram.webhookUrl` is set (otherwise it long-polls). -- **Sessions:** direct chats collapse into the agent main session (`agent::`); groups use `agent::telegram:group:`; replies route back to the same provider. -- **Config knobs:** `telegram.botToken`, `telegram.dmPolicy`, `telegram.groups` (allowlist + mention defaults), `telegram.allowFrom`, `telegram.groupAllowFrom`, `telegram.groupPolicy`, `telegram.mediaMaxMb`, `telegram.proxy`, `telegram.webhookSecret`, `telegram.webhookUrl`. -- **Draft streaming:** optional `telegram.streamMode` uses `sendMessageDraft` in private topic chats (Bot API 9.3+). This is separate from provider block streaming. +- **Proxy:** optional `channels.telegram.proxy` uses `undici.ProxyAgent` through grammY’s `client.baseFetch`. +- **Webhook support:** `webhook-set.ts` wraps `setWebhook/deleteWebhook`; `webhook.ts` hosts the callback with health + graceful shutdown. Gateway enables webhook mode when `channels.telegram.webhookUrl` is set (otherwise it long-polls). +- **Sessions:** direct chats collapse into the agent main session (`agent::`); groups use `agent::telegram:group:`; replies route back to the same channel. +- **Config knobs:** `channels.telegram.botToken`, `channels.telegram.dmPolicy`, `channels.telegram.groups` (allowlist + mention defaults), `channels.telegram.allowFrom`, `channels.telegram.groupAllowFrom`, `channels.telegram.groupPolicy`, `channels.telegram.mediaMaxMb`, `channels.telegram.proxy`, `channels.telegram.webhookSecret`, `channels.telegram.webhookUrl`. +- **Draft streaming:** optional `channels.telegram.streamMode` uses `sendMessageDraft` in private topic chats (Bot API 9.3+). This is separate from channel block streaming. - **Tests:** grammy mocks cover DM + group mention gating and outbound send; more media/webhook fixtures still welcome. Open questions diff --git a/docs/providers/imessage.md b/docs/channels/imessage.md similarity index 56% rename from docs/providers/imessage.md rename to docs/channels/imessage.md index c68465047..a67c5b744 100644 --- a/docs/providers/imessage.md +++ b/docs/channels/imessage.md @@ -13,31 +13,33 @@ Status: external CLI integration. Gateway spawns `imsg rpc` (JSON-RPC over stdio 1) Ensure Messages is signed in on this Mac. 2) Install `imsg`: - `brew install steipete/tap/imsg` -3) Configure Clawdbot with `imessage.cliPath` and `imessage.dbPath`. +3) Configure Clawdbot with `channels.imessage.cliPath` and `channels.imessage.dbPath`. 4) Start the gateway and approve any macOS prompts (Automation + Full Disk Access). Minimal config: ```json5 { - imessage: { - enabled: true, - cliPath: "/usr/local/bin/imsg", - dbPath: "/Users//Library/Messages/chat.db" + channels: { + imessage: { + enabled: true, + cliPath: "/usr/local/bin/imsg", + dbPath: "/Users//Library/Messages/chat.db" + } } } ``` ## What it is -- iMessage provider backed by `imsg` on macOS. +- iMessage channel backed by `imsg` on macOS. - Deterministic routing: replies always go back to iMessage. - DMs share the agent's main session; groups are isolated (`agent::imessage:group:`). -- If a multi-participant thread arrives with `is_group=false`, you can still isolate it by `chat_id` using `imessage.groups` (see “Group-ish threads” below). +- If a multi-participant thread arrives with `is_group=false`, you can still isolate it by `chat_id` using `channels.imessage.groups` (see “Group-ish threads” below). ## Requirements - macOS with Messages signed in. - Full Disk Access for Clawdbot + `imsg` (Messages DB access). - Automation permission when sending. -- `imessage.cliPath` can point to any command that proxies stdin/stdout (for example, a wrapper script that SSHes to another Mac and runs `imsg rpc`). +- `channels.imessage.cliPath` can point to any command that proxies stdin/stdout (for example, a wrapper script that SSHes to another Mac and runs `imsg rpc`). ## Setup (fast path) 1) Ensure Messages is signed in on this Mac. @@ -54,7 +56,7 @@ If you want the bot to send from a **separate iMessage identity** (and keep your 5) Install `imsg`: - `brew install steipete/tap/imsg` 6) Set up SSH so `ssh @localhost true` works without a password. -7) Point `imessage.accounts.bot.cliPath` at an SSH wrapper that runs `imsg` as the bot user. +7) Point `channels.imessage.accounts.bot.cliPath` at an SSH wrapper that runs `imsg` as the bot user. First-run note: sending/receiving may require GUI approvals (Automation + Full Disk Access) in the *bot macOS user*. If `imsg rpc` looks stuck or exits, log into that user (Screen Sharing helps), run a one-time `imsg chats --limit 1` / `imsg send ...`, approve prompts, then retry. @@ -72,24 +74,26 @@ exec /usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=5 -T @local Example config: ```json5 { - imessage: { - enabled: true, - accounts: { - bot: { - name: "Bot", - enabled: true, - cliPath: "/path/to/imsg-bot", - dbPath: "/Users//Library/Messages/chat.db" + channels: { + imessage: { + enabled: true, + accounts: { + bot: { + name: "Bot", + enabled: true, + cliPath: "/path/to/imsg-bot", + dbPath: "/Users//Library/Messages/chat.db" + } } } } } ``` -For single-account setups, use flat options (`imessage.cliPath`, `imessage.dbPath`) instead of the `accounts` map. +For single-account setups, use flat options (`channels.imessage.cliPath`, `channels.imessage.dbPath`) instead of the `accounts` map. ### Remote/SSH variant (optional) -If you want iMessage on another Mac, set `imessage.cliPath` to a wrapper that runs `imsg` on the remote macOS host over SSH. Clawdbot only needs stdio. +If you want iMessage on another Mac, set `channels.imessage.cliPath` to a wrapper that runs `imsg` on the remote macOS host over SSH. Clawdbot only needs stdio. Example wrapper: ```bash @@ -97,11 +101,11 @@ Example wrapper: exec ssh -T mac-mini imsg "$@" ``` -Multi-account support: use `imessage.accounts` with per-account config and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. Don’t commit `~/.clawdbot/clawdbot.json` (it often contains tokens). +Multi-account support: use `channels.imessage.accounts` with per-account config and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. Don’t commit `~/.clawdbot/clawdbot.json` (it often contains tokens). ## Access control (DMs + groups) DMs: -- Default: `imessage.dmPolicy = "pairing"`. +- Default: `channels.imessage.dmPolicy = "pairing"`. - Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour). - Approve via: - `clawdbot pairing list imessage` @@ -109,30 +113,32 @@ DMs: - Pairing is the default token exchange for iMessage DMs. Details: [Pairing](/start/pairing) Groups: -- `imessage.groupPolicy = open | allowlist | disabled`. -- `imessage.groupAllowFrom` controls who can trigger in groups when `allowlist` is set. +- `channels.imessage.groupPolicy = open | allowlist | disabled`. +- `channels.imessage.groupAllowFrom` controls who can trigger in groups when `allowlist` is set. - Mention gating uses `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) because iMessage has no native mention metadata. - Multi-agent override: set per-agent patterns on `agents.list[].groupChat.mentionPatterns`. ## How it works (behavior) -- `imsg` streams message events; the gateway normalizes them into the shared provider envelope. +- `imsg` streams message events; the gateway normalizes them into the shared channel envelope. - Replies always route back to the same chat id or handle. ## Group-ish threads (`is_group=false`) Some iMessage threads can have multiple participants but still arrive with `is_group=false` depending on how Messages stores the chat identifier. -If you explicitly configure a `chat_id` under `imessage.groups`, Clawdbot treats that thread as a “group” for: +If you explicitly configure a `chat_id` under `channels.imessage.groups`, Clawdbot treats that thread as a “group” for: - session isolation (separate `agent::imessage:group:` session key) - group allowlisting / mention gating behavior Example: ```json5 { - imessage: { - groupPolicy: "allowlist", - groupAllowFrom: ["+15555550123"], - groups: { - "42": { "requireMention": false } + channels: { + imessage: { + groupPolicy: "allowlist", + groupAllowFrom: ["+15555550123"], + groups: { + "42": { "requireMention": false } + } } } } @@ -140,12 +146,12 @@ Example: This is useful when you want an isolated personality/model for a specific thread (see [Multi-agent routing](/concepts/multi-agent)). For filesystem isolation, see [Sandboxing](/gateway/sandboxing). ## Media + limits -- Optional attachment ingestion via `imessage.includeAttachments`. -- Media cap via `imessage.mediaMaxMb`. +- Optional attachment ingestion via `channels.imessage.includeAttachments`. +- Media cap via `channels.imessage.mediaMaxMb`. ## Limits -- Outbound text is chunked to `imessage.textChunkLimit` (default 4000). -- Media uploads are capped by `imessage.mediaMaxMb` (default 16). +- Outbound text is chunked to `channels.imessage.textChunkLimit` (default 4000). +- Media uploads are capped by `channels.imessage.mediaMaxMb` (default 16). ## Addressing / delivery targets Prefer `chat_id` for stable routing: @@ -163,20 +169,20 @@ imsg chats --limit 20 Full configuration: [Configuration](/gateway/configuration) Provider options: -- `imessage.enabled`: enable/disable provider startup. -- `imessage.cliPath`: path to `imsg`. -- `imessage.dbPath`: Messages DB path. -- `imessage.service`: `imessage | sms | auto`. -- `imessage.region`: SMS region. -- `imessage.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). -- `imessage.allowFrom`: DM allowlist (handles or `chat_id:*`). `open` requires `"*"`. -- `imessage.groupPolicy`: `open | allowlist | disabled` (default: allowlist). -- `imessage.groupAllowFrom`: group sender allowlist. -- `imessage.historyLimit` / `imessage.accounts.*.historyLimit`: max group messages to include as context (0 disables). -- `imessage.groups`: per-group defaults + allowlist (use `"*"` for global defaults). -- `imessage.includeAttachments`: ingest attachments into context. -- `imessage.mediaMaxMb`: inbound/outbound media cap (MB). -- `imessage.textChunkLimit`: outbound chunk size (chars). +- `channels.imessage.enabled`: enable/disable channel startup. +- `channels.imessage.cliPath`: path to `imsg`. +- `channels.imessage.dbPath`: Messages DB path. +- `channels.imessage.service`: `imessage | sms | auto`. +- `channels.imessage.region`: SMS region. +- `channels.imessage.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). +- `channels.imessage.allowFrom`: DM allowlist (handles or `chat_id:*`). `open` requires `"*"`. +- `channels.imessage.groupPolicy`: `open | allowlist | disabled` (default: allowlist). +- `channels.imessage.groupAllowFrom`: group sender allowlist. +- `channels.imessage.historyLimit` / `channels.imessage.accounts.*.historyLimit`: max group messages to include as context (0 disables). +- `channels.imessage.groups`: per-group defaults + allowlist (use `"*"` for global defaults). +- `channels.imessage.includeAttachments`: ingest attachments into context. +- `channels.imessage.mediaMaxMb`: inbound/outbound media cap (MB). +- `channels.imessage.textChunkLimit`: outbound chunk size (chars). Related global options: - `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`). diff --git a/docs/channels/index.md b/docs/channels/index.md new file mode 100644 index 000000000..80db578dd --- /dev/null +++ b/docs/channels/index.md @@ -0,0 +1,30 @@ +--- +summary: "Messaging platforms Clawdbot can connect to" +read_when: + - You want to choose a chat channel for Clawdbot + - You need a quick overview of supported messaging platforms +--- +# Chat Channels + +Clawdbot can talk to you on any chat app you already use. Each channel connects via the Gateway. +Text is supported everywhere; media and reactions vary by channel. + +## Supported channels + +- [WhatsApp](/channels/whatsapp) — Most popular; uses Baileys and requires QR pairing. +- [Telegram](/channels/telegram) — Bot API via grammY; supports groups. +- [Discord](/channels/discord) — Discord Bot API + Gateway; supports servers, channels, and DMs. +- [Slack](/channels/slack) — Bolt SDK; workspace apps. +- [Signal](/channels/signal) — signal-cli; privacy-focused. +- [iMessage](/channels/imessage) — macOS only; native integration. +- [Microsoft Teams](/channels/msteams) — Bot Framework; enterprise support. +- [WebChat](/web/webchat) — Gateway WebChat UI over WebSocket. + +## Notes + +- Channels can run simultaneously; configure multiple and Clawdbot will route per chat. +- Group behavior varies by channel; see [Groups](/concepts/groups). +- DM pairing and allowlists are enforced for safety; see [Security](/gateway/security). +- Telegram internals: [grammY notes](/channels/grammy). +- Troubleshooting: [Channel troubleshooting](/channels/troubleshooting). +- Model providers are documented separately; see [Model Providers](/providers/models). diff --git a/docs/providers/location.md b/docs/channels/location.md similarity index 78% rename from docs/providers/location.md rename to docs/channels/location.md index 7d610e7ff..f38031fb6 100644 --- a/docs/providers/location.md +++ b/docs/channels/location.md @@ -1,13 +1,13 @@ --- -summary: "Inbound provider location parsing (Telegram + WhatsApp) and context fields" +summary: "Inbound channel location parsing (Telegram + WhatsApp) and context fields" read_when: - - Adding or modifying provider location parsing + - Adding or modifying channel location parsing - Using location context fields in agent prompts or tools --- -# Provider location parsing +# Channel location parsing -Clawdbot normalizes shared locations from chat providers into: +Clawdbot normalizes shared locations from chat channels into: - human-readable text appended to the inbound body, and - structured fields in the auto-reply context payload. @@ -25,7 +25,7 @@ Locations are rendered as friendly lines without brackets: - Live share: - `🛰 Live location: 48.858844, 2.294351 ±12m` -If the provider includes a caption/comment, it is appended on the next line: +If the channel includes a caption/comment, it is appended on the next line: ``` 📍 48.858844, 2.294351 ±12m Meet here @@ -41,6 +41,6 @@ When a location is present, these fields are added to `ctx`: - `LocationSource` (`pin | place | live`) - `LocationIsLive` (boolean) -## Provider notes +## Channel notes - **Telegram**: venues map to `LocationName/LocationAddress`; live locations use `live_period`. - **WhatsApp**: `locationMessage.comment` and `liveLocationMessage.caption` are appended as the caption line. diff --git a/docs/providers/msteams.md b/docs/channels/msteams.md similarity index 87% rename from docs/providers/msteams.md rename to docs/channels/msteams.md index 416021220..534d261ae 100644 --- a/docs/providers/msteams.md +++ b/docs/channels/msteams.md @@ -1,7 +1,7 @@ --- summary: "Microsoft Teams bot support status, capabilities, and configuration" read_when: - - Working on MS Teams provider features + - Working on MS Teams channel features --- # Microsoft Teams (Bot Framework) @@ -21,39 +21,43 @@ Status: text + DM attachments are supported; channel/group attachments require M Minimal config: ```json5 { - msteams: { - enabled: true, - appId: "", - appPassword: "", - tenantId: "", - webhook: { port: 3978, path: "/api/messages" } + channels: { + msteams: { + enabled: true, + appId: "", + appPassword: "", + tenantId: "", + webhook: { port: 3978, path: "/api/messages" } + } } } ``` -Note: group chats are blocked by default (`msteams.groupPolicy: "allowlist"`). To allow group replies, set `msteams.groupAllowFrom` (or use `groupPolicy: "open"` to allow any member, mention-gated). +Note: group chats are blocked by default (`channels.msteams.groupPolicy: "allowlist"`). To allow group replies, set `channels.msteams.groupAllowFrom` (or use `groupPolicy: "open"` to allow any member, mention-gated). ## Goals - Talk to Clawdbot via Teams DMs, group chats, or channels. -- Keep routing deterministic: replies always go back to the provider they arrived on. +- Keep routing deterministic: replies always go back to the channel they arrived on. - Default to safe channel behavior (mentions required unless configured otherwise). ## Access control (DMs + groups) **DM access** -- Default: `msteams.dmPolicy = "pairing"`. Unknown senders are ignored until approved. -- `msteams.allowFrom` accepts AAD object IDs or UPNs. +- Default: `channels.msteams.dmPolicy = "pairing"`. Unknown senders are ignored until approved. +- `channels.msteams.allowFrom` accepts AAD object IDs or UPNs. **Group access** -- Default: `msteams.groupPolicy = "allowlist"` (blocked unless you add `groupAllowFrom`). -- `msteams.groupAllowFrom` controls which senders can trigger in group chats/channels (falls back to `msteams.allowFrom`). +- Default: `channels.msteams.groupPolicy = "allowlist"` (blocked unless you add `groupAllowFrom`). +- `channels.msteams.groupAllowFrom` controls which senders can trigger in group chats/channels (falls back to `channels.msteams.allowFrom`). - Set `groupPolicy: "open"` to allow any member (still mention‑gated by default). Example: ```json5 { - msteams: { - groupPolicy: "allowlist", - groupAllowFrom: ["user@org.com"] + channels: { + msteams: { + groupPolicy: "allowlist", + groupAllowFrom: ["user@org.com"] + } } } ``` @@ -189,10 +193,10 @@ This is often easier than hand-editing JSON manifests. - `https://:3978/api/messages` (or your chosen path/port). 5. **Run the gateway** - - The Teams provider starts automatically when `msteams` config exists and credentials are set. + - The Teams channel starts automatically when `msteams` config exists and credentials are set. ## History context -- `msteams.historyLimit` controls how many recent channel/group messages are wrapped into the prompt. +- `channels.msteams.historyLimit` controls how many recent channel/group messages are wrapped into the prompt. - Falls back to `messages.groupChat.historyLimit`. Set `0` to disable (default 50). ## Current Teams RSC Permissions (Manifest) @@ -336,22 +340,22 @@ Teams markdown is more limited than Slack or Discord: - Adaptive Cards are used for polls; other card types are not yet supported ## Configuration -Key settings (see `/gateway/configuration` for shared provider patterns): +Key settings (see `/gateway/configuration` for shared channel patterns): -- `msteams.enabled`: enable/disable the provider. -- `msteams.appId`, `msteams.appPassword`, `msteams.tenantId`: bot credentials. -- `msteams.webhook.port` (default `3978`) -- `msteams.webhook.path` (default `/api/messages`) -- `msteams.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing) -- `msteams.allowFrom`: allowlist for DMs (AAD object IDs or UPNs). -- `msteams.textChunkLimit`: outbound text chunk size. -- `msteams.mediaAllowHosts`: allowlist for inbound attachment hosts (defaults to Microsoft/Teams domains). -- `msteams.requireMention`: require @mention in channels/groups (default true). -- `msteams.replyStyle`: `thread | top-level` (see [Reply Style](#reply-style-threads-vs-posts)). -- `msteams.teams..replyStyle`: per-team override. -- `msteams.teams..requireMention`: per-team override. -- `msteams.teams..channels..replyStyle`: per-channel override. -- `msteams.teams..channels..requireMention`: per-channel override. +- `channels.msteams.enabled`: enable/disable the channel. +- `channels.msteams.appId`, `channels.msteams.appPassword`, `channels.msteams.tenantId`: bot credentials. +- `channels.msteams.webhook.port` (default `3978`) +- `channels.msteams.webhook.path` (default `/api/messages`) +- `channels.msteams.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing) +- `channels.msteams.allowFrom`: allowlist for DMs (AAD object IDs or UPNs). +- `channels.msteams.textChunkLimit`: outbound text chunk size. +- `channels.msteams.mediaAllowHosts`: allowlist for inbound attachment hosts (defaults to Microsoft/Teams domains). +- `channels.msteams.requireMention`: require @mention in channels/groups (default true). +- `channels.msteams.replyStyle`: `thread | top-level` (see [Reply Style](#reply-style-threads-vs-posts)). +- `channels.msteams.teams..replyStyle`: per-team override. +- `channels.msteams.teams..requireMention`: per-team override. +- `channels.msteams.teams..channels..replyStyle`: per-channel override. +- `channels.msteams.teams..channels..requireMention`: per-channel override. ## Routing & Sessions - Session keys follow the standard agent format (see [/concepts/session](/concepts/session)): @@ -399,7 +403,7 @@ Teams recently introduced two channel UI styles over the same underlying data mo - **Channels/groups:** Attachments live in M365 storage (SharePoint/OneDrive). The webhook payload only includes an HTML stub, not the actual file bytes. **Graph API permissions are required** to download channel attachments. Without Graph permissions, channel messages with images will be received as text-only (the image content is not accessible to the bot). -By default, Clawdbot only downloads media from Microsoft/Teams hostnames. Override with `msteams.mediaAllowHosts` (use `["*"]` to allow any host). +By default, Clawdbot only downloads media from Microsoft/Teams hostnames. Override with `channels.msteams.mediaAllowHosts` (use `["*"]` to allow any host). ## Polls (Adaptive Cards) Clawdbot sends Teams polls as Adaptive Cards (there is no native Teams poll API). @@ -458,7 +462,7 @@ Bots have limited support in private channels: ### Common issues - **Images not showing in channels:** Graph permissions or admin consent missing. Reinstall the Teams app and fully quit/reopen Teams. -- **No responses in channel:** mentions are required by default; set `msteams.requireMention=false` or configure per team/channel. +- **No responses in channel:** mentions are required by default; set `channels.msteams.requireMention=false` or configure per team/channel. - **Version mismatch (Teams still shows old manifest):** remove + re-add the app and fully quit Teams to refresh. - **401 Unauthorized from webhook:** Expected when testing manually without Azure JWT - means endpoint is reachable but auth failed. Use Azure Web Chat to test properly. diff --git a/docs/channels/signal.md b/docs/channels/signal.md new file mode 100644 index 000000000..2099bd644 --- /dev/null +++ b/docs/channels/signal.md @@ -0,0 +1,123 @@ +--- +summary: "Signal support via signal-cli (JSON-RPC + SSE), setup, and number model" +read_when: + - Setting up Signal support + - Debugging Signal send/receive +--- +# Signal (signal-cli) + + +Status: external CLI integration. Gateway talks to `signal-cli` over HTTP JSON-RPC + SSE. + +## Quick setup (beginner) +1) Use a **separate Signal number** for the bot (recommended). +2) Install `signal-cli` (Java required). +3) Link the bot device and start the daemon: + - `signal-cli link -n "Clawdbot"` +4) Configure Clawdbot and start the gateway. + +Minimal config: +```json5 +{ + channels: { + signal: { + enabled: true, + account: "+15551234567", + cliPath: "signal-cli", + dmPolicy: "pairing", + allowFrom: ["+15557654321"] + } + } +} +``` + +## What it is +- Signal channel via `signal-cli` (not embedded libsignal). +- Deterministic routing: replies always go back to Signal. +- DMs share the agent's main session; groups are isolated (`agent::signal:group:`). + +## The number model (important) +- The gateway connects to a **Signal device** (the `signal-cli` account). +- If you run the bot on **your personal Signal account**, it will ignore your own messages (loop protection). +- For "I text the bot and it replies," use a **separate bot number**. + +## Setup (fast path) +1) Install `signal-cli` (Java required). +2) Link a bot account: + - `signal-cli link -n "Clawdbot"` then scan the QR in Signal. +3) Configure Signal and start the gateway. + +Example: +```json5 +{ + channels: { + signal: { + enabled: true, + account: "+15551234567", + cliPath: "signal-cli", + dmPolicy: "pairing", + allowFrom: ["+15557654321"] + } + } +} +``` + +Multi-account support: use `channels.signal.accounts` with per-account config and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. + +## Access control (DMs + groups) +DMs: +- Default: `channels.signal.dmPolicy = "pairing"`. +- Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour). +- Approve via: + - `clawdbot pairing list signal` + - `clawdbot pairing approve signal ` +- Pairing is the default token exchange for Signal DMs. Details: [Pairing](/start/pairing) +- UUID-only senders (from `sourceUuid`) are stored as `uuid:` in `channels.signal.allowFrom`. + +Groups: +- `channels.signal.groupPolicy = open | allowlist | disabled`. +- `channels.signal.groupAllowFrom` controls who can trigger in groups when `allowlist` is set. + +## How it works (behavior) +- `signal-cli` runs as a daemon; the gateway reads events via SSE. +- Inbound messages are normalized into the shared channel envelope. +- Replies always route back to the same number or group. + +## Media + limits +- Outbound text is chunked to `channels.signal.textChunkLimit` (default 4000). +- Attachments supported (base64 fetched from `signal-cli`). +- Default media cap: `channels.signal.mediaMaxMb` (default 8). +- Use `channels.signal.ignoreAttachments` to skip downloading media. +- Group history context uses `channels.signal.historyLimit` (or `channels.signal.accounts.*.historyLimit`), falling back to `messages.groupChat.historyLimit`. Set `0` to disable (default 50). + +## Delivery targets (CLI/cron) +- DMs: `signal:+15551234567` (or plain E.164). +- Groups: `signal:group:`. +- Usernames: `username:` (if supported by your Signal account). + +## Configuration reference (Signal) +Full configuration: [Configuration](/gateway/configuration) + +Provider options: +- `channels.signal.enabled`: enable/disable channel startup. +- `channels.signal.account`: E.164 for the bot account. +- `channels.signal.cliPath`: path to `signal-cli`. +- `channels.signal.httpUrl`: full daemon URL (overrides host/port). +- `channels.signal.httpHost`, `channels.signal.httpPort`: daemon bind (default 127.0.0.1:8080). +- `channels.signal.autoStart`: auto-spawn daemon (default true if `httpUrl` unset). +- `channels.signal.receiveMode`: `on-start | manual`. +- `channels.signal.ignoreAttachments`: skip attachment downloads. +- `channels.signal.ignoreStories`: ignore stories from the daemon. +- `channels.signal.sendReadReceipts`: forward read receipts. +- `channels.signal.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). +- `channels.signal.allowFrom`: DM allowlist (E.164 or `uuid:`). `open` requires `"*"`. +- `channels.signal.groupPolicy`: `open | allowlist | disabled` (default: allowlist). +- `channels.signal.groupAllowFrom`: group sender allowlist. +- `channels.signal.historyLimit`: max group messages to include as context (0 disables). +- `channels.signal.textChunkLimit`: outbound chunk size (chars). +- `channels.signal.mediaMaxMb`: inbound/outbound media cap (MB). + +Related global options: +- `agents.list[].groupChat.mentionPatterns` (Signal does not support native mentions). +- `messages.groupChat.mentionPatterns` (global fallback). +- `messages.responsePrefix`. diff --git a/docs/providers/slack.md b/docs/channels/slack.md similarity index 68% rename from docs/providers/slack.md rename to docs/channels/slack.md index dfba65c26..87b0613e1 100644 --- a/docs/providers/slack.md +++ b/docs/channels/slack.md @@ -13,16 +13,18 @@ read_when: "Setting up Slack or debugging Slack socket mode" Minimal config: ```json5 { - slack: { - enabled: true, - appToken: "xapp-...", - botToken: "xoxb-..." + channels: { + slack: { + enabled: true, + appToken: "xapp-...", + botToken: "xoxb-..." + } } } ``` ## Setup -1) Create a Slack app (From scratch) in https://api.slack.com/apps. +1) Create a Slack app (From scratch) in https://api.channels.slack.com/apps. 2) **Socket Mode** → toggle on. Then go to **Basic Information** → **App-Level Tokens** → **Generate Token and Scopes** with scope `connections:write`. Copy the **App Token** (`xapp-...`). 3) **OAuth & Permissions** → add bot token scopes (use the manifest below). Click **Install to Workspace**. Copy the **Bot User OAuth Token** (`xoxb-...`). 4) **Event Subscriptions** → enable events and subscribe to: @@ -33,12 +35,12 @@ Minimal config: - `channel_rename` - `pin_added`, `pin_removed` 5) Invite the bot to channels you want it to read. -6) Slash Commands → create `/clawd` if you use `slack.slashCommand`. If you enable native commands, add one slash command per built-in command (same names as `/help`). Native defaults to off for Slack unless you set `slack.commands.native: true` (global `commands.native` is `"auto"` which leaves Slack off). +6) Slash Commands → create `/clawd` if you use `channels.slack.slashCommand`. If you enable native commands, add one slash command per built-in command (same names as `/help`). Native defaults to off for Slack unless you set `channels.slack.commands.native: true` (global `commands.native` is `"auto"` which leaves Slack off). 7) App Home → enable the **Messages Tab** so users can DM the bot. Use the manifest below so scopes and events stay in sync. -Multi-account support: use `slack.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. +Multi-account support: use `channels.slack.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. ## Clawdbot config (minimal) @@ -50,16 +52,18 @@ Or via config: ```json5 { - slack: { - enabled: true, - appToken: "xapp-...", - botToken: "xoxb-..." + channels: { + slack: { + enabled: true, + appToken: "xapp-...", + botToken: "xoxb-..." + } } } ``` ## History context -- `slack.historyLimit` (or `slack.accounts.*.historyLimit`) controls how many recent channel/group messages are wrapped into the prompt. +- `channels.slack.historyLimit` (or `channels.slack.accounts.*.historyLimit`) controls how many recent channel/group messages are wrapped into the prompt. - Falls back to `messages.groupChat.historyLimit`. Set `0` to disable (default 50). ## Manifest (optional) @@ -138,42 +142,42 @@ Use this Slack app manifest to create the app quickly (adjust the name/command i } ``` -If you enable native commands, add one `slash_commands` entry per command you want to expose (matching the `/help` list). Override with `slack.commands.native`. +If you enable native commands, add one `slash_commands` entry per command you want to expose (matching the `/help` list). Override with `channels.slack.commands.native`. ## Scopes (current vs optional) Slack's Conversations API is type-scoped: you only need the scopes for the conversation types you actually touch (channels, groups, im, mpim). See -https://api.slack.com/docs/conversations-api for the overview. +https://api.channels.slack.com/docs/conversations-api for the overview. ### Required scopes - `chat:write` (send/update/delete messages via `chat.postMessage`) - https://api.slack.com/methods/chat.postMessage + https://api.channels.slack.com/methods/chat.postMessage - `im:write` (open DMs via `conversations.open` for user DMs) - https://api.slack.com/methods/conversations.open + https://api.channels.slack.com/methods/conversations.open - `channels:history`, `groups:history`, `im:history`, `mpim:history` - https://api.slack.com/methods/conversations.history + https://api.channels.slack.com/methods/conversations.history - `channels:read`, `groups:read`, `im:read`, `mpim:read` - https://api.slack.com/methods/conversations.info + https://api.channels.slack.com/methods/conversations.info - `users:read` (user lookup) - https://api.slack.com/methods/users.info + https://api.channels.slack.com/methods/users.info - `reactions:read`, `reactions:write` (`reactions.get` / `reactions.add`) - https://api.slack.com/methods/reactions.get - https://api.slack.com/methods/reactions.add + https://api.channels.slack.com/methods/reactions.get + https://api.channels.slack.com/methods/reactions.add - `pins:read`, `pins:write` (`pins.list` / `pins.add` / `pins.remove`) - https://api.slack.com/scopes/pins:read - https://api.slack.com/scopes/pins:write + https://api.channels.slack.com/scopes/pins:read + https://api.channels.slack.com/scopes/pins:write - `emoji:read` (`emoji.list`) - https://api.slack.com/scopes/emoji:read + https://api.channels.slack.com/scopes/emoji:read - `files:write` (uploads via `files.uploadV2`) - https://api.slack.com/messaging/files/uploading + https://api.channels.slack.com/messaging/files/uploading ### Not needed today (but likely future) - `mpim:write` (only if we add group-DM open/DM start via `conversations.open`) - `groups:write` (only if we add private-channel management: create/rename/invite/archive) - `chat:write.public` (only if we want to post to channels the bot isn't in) - https://api.slack.com/scopes/chat:write.public + https://api.channels.slack.com/scopes/chat:write.public - `users:read.email` (only if we need email fields from `users.info`) - https://api.slack.com/changelog/2017-04-narrowing-email-access + https://api.channels.slack.com/changelog/2017-04-narrowing-email-access - `files:read` (only if we start listing/reading file metadata) ## Config @@ -234,11 +238,11 @@ Ack reactions are controlled globally via `messages.ackReaction` + ack reaction after the bot replies. ## Limits -- Outbound text is chunked to `slack.textChunkLimit` (default 4000). -- Media uploads are capped by `slack.mediaMaxMb` (default 20). +- Outbound text is chunked to `channels.slack.textChunkLimit` (default 4000). +- Media uploads are capped by `channels.slack.mediaMaxMb` (default 20). ## Reply threading -By default, Clawdbot replies in the main channel. Use `slack.replyToMode` to control automatic threading: +By default, Clawdbot replies in the main channel. Use `channels.slack.replyToMode` to control automatic threading: | Mode | Behavior | | --- | --- | @@ -256,20 +260,20 @@ For fine-grained control, use these tags in agent responses: ## Sessions + routing - DMs share the `main` session (like WhatsApp/Telegram). - Channels map to `agent::slack:channel:` sessions. -- Slash commands use `agent::slack:slash:` sessions (prefix configurable via `slack.slashCommand.sessionPrefix`). -- Native command registration uses `commands.native` (global default `"auto"` → Slack off) and can be overridden per-workspace with `slack.commands.native`. Text commands require standalone `/...` messages and can be disabled with `commands.text: false`. Slack slash commands are managed in the Slack app and are not removed automatically. Use `commands.useAccessGroups: false` to bypass access-group checks for commands. +- Slash commands use `agent::slack:slash:` sessions (prefix configurable via `channels.slack.slashCommand.sessionPrefix`). +- Native command registration uses `commands.native` (global default `"auto"` → Slack off) and can be overridden per-workspace with `channels.slack.commands.native`. Text commands require standalone `/...` messages and can be disabled with `commands.text: false`. Slack slash commands are managed in the Slack app and are not removed automatically. Use `commands.useAccessGroups: false` to bypass access-group checks for commands. - Full command list + config: [Slash commands](/tools/slash-commands) ## DM security (pairing) -- Default: `slack.dm.policy="pairing"` — unknown DM senders get a pairing code (expires after 1 hour). +- Default: `channels.slack.dm.policy="pairing"` — unknown DM senders get a pairing code (expires after 1 hour). - Approve via: `clawdbot pairing approve slack `. -- To allow anyone: set `slack.dm.policy="open"` and `slack.dm.allowFrom=["*"]`. +- To allow anyone: set `channels.slack.dm.policy="open"` and `channels.slack.dm.allowFrom=["*"]`. ## Group policy -- `slack.groupPolicy` controls channel handling (`open|disabled|allowlist`). -- `allowlist` requires channels to be listed in `slack.channels`. +- `channels.slack.groupPolicy` controls channel handling (`open|disabled|allowlist`). +- `allowlist` requires channels to be listed in `channels.slack.channels`. -Channel options (`slack.channels.` or `slack.channels.`): +Channel options (`channels.slack.channels.` or `channels.slack.channels.`): - `allow`: allow/deny the channel when `groupPolicy="allowlist"`. - `requireMention`: mention gating for the channel. - `allowBots`: allow bot-authored messages in this channel (default: false). @@ -284,7 +288,7 @@ Use these with cron/CLI sends: - `channel:` for channels ## Tool actions -Slack tool actions can be gated with `slack.actions.*`: +Slack tool actions can be gated with `channels.slack.actions.*`: | Action group | Default | Notes | | --- | --- | --- | @@ -295,10 +299,10 @@ Slack tool actions can be gated with `slack.actions.*`: | emojiList | enabled | Custom emoji list | ## Notes -- Mention gating is controlled via `slack.channels` (set `requireMention` to `true`); `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) also count as mentions. +- Mention gating is controlled via `channels.slack.channels` (set `requireMention` to `true`); `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) also count as mentions. - Multi-agent override: set per-agent patterns on `agents.list[].groupChat.mentionPatterns`. -- Reaction notifications follow `slack.reactionNotifications` (use `reactionAllowlist` with mode `allowlist`). -- Bot-authored messages are ignored by default; enable via `slack.allowBots` or `slack.channels..allowBots`. -- Warning: If you allow replies to other bots (`slack.allowBots=true` or `slack.channels..allowBots=true`), prevent bot-to-bot reply loops with `requireMention`, `slack.channels..users` allowlists, and/or clear guardrails in `AGENTS.md` and `SOUL.md`. +- Reaction notifications follow `channels.slack.reactionNotifications` (use `reactionAllowlist` with mode `allowlist`). +- Bot-authored messages are ignored by default; enable via `channels.slack.allowBots` or `channels.slack.channels..allowBots`. +- Warning: If you allow replies to other bots (`channels.slack.allowBots=true` or `channels.slack.channels..allowBots=true`), prevent bot-to-bot reply loops with `requireMention`, `channels.slack.channels..users` allowlists, and/or clear guardrails in `AGENTS.md` and `SOUL.md`. - For the Slack tool, reaction removal semantics are in [/tools/reactions](/tools/reactions). - Attachments are downloaded to the media store when permitted and under the size limit. diff --git a/docs/providers/telegram.md b/docs/channels/telegram.md similarity index 60% rename from docs/providers/telegram.md rename to docs/channels/telegram.md index 325b5c598..dd83a3ba4 100644 --- a/docs/providers/telegram.md +++ b/docs/channels/telegram.md @@ -12,24 +12,26 @@ Status: production-ready for bot DMs + groups via grammY. Long-polling by defaul 1) Create a bot with **@BotFather** and copy the token. 2) Set the token: - Env: `TELEGRAM_BOT_TOKEN=...` - - Or config: `telegram.botToken: "..."`. + - Or config: `channels.telegram.botToken: "..."`. 3) Start the gateway. 4) DM access is pairing by default; approve the pairing code on first contact. Minimal config: ```json5 { - telegram: { - enabled: true, - botToken: "123:abc", - dmPolicy: "pairing" + channels: { + telegram: { + enabled: true, + botToken: "123:abc", + dmPolicy: "pairing" + } } } ``` ## What it is -- A Telegram Bot API provider owned by the Gateway. -- Deterministic routing: replies go back to Telegram; the model never chooses providers. +- A Telegram Bot API channel owned by the Gateway. +- Deterministic routing: replies go back to Telegram; the model never chooses channels. - DMs share the agent's main session; groups stay isolated (`agent::telegram:group:`). ## Setup (fast path) @@ -47,22 +49,24 @@ Example: ```json5 { - telegram: { - enabled: true, - botToken: "123:abc", - dmPolicy: "pairing", - groups: { "*": { requireMention: true } } + channels: { + telegram: { + enabled: true, + botToken: "123:abc", + dmPolicy: "pairing", + groups: { "*": { requireMention: true } } + } } } ``` Env option: `TELEGRAM_BOT_TOKEN=...` (works for the default account). -Multi-account support: use `telegram.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. +Multi-account support: use `channels.telegram.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. 3) Start the gateway. Telegram starts when a token is resolved (env or config). 4) DM access defaults to pairing. Approve the code when the bot is first contacted. -5) For groups: add the bot, decide privacy/admin behavior (below), then set `telegram.groups` to control mention gating + allowlists. +5) For groups: add the bot, decide privacy/admin behavior (below), then set `channels.telegram.groups` to control mention gating + allowlists. ## Token + privacy + permissions (Telegram side) @@ -84,7 +88,7 @@ Admin status is set inside the group (Telegram UI). Admin bots always receive al group messages, so use admin if you need full visibility. ## How it works (behavior) -- Inbound messages are normalized into the shared provider envelope with reply context and media placeholders. +- Inbound messages are normalized into the shared channel envelope with reply context and media placeholders. - Group replies require a mention by default (native @mention or `agents.list[].groupChat.mentionPatterns` / `messages.groupChat.mentionPatterns`). - Multi-agent override: set per-agent patterns on `agents.list[].groupChat.mentionPatterns`. - Replies always route back to the same Telegram chat. @@ -97,9 +101,9 @@ group messages, so use admin if you need full visibility. - If Telegram rejects the HTML payload, Clawdbot retries the same message as plain text. ## Limits -- Outbound text is chunked to `telegram.textChunkLimit` (default 4000). -- Media downloads/uploads are capped by `telegram.mediaMaxMb` (default 5). -- Group history context uses `telegram.historyLimit` (or `telegram.accounts.*.historyLimit`), falling back to `messages.groupChat.historyLimit`. Set `0` to disable (default 50). +- Outbound text is chunked to `channels.telegram.textChunkLimit` (default 4000). +- Media downloads/uploads are capped by `channels.telegram.mediaMaxMb` (default 5). +- Group history context uses `channels.telegram.historyLimit` (or `channels.telegram.accounts.*.historyLimit`), falling back to `messages.groupChat.historyLimit`. Set `0` to disable (default 50). ## Group activation modes @@ -109,22 +113,26 @@ By default, the bot only responds to mentions in groups (`@botname` or patterns ```json5 { - telegram: { - groups: { - "-1001234567890": { requireMention: false } // always respond in this group + channels: { + telegram: { + groups: { + "-1001234567890": { requireMention: false } // always respond in this group + } } } } ``` -**Important:** Setting `telegram.groups` creates an **allowlist** - only listed groups (or `"*"`) will be accepted. +**Important:** Setting `channels.telegram.groups` creates an **allowlist** - only listed groups (or `"*"`) will be accepted. To allow all groups with always-respond: ```json5 { - telegram: { - groups: { - "*": { requireMention: false } // all groups, always respond + channels: { + telegram: { + groups: { + "*": { requireMention: false } // all groups, always respond + } } } } @@ -133,9 +141,11 @@ To allow all groups with always-respond: To keep mention-only for all groups (default behavior): ```json5 { - telegram: { - groups: { - "*": { requireMention: true } // or omit groups entirely + channels: { + telegram: { + groups: { + "*": { requireMention: true } // or omit groups entirely + } } } } @@ -162,49 +172,49 @@ Telegram forum topics include a `message_thread_id` per message. Clawdbot: - Appends `:topic:` to the Telegram group session key so each topic is isolated. - Sends typing indicators and replies with `message_thread_id` so responses stay in the topic. - Exposes `MessageThreadId` + `IsForum` in template context for routing/templating. -- Topic-specific configuration is available under `telegram.groups..topics.` (skills, allowlists, auto-reply, system prompts, disable). +- Topic-specific configuration is available under `channels.telegram.groups..topics.` (skills, allowlists, auto-reply, system prompts, disable). Private chats can include `message_thread_id` in some edge cases. Clawdbot keeps the DM session key unchanged, but still uses the thread id for replies/draft streaming when it is present. ## Access control (DMs + groups) ### DM access -- Default: `telegram.dmPolicy = "pairing"`. Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour). +- Default: `channels.telegram.dmPolicy = "pairing"`. Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour). - Approve via: - `clawdbot pairing list telegram` - `clawdbot pairing approve telegram ` - Pairing is the default token exchange used for Telegram DMs. Details: [Pairing](/start/pairing) -- `telegram.allowFrom` accepts numeric user IDs (recommended) or `@username` entries. It is **not** the bot username; use the human sender’s ID (get it from `@userinfobot` or the `from.id` field in the gateway log). +- `channels.telegram.allowFrom` accepts numeric user IDs (recommended) or `@username` entries. It is **not** the bot username; use the human sender’s ID (get it from `@userinfobot` or the `from.id` field in the gateway log). ### Group access Two independent controls: -**1. Which groups are allowed** (group allowlist via `telegram.groups`): +**1. Which groups are allowed** (group allowlist via `channels.telegram.groups`): - No `groups` config = all groups allowed - With `groups` config = only listed groups or `"*"` are allowed - Example: `"groups": { "-1001234567890": {}, "*": {} }` allows all groups -**2. Which senders are allowed** (sender filtering via `telegram.groupPolicy`): +**2. Which senders are allowed** (sender filtering via `channels.telegram.groupPolicy`): - `"open"` = all senders in allowed groups can message -- `"allowlist"` = only senders in `telegram.groupAllowFrom` can message +- `"allowlist"` = only senders in `channels.telegram.groupAllowFrom` can message - `"disabled"` = no group messages accepted at all Default is `groupPolicy: "allowlist"` (blocked unless you add `groupAllowFrom`). -Most users want: `groupPolicy: "allowlist"` + `groupAllowFrom` + specific groups listed in `telegram.groups` +Most users want: `groupPolicy: "allowlist"` + `groupAllowFrom` + specific groups listed in `channels.telegram.groups` ## Long-polling vs webhook - Default: long-polling (no public URL required). -- Webhook mode: set `telegram.webhookUrl` (optionally `telegram.webhookSecret` + `telegram.webhookPath`). +- Webhook mode: set `channels.telegram.webhookUrl` (optionally `channels.telegram.webhookSecret` + `channels.telegram.webhookPath`). - The local listener binds to `0.0.0.0:8787` and serves `POST /telegram-webhook` by default. - - If your public URL is different, use a reverse proxy and point `telegram.webhookUrl` at the public endpoint. + - If your public URL is different, use a reverse proxy and point `channels.telegram.webhookUrl` at the public endpoint. ## Reply threading Telegram supports optional threaded replies via tags: - `[[reply_to_current]]` -- reply to the triggering message. - `[[reply_to:]]` -- reply to a specific message id. -Controlled by `telegram.replyToMode`: +Controlled by `channels.telegram.replyToMode`: - `first` (default), `all`, `off`. ## Audio messages (voice vs file) @@ -214,7 +224,7 @@ Clawdbot defaults to audio files for backward compatibility. To force a voice note bubble in agent replies, include this tag anywhere in the reply: - `[[audio_as_voice]]` — send audio as a voice note instead of a file. -The tag is stripped from the delivered text. Other providers ignore this tag. +The tag is stripped from the delivered text. Other channels ignore this tag. ## Streaming (drafts) Telegram can stream **draft bubbles** while the agent is generating a response. @@ -227,32 +237,32 @@ Requirements (Telegram Bot API 9.3+): - Streaming is ignored for groups/supergroups/channels. Config: -- `telegram.streamMode: "off" | "partial" | "block"` (default: `partial`) +- `channels.telegram.streamMode: "off" | "partial" | "block"` (default: `partial`) - `partial`: update the draft bubble with the latest streaming text. - `block`: update the draft bubble in larger blocks (chunked). - `off`: disable draft streaming. - Optional (only for `streamMode: "block"`): - - `telegram.draftChunk: { minChars?, maxChars?, breakPreference? }` - - defaults: `minChars: 200`, `maxChars: 800`, `breakPreference: "paragraph"` (clamped to `telegram.textChunkLimit`). + - `channels.telegram.draftChunk: { minChars?, maxChars?, breakPreference? }` + - defaults: `minChars: 200`, `maxChars: 800`, `breakPreference: "paragraph"` (clamped to `channels.telegram.textChunkLimit`). -Note: draft streaming is separate from **block streaming** (provider messages). -Block streaming is off by default and requires `telegram.blockStreaming: true` +Note: draft streaming is separate from **block streaming** (channel messages). +Block streaming is off by default and requires `channels.telegram.blockStreaming: true` if you want early Telegram messages instead of draft updates. Reasoning stream (Telegram only): - `/reasoning stream` streams reasoning into the draft bubble while the reply is generating, then sends the final answer without reasoning. -- If `telegram.streamMode` is `off`, reasoning stream is disabled. +- If `channels.telegram.streamMode` is `off`, reasoning stream is disabled. More context: [Streaming + chunking](/concepts/streaming). ## Retry policy -Outbound Telegram API calls retry on transient network/429 errors with exponential backoff and jitter. Configure via `telegram.retry`. See [Retry policy](/concepts/retry). +Outbound Telegram API calls retry on transient network/429 errors with exponential backoff and jitter. Configure via `channels.telegram.retry`. See [Retry policy](/concepts/retry). ## Agent tool (messages + reactions) - Tool: `telegram` with `sendMessage` action (`to`, `content`, optional `mediaUrl`, `replyToMessageId`, `messageThreadId`). - Tool: `telegram` with `react` action (`chatId`, `messageId`, `emoji`). - Reaction removal semantics: see [/tools/reactions](/tools/reactions). -- Tool gating: `telegram.actions.reactions` and `telegram.actions.sendMessage` (default: enabled). +- Tool gating: `channels.telegram.actions.reactions` and `channels.telegram.actions.sendMessage` (default: enabled). ## Delivery targets (CLI/cron) - Use a chat id (`123456789`) or a username (`@name`) as the target. @@ -261,59 +271,59 @@ Outbound Telegram API calls retry on transient network/429 errors with exponenti ## Troubleshooting **Bot doesn’t respond to non-mention messages in a group:** -- If you set `telegram.groups.*.requireMention=false`, Telegram’s Bot API **privacy mode** must be disabled. +- If you set `channels.telegram.groups.*.requireMention=false`, Telegram’s Bot API **privacy mode** must be disabled. - BotFather: `/setprivacy` → **Disable** (then remove + re-add the bot to the group) -- `clawdbot providers status` shows a warning when config expects unmentioned group messages. -- `clawdbot providers status --probe` can additionally check membership for explicit numeric group IDs (it can’t audit wildcard `"*"` rules). +- `clawdbot channels status` shows a warning when config expects unmentioned group messages. +- `clawdbot channels status --probe` can additionally check membership for explicit numeric group IDs (it can’t audit wildcard `"*"` rules). - Quick test: `/activation always` (session-only; use config for persistence) **Bot not seeing group messages at all:** -- If `telegram.groups` is set, the group must be listed or use `"*"` +- If `channels.telegram.groups` is set, the group must be listed or use `"*"` - Check Privacy Settings in @BotFather → "Group Privacy" should be **OFF** - Verify bot is actually a member (not just an admin with no read access) - Check gateway logs: `clawdbot logs --follow` (look for "skipping group message") **Bot responds to mentions but not `/activation always`:** - The `/activation` command updates session state but doesn't persist to config -- For persistent behavior, add group to `telegram.groups` with `requireMention: false` +- For persistent behavior, add group to `channels.telegram.groups` with `requireMention: false` **Commands like `/status` don't work:** -- Make sure your Telegram user ID is authorized (via pairing or `telegram.allowFrom`) +- Make sure your Telegram user ID is authorized (via pairing or `channels.telegram.allowFrom`) - Commands require authorization even in groups with `groupPolicy: "open"` ## Configuration reference (Telegram) Full configuration: [Configuration](/gateway/configuration) Provider options: -- `telegram.enabled`: enable/disable provider startup. -- `telegram.botToken`: bot token (BotFather). -- `telegram.tokenFile`: read token from file path. -- `telegram.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). -- `telegram.allowFrom`: DM allowlist (ids/usernames). `open` requires `"*"`. -- `telegram.groupPolicy`: `open | allowlist | disabled` (default: allowlist). -- `telegram.groupAllowFrom`: group sender allowlist (ids/usernames). -- `telegram.groups`: per-group defaults + allowlist (use `"*"` for global defaults). - - `telegram.groups..requireMention`: mention gating default. - - `telegram.groups..skills`: skill filter (omit = all skills, empty = none). - - `telegram.groups..allowFrom`: per-group sender allowlist override. - - `telegram.groups..systemPrompt`: extra system prompt for the group. - - `telegram.groups..enabled`: disable the group when `false`. - - `telegram.groups..topics..*`: per-topic overrides (same fields as group). - - `telegram.groups..topics..requireMention`: per-topic mention gating override. -- `telegram.replyToMode`: `off | first | all` (default: `first`). -- `telegram.textChunkLimit`: outbound chunk size (chars). -- `telegram.streamMode`: `off | partial | block` (draft streaming). -- `telegram.mediaMaxMb`: inbound/outbound media cap (MB). -- `telegram.retry`: retry policy for outbound Telegram API calls (attempts, minDelayMs, maxDelayMs, jitter). -- `telegram.proxy`: proxy URL for Bot API calls (SOCKS/HTTP). -- `telegram.webhookUrl`: enable webhook mode. -- `telegram.webhookSecret`: webhook secret (optional). -- `telegram.webhookPath`: local webhook path (default `/telegram-webhook`). -- `telegram.actions.reactions`: gate Telegram tool reactions. -- `telegram.actions.sendMessage`: gate Telegram tool message sends. +- `channels.telegram.enabled`: enable/disable channel startup. +- `channels.telegram.botToken`: bot token (BotFather). +- `channels.telegram.tokenFile`: read token from file path. +- `channels.telegram.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). +- `channels.telegram.allowFrom`: DM allowlist (ids/usernames). `open` requires `"*"`. +- `channels.telegram.groupPolicy`: `open | allowlist | disabled` (default: allowlist). +- `channels.telegram.groupAllowFrom`: group sender allowlist (ids/usernames). +- `channels.telegram.groups`: per-group defaults + allowlist (use `"*"` for global defaults). + - `channels.telegram.groups..requireMention`: mention gating default. + - `channels.telegram.groups..skills`: skill filter (omit = all skills, empty = none). + - `channels.telegram.groups..allowFrom`: per-group sender allowlist override. + - `channels.telegram.groups..systemPrompt`: extra system prompt for the group. + - `channels.telegram.groups..enabled`: disable the group when `false`. + - `channels.telegram.groups..topics..*`: per-topic overrides (same fields as group). + - `channels.telegram.groups..topics..requireMention`: per-topic mention gating override. +- `channels.telegram.replyToMode`: `off | first | all` (default: `first`). +- `channels.telegram.textChunkLimit`: outbound chunk size (chars). +- `channels.telegram.streamMode`: `off | partial | block` (draft streaming). +- `channels.telegram.mediaMaxMb`: inbound/outbound media cap (MB). +- `channels.telegram.retry`: retry policy for outbound Telegram API calls (attempts, minDelayMs, maxDelayMs, jitter). +- `channels.telegram.proxy`: proxy URL for Bot API calls (SOCKS/HTTP). +- `channels.telegram.webhookUrl`: enable webhook mode. +- `channels.telegram.webhookSecret`: webhook secret (optional). +- `channels.telegram.webhookPath`: local webhook path (default `/telegram-webhook`). +- `channels.telegram.actions.reactions`: gate Telegram tool reactions. +- `channels.telegram.actions.sendMessage`: gate Telegram tool message sends. Related global options: - `agents.list[].groupChat.mentionPatterns` (mention gating patterns). - `messages.groupChat.mentionPatterns` (global fallback). -- `commands.native` (defaults to `"auto"` → on for Telegram/Discord, off for Slack), `commands.text`, `commands.useAccessGroups` (command behavior). Override with `telegram.commands.native`. +- `commands.native` (defaults to `"auto"` → on for Telegram/Discord, off for Slack), `commands.text`, `commands.useAccessGroups` (command behavior). Override with `channels.telegram.commands.native`. - `messages.responsePrefix`, `messages.ackReaction`, `messages.ackReactionScope`, `messages.removeAckAfterReply`. diff --git a/docs/channels/troubleshooting.md b/docs/channels/troubleshooting.md new file mode 100644 index 000000000..d40a92af2 --- /dev/null +++ b/docs/channels/troubleshooting.md @@ -0,0 +1,21 @@ +--- +summary: "Channel-specific troubleshooting shortcuts (Discord/Telegram/WhatsApp)" +read_when: + - A channel connects but messages don’t flow + - Investigating channel misconfiguration (intents, permissions, privacy mode) +--- +# Channel troubleshooting + +Start with: + +```bash +clawdbot doctor +clawdbot channels status --probe +``` + +`channels status --probe` prints warnings when it can detect common channel misconfigurations, and includes small live checks (credentials, some permissions/membership). + +## Channels +- Discord: [/channels/discord#troubleshooting](/channels/discord#troubleshooting) +- Telegram: [/channels/telegram#troubleshooting](/channels/telegram#troubleshooting) +- WhatsApp: [/channels/whatsapp#troubleshooting-quick](/channels/whatsapp#troubleshooting-quick) diff --git a/docs/providers/whatsapp.md b/docs/channels/whatsapp.md similarity index 76% rename from docs/providers/whatsapp.md rename to docs/channels/whatsapp.md index 4a2462fc9..1fc619c23 100644 --- a/docs/providers/whatsapp.md +++ b/docs/channels/whatsapp.md @@ -1,9 +1,9 @@ --- -summary: "WhatsApp (web provider) integration: login, inbox, replies, media, and ops" +summary: "WhatsApp (web channel) integration: login, inbox, replies, media, and ops" read_when: - - Working on WhatsApp/web provider behavior or inbox routing + - Working on WhatsApp/web channel behavior or inbox routing --- -# WhatsApp (web provider) +# WhatsApp (web channel) Status: WhatsApp Web via Baileys only. Gateway owns the session(s). @@ -11,15 +11,17 @@ Status: WhatsApp Web via Baileys only. Gateway owns the session(s). ## Quick setup (beginner) 1) Use a **separate phone number** if possible (recommended). 2) Configure WhatsApp in `~/.clawdbot/clawdbot.json`. -3) Run `clawdbot providers login` to scan the QR code (Linked Devices). +3) Run `clawdbot channels login` to scan the QR code (Linked Devices). 4) Start the gateway. Minimal config: ```json5 { - whatsapp: { - dmPolicy: "allowlist", - allowFrom: ["+15551234567"] + channels: { + whatsapp: { + dmPolicy: "allowlist", + allowFrom: ["+15551234567"] + } } } ``` @@ -44,17 +46,19 @@ Use a **separate phone number** for Clawdbot. Best UX, clean routing, no self-ch **WhatsApp Business:** You can use WhatsApp Business on the same device with a different number. Great for keeping your personal WhatsApp separate — install WhatsApp Business and register the Clawdbot number there. **Sample config (dedicated number, single-user allowlist):** -```json +```json5 { - "whatsapp": { - "dmPolicy": "allowlist", - "allowFrom": ["+15551234567"] + channels: { + whatsapp: { + dmPolicy: "allowlist", + allowFrom: ["+15551234567"] + } } } ``` **Pairing mode (optional):** -If you want pairing instead of allowlist, set `whatsapp.dmPolicy` to `pairing`. Unknown senders get a pairing code; approve with: +If you want pairing instead of allowlist, set `channels.whatsapp.dmPolicy` to `pairing`. Unknown senders get a pairing code; approve with: `clawdbot pairing approve whatsapp ` ### Personal number (fallback) @@ -96,13 +100,13 @@ on outbound replies. - Result: unreliable delivery and frequent blocks, so support was removed. ## Login + credentials -- Login command: `clawdbot providers login` (QR via Linked Devices). -- Multi-account login: `clawdbot providers login --account ` (`` = `accountId`). +- Login command: `clawdbot channels login` (QR via Linked Devices). +- Multi-account login: `clawdbot channels login --account ` (`` = `accountId`). - Default account (when `--account` is omitted): `default` if present, otherwise the first configured account id (sorted). - Credentials stored in `~/.clawdbot/credentials/whatsapp//creds.json`. - Backup copy at `creds.json.bak` (restored on corruption). - Legacy compatibility: older installs stored Baileys files directly in `~/.clawdbot/credentials/`. -- Logout: `clawdbot providers logout` (or `--account `) deletes WhatsApp auth state (but keeps shared `oauth.json`). +- Logout: `clawdbot channels logout` (or `--account `) deletes WhatsApp auth state (but keeps shared `oauth.json`). - Logged-out socket => error instructs re-link. ## Inbound flow (DM + group) @@ -110,17 +114,17 @@ on outbound replies. - Inbox listeners are detached on shutdown to avoid accumulating event handlers in tests/restarts. - Status/broadcast chats are ignored. - Direct chats use E.164; groups use group JID. -- **DM policy**: `whatsapp.dmPolicy` controls direct chat access (default: `pairing`). +- **DM policy**: `channels.whatsapp.dmPolicy` controls direct chat access (default: `pairing`). - Pairing: unknown senders get a pairing code (approve via `clawdbot pairing approve whatsapp `; codes expire after 1 hour). - - Open: requires `whatsapp.allowFrom` to include `"*"`. - - Self messages are always allowed; “self-chat mode” still requires `whatsapp.allowFrom` to include your own number. + - Open: requires `channels.whatsapp.allowFrom` to include `"*"`. + - Self messages are always allowed; “self-chat mode” still requires `channels.whatsapp.allowFrom` to include your own number. ### Personal-number mode (fallback) -If you run Clawdbot on your **personal WhatsApp number**, enable `whatsapp.selfChatMode` (see sample above). +If you run Clawdbot on your **personal WhatsApp number**, enable `channels.whatsapp.selfChatMode` (see sample above). Behavior: - Outbound DMs never trigger pairing replies (prevents spamming contacts). -- Inbound unknown senders still follow `whatsapp.dmPolicy`. +- Inbound unknown senders still follow `channels.whatsapp.dmPolicy`. - Self-chat mode (allowFrom includes your number) avoids auto read receipts and ignores mention JIDs. - Read receipts sent for non-self-chat DMs. @@ -133,13 +137,13 @@ No. Default DM policy is **pairing**, so unknown senders only get a pairing code Pairing is a DM gate for unknown senders: - First DM from a new sender returns a short code (message is not processed). - Approve with: `clawdbot pairing approve whatsapp ` (list with `clawdbot pairing list whatsapp`). -- Codes expire after 1 hour; pending requests are capped at 3 per provider. +- Codes expire after 1 hour; pending requests are capped at 3 per channel. **Can multiple people use different Clawdbots on one WhatsApp number?** Yes, by routing each sender to a different agent via `bindings` (peer `kind: "dm"`, sender E.164 like `+15551234567`). Replies still come from the **same WhatsApp account**, and direct chats collapse to each agent’s main session, so use **one agent per person**. DM access control (`dmPolicy`/`allowFrom`) is global per WhatsApp account. See [Multi-Agent Routing](/concepts/multi-agent). **Why do you ask for my phone number in the wizard?** -The wizard uses it to set your **allowlist/owner** so your own DMs are permitted. It’s not used for auto-sending. If you run on your personal WhatsApp number, use that same number and enable `whatsapp.selfChatMode`. +The wizard uses it to set your **allowlist/owner** so your own DMs are permitted. It’s not used for auto-sending. If you run on your personal WhatsApp number, use that same number and enable `channels.whatsapp.selfChatMode`. ## Message normalization (what the model sees) - `Body` is the current message body with envelope. @@ -158,12 +162,12 @@ The wizard uses it to set your **allowlist/owner** so your own DMs are permitted ## Groups - Groups map to `agent::whatsapp:group:` sessions. -- Group policy: `whatsapp.groupPolicy = open|disabled|allowlist` (default `allowlist`). +- Group policy: `channels.whatsapp.groupPolicy = open|disabled|allowlist` (default `allowlist`). - Activation modes: - `mention` (default): requires @mention or regex match. - `always`: always triggers. - `/activation mention|always` is owner-only and must be sent as a standalone message. -- Owner = `whatsapp.allowFrom` (or self E.164 if unset). +- Owner = `channels.whatsapp.allowFrom` (or self E.164 if unset). - **History injection**: - Recent messages (default 50) inserted under: `[Chat messages since your last reply - for context]` @@ -174,7 +178,7 @@ The wizard uses it to set your **allowlist/owner** so your own DMs are permitted ## Reply delivery (threading) - WhatsApp Web sends standard messages (no quoted reply threading in the current gateway). -- Reply tags are ignored on this provider. +- Reply tags are ignored on this channel. ## Acknowledgment reactions (auto-react on receipt) @@ -223,22 +227,22 @@ WhatsApp can automatically send emoji reactions to incoming messages immediately - In groups with `requireMention: false` (activation: always), `group: "mentions"` will react to all messages (not just @mentions). - Fire-and-forget: reaction failures are logged but don't prevent the bot from replying. - Participant JID is automatically included for group reactions. -- WhatsApp ignores `messages.ackReaction`; use `whatsapp.ackReaction` instead. +- WhatsApp ignores `messages.ackReaction`; use `channels.whatsapp.ackReaction` instead. ## Agent tool (reactions) - Tool: `whatsapp` with `react` action (`chatJid`, `messageId`, `emoji`, optional `remove`). - Optional: `participant` (group sender), `fromMe` (reacting to your own message), `accountId` (multi-account). - Reaction removal semantics: see [/tools/reactions](/tools/reactions). -- Tool gating: `whatsapp.actions.reactions` (default: enabled). +- Tool gating: `channels.whatsapp.actions.reactions` (default: enabled). ## Limits -- Outbound text is chunked to `whatsapp.textChunkLimit` (default 4000). -- Inbound media saves are capped by `whatsapp.mediaMaxMb` (default 50 MB). +- Outbound text is chunked to `channels.whatsapp.textChunkLimit` (default 4000). +- Inbound media saves are capped by `channels.whatsapp.mediaMaxMb` (default 50 MB). - Outbound media items are capped by `agents.defaults.mediaMaxMb` (default 5 MB). ## Outbound send (text + media) - Uses active web listener; error if gateway not running. -- Text chunking: 4k max per message (configurable via `whatsapp.textChunkLimit`). +- Text chunking: 4k max per message (configurable via `channels.whatsapp.textChunkLimit`). - Media: - Image/video/audio/document supported. - Audio sent as PTT; `audio/ogg` => `audio/ogg; codecs=opus`. @@ -258,7 +262,7 @@ WhatsApp can automatically send emoji reactions to incoming messages immediately - **Gateway heartbeat** logs connection health (`web.heartbeatSeconds`, default 60s). - **Agent heartbeat** is global (`agents.defaults.heartbeat.*`) and runs in the main session. - Uses the configured heartbeat prompt (default: `Read HEARTBEAT.md if exists. Consider outstanding tasks. Checkup sometimes on your human during (user local) day time.`) + `HEARTBEAT_OK` skip behavior. - - Delivery defaults to the last used provider (or configured target). + - Delivery defaults to the last used channel (or configured target). ## Reconnect behavior - Backoff policy: `web.reconnect`: @@ -267,22 +271,22 @@ WhatsApp can automatically send emoji reactions to incoming messages immediately - Logged-out => stop and require re-link. ## Config quick map -- `whatsapp.dmPolicy` (DM policy: pairing/allowlist/open/disabled). -- `whatsapp.selfChatMode` (same-phone setup; bot uses your personal WhatsApp number). -- `whatsapp.allowFrom` (DM allowlist). -- `whatsapp.mediaMaxMb` (inbound media save cap). -- `whatsapp.ackReaction` (auto-reaction on message receipt: `{emoji, direct, group}`). -- `whatsapp.accounts..*` (per-account settings + optional `authDir`). -- `whatsapp.accounts..mediaMaxMb` (per-account inbound media cap). -- `whatsapp.accounts..ackReaction` (per-account ack reaction override). -- `whatsapp.groupAllowFrom` (group sender allowlist). -- `whatsapp.groupPolicy` (group policy). -- `whatsapp.historyLimit` / `whatsapp.accounts..historyLimit` (group history context; `0` disables). -- `whatsapp.groups` (group allowlist + mention gating defaults; use `"*"` to allow all) -- `whatsapp.actions.reactions` (gate WhatsApp tool reactions). +- `channels.whatsapp.dmPolicy` (DM policy: pairing/allowlist/open/disabled). +- `channels.whatsapp.selfChatMode` (same-phone setup; bot uses your personal WhatsApp number). +- `channels.whatsapp.allowFrom` (DM allowlist). +- `channels.whatsapp.mediaMaxMb` (inbound media save cap). +- `channels.whatsapp.ackReaction` (auto-reaction on message receipt: `{emoji, direct, group}`). +- `channels.whatsapp.accounts..*` (per-account settings + optional `authDir`). +- `channels.whatsapp.accounts..mediaMaxMb` (per-account inbound media cap). +- `channels.whatsapp.accounts..ackReaction` (per-account ack reaction override). +- `channels.whatsapp.groupAllowFrom` (group sender allowlist). +- `channels.whatsapp.groupPolicy` (group policy). +- `channels.whatsapp.historyLimit` / `channels.whatsapp.accounts..historyLimit` (group history context; `0` disables). +- `channels.whatsapp.groups` (group allowlist + mention gating defaults; use `"*"` to allow all) +- `channels.whatsapp.actions.reactions` (gate WhatsApp tool reactions). - `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) - `messages.groupChat.historyLimit` -- `whatsapp.messagePrefix` (inbound prefix; per-account: `whatsapp.accounts..messagePrefix`; deprecated: `messages.messagePrefix`) +- `channels.whatsapp.messagePrefix` (inbound prefix; per-account: `channels.whatsapp.accounts..messagePrefix`; deprecated: `messages.messagePrefix`) - `messages.responsePrefix` (outbound prefix) - `agents.defaults.mediaMaxMb` - `agents.defaults.heartbeat.every` @@ -290,7 +294,7 @@ WhatsApp can automatically send emoji reactions to incoming messages immediately - `agents.defaults.heartbeat.target` - `agents.defaults.heartbeat.to` - `session.*` (scope, idle, store, mainKey) -- `web.enabled` (disable provider startup when false) +- `web.enabled` (disable channel startup when false) - `web.heartbeatSeconds` - `web.reconnect.*` @@ -302,12 +306,12 @@ WhatsApp can automatically send emoji reactions to incoming messages immediately ## Troubleshooting (quick) **Not linked / QR login required** -- Symptom: `providers status` shows `linked: false` or warns “Not linked”. -- Fix: run `clawdbot providers login` on the gateway host and scan the QR (WhatsApp → Settings → Linked Devices). +- Symptom: `channels status` shows `linked: false` or warns “Not linked”. +- Fix: run `clawdbot channels login` on the gateway host and scan the QR (WhatsApp → Settings → Linked Devices). **Linked but disconnected / reconnect loop** -- Symptom: `providers status` shows `running, disconnected` or warns “Linked but disconnected”. -- Fix: `clawdbot doctor` (or restart the gateway). If it persists, relink via `providers login` and inspect `clawdbot logs --follow`. +- Symptom: `channels status` shows `running, disconnected` or warns “Linked but disconnected”. +- Fix: `clawdbot doctor` (or restart the gateway). If it persists, relink via `channels login` and inspect `clawdbot logs --follow`. **Bun runtime** - Bun is **not recommended**. WhatsApp (Baileys) and Telegram are unreliable on Bun. diff --git a/docs/cli/index.md b/docs/cli/index.md index 24ffe0f3e..63c92bc4b 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -51,7 +51,7 @@ clawdbot [--dev] [--profile ] reset uninstall update - providers + channels list status logs @@ -257,8 +257,8 @@ Options: - `--tailscale-reset-on-exit` - `--install-daemon` - `--no-install-daemon` (alias: `--skip-daemon`) -- `--daemon-runtime ` (bun not recommended for WhatsApp/Telegram) -- `--skip-providers` +- `--daemon-runtime ` +- `--skip-channels` - `--skip-skills` - `--skip-health` - `--skip-ui` @@ -266,7 +266,7 @@ Options: - `--json` ### `configure` / `config` -Interactive configuration wizard (models, providers, skills, gateway). +Interactive configuration wizard (models, channels, skills, gateway). ### `doctor` Health checks + quick fixes (config + gateway + legacy services). @@ -277,41 +277,41 @@ Options: - `--non-interactive`: skip prompts; apply safe migrations only. - `--deep`: scan system services for extra gateway installs. -## Provider helpers +## Channel helpers -### `providers` -Manage chat provider accounts (WhatsApp/Telegram/Discord/Slack/Signal/iMessage/MS Teams). +### `channels` +Manage chat channel accounts (WhatsApp/Telegram/Discord/Slack/Signal/iMessage/MS Teams). Subcommands: -- `providers list`: show configured chat providers and auth profiles (Claude Code + Codex CLI OAuth sync included). -- `providers status`: check gateway reachability and provider health (`--probe` runs extra checks; use `clawdbot health` or `clawdbot status --deep` for gateway health probes). -- Tip: `providers status` prints warnings with suggested fixes when it can detect common misconfigurations (then points you to `clawdbot doctor`). -- `providers logs`: show recent provider logs from the gateway log file. -- `providers add`: wizard-style setup when no flags are passed; flags switch to non-interactive mode. -- `providers remove`: disable by default; pass `--delete` to remove config entries without prompts. -- `providers login`: interactive provider login (WhatsApp Web only). -- `providers logout`: log out of a provider session (if supported). +- `channels list`: show configured channels and auth profiles (Claude Code + Codex CLI OAuth sync included). +- `channels status`: check gateway reachability and channel health (`--probe` runs extra checks; use `clawdbot health` or `clawdbot status --deep` for gateway health probes). +- Tip: `channels status` prints warnings with suggested fixes when it can detect common misconfigurations (then points you to `clawdbot doctor`). +- `channels logs`: show recent channel logs from the gateway log file. +- `channels add`: wizard-style setup when no flags are passed; flags switch to non-interactive mode. +- `channels remove`: disable by default; pass `--delete` to remove config entries without prompts. +- `channels login`: interactive channel login (WhatsApp Web only). +- `channels logout`: log out of a channel session (if supported). Common options: -- `--provider `: `whatsapp|telegram|discord|slack|signal|imessage|msteams` -- `--account `: provider account id (default `default`) +- `--channel `: `whatsapp|telegram|discord|slack|signal|imessage|msteams` +- `--account `: channel account id (default `default`) - `--name