Plugin Development
This guide will help you develop NekoBot plugins.
Plugin Structure
A standard NekoBot plugin contains the following files:
my_plugin/
__init__.py # Framework discovery entry, only re-export
main.py # Plugin logic, all @plugin / @command / @event_handler here
requirements.txt # Optional, third-party dependencies
metadata.yaml # Plugin metadata
README.md # Plugin documentationQuick Start
1. Create plugin using template
Use the plugin example repository as a template:
# Clone plugin example
git clone https://github.com/OfficialNekoTeam/nekobot_plugin_template.git my_plugin
cd my_plugin
# Modify plugin name and configuration
# Edit metadata.yaml and main.py2. Install plugin to NekoBot
Place the plugin in NekoBot's plugin directory:
cd /path/to/nekobot/data/plugins
git clone https://github.com/your/plugin_repo.git3. Load plugin
NekoBot automatically scans the data/plugins directory to load plugins. You can also load manually:
# Enable plugin in NekoBot configuration
# Plugins are automatically loaded and hot-reloadedPlugin Metadata
The metadata.yaml file defines basic plugin information:
name: my_plugin # Unique identifier, must match @plugin(name=)
display_name: My Plugin
version: 1.0.0
description: Plugin description
author: yourname
repository: https://github.com/you/my_plugin
tags:
- utility
nekobot_version: ">=0.1.0"
support_platforms:
- onebot_v11Plugin Implementation
Basic Structure
main.py is the core file of the plugin:
from packages.decorators import command, event_handler, plugin
from packages.plugins import BasePlugin
@plugin(name="my_plugin", version="1.0.0", description="Plugin description")
class MyPlugin(BasePlugin):
@command(name="hello", aliases=("hi",), description="Say hello")
async def cmd_hello(self, payload: dict) -> None:
args = payload.get("command_args", [])
name = args[0] if args else "World"
await self.context.reply(f"Hello, {name}!")
@event_handler(event="message.group", description="Group message handling")
async def on_group_message(self, payload: dict) -> None:
text = payload.get("plain_text", "")
if isinstance(text, str) and "ping" in text.lower():
await self.context.reply("pong")Entry File
__init__.py is very simple, only re-exporting:
from .main import MyPlugin
__all__ = ["MyPlugin"]Decorators Explained
@plugin Decorator
Marks a class as a plugin:
@plugin(
name="plugin_name", # Plugin unique identifier
version="1.0.0", # Version number
description="Plugin description", # Plugin description
)
class MyPlugin(BasePlugin):
pass@command Decorator
Registers a command handler:
@command(
name="command_name", # Command name
aliases=("alias1", "alias2"), # Command aliases
description="Command description", # Command description
)
async def cmd_handler(self, payload: dict) -> None:
# payload contains command arguments and context information
args = payload.get("command_args", []) # Command argument list
await self.context.reply("Response message")@event_handler Decorator
Registers an event handler:
@event_handler(
event="message.group", # Event type
description="Event handling description",
)
async def event_handler(self, payload: dict) -> None:
# payload contains event data
text = payload.get("plain_text", "")
# Process event...@provider Decorator
Registers an LLM provider:
from packages.decorators import provider
from packages.providers import BaseProvider, ProviderKind
@provider(
name="my_chat_provider", # Provider unique identifier
kind=ProviderKind.CHAT, # Provider type: chat, embedding, tts, stt, rerank
description="Custom chat provider",
capabilities=("streaming", "function_calling"), # Supported capabilities
)
class MyChatProvider(BaseProvider):
async def chat(self, request: ProviderRequest) -> ProviderResponse:
# Implement chat logic
return ProviderResponse(
content="Hello from custom provider",
metadata={"model": "custom-model"}
)@config_schema Decorator
Defines configuration schema for plugins or providers:
from packages.decorators import config_schema
# Add configuration schema to plugin class
@config_schema("my_plugin_config")
class MyPlugin(BasePlugin):
pass
# Add configuration schema to provider class
@config_schema("my_provider_config")
class MyProvider(BaseProvider):
pass@requires_permissions Decorator
Adds permission requirements to plugin classes or methods:
from packages.decorators import requires_permissions
# Add permission requirements to entire plugin class
@requires_permissions("admin", "plugin_manager")
class AdminPlugin(BasePlugin):
pass
# Add permission requirements to specific method
class MyPlugin(BasePlugin):
@requires_permissions("user.write")
async def sensitive_operation(self):
passAvailable Event Types
NekoBot supports the following event types:
message.private: Private messagemessage.group: Group messagemessage.channel: Channel messagenotice.friend_add: Friend add notificationnotice.group_increase: Group member increasenotice.group_decrease: Group member decreaserequest.friend: Friend requestrequest.group: Group join request
Provider Types
Plugins can register the following types of LLM providers:
- chat: Chat conversation provider, implements
chatmethod - embedding: Text embedding provider, implements
embeddingmethod - tts: Text-to-speech provider, implements
ttsmethod - stt: Speech-to-text provider, implements
sttmethod - rerank: Reranking provider, implements
rerankmethod
Each provider type has a corresponding base class:
ChatProvider- Chat providerEmbeddingProvider- Embedding providerTTSProvider- Text-to-speech providerSTTProvider- Speech-to-text providerRerankProvider- Reranking provider
Context Object
Plugins can access the context object via self.context:
# Reply to message
await self.context.reply("Message content")
# Get current conversation
conversation = self.context.conversation
# Get current user
user_id = self.context.user_id
# Get current group (if in group chat)
group_id = self.context.group_idPermission Control
Plugins can define permission requirements:
from packages.decorators import command, plugin
from packages.plugins import BasePlugin
@plugin(name="admin_plugin", version="1.0.0")
class AdminPlugin(BasePlugin):
@command(
name="shutdown",
description="Shutdown bot",
permissions=("admin",) # Requires admin permission
)
async def cmd_shutdown(self, payload: dict) -> None:
await self.context.reply("Shutting down...")
# Perform shutdown operationConfiguration Management
Plugins can define configuration schema:
from packages.decorators import plugin
from packages.plugins import BasePlugin
from packages.schema import ObjectSchema, StringSchema
@plugin(
name="configurable_plugin",
version="1.0.0",
config_schema=ObjectSchema(
properties={
"api_key": StringSchema(description="API key"),
"endpoint": StringSchema(
description="API endpoint",
default="https://api.example.com"
)
}
)
)
class ConfigurablePlugin(BasePlugin):
def __init__(self):
super().__init__()
# Access configuration via self.config
api_key = self.config.get("api_key")Tool Integration
Plugins can register AI tools:
from packages.decorators import plugin, agent_tool
from packages.plugins import BasePlugin
@plugin(name="tool_plugin", version="1.0.0")
class ToolPlugin(BasePlugin):
@agent_tool(
name="get_weather",
description="Get weather information",
parameters_schema={
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
)
async def tool_get_weather(self, city: str) -> str:
# Implement weather query logic
return f"Weather in {city} is sunny"Dependency Management
If plugins require third-party libraries, declare them in requirements.txt:
requests>=2.28.0
pydantic>=2.0.0Testing Plugins
Local Testing
# Create test environment
import asyncio
from my_plugin import MyPlugin
async def test_plugin():
plugin = MyPlugin()
# Simulate command calls
# ...
asyncio.run(test_plugin())Testing in NekoBot
- Place plugin in
data/pluginsdirectory - Start NekoBot
- Test plugin functionality using commands
- Check log output
Publishing Plugins
1. Complete Documentation
Ensure README.md includes:
- Plugin feature introduction
- Installation and usage instructions
- Configuration options
- Command and event list
2. Version Management
Follow semantic versioning:
MAJOR: Incompatible API changesMINOR: Backward-compatible feature additionsPATCH: Backward-compatible bug fixes
3. Submit to Plugin Store
Submit plugin to NekoBot plugin store:
- Ensure plugin complies with specifications
- Provide complete metadata
- Publish after review
Example Plugin
Reference official plugin example: https://github.com/OfficialNekoTeam/nekobot_plugin_template
This example includes:
- Complete plugin structure
- Command and event handler examples
- Configuration and tool integration examples
- Detailed documentation
Best Practices
- Error Handling: Use try-except to catch exceptions, avoid plugin crashes affecting main program
- Logging: Use
self.loggerto record plugin runtime logs - Resource Cleanup: Release resources in
on_unloadmethod - Performance Optimization: Avoid blocking operations, use async functions
- Code Standards: Follow PEP 8 code standards
FAQ
Q: What if plugin fails to load?
A: Check if plugin structure is correct, view NekoBot logs for detailed error information.
Q: What if commands don't work?
A: Check if command names conflict, if permission settings are correct.
Q: How to debug plugins?
A: Add log output in plugin, check NekoBot logs.
Q: What if plugin hot-reload fails?
A: Ensure plugin code has no syntax errors, try manual reload.
Next Steps
- MCP Tool Integration - Expose plugin functionality as AI tools
- Framework Configuration - Learn about system configuration options
- View Plugin Example
- Reference NekoBot source code for API details
- Join developer community