Gateway
PilotDeck ships with 16+ chat platform channels, all toggled by the adapters.<name> block in ~/.pilotdeck/pilotdeck.yaml. This page covers what to put in the YAML and how to start, nothing more.
Same launch command for everything:
cd /path/to/PilotDeck
npm install
npm run server
Feishu / Lark (Recommended)
PilotDeck defaults to Stream Mode: it opens an outbound WSS to the Lark cloud — no public URL, no ngrok, no reverse proxy required.
1. Lark Developer Console
In Lark Open Platform (or Lark international) create a self-built application:
| Step | What matters |
|---|---|
| Credentials | Note the App ID (cli_xxx) and App Secret |
| Events & Callbacks → Subscription Mode | Pick "Persistent connection" (NOT Webhook) |
| Event subscriptions | Add im.message.receive_v1 |
| Permissions | im:message, im:message:send_as_bot, im:chat:readonly |
| Versions & Releases | Create a version and publish, otherwise the bot won't receive any events |
Marketplace apps don't support persistent connections — they have to use Webhook mode (see bottom).
2. YAML
adapters:
feishu:
enabled: true
appId: cli_xxxxxxxxxxxx
appSecret: xxxxxxxxxxxxxxxxxxxxxxxx
defaultSessionLabel: default
# domainName: lark # Use 'lark' for the international edition (default 'feishu')
When you see feishu: stream mode connected (appId=...) in the startup log, you're ready — go @-mention the bot in Lark.
WeChat (iLink Bot)
Requires being on the ClawBot beta allowlist. The WeChat channel is disabled by default to prevent stray QR-login flows on machines without access.
YAML
adapters:
weixin:
enabled: true # Required — without this WeixinChannel is never instantiated
No other credentials needed: at startup the terminal prints a QR-login URL, scan with an allowlisted WeChat account, and credentials get cached at ~/.pilotdeck/weixin-credentials.json for subsequent runs. Send /new to start a fresh session; delete the credentials file to force re-login.
QQ Official Bot
Connects to the QQ Official Bot Gateway over WSS. Both group chats and DMs are supported. Currently configured via environment variables (not YAML).
1. QQ Developer Console
In q.qq.com create a bot, grab AppId / AppSecret, and subscribe to:
GROUP_AT_MESSAGE_CREATE— bot is @-mentioned in a groupC2C_MESSAGE_CREATE— direct message to bot
2. Launch
export QQ_BOT_APPID=102xxxxxxx
export QQ_BOT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxx
# Optional: restrict to specific groups
# export QQ_ALLOW_GROUPS=GROUP_OPENID_A,GROUP_OPENID_B
npm run server
When you see qq: authenticated, listening for group messages, the bot is online.
During the sandbox phase the bot only responds in your designated test groups; after store approval it can serve any group.
Other Platforms (One-Block YAML)
Telegram, Discord, Slack, Matrix, Mattermost, Signal, WhatsApp, BlueBubbles, DingTalk, WeCom, Email, SMS, HomeAssistant, ApiServer, and Webhook — 16 channels in total — all share the same schema:
adapters:
<name>:
enabled: true
token: xxx # Most platforms use a token
apiKey: xxx # Some platforms
webhookUrl: https://... # Some platforms
extra:
# Platform-specific fields (e.g. Slack's appToken, Matrix's homeserver)
The exact fields are wired in src/adapters/channel/loadEnabledChannels.ts. Common examples:
Telegram
adapters:
telegram:
enabled: true
token: 123456:ABC... # From @BotFather
Discord
adapters:
discord:
enabled: true
token: NTk3... # Discord Developer Portal → Bot → Token
Slack
adapters:
slack:
enabled: true
token: xoxb-... # Bot User OAuth Token
extra:
appToken: xapp-... # Socket Mode app-level token
DingTalk Stream
adapters:
dingtalk:
enabled: true
extra:
clientId: dingxxxxxxxx
clientSecret: xxxxxxxxxxxxxxxxxxxxxxxx
Matrix
adapters:
matrix:
enabled: true
token: syt_... # access token
extra:
homeserver: https://matrix.org
userId: "@bot:matrix.org"
Each channel implementation lives in src/adapters/channel/<name>/ as a trio: <Name>Channel.ts + <Name>SessionMapper.ts + <name>-render.ts.
Conventions That Apply Everywhere
| Behavior | Notes |
|---|---|
/new | A user typing /new in any channel starts a fresh session; /new hello opens the new session and uses hello as the first message |
| Session keys | Format <channel>:chat=<id>:general or <channel>:chat=<id>:s_<uuid> |
| Concurrency guard | While a turn is running for a chat, new messages from the same chat are dropped (avoids out-of-order replies) |
| Logging | Each channel prints <channel>: ready / <channel>: connected at startup; if you don't see it the channel isn't enabled or the credentials are wrong |
Webhook Mode (Feishu Fallback)
If your Feishu app is a marketplace app and must use webhooks:
adapters:
feishu:
enabled: true
connectionMode: webhook
appId: cli_xxx
appSecret: xxx
encryptKey: xxx # Only if encryption is enabled in the Lark console
verifyToken: xxx # Only if verification token is enabled
Point your Feishu console "Event Subscription URL" at https://<your-tunnel>/feishu/webhook. PilotDeck handles url_verification, AES-256-CBC encrypted events, and event_id deduplication automatically.