# How to Implement Per-Group Service Enabling and Disabling in HoshinoBot

> Learn to implement per-group service enabling and disabling in HoshinoBot. Master persistent JSON configuration with set enable and set disable methods for fine-grained feature control.

- Repository: [ice9coffee/hoshinobot](https://github.com/ice9coffee/hoshinobot)
- Tags: how-to-guide
- Published: 2026-03-03

---

**HoshinoBot uses a `Service` class with persistent JSON configuration to control which groups can access specific features via `set_enable()` and `set_disable()` methods.**

Per-group service enabling and disabling in HoshinoBot allows bot administrators to restrict functionality to specific QQ groups or disable unwanted features globally or locally. This granular control is built into the core `Service` class in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py), which manages command triggers, scheduled jobs, and access permissions across the ice9coffee/hoshinobot framework.

## Understanding HoshinoBot's Service Architecture

### The Service Class

In HoshinoBot, functionality is organized into **services**—logical units that encapsulate commands, message handlers, and scheduled tasks. When you create a service in a module, you instantiate the `Service` class:

```python
from hoshino import Service, priv

sv = Service('weather', use_priv=priv.NORMAL, manage_priv=priv.ADMIN, visible=True)

```

The service name `'weather'` becomes the unique identifier for configuration storage and management commands.

### Configuration Persistence

Service configurations are persisted to JSON files stored in `~/.hoshino/service_config/`. According to the source code in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py), the `_load_service_config` method (lines 30-41) initializes each service by reading its configuration file, while `_save_service_config` (lines 43-58) writes changes back to disk.

Each service maintains two critical sets:
- `enable_group`: Groups explicitly allowed to use the service
- `disable_group`: Groups explicitly blocked from using the service

## Enabling and Disabling Services for Specific Groups

### Using Management Commands

HoshinoBot ships with a built-in management module located at [`hoshino/modules/botmanage/service_manage.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/botmanage/service_manage.py) that provides user-facing commands. Group administrators can enable or disable services directly in chat:

```bash

# Enable the weather service for the current group

.enable weather

# Disable the weather service for the current group

.disable weather

```

Super-users can manage multiple groups simultaneously by specifying group IDs:

```bash

# Super-user enabling service for specific groups

.enable weather 12345 67890 112233

```

Behind the scenes, these commands parse the service name and group IDs, then invoke the corresponding `Service` methods.

### Programmatic Control with set_enable and set_disable

For developers building custom modules, the `Service` class exposes direct methods to control group access. In [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py), the `set_enable` method (lines 44-48) adds a group to the enabled list while removing it from disabled:

```python
sv = Service.get_loaded_services()['weather']
sv.set_enable(123456)  # Group ID as integer

```

Conversely, `set_disable` (lines 50-54) blocks a specific group:

```python
sv.set_disable(123456)

```

Both methods automatically persist changes to the JSON configuration file via `_save_service_config`, ensuring settings survive bot restarts.

## Checking Service Availability at Runtime

### The check_enabled Method

Before executing any command or trigger, HoshinoBot verifies whether the service is active for the current group. The `check_enabled` method in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py) (lines 158-159) implements the following logic:

- If the group is in `enable_group`, the service is active
- If the group is not explicitly enabled but the service defaults to enabled and the group is not in `disable_group`, the service is active
- Otherwise, the service is inactive

Every trigger decorator (`@sv.on_command`, `@sv.on_message`, etc.) internally calls `Service._check_all(event)`, which invokes `check_enabled` to filter incoming events. This ensures disabled services consume no processing resources for unauthorized groups.

## Practical Implementation Examples

### Defining a Service with Group Control

```python

# my_module.py

from hoshino import Service, priv

# Create a visible service manageable by group admins

sv = Service('my_feature', 
             use_priv=priv.NORMAL, 
             manage_priv=priv.ADMIN, 
             visible=True)

@sv.on_command('mycommand')
async def my_command(session):
    await session.send('Command executed!')

```

### Programmatically Managing Group Access

```python
def toggle_service_for_group(service_name: str, group_id: int, enable: bool):
    """
    Enable or disable a service for a specific group.
    
    Args:
        service_name: The service identifier used during Service creation
        group_id: The QQ group ID (integer)
        enable: True to enable, False to disable
    """
    services = Service.get_loaded_services()
    
    if service_name not in services:
        raise ValueError(f"Service '{service_name}' not found")
    
    sv = services[service_name]
    
    if enable:
        sv.set_enable(group_id)
        print(f"Enabled {service_name} for group {group_id}")
    else:
        sv.set_disable(group_id)
        print(f"Disabled {service_name} for group {group_id}")

# Usage examples

toggle_service_for_group('my_feature', 123456789, enable=True)
toggle_service_for_group('my_feature', 987654321, enable=False)

```

### Checking Service Status Before Execution

```python
async def safe_service_call(session, service_name: str):
    """
    Check if service is enabled for current group before processing.
    """
    gid = session.event.group_id
    sv = Service.get_loaded_services().get(service_name)
    
    if not sv:
        await session.send("Service not found")
        return False
        
    if not sv.check_enabled(gid):
        await session.send("This service is disabled for this group")
        return False
        
    return True

```

## Summary

- **Service Architecture**: HoshinoBot organizes functionality into `Service` objects defined in [`hoshino/service.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/service.py), each maintaining independent configuration in `~/.hoshino/service_config/`.
- **Per-Group Control**: Use `Service.set_enable(group_id)` and `Service.set_disable(group_id)` to manage access, which automatically persists to JSON configuration files.
- **Runtime Checking**: The `check_enabled(group_id)` method filters all incoming events, ensuring disabled services never execute for unauthorized groups.
- **User Commands**: Built-in management commands in [`hoshino/modules/botmanage/service_manage.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/botmanage/service_manage.py) provide `.enable` and `.disable` chat interfaces for administrators.

## Frequently Asked Questions

### How do I check if a service is enabled for a specific group programmatically?

Use the `check_enabled()` method on the service instance, passing the group ID as an integer. This method returns `True` if the service is active for that group, considering both explicit enable lists and default global settings. For example: `sv.check_enabled(123456)`.

### Where does HoshinoBot store per-group service configuration?

Configuration files are stored in the `~/.hoshino/service_config/` directory as individual JSON files named after each service (e.g., [`weather.json`](https://github.com/ice9coffee/hoshinobot/blob/main/weather.json)). The `Service` class automatically loads these on initialization and writes updates via `_save_service_config()` whenever `set_enable()` or `set_disable()` is called.

### Can super-users manage services for groups they are not in?

Yes. According to the implementation in [`hoshino/modules/botmanage/service_manage.py`](https://github.com/ice9coffee/hoshinobot/blob/main/hoshino/modules/botmanage/service_manage.py), super-users can specify multiple group IDs after the service name when using the `.enable` or `.disable` commands. Regular group administrators can only toggle services for their current group.

### What happens if a service is disabled for a group—will commands still trigger?

No. The `Service._check_all()` method intercepts all incoming events before they reach command handlers. If `check_enabled()` returns `False` for the current group ID, the event is silently dropped, meaning disabled services consume no processing resources and produce no responses for unauthorized groups.