An opinionated, minimalistic Discord bot orchestration library for sending and receiving messages across multiple bot accounts sharing common channels.
- Multi-bot orchestration — run multiple bot accounts in a single session, automatically intersecting their accessible channels
- Event-driven message matching — register filters (
contains,starts_with, or custom closures) and receive matching messages through typed receivers - Message replies and reactions — send messages, reply to specific messages, and attach emoji reactions (Unicode or custom guild emojis)
- Resilient pipeline — configurable backoff delays, send timeouts, retry jitter, and automatic reconnection handling on disconnection
- Python bindings — full API exposed via PyO3/maturin with async support
Add the dependency:
[dependencies]
dischorus = { git = "https://github.com/oteffahi/dischorus" }Set your bot token in a .env file:
DISCORD_TOKEN=your_bot_token_here
use dischorus::{
PipelineConfig,
message::{Message, MessageEvent, Reaction, ReactionEmoji},
session::SessionBuilder,
};
#[tokio::main]
async fn main() {
dischorus::logging::init_logs_from_env_or("info");
let mut builder = SessionBuilder::new();
let bot = builder.add_user("DISCORD_TOKEN");
let session = builder
.build(PipelineConfig::new(100).delays(500, 1000))
.await
.unwrap();
let receiver = session
.register_event(MessageEvent::contains("ping"))
.capacity(50)
.channel_timeout(10_000)
.await;
let wave = Reaction::new(bot, ReactionEmoji::unicode("👋"));
while let Ok(event) = receiver.recv_async().await {
session
.schedule_message(
Message::reply(event.message_id(), bot, "pong")
.reactions(vec![wave.clone()]),
)
.await
.unwrap();
}
}uv add "dischorus @ git+https://github.com/oteffahi/dischorus#subdirectory=python"Or install manually from a clone:
git clone https://github.com/oteffahi/dischorus
cd dischorus/python
uv run maturin developSet your bot token in a .env file:
DISCORD_TOKEN=your_bot_token_here
import asyncio
import dischorus
async def main():
dischorus.init_logs("info")
builder = dischorus.SessionBuilder()
bot = builder.add_user("DISCORD_TOKEN")
session = await builder.build(
dischorus.PipelineConfig.new(100, delays=(500, 1000))
)
receiver = await session.register_event(
dischorus.MessageEvent.contains("ping"),
capacity=50,
channel_timeout_ms=10000,
)
wave = dischorus.Reaction.new(bot, dischorus.ReactionEmoji.unicode("👋"))
while True:
event = await receiver.recv()
if event is None:
break
msg = dischorus.Message.reply(event.message_id(), bot, "pong", reactions=[wave])
await session.schedule_message(msg)
asyncio.run(main())This project is licensed under the MIT License.