chat-platform¶
Writing a bot that reads a Discord channel should not put a Discord SDK in your dependency graph, and supporting Slack later should not mean a second code path.
This module is the contract. Providers live in their own modules and register themselves, so your code depends on an interface and never on a gateway client.
c, _ := chatplatform.NewClient(ctx, "discord", chatplatform.ClientConfig{
Token: tok,
Needs: []chatplatform.Need{chatplatform.NeedMessages},
})
defer c.Close()
p, _ := c.Provider(ctx, guild, chatplatform.WithAllowedChannels(chans...))
for msg := range p.Reader.Messages() {
p.Actor.ReplyInThread(ctx, msg.Ref(), "help", answer)
}
Where to start¶
- Getting started — read a channel and reply in a thread, in about thirty lines.
- Get a moderator's approval before the bot posts — buttons, a prefilled form and a human gate, end to end.
- Author a provider — for a platform not covered yet, shipped as your own module.
- Declare a command surface — typed arguments and subcommands, with a bad spec refused before anything connects.
- Read command arguments — which subcommand ran, and telling a resolved identifier from text somebody typed.
- Run the conformance harness — check the behaviour the compiler cannot.
Look something up¶
- Providers — what exists, and exactly how the Discord provider behaves.
- Configuration —
ClientConfigandScopefield by field, everyNeedand what declaring one costs. - The provider registry —
Register,Lookup,Registered,NewClientand theFactorya provider supplies. - Reader, Actor and the value types — the two core interfaces, method by method.
- Capability interfaces — the ten optional
interfaces, the spec types, and what
Validaterejects. - Errors — every sentinel, which call returns it, and what to do about it.
- Conformance harness — every check it runs, and what it does not.
What this does not do¶
Plain channel posts, attachments, direct messages, channel history, retries, logging and delivery guarantees are all deliberately absent, and each absence is load-bearing.
What this contract does not do is the page to read before planning anything around this module.
Design in four points¶
- Reading and acting are separate. Ask
for read-only and there is no
Actorat all, so shadow mode is enforced by the type system rather than by remembering to check a flag. - Capabilities are opt-in. Moderation, member lookup, interactive components and slash commands are optional interfaces found by type assertion. A read-only bridge with none of them is a legitimate provider.
- Reconnect losses are surfaced. A reconnect
that restarted the session rather than resuming dropped every message during
the gap — with no error and nothing to notice.
ConnStatesays so. - No vendor SDK in the core. This module has no third-party dependencies at all, and a guard test keeps it that way.
Further reading¶
Everything written about the estate, including the curated guides, is on the blog.
Ask phpbotscout

He answers questions about the projects over on the Discord, citing the docs where they already cover it, and offering to raise an issue where they don't. Bring a bug, an idea, or a questionable engineering decision.