Discord daemon with per-channel hooks. UNIX philosophy for Discord bots.
One daemon, many hooks. Each Discord channel routes to its own script. Your hook receives a message on stdin, writes a reply to stdout. That's it.
bun install -g discorddaemonFirst time? See the Setup Guide for step-by-step instructions from bot creation to channel configuration.
-
Create a Discord bot at Discord Developer Portal and grab the token.
-
Scaffold config and hooks:
ddd init # creates ~/.config/ddd/ddd.toml and hooks/- Edit
~/.config/ddd/ddd.toml:
[bot]
token = "YOUR_BOT_TOKEN" # or set DDD_TOKEN env var
[channels.general]
id = "CHANNEL_ID_HERE"
on_message = "./hooks/echo.sh"- List available channels (optional):
ddd channels # shows channel IDs and names as NDJSON- Start the daemon:
ddd startHooks are any executable. Shell scripts, Python, Rust binaries — anything that reads stdin and writes stdout.
{
"id": "message_id",
"channel_id": "123456",
"channel_name": "general",
"author": {
"id": "user_id",
"username": "someone",
"bot": false
},
"content": "hello world",
"timestamp": "2026-03-23T12:00:00.000Z",
"attachments": []
}Plain text. If non-empty, sent as a reply. If empty, nothing happens.
0— success- non-zero — error logged to stderr
30 seconds by default.
#!/usr/bin/env bash
# echo.sh — echoes back the message content
jq -r '.content' | sed 's/^/echo: /'- One tool, one job. ddd connects to Discord. Your hooks do everything else.
- Text streams as interface. stdin JSON in, stdout text out. Composable with any language.
- No framework lock-in. Hooks are processes, not plugins. Swap them without restarting.
MIT