Chat Channel Capability Matrix
chat-channels specs/chat-channels/capability-matrix.kmd
Canonical feature surface that every Koder bot chat channel (Telegram, WhatsApp, WebChat, Signal, Google Chat, Koder Chat, and future) must declare via `Channel.Capabilities()`. The matrix in `meta/docs/stack/registries/chat-channels-parity.md` audits the current state across the implemented channels.
Quando esta spec se aplica
Todos os triggers
- Adicionar nova plataforma de chat ao bot-server
- Implementar feature cross-channel (multimodal history, model override, CI tool, etc.)
- Auditar paridade entre os canais existentes
Corpo da especificação
Spec: Chat Channel Capability Matrix
Defines the contract every concrete chat channel adapter under
core/bot-server/internal/channel/ must honor. Each channel
implementation reports its real support level via the
Capabilities() Capabilities method on the Channel interface.
The Koder bot-server runtime uses these capabilities to:
- Route tools that depend on platform features (e.g.
set_chat_photoonly fires on channels withAdmin.SetPhoto = true). - Skip multimodal history re-injection on channels without
Receive.Image(#010). - Decide whether to send progress updates as edits or new messages
(#015) based on
Send.EditMessage. - Lint the actual implementations against the parity registry — drift must surface as a CI failure, not a runtime surprise.
1 — Capability categories
A channel's capabilities are grouped into seven domains. Each domain
contains a small, closed list of named features. Adding a feature
requires updating both this spec and the Capabilities struct in
internal/channel/channel.go in the same change.
1.1 — Receive (inbound message kinds)
| Feature | Wire type the channel can receive from a user |
|---|---|
Text |
Plain or formatted text message |
Image |
Photo / static image |
Video |
Video file (MP4, MOV, WebM) |
Audio |
Audio file (MP3, M4A, AAC) — distinct from voice notes |
Voice |
Push-to-talk voice note (Opus/OGG on Telegram) |
Document |
Arbitrary file attachment |
Location |
Geo-coordinates (lat/lon) |
Contact |
vCard / shared phone number |
Sticker |
Sticker / GIF / animated reaction sticker |
ReplyThread |
Quote-and-reply with parent-id preserved |
Edit |
Inbound edit of a previous message |
Reaction |
Emoji reaction on a message |
1.2 — Send (outbound rendering)
| Feature | What the channel can deliver back to the user |
|---|---|
Text |
Plain text — every channel must support this; required |
Image, Video, Audio, Voice, Document, Location, Sticker |
Mirror of Receive set |
MarkdownFormatting |
Bold, italic, inline code, code block, lists |
EditMessage |
In-place edit of a previously-sent bot message (gates real progress, #015) |
DeleteMessage |
Delete a previously-sent bot message |
Typing |
Transient "typing…" indicator (TypingSender interface) |
Thinking |
Persistent "thinking…" message with cleanup (ThinkingIndicator interface) |
1.3 — Admin (chat administration)
| Feature | Capability |
|---|---|
SetPhoto |
Change chat avatar (BOTSRV-008) |
SetTitle |
Change chat title |
SetDescription |
Change chat description / topic |
AddMember, RemoveMember |
Membership management |
Promote, Demote |
Role assignment |
ListMembers |
Enumerate participants |
Leave |
Bot can leave the chat |
1.4 — Identity (who is sending)
| Feature | Field exposed |
|---|---|
UserName |
Display name |
UserEmail |
Email address — Telegram = no, Google Chat = yes |
UserAvatarURL |
Profile picture URL |
ChatTitle |
Group/channel title |
ChatType |
private / group / supergroup / channel |
MemberCount |
Number of members in chat |
1.5 — History (persistence semantics)
| Feature | Behavior |
|---|---|
PassiveLogging |
Persists messages from approved chats even when the agent does not respond (#011). Required for "leia o histórico" to work |
MultimodalHistory |
Carries attachments forward across turns when the LLM backend is multimodal (#010) |
1.6 — Commands (built-in / bot-driven)
| Command | Status |
|---|---|
/clear |
Required if Admin.DeleteMessage is true |
/help |
Required — every channel honors |
/status |
Required — health summary (see #013-adjacent) |
/model |
Required when bot supports per-session model override (#013) |
/keyboard |
Optional — channel-specific quick-reply rendering |
/setavatar |
Optional — only when Admin.SetPhoto is true |
1.7 — Gate (access control)
| Feature | Behavior |
|---|---|
InviteCode |
First-time DM gated by invite code |
ApprovedChatList |
Group chats explicitly opted-in by admin |
OwnerOnly |
Restricted to a specific user-id (KODE_OWNER_USER_ID) |
PublicByDefault |
No gate — every visitor can interact |
2 — Capabilities struct
Concrete shape lives in core/bot-server/internal/channel/capabilities.go
(introduced by #009 implementation). A channel returns a value with
the booleans set to its real support level — the runtime never reads
or assumes anything beyond what the channel declares.
type Capabilities struct {
Receive ReceiveCapabilities
Send SendCapabilities
Admin AdminCapabilities
Identity IdentityCapabilities
History HistoryCapabilities
Commands CommandsCapabilities
Gate GateCapabilities
}
Each domain is a struct of named bools. New features extend the struct (additive change, never reorder).
3 — Required vs recommended
Required (every channel MUST set true):
Send.Text— without this the bot is silent.Identity.UserName— without name, gate flow breaks.Gate.PublicByDefaultOR (Gate.InviteCodeANDGate.ApprovedChatList) — must declare some access model.Commands./help— entry point for users who don't know what to do.
Recommended (channel SHOULD support if the platform allows):
Send.MarkdownFormatting,Send.EditMessage,Send.TypingReceive.Image,Receive.Document,Receive.VoiceHistory.PassiveLogging(required for groups),History.MultimodalHistory(required whenReceive.Image=true)
Platform-dependent (declared per-channel, no global default):
Admin.*— only platforms that grant bots admin privilegesIdentity.UserEmail— only platforms with verified emailReceive.Reaction,Receive.Edit— only platforms that surface those events to bots
4 — Compliance audit
Audit lives in meta/docs/stack/registries/chat-channels-parity.md,
one row per channel × one column per feature. CI enforcement (#009
acceptance criterion 3) runs the audit on every PR via
koder-housekeep:
- For each channel implementation, instantiate it with mock config.
- Call
Capabilities(), serialize to a deterministic JSON shape. - Compare against the registry's recorded shape.
- Fail if drift detected.
This makes the registry a single source of truth that drifts
visibly when a channel's Capabilities() changes — preventing the
silent skew that motivated this spec (the 08/05 Telegram group test).
5 — Adding a new channel
When introducing a new platform (#016 adds Signal / Google Chat / Koder Chat), the implementer:
- Reads this spec + the registry to know the canonical surface.
- Writes the channel impl honoring
Channel.Capabilities(). - Adds a row to the registry with the supported features.
- Runs the housekeep audit; CI must be green.
- Documents auth setup in
meta/docs/stack/modules/core-bot-server.md.
A channel may declare a feature false and ship — that is honest.
What a channel must not do is declare a feature true while the
implementation either crashes or silently no-ops on that path. The
audit catches mismatches between declaration and behavior via the
test fixtures referenced in Capabilities() itself.
Referências
core/bot-server/backlog/pending/009-channel-capability-spec.mdmeta/docs/stack/registries/chat-channels-parity.mdcore/bot-server/internal/channel/channel.go