Channel adapters
Built-in adapters, auth shapes, capabilities
| Adapter | Auth | Transport | Public URL? | Notes |
|---|---|---|---|---|
slack-bot | bot token + app token | Socket Mode | no | standard intent-shaped wiring |
discord-bot | bot token | gateway intents | no | |
telegram-bot | bot token | long polling | no | |
github | fine-grained PAT, or GitHub App (appId + privateKey; installations auto-resolved per repo) | webhook delivery | yes | pairs with a tunnel for inbound webhooks |
kakaotalk | sub-device login (email + password, stored encrypted) | LOCO protocol | no | survives 7-day token expiry via host-side renewal cron |
channels.<adapter> shape
{
"channels": {
"slack-bot": {
"enabled": true,
"quotedReply": { "enabled": true, "queueDelayMs": 10000 }
},
"discord-bot": { "enabled": true },
"telegram-bot": { "enabled": true },
"github": {
"enabled": true,
"webhookPort": 8975,
"webhookUrl": "https://hooks.example.com/github"
},
"kakaotalk": { "enabled": true }
}
}| Field | Adapters | Notes |
|---|---|---|
enabled | all | live-reloadable |
quotedReply | all | auto-anchor delayed replies with a > @author: … blockquote prefix; defaults to on, 10s |
quotedReply.enabled | all | set false to never prepend the anchor |
quotedReply.queueDelayMs | all | reply delay threshold in ms; 0 anchors every reply, large values anchor only very late replies |
webhookPort | github | container-side port the webhook server listens on; default 8975 |
webhookUrl | github | optional override; when omitted, the URL comes from a channel-owned tunnel |
Credentials live in secrets.json#channels.<adapter> (/reference/secrets-json).
CLI verbs
typeclaw channel add <adapter> # interactive
typeclaw channel set <adapter> # rotate credentials (not KakaoTalk)
typeclaw channel reauth kakaotalk # KakaoTalk-specific re-login flowRouting model
When a message arrives:
- The adapter publishes it to the in-process message stream with a
(adapter, workspace, chat, thread, authorId)coordinate. - The channel router gates the message on
channel.respondpermission (/concepts/permissions-model). No permission → silent drop. - A session is created (or resumed) for that coordinate.
- Outgoing tool calls (
channel_send,channel_reply) flow back through the adapter.
The router never blocks on a slow adapter. Each adapter owns its own outbound queue.
When the agent's first send of a turn lands later than quotedReply.queueDelayMs after the inbound was received, OR the channel had observed messages between the inbound and the reply, the router prepends a single-line > @author: excerpt markdown blockquote referencing the inbound so the user can see which message the reply is anchored to even after the channel has scrolled. Slack and Discord get platform-native <@authorId> mentions inside the quote; Telegram, KakaoTalk, and GitHub fall back to plain author names because they have no reliable id-only mention syntax inside markdown. Anchoring is first-send-only per turn — multi-part replies don't repeat the quote on every chunk.
Per-adapter quirks
| Adapter | Quirk |
|---|---|
slack-bot | threads stay sticky — replies in the same thread route to the same session. Bot token needs reactions:write for channel_react and the auto-:eyes: engage reaction; without it Slack returns missing_scope on every engaged message. See the manifest in Add a channel for the full scope list |
discord-bot | requires MESSAGE_CONTENT intent enabled in the Discord developer portal; bot must be invited to a server with bot + applications.commands scopes and the recommended permission bitfield 277025508416 before it can receive anything (channel add discord-bot prints a ready-to-click invite URL with this value pre-filled) |
telegram-bot | long polling means no public URL, but only one process can poll a given bot token at a time |
github | adapter restarts on tunnel URL change and re-registers the webhook automatically. Reviews fire only on an explicit review_requested event — in PAT mode the bot is a real user requested by its login; in GitHub App mode the App can't be a requested_reviewer, so you request its decoy user account instead (GitHub decoy reviewer). Team-reviewer requests are honored when the bot is a member of the requested team. |
kakaotalk | LOCO clients hold the current token in a closure; token renewal triggers a container restart via the host daemon |
To invite the discord-bot by hand, substitute your application ID into:
https://discord.com/oauth2/authorize?client_id=YOUR_APP_ID&scope=bot+applications.commands&permissions=277025508416