Package a plugin
Use a plugin to give the Bub app behavior you want to reuse or share. A Python package declares an entry point in the bub group; Bub imports that target and registers its hook implementations. You can also reuse an existing plugin in your own service while keeping your host’s entry point.
For a complete first example, follow Write your first plugin. This guide covers the choices you make when packaging a plugin of your own.
Portable Agent Plugins use a different format: plugin.json, skills, and MCP servers. The Agent Plugins integration loads those packages through a Python plugin.
Declare an entry point
Section titled “Declare an entry point”A plugin needs the application dependencies described in Install Bub. Declare bub[app]>=0.6.0 in the package dependencies for this guide. See Upgrade to 0.6.0 when updating an existing plugin.
[project.entry-points."bub"]
myplugin = "bub_myplugin.plugin"
The key myplugin identifies the plugin in diagnostics. The value names the Python object to import.
Choose one target form:
| Target | Registration | Use it when |
|---|---|---|
bub_myplugin.plugin |
Register the module | Hooks are module-level functions |
bub_myplugin.plugin:plugin |
Register the instance | Hooks share state on an object |
bub_myplugin.plugin:MyPlugin |
Call the class or factory with BubFramework, then register its result |
Hooks need the framework |
For the module form, define hooks at module level:
from bub import hookimpl
@hookimpl
def build_prompt(message, session_id, state):
return "Describe this workspace."
For the instance form, create the object in the target module:
from bub import hookimpl
class MyPlugin:
@hookimpl
def build_prompt(self, message, session_id, state):
return "Describe this workspace."
plugin = MyPlugin()
Every callable target receives the framework, including classes. Accept it in the constructor or factory:
from bub import BubFramework, hookimpl
class MyPlugin:
def __init__(self, framework: BubFramework) -> None:
self.framework = framework
@hookimpl
def build_prompt(self, message, session_id, state):
return f"Describe the workspace at {self.framework.workspace}."
These examples replace the prompt. Choose the hook for your actual task from Change application behavior.
Register tools during import
Section titled “Register tools during import”If the package defines @tool functions, import their module from the entry-point module before an agent is created:
from . import tools # noqa: F401
The application takes a snapshot of registered tools when it creates a BubAgent. See Add application tools for registration, deferred loading, and code mode.
Install into the application’s environment
Section titled “Install into the application’s environment”An editable install lets you change Python source without rebuilding the package. Use the same environment that runs Bub.
For a uv project, run from the plugin directory:
uv sync
uv run bub hooks
To install into an existing activated application environment, use uv pip install -e . and run bub hooks there.
bub hooks confirms registration. Check priority and return values by running the task your hook should handle. Bub registers builtin hooks before entry-point plugins. Hooks at equal priority generally run in reverse registration order; tryfirst and trylast affect that order. The dispatch rules explain which implementation runs first.
If the plugin is missing, check its entry-point group, the active environment, and startup logs for an import failure. Changes to package metadata require reinstalling the package.
Share the plugin
Section titled “Share the plugin”Build and install a wheel into a separate environment before publishing it. Confirm that the entry point loads and that a representative task uses your hook. If you bundle skills or several plugins, follow Package a Bub application.