Extend Hexis with custom tools, hooks, and skills via the plugin system.
Plugins are Python packages that implement the HexisPlugin ABC. They are:
- Discovered from
plugins/installed/directory - Loaded at startup via
load_plugins(pool) - Registered via the
HexisPluginApiinjection object
plugins/installed/my_plugin/
├── __init__.py # exports HexisPlugin subclass
├── tools.py # custom ToolHandler implementations
└── skills/
└── my-skill/
└── SKILL.md # skill definition
@dataclass
class PluginManifest:
id: str # Unique identifier
name: str # Display name
version: str = "0.0.0" # Semantic version
description: str = "" # Purpose
config_schema: dict = field(default_factory=dict) # JSON schemaclass HexisPlugin(ABC):
@property
def manifest(self) -> PluginManifest:
"""Return plugin metadata"""
def register(self, api: HexisPluginApi) -> None:
"""Called once during loading; register capabilities"""The injection object provided to plugins during registration:
class HexisPluginApi:
@property
def plugin_id(self) -> str # Plugin ID
@property
def pool(self) -> asyncpg.Pool # DB connection pool
@property
def config(self) -> dict # Plugin config from DB
@property
def logger(self) -> logging.Logger # Namespaced logger
def register_tool(handler: ToolHandler, *, optional: bool = False) -> None
def register_hook(event: HookEvent, handler: HookHandler) -> None
def register_skill_dir(path: Path) -> NoneAdd a custom tool to the registry:
api.register_tool(MyToolHandler()) # always available
api.register_tool(MyToolHandler(), optional=True) # requires explicit enableIf a plugin tool name conflicts with core tools, the plugin tool is skipped with a warning.
Listen for execution events:
api.register_hook(HookEvent.BEFORE_TOOL_CALL, MyHook())
api.register_hook(HookEvent.AFTER_TOOL_CALL, MyHook())| Event | Description |
|---|---|
BEFORE_TOOL_CALL |
Can block or mutate arguments |
AFTER_TOOL_CALL |
Observe/log execution results |
Add a directory of skills:
api.register_skill_dir(Path(__file__).parent / "skills")from plugins.base import HexisPlugin, PluginManifest, HexisPluginApi, HookEvent
class MyPlugin(HexisPlugin):
@property
def manifest(self) -> PluginManifest:
return PluginManifest(
id="my_plugin",
name="My Plugin",
version="1.0.0",
description="Adds custom weather tool",
)
def register(self, api: HexisPluginApi) -> None:
api.register_tool(WeatherToolHandler())
api.register_hook(HookEvent.AFTER_TOOL_CALL, LoggingHook())
api.register_skill_dir(Path(__file__).parent / "skills")Plugin config is stored in the config table under plugin.<plugin_id> and validated against the manifest's config_schema.
- Tools Reference -- tool handler pattern
- Skills -- skill format and management