Plugin System
Overview
The Athomic Plugin System provides a powerful and clean way to extend the core functionality of the application without modifying its source code. Plugins can introduce new API routes, register custom services into the lifecycle, or execute logic at specific points in the application's startup sequence.
The system is built on Python's native importlib.metadata and entry points, making it a standard and robust way to create a pluggable architecture.
How It Works
- Entry Point: A plugin is a separate, installable Python package that defines an entry point in its
pyproject.tomlunder the[project.entry-points."nala.plugins"]group. - Discovery: At startup, the
PluginManagerdiscovers all installed packages that declare this entry point. - Hooks: Plugins define functions decorated with
@hookimpl. ThePluginManagerregisters these functions as implementations for specific, predefined hooks. - Execution: When the core application reaches a certain point, it calls
plugin_manager.call_hook("hook_name"), which executes all registered implementations for that hook.
Available Hooks
on_athomic_startup(athomic: Athomic): Called early in the startup sequence. Ideal for registering custom services with theLifecycleRegistry.get_api_routers() -> List[APIRouter]: Called by the web server layer. Each plugin can return a list of FastAPIAPIRouterobjects, which will be automatically mounted into the main application.
Creating a Plugin
See the plugins/nala-plugin-greetings directory for a complete example of a simple plugin.
API Reference
nala.athomic.plugins.hooks.hookimpl(func=None, *, priority=100)
hookimpl(func: Callable) -> Callable
hookimpl(
func: None = None, *, priority: int = 100
) -> Callable[[Callable], Callable]
Marks a function as a hook implementation.
May be used either as a bare decorator (@hookimpl) or as a factory
(@hookimpl(priority=50)). Lower priority values run first when
multiple plugins implement the same hook; the default is 100.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Optional[Callable]
|
When called without parentheses, the decorated function is passed here directly by the Python decorator protocol. |
None
|
priority
|
int
|
Execution order relative to other implementations of the same hook. Lower = earlier. Defaults to 100. |
100
|
nala.athomic.plugins.manager.PluginManager
Bases: PluginManagerProtocol
Mediates the interaction between the Athomic core and external plugins.
It implements the Mediator, Observer, and Registry patterns to handle plugin discovery, registration, and resilient hook execution.
__init__(settings=None, notification_provider=None)
Initializes the PluginManager and its internal hook registry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[PluginsSettings]
|
Plugin configuration. Defaults to the global settings'
|
None
|
notification_provider
|
Optional[NotificationProtocol]
|
Optional pre-built notification provider used
when hook errors trigger alerts. When |
None
|
call_hook(hook_name, **kwargs)
async
Executes all registered implementations for a given hook with resilience, observability (tracing/metrics), and failure notification.
describe_plugin(name)
Returns introspection data for a loaded plugin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The entry-point name of the plugin (as reported in
|
required |
Returns:
| Type | Description |
|---|---|
Optional[Dict[str, Any]]
|
A dict with |
Optional[Dict[str, Any]]
|
plugin with that name has been loaded. |
discover_and_load()
async
Discovers plugins using Python's entry points (group="nala.plugins"), loads their modules, and registers all functions marked with @hookimpl.
get_api_routers()
async
Public contract method for the API layer. It calls the 'get_api_routers' hook, aggregates the results (a list of lists), and flattens them into a single list of router objects.