Django-inspired modular framework for Discord bots
Project description
HazelAura
Django-inspired modular framework for Discord bots.
pip install hazelaura
aura create --project mybot
cd mybot && aura run dev
Feature Overview
| Feature | Description |
|---|---|
| Settings system | core/settings.py — Django-style central config with env-var overrides |
| Auto-discovery | INSTALLED_APPS — zero-import app loading (commands, events, services) |
| Middleware pipeline | Async middleware chain runs before every command |
| Dependency injection | Named services auto-injected into command parameters |
| Command router | Decorator-based router.command() — register anywhere, flush at startup |
| Superuser system | aura createsuperuser + @is_superuser() decorator |
| Role-based auth | @require_roles() / @require_permissions() decorators |
| Global error handler | Clean, structured error responses for all failure modes |
| Hot-reload | aura run dev watches for file changes and reloads extensions |
| Interactive shell | aura shell — IPython/code.interact with full project context |
| Built-in DB | SQLite via DatabaseService (swap engine in settings) |
| Built-in cache | In-memory TTL cache via CacheService |
Project Structure
mybot/
├── core/
│ └── settings.py ← All configuration
├── cogs/
│ └── example/
│ ├── __init__.py
│ ├── commands.py ← Cog + commands (auto-discovered)
│ ├── events.py ← Event listeners (auto-discovered)
│ ├── services.py ← Business logic layer
│ └── models.py ← Data-access helpers
├── utils/
├── data/ ← SQLite DB + logs (git-ignored)
├── .env ← Secrets (git-ignored)
├── main.py
└── requirements.txt
CLI Reference
aura create --project <n> Scaffold a new project
aura create --app <n> Scaffold a new cog/app
aura run dev Start bot with hot-reload
aura migrate Run DB schema migrations
aura createsuperuser Register a Discord superuser
aura shell Interactive Python shell
aura help Show help
Settings
# core/settings.py
from hazelaura.core.settings import BaseSettings
class Settings(BaseSettings):
TOKEN = os.getenv("DISCORD_TOKEN")
PREFIX = "!"
DEBUG = True
INSTALLED_APPS = ["cogs.music", "cogs.admin"]
MIDDLEWARE = [
"hazelaura.core.builtin.middleware.logging_middleware",
"mybot.core.middleware.my_custom_middleware",
]
DATABASE = {"ENGINE": "sqlite", "NAME": "data/db.sqlite3"}
settings = Settings()
Every attribute can be overridden by an environment variable prefixed HAZEL_,
e.g. HAZEL_PREFIX=>> overrides PREFIX.
Auto-Discovery
List your app packages in INSTALLED_APPS. HazelAura will automatically
import commands.py, events.py, and services.py from each package and
register any discord.ext.commands.Cog subclasses with the bot.
INSTALLED_APPS = [
"cogs.music",
"cogs.moderation",
"cogs.economy",
]
Each app follows the convention:
cogs/music/
├── __init__.py
├── commands.py ← defines MusicCommands(commands.Cog) + setup()
├── events.py ← defines MusicEvents(commands.Cog) + setup()
└── services.py ← MusicService class
Middleware
# core/settings.py
MIDDLEWARE = [
"hazelaura.core.builtin.middleware.logging_middleware",
"mybot.core.middleware.rate_limit_middleware",
]
# mybot/core/middleware.py
async def rate_limit_middleware(ctx, call_next):
if is_rate_limited(ctx.author.id):
return await ctx.send("⏳ Slow down!")
await call_next(ctx)
Dependency Injection
from hazelaura.core.injector import injector
# Register a custom service
injector.register("payments", PaymentService())
# Auto-inject into commands by parameter name
@bot.command()
async def subscribe(ctx, db, cache, payments):
user = db.fetchone("SELECT * FROM users WHERE id=?", (ctx.author.id,))
...
Auth Decorators
from hazelaura import is_superuser, require_roles, require_permissions
@bot.command()
@is_superuser()
async def shutdown(ctx): ...
@bot.command()
@require_roles("Admin", "Moderator")
async def ban(ctx, member): ...
@bot.command()
@require_permissions(manage_guild=True)
async def settings_cmd(ctx): ...
Command Router
Register commands anywhere — in any module — without touching the bot object:
from hazelaura.core.router import router
@router.command("ping")
async def ping(ctx):
await ctx.send("pong")
@router.group("admin")
async def admin(ctx):
pass
@router.subcommand("admin", "reload")
async def admin_reload(ctx, extension: str):
await ctx.bot.reload_extension(extension)
await ctx.send(f"✅ Reloaded {extension}")
Superuser System
# Register a superuser
aura createsuperuser
# → Enter the Discord user ID
# Or non-interactively
aura createsuperuser --id 123456789012345678
from hazelaura import is_superuser
@bot.command()
@is_superuser()
async def secret(ctx):
await ctx.send("🔐 Superuser-only command!")
License
MIT — HazelTech
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hazelaura-1.0.2.tar.gz.
File metadata
- Download URL: hazelaura-1.0.2.tar.gz
- Upload date:
- Size: 28.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddb3f11c83280056b4f7167dca92a945cf531339776dda3bd78f93de7c92f8ea
|
|
| MD5 |
f8b87eae96727e5c0abbfc17019ce454
|
|
| BLAKE2b-256 |
86e93c81ddff4579bc1260f90bfd2b258b068c0ef3164db36ab5724c4d8a3270
|
File details
Details for the file hazelaura-1.0.2-py3-none-any.whl.
File metadata
- Download URL: hazelaura-1.0.2-py3-none-any.whl
- Upload date:
- Size: 34.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71b0958762fe20b83d11f198a85858ec064efebf82419ee89ecdb7d681f711bf
|
|
| MD5 |
725caa5d9d224b2b6f89e2bedbafee14
|
|
| BLAKE2b-256 |
905cd45862933c52e91720b8cbf761bf34ed0b24a39d2b429ad6c9e4ebbaa2f3
|