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.

  1. Create the package directory under hoshino/modules/your_module. The folder name determines how you will reference the module in configuration.

  2. Create the main module file (e.g., hello.py) that instantiates a Service and 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!')
  1. Add an optional __init__.py in the module folder if you need to organize multiple files or import submodules.

  2. (Optional) Create module-specific configuration by adding hoshino/config/hello.py with custom variables:


# Custom configuration values for the hello module

GREETING_MESSAGE = 'Hello! 👋'
ENABLE_EMOJI = True
  1. Enable the module by editing hoshino/config_example/__bot__.py (or your production copy at hoshino/config/__bot__.py) and adding the module name to the set:
MODULES_ON = {
    'botmanage',
    'dice',
    'groupmaster',
    'hello',  # ← Add your module name here

    # other modules...

}
  1. Restart the bot. When hoshino.init() executes, it scans MODULES_ON and imports your module automatically from hoshino/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 string
  • on_fullmatch – Matches exact message content
  • on_rex – Matches regular expression patterns
  • on_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 Service object from hoshino/service.py to register handlers using decorators like @sv.on_prefix()
  • Add the module name to the MODULES_ON set in your bot configuration file
  • Optionally create hoshino/config/{module_name}.py for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →