Core Bot Lifecycle¶
This page details how the main Discord process boots, wires shared services, and loads extensions.
Entry point¶
The bot starts in apps/bot/main.py inside the main() coroutine. The sequence is:
- Configure Sentry (when
SENTRY_DSNis present) and set up filtered Discord logging viasetup_logging(). - Create an
aiohttp.ClientSessionand instantiatecore.Genji, passing the configured prefix ("?"in production,"!"otherwise). - Start the asynchronous context manager for the bot and call
bot.start(DISCORD_TOKEN)to connect to the Discord gateway.
core/genji.py defines the Genji subclass of commands.Bot. During __init__ the class:
- Applies the gateway intents defined at module level.
- Stores the shared HTTP session and constructs a
VideoThumbnailHandlerhelper. - Loads
configs/prod.tomlwhenAPP_ENVIRONMENTis"production", orconfigs/dev.tomlfor all other environments, using theutilities.config.decodehelper.
Extension loading¶
Genji.setup_hook runs once the Discord connection is preparing. It loads every module under extensions/ (discovered
via pkgutil in extensions.__init__.EXTENSIONS) plus the debugging cog jishaku. After extensions are loaded, the
method schedules self.rabbit.start() on the bot loop so that queue consumers begin once all handlers are registered.
Each extension exposes an async setup(bot) function that attaches services or cogs to the bot. Notable patterns
include:
extensions.api_service.setupinstantiatesAPIServiceand assigns it tobot.apifor use across other modules.extensions.newsfeed.setup,extensions.completions.setup,extensions.playtest.setup, andextensions.xp.setupcreate service classes that are stored on the bot for later access.extensions.notifications.setupattachesNotificationHandlertobot.notifications.extensions.rabbit.setupprepares theRabbitHandler, whichsetup_hookstarts after all handlers are registered.
Service lifecycle¶
Handler classes that inherit from utilities.base.BaseHandler (for example CompletionHandler, PlaytestHandler, and
XPHandler) lazily resolve the configured guild and their target channels. The base class spawns a task that waits for
the bot to become ready, fetches bot.config.guild, and calls each handlers's _resolve_channels() hook before
handling
work.
When adding a new feature module:
- Create an extension module under
extensions/with anasync def setup(bot)entry point. - Attach any long-lived handler to the bot (optionally inheriting from
BaseHandler). - Register queue handlers with
queue_consumerif the feature processes RabbitMQ events ( see Messaging & Queues). - Ensure the module is importable so that
extensions.__init__discovers it automatically during startup.
File Locations¶
All bot code is located in apps/bot/:
apps/bot/
├── main.py # Entry point
├── core/
│ └── genji.py # Main bot class
├── extensions/ # Feature modules
│ ├── __init__.py # Extension discovery
│ ├── api_service.py # API client
│ ├── rabbit.py # RabbitMQ service
│ ├── newsfeed.py # Newsfeed service
│ ├── completions.py # Completions service
│ ├── playtest.py # Playtest service
│ ├── notifications.py # Notification service
│ └── xp.py # XP service
├── utilities/ # Shared utilities
│ ├── base.py # BaseHandler
│ ├── config.py # Config schema
│ └── formatter.py # Embed formatters
└── configs/ # TOML configuration
├── dev.toml
└── prod.toml
Next Steps¶
- Services & Extensions - Understand the service architecture
- Messaging & Queues - Learn about queue consumers
- Configuration - Configure the bot