# How HoshinoBot Group Management and Anti-Spam Features Work: A Deep Dive into the Service Architecture

> Discover how HoshinoBot's group management and anti-spam features function. Explore its modular service architecture handling permissions, configurations, and block lists for effective bot control.

- Repository: [ice9coffee/hoshinobot](https://github.com/ice9coffee/hoshinobot)
- Tags: deep-dive
- Published: 2026-03-03

---

**HoshinoBot implements group management and anti-spam through a modular `Service` class that wraps NoneBot event handlers with automatic permission checks, per-group configuration, and block-list integration.**

The [ice9coffee/hoshinobot](https://github.com/ice9coffee/hoshinobot) repository structures every group-management function—whether anti-spam, anti-recall, or keyword filtering—around a lightweight **Service** abstraction. This design ensures consistent privilege validation and allows administrators to toggle features per group without modifying core logic.

## Core Architecture: The `Service` Class and Permission Layer

### Service Registration and Event Binding

At the heart of HoshinoBot's group management system lies the **`Service`** class defined in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py). This class acts as a wrapper that registers callbacks with the underlying **NoneBot** event system while automatically handling group-level enable/disable states.

When you create a service instance, you define its visibility and default availability:

```python
from hoshino import Service

sv = Service('anti-kfc', enable_on_default=False)

```

The `Service` class provides decorators such as **`@sv.on_message`**, **`@sv.on_keyword`**, and **`@sv.on_notice`** to bind handler functions. These decorators create a **`ServiceFunc`** object and register it with the global trigger registry. When a matching event arrives—whether a keyword in chat or a message recall notice—the service's internal **`_check_all`** method executes a series of validation checks before running your handler.

### Privilege and Block-List Checks

Before any anti-spam handler executes, the service validates the context through the **`hoshino.priv`** module. This system enforces a privilege hierarchy (**`SUPERUSER`**, **`ADMIN`**, **`NORMAL`**) and maintains global block-lists for users and groups.

The `_check_all` method performs three critical validations:

1. **`self.check_enabled(group_id)`** — Verifies the service is explicitly enabled for the current group
2. **`not priv.check_block_group(group_id)`** — Confirms the group is not globally blacklisted
3. **`priv.check_priv(event, self.use_priv)`** — Ensures the sender has sufficient privilege to trigger the service

If any check fails, the handler aborts silently. When handlers need to punish offenders, they call **`priv.set_block_user(user_id, duration)`** to mute users or **`priv.set_block_group(group_id)`** to blacklist entire groups.

## How Anti-Spam Modules Are Structured

HoshinoBot organizes all group-management logic under `hoshino/modules/groupmaster/`. Each anti-spam rule lives in a separate Python file, creating a **Service** instance and attaching specialized handlers via decorators.

### Keyword-Based Filtering

The [`anti_kfc.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_kfc.py) module demonstrates the standard pattern for keyword-based anti-spam. It creates a service disabled by default, then registers a keyword trigger for "疯狂星期四" (Crazy Thursday) spam:

```python
from hoshino import Service, priv, util

sv = Service('anti-kfc', enable_on_default=False)

@sv.on_keyword('kfc', '疯狂星期四')
async def anti_kfc_crazy_thursday(bot, ev):
    # Block user for 4 minutes (240 seconds)

    priv.set_block_user(ev.user_id, timedelta(seconds=240))
    await util.silence(ev, 4 * 60, skip_su=False)
    await bot.send(ev, f'{ms.at(ev.user_id)} 检测到关键词，已被禁言4分钟')
    try:
        await bot.delete_msg(self_id=ev.self_id, message_id=ev.message_id)
    except CQHttpError:
        pass

```

This handler demonstrates the complete enforcement chain: **block-list registration**, **timed muting via `util.silence`**, **warning message delivery**, and **offending message deletion**.

### Notice Event Handling

For non-message events like message recalls, [`anti_msg_recall.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_msg_recall.py) uses **`@sv.on_notice`** to monitor `group_recall` events. When a user withdraws a message, the bot captures the recall event and reposts the original content to the group, preventing information hiding.

Other modules follow this pattern with specialized triggers:
- **[`anti_holo.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_holo.py)** — Blocks Hololive-related keywords with immediate 10-minute mutes
- **[`anti_abuse.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_abuse.py)** — Implements a word-list filter and provides a `ban_word` command for admins to add forbidden terms dynamically
- **[`anti_lex.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_lex.py)** — Combines scheduled jobs (`@sv.scheduled_job`) with keyword triggers for periodic reminders

### The Groupmaster Module Directory

All group-management modules reside in `hoshino/modules/groupmaster/`, ensuring a unified location for moderation logic:

- **[`anti_msg_recall.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_msg_recall.py)** — Anti-recall message reposting
- **[`anti_kfc.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_kfc.py)** — Scam keyword filtering
- **[`anti_holo.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_holo.py)** — VTuber spam prevention
- **[`anti_abuse.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_abuse.py)** — Banned word filtering and red-packet abuse detection
- **[`anti_lex.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_lex.py)** — Scheduled broadcasts and keyword reminders
- **[`join_approve.py`](https://github.com/ice9coffee/hoshinobot/blob/main/join_approve.py)** — Automated group join approval workflows
- **[`sleeping_set.py`](https://github.com/ice9coffee/hoshinobot/blob/main/sleeping_set.py)** — Night-mode group restrictions

Each module follows the **Service** pattern, guaranteeing consistent privilege handling and per-group toggling capabilities.

## Execution Flow of an Anti-Spam Rule

When a group message triggers an anti-spam rule, HoshinoBot executes a strict validation pipeline before taking action:

1. **Service Creation** — The module initializes a `Service` instance, often with `enable_on_default=False` to require explicit admin activation
2. **Trigger Registration** — Decorators like `@sv.on_keyword` bind the handler to specific event types in the NoneBot router
3. **Event Reception** — NoneBot routes the group message to the appropriate trigger registry (keyword, notice, or command)
4. **Permission Validation** — `Service._check_all` validates group enablement status, global block-lists, and user privileges in sequence
5. **Handler Execution** — Upon passing all checks, the handler executes its logic: calling **`priv.set_block_user`** to update the block-list, invoking **`util.silence`** to apply timed mutes, sending warning messages, and optionally deleting the offending content via **`bot.delete_msg`**

This architecture ensures that adding a new anti-spam rule requires only creating a new module with a `Service` instance and attaching the appropriate decorator—no changes to core routing or permission logic are necessary.

## Practical Implementation Examples

### Creating a Custom Keyword Anti-Spam Rule

To add a new spam filter, create a file under `hoshino/modules/groupmaster/` following this template:

```python

# my_anti_spam.py

from datetime import timedelta
from hoshino import Service, priv, util
from hoshino.typing import CQEvent, CQHttpError, MessageSegment as ms

sv = Service('anti-spam-custom', enable_on_default=False)

@sv.on_keyword('spamword', 'advertisement')
async def block_spam(bot, ev: CQEvent):
    # Apply 5-minute block and mute

    priv.set_block_user(ev.user_id, timedelta(minutes=5))
    await util.silence(ev, 5 * 60, skip_su=False)
    
    # Notify and clean up

    await bot.send(ev, f'{ms.at(ev.user_id)} 广告信息已屏蔽')
    try:
        await bot.delete_msg(self_id=ev.self_id, message_id=ev.message_id)
    except CQHttpError:
        pass

```

The `Service` wrapper automatically guards this handler with the `_check_all` logic, ensuring it only runs when enabled for the group and the user isn't already blocked.

### Enabling Services Per Group

Administrators toggle modules using the service's **`set_enable`** method:

```python
from hoshino import Service, priv

sv = Service('admin-commands', visible=False)

@sv.on_command('enable_filter', aliases=('开启过滤',))
async def enable_filter(session):
    from hoshino.modules.groupmaster.my_anti_spam import sv as filter_sv
    filter_sv.set_enable(session.ctx['group_id'])
    await session.send('已在本群启用自定义过滤规则')

```

Users with **`priv.ADMIN`** or higher can invoke this command to activate specific anti-spam rules for their groups.

## Summary

- **HoshinoBot's group management** relies on the **`Service`** class in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py) to wrap NoneBot handlers with automatic permission and configuration checks
- **Anti-spam modules** reside in `hoshino/modules/groupmaster/` and use decorators like **`@sv.on_keyword`** and **`@sv.on_notice`** to register triggers
- **Permission enforcement** occurs through `hoshino.priv`, providing **`set_block_user`**, **`check_priv`**, and privilege levels (**`SUPERUSER`**, **`ADMIN`**, **`NORMAL`**)
- **Enforcement actions** typically combine **`util.silence`** for timed mutes, **`priv.set_block_user`** for block-list updates, and **`bot.delete_msg`** for content removal
- **Per-group toggling** is handled via `Service.set_enable()` and `Service.set_disable()`, allowing fine-grained control without code changes

## Frequently Asked Questions

### How do I enable anti-spam features for specific groups only?

Use **`enable_on_default=False`** when creating the `Service` instance, then provide an admin command that calls **`sv.set_enable(group_id)`**. Only groups where an administrator explicitly enables the service will process its anti-spam handlers, as the `_check_all` method validates enablement status before execution.

### What privilege levels control group management features?

HoshinoBot implements three privilege tiers in `hoshino.priv`: **`SUPERUSER`** (bot owner), **`ADMIN`** (group administrators), and **`NORMAL`** (regular users). The `Service` class checks these via **`priv.check_priv(event, required_level)`**, and anti-spam handlers typically require `ADMIN` or higher to modify block-lists or enable services.

### Can I customize the mute duration for spam violations?

Yes. When calling **`priv.set_block_user(user_id, duration)`**, pass a `timedelta` object specifying the exact blocking period. Additionally, use **`util.silence(event, seconds)`** to apply the mute duration—both [`anti_kfc.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_kfc.py) (4 minutes) and [`anti_holo.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_holo.py) (10 minutes) demonstrate different duration configurations.

### How does the anti-recall feature capture deleted messages?

The [`anti_msg_recall.py`](https://github.com/ice9coffee/hoshinobot/blob/main/anti_msg_recall.py) module registers a handler via **`@sv.on_notice`** listening for `group_recall` events. When NoneBot detects a message withdrawal, the handler receives the original message ID and content from the event object, allowing the bot to repost the content before it disappears from the group history.