A Discord bot that automatically creates a thread for messages posted in selected text channels, so conversations don’t turn into one endless scroll of chaos.
It supports:
- Per-message threads (every qualifying message becomes a new thread), or
- First message per user per day (one thread per user per channel per UTC day)
Configuration is stored in a local SQLite database (via aiosqlite) and managed through Discord commands.
When enabled for a channel, the bot can:
- Create a thread from a qualifying message
- Generate a thread title from a template (supports tokens)
- Enforce a channel-level cooldown (rate limiting)
- Restrict who it applies to:
- everyone
- non_staff (skips admins / managers / manage messages)
- roles (only specific role IDs allowed)
- Ignore:
- bot messages
- command messages (based on your prefix)
- replies (only top-level messages)
- If the root message is deleted, the bot attempts to delete the associated thread, and removes the mapping from the DB.
- If a thread is deleted manually, the bot cleans up the mapping row.
Prefix is controlled by COMMAND_PREFIX (default: !).
-
!threadsor!th
Shows help and template token tips. -
!threads list
Shows configured channels for the server. -
!threads info #channel
Shows the effective config for a channel.
-
!threads enable [#channel]
Enables auto-threading for the channel (defaults to the channel you run the command in). -
!threads disable [#channel]
Disables auto-threading for the channel.
-
!threads set mode #channel <per_message|first_message_per_user_per_day> -
!threads set archive #channel <60|1440|4320|10080>
(minutes: 1 hour, 1 day, 3 days, 7 days) -
!threads set template #channel <template...>
Max ~200 characters. -
!threads set scope #channel <everyone|non_staff|roles> -
!threads roles add #channel @Role -
!threads roles remove #channel @Role -
!threads set cooldown #channel <seconds> -
!threads set min_snippet #channel <int> -
!threads set only_top_level #channel <on|off> -
!threads set ignore_bots #channel <on|off> -
!threads set ignore_commands #channel <on|off>
Thread titles are built from a template string.
Supported tokens:
{author}: display name of the message author{snippet}: cleaned snippet from message content{channel}: channel name{message_id}: root message ID
Default template:
💬 {author} — {snippet}
Notes:
- Markdown, inline/multiline code blocks, and links are stripped from
{snippet}. - Title length is capped at 60 characters.
- Python 3.10+ recommended
discord.py>=2.4.0aiosqlite>=0.19.0python-dotenv>=1.0.1uvloopis optional (used automatically when available; ignored on Windows)
See requirements.txt.
- Create an application + bot
- Copy the bot token
- Invite the bot to your server using the OAuth2 URL Generator
This bot uses:
- Server Members Intent (
intents.members = True) - Message Content Intent (
intents.message_content = True)
These may need to be enabled in the Developer Portal depending on your bot’s size/verification status.
Copy the sample env file:
cp .env.example .envEdit .env:
DISCORD_TOKEN=your_token_here
COMMAND_PREFIX=!
DB_PATH=cogs/data/threads.dbDB_PATH is where the SQLite DB will live. The bot will create the folder if it doesn’t exist.
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python bot.pypython3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python bot.pyYou should see:
Threads is online as <botname> (prefix: !)
For smooth operation, the bot typically needs (per enabled channel):
- View Channel
- Read Message History
- Send Messages
- Add Reactions (optional, used for 🧵 reaction)
- Create Public Threads (or Create Private Threads if you adapt it)
- Manage Threads (needed if you want it to reliably delete threads)
If the bot lacks permissions, it will silently fail to create/delete threads (because Discord forbids it, not because the bot is “shy”).
On every message in a guild text channel:
- Load channel config from the DB
- If not enabled, exit
- Apply filters (ignore bots, ignore commands, only top-level, scope rules)
- Enforce mode:
per_message: always eligiblefirst_message_per_user_per_day: only the user’s first message that UTC day
- Enforce cooldown (channel-level throttle)
- Create thread:
- Name from template
- Archive duration from config
- Persist mapping
root_message_id -> thread_idfor cleanup later
SQLite with migrations under:
cogs/db/migrations/
Tables (high level):
guilds: guild metadatachannels: per-channel configurationchannel_roles: role whitelist when scope isrolesthrottles: last thread creation timestamps per channelfirst_message_log: used for the per-user-per-day modeaudit_log: records config actionsthread_roots: mapping root message → thread for cleanup
Migrations are run automatically on startup (PRAGMA user_version is used).
Enable auto-threading in a channel:
!threads enable #general
Thread title template:
!threads set template #general 🧵 {author}: {snippet}
Restrict to non-staff:
!threads set scope #general non_staff
Enable role-only mode:
!threads set scope #general roles
!threads roles add #general @Members
First thread per user per day:
!threads set mode #general first_message_per_user_per_day
Add a 30-second cooldown:
!threads set cooldown #general 30
MIT (See LICENSE).