How to Create and Load Custom Modules into HoshinoBot: The Complete Guide
To create and load custom modules into HoshinoBot, create a Python package under hoshino/modules/, instantiate a Service object to register your handlers, and add the module name to MODULES_ON in your bot configuration file.
HoshinoBot is an open-source QQ bot framework developed by ice9coffee/hoshinobot that uses a modular architecture where each functional extension is treated as an independent plugin. Creating custom modules allows you to extend the bot's capabilities while maintaining clean separation between core functionality and third-party features. This guide covers the exact steps to build, configure, and load custom modules using the bot's internal APIs.
Understanding HoshinoBot's Module Architecture
HoshinoBot automatically discovers and loads modules during the initialization phase. The system relies on a specific directory structure and a configuration-based whitelist to determine which packages to import.
The MODULES_ON Configuration
During bot start-up, hoshino/__init__.py reads the list config.MODULES_ON and automatically loads every folder name found there as a plugin. This configuration is defined in the user-editable file hoshino/config_example/__bot__.py, where you declare which modules should be active by adding their folder names to the MODULES_ON set.
The Service Class API
Each module must define one or more Service objects using the Service class located in hoshino/service.py. The Service class provides decorator methods such as on_prefix, on_rex, on_command, and on_fullmatch that register your callback functions with Hoshino's trigger system. As implemented in ice9coffee/hoshinobot, the Service constructor accepts parameters like name, help_, enable_on_default, and visible to control module behavior and visibility.
Step-by-Step Guide to Creating a Custom Module
Follow these exact steps to create a functional custom module that HoshinoBot will recognize and load automatically.
-
Create the package directory under
hoshino/modules/your_module. The folder name determines how you will reference the module in configuration. -
Create the main module file (e.g.,
hello.py) that instantiates aServiceand defines handlers:
from hoshino import Service, priv
# Define the service; name should match the folder name
sv = Service('hello', help_='Say hello to the bot', enable_on_default=True)
@sv.on_prefix('hi')
async def say_hello(bot, ev):
"""Triggered by messages starting with 'hi'."""
await bot.send(ev, 'Hello! 👋')
@sv.on_fullmatch('hello')
async def hello_fullmatch(bot, ev):
"""Triggered by exact message 'hello'."""
await bot.send(ev, 'Greetings!')
-
Add an optional
__init__.pyin the module folder if you need to organize multiple files or import submodules. -
(Optional) Create module-specific configuration by adding
hoshino/config/hello.pywith custom variables:
# Custom configuration values for the hello module
GREETING_MESSAGE = 'Hello! 👋'
ENABLE_EMOJI = True
- Enable the module by editing
hoshino/config_example/__bot__.py(or your production copy athoshino/config/__bot__.py) and adding the module name to the set:
MODULES_ON = {
'botmanage',
'dice',
'groupmaster',
'hello', # ← Add your module name here
# other modules...
}
- Restart the bot. When
hoshino.init()executes, it scansMODULES_ONand imports your module automatically fromhoshino/modules/hello/.
Module Configuration and Advanced Options
HoshinoBot supports sophisticated configuration patterns beyond basic command handlers. You can reference built-in modules like dice (located at hoshino/modules/dice/dice.py) to see production-ready patterns for complex triggers and permission management.
Directory Structure Reference
A complete custom module follows this layout:
hoshino/
├─ modules/
│ └─ hello/
│ ├─ __init__.py # Optional package initializer
│ └─ hello.py # Main logic with Service definitions
├─ config/
│ └─ hello.py # Optional module-specific config
└─ config_example/
└─ __bot__.py # Add 'hello' to MODULES_ON here
Trigger Types Available
The Service class in hoshino/service.py exposes several decorators for different message matching patterns:
on_prefix– Matches messages starting with the specified stringon_fullmatch– Matches exact message contenton_rex– Matches regular expression patternson_command– Matches commands with specific syntax and argument parsing
Summary
To successfully create and load custom modules into HoshinoBot:
- Place module code under
hoshino/modules/{module_name}/as a valid Python package - Instantiate a
Serviceobject fromhoshino/service.pyto register handlers using decorators like@sv.on_prefix() - Add the module name to the
MODULES_ONset in your bot configuration file - Optionally create
hoshino/config/{module_name}.pyfor module-specific settings - Restart the bot to trigger the automatic loading mechanism in
hoshino/__init__.py
Frequently Asked Questions
What is the minimum required code for a functional HoshinoBot module?
At minimum, a module needs a Python file under hoshino/modules/{name}/ that creates a Service instance and registers at least one handler using a decorator like @sv.on_prefix() or @sv.on_fullmatch(). The folder name must match the service name, and the module must be listed in MODULES_ON.
Can I create modules without editing the config_example files?
Yes. Copy hoshino/config_example/__bot__.py to hoshino/config/__bot__.py and edit the copy instead. HoshinoBot prioritizes the configuration in the config/ directory over the example files, allowing you to keep custom modules separate from the repository examples.
How do I debug why my custom module isn't loading?
Check three specific locations: ensure the folder name under hoshino/modules/ exactly matches the string added to MODULES_ON, verify there are no Python syntax errors in your module files, and check that the Service object is properly instantiated before decorators are applied. The bot imports modules during hoshino.init(), so any import errors will appear in the console during startup.
Are there permission controls available for custom modules?
Yes. The Service class accepts a priv parameter (imported from hoshino import priv) to restrict commands to specific privilege levels such as priv.ADMIN or priv.SUPERUSER. You can also use the @sv.only_to_me() decorator or check await priv.check_priv(ev, priv.ADMIN) within your handler functions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →