| name | build-botcore-plugins |
| source | botcore |
| description | Guides development of botcore plugins from protocol implementation to distribution. Covers BotCorePlugin protocol, PluginRegistry API, async command authoring with AFD/CommandResult, MCP server factory (create_mcp_server, meta-tool pattern), CLI generation (build_namespace), entry-point registration, docs registration, and skills directory bundling. Use when building a new botcore plugin, adding commands to a plugin, registering entry points, or integrating with the MCP server factory. Triggers: plugin, botcore plugin, BotCorePlugin, PluginRegistry, entry point, command authoring, CommandResult, MCP server, create_mcp_server, build_namespace, plugin protocol, register commands.
|
| version | 1.0.0 |
| triggers | ["plugin","botcore plugin","BotCorePlugin","PluginRegistry","entry point","command authoring","CommandResult","MCP server","create_mcp_server","build_namespace","plugin protocol","register commands","plugin development","plugin registration"] |
| portable | true |
Building Botcore Plugins
Expert guidance for creating plugins that extend botcore with new commands, documentation, skills, and MCP server integration.
Capabilities
- Implement Plugin Protocol -- Create classes that satisfy
BotCorePlugin with register() and config_schema() methods
- Author Async Commands -- Write async functions returning
CommandResult using the AFD success/error pattern
- Register with PluginRegistry -- Add commands, docs, skills dirs, CLI/MCP names to the plugin registry
- Configure MCP Server -- Use
create_mcp_server() factory to expose plugin commands as MCP tools
- Set Up Entry Points -- Configure
pyproject.toml so plugins are auto-discovered via importlib.metadata
- Bundle Skills -- Package skill directories alongside plugin code for distribution
Routing Logic
Core Principles
1. Protocol Over Inheritance
Plugins implement the `BotCorePlugin` protocol — there is no base class to inherit.
The protocol requires exactly two methods: `register(registry)` and `config_schema()`.
This keeps plugins decoupled from botcore internals. Any class with the right method signatures satisfies the protocol. Type checkers verify compliance at development time.
2. Commands Are Async, Returns Are Typed
Every command must be an `async` function returning `CommandResult[T]`.
Use `success(data, reasoning=...)` for successful outcomes and `error(message)` for failures.
Never raise exceptions for expected failure modes — return `error()` instead.
The AFD framework handles serialization, error formatting, and transport. Commands that raise exceptions break the MCP tool contract.
3. Register Everything Explicitly
All commands, docs, and skills dirs must be registered in `register()`.
Do not rely on auto-discovery within the plugin itself — only entry-point discovery is automatic.
Explicit registration makes the plugin's surface area visible in one place. Reviewers and agents can read register() to understand what a plugin provides.
4. One Plugin Per Package
Each Python package should expose at most one `BotCorePlugin` via entry points.
Split orthogonal concerns into separate packages rather than overloading one plugin.
Workflow
Step 1: Scaffold the Plugin
Create the package structure:
my-plugin/
├── src/my_plugin/
│ ├── __init__.py
│ ├── plugin.py # BotCorePlugin implementation
│ ├── commands/ # Command modules
│ │ ├── __init__.py
│ │ └── core.py
│ └── skills/ # Optional bundled skills
│ └── my-skill/
│ └── SKILL.md
└── pyproject.toml # Entry point registration
Step 2: Implement the Plugin Class
from botcore import BotCorePlugin, PluginRegistry
from pathlib import Path
from my_plugin.commands import my_command, my_other_command
class MyPlugin(BotCorePlugin):
def register(self, registry: PluginRegistry) -> None:
registry.add_commands([my_command, my_other_command])
registry.add_docs("my-plugin", MY_DOCS)
registry.set_cli_name("myplugin")
registry.set_mcp_name("my")
skills_dir = Path(__file__).parent / "skills"
if skills_dir.exists():
registry.add_skills_dir(skills_dir)
def config_schema(self):
return None
Step 3: Write Commands
from afd import CommandResult, success, error
async def my_command(name: str, verbose: bool = False) -> CommandResult[dict]:
"""One-line description of what this command does."""
if not name:
return error("name is required")
result = {"name": name, "processed": True}
return success(result, reasoning=f"Processed {name}")
Step 4: Register Entry Point
In pyproject.toml:
[project.entry-points."botcore.plugins"]
my-plugin = "my_plugin.plugin:MyPlugin"
Step 5: Verify Discovery
Install the package and confirm the plugin loads:
pip install -e .
python -c "from botcore.plugin import discover_plugins; print(discover_plugins())"
Checklist