A clean, extensible framework for building Discord bots with hybrid commands (prefix + slash) using discord.py.
- Hybrid commands: every command works as both
!commandand/commandfrom a single implementation. - Auto-loading extensions: drop a new extension folder in
src/extensions/and it's loaded automatically. No manual registration. - One command per file: commands are standalone functions, one per file, so extensions stay readable no matter how many commands they have.
- Typed, centralized config: all environment variables are loaded and validated once, in
src/config.py. - Centralized logging: consistent log format across the whole framework via
src/logger.py.
- Python 3.11+
- A Discord bot application (create one here)
- Clone the repo:
git clone https://github.com/payaci/discord-framework.git
cd discord-framework- Create a virtual environment and install dependencies:
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt- Copy
.env.exampleto.envand fill it in:
cp .env.example .envDISCORD_TOKEN: your bot's token (Developer Portal, your app, Bot, Reset Token)COMMAND_PREFIX: prefix for text commands (default:!)LOG_LEVEL:DEBUG,INFO,WARNING, orERROR(default:INFO)
Make sure Message Content Intent is enabled in the Developer Portal (Bot, Privileged Gateway Intents). It's required for prefix commands to work.
- Run the bot:
python run.pyAn extension is a folder inside src/extensions/ containing:
- One
.pyfile per command (a standalone function decorated with@commands.hybrid_command) - An
__init__.pythat imports each command and registers it viasetup(bot)
Example: adding a hello extension with one command
src/extensions/hello/say_hello.py:
from discord.ext import commands
@commands.hybrid_command(name="hello", description="Say hello.")
async def say_hello(ctx: commands.Context) -> None:
await ctx.send(f"Hello, {ctx.author.mention}!")src/extensions/hello/__init__.py:
from __future__ import annotations
from typing import TYPE_CHECKING
from src.extensions.hello.say_hello import say_hello
if TYPE_CHECKING:
from src.bot import Bot
async def setup(bot: Bot) -> None:
bot.add_command(say_hello)That's it. Restart the bot and both !hello and /hello will work. No registration elsewhere in the codebase is needed.
Use discord.py's built-in checks, for example admin-only commands:
@commands.hybrid_command(name="example")
@commands.has_permissions(administrator=True)
async def example(ctx: commands.Context) -> None:
...See src/extensions/admin/purge.py for a full example, including error handling for missing permissions.
MIT. See LICENSE.