Skip to main content

Plugin API Contracts

This document defines the technical API contracts for BrainDrive plugins. For conceptual overview and development workflow, see How BrainDrive Plugins Work.

Table of Contents


Lifecycle Manager Interface

Every plugin can include a lifecycle_manager.py file that implements the plugin lifecycle. This Python class handles installation, removal, and configuration.

Required Structure

class LifecycleManager:
"""
Plugin lifecycle manager implementing the BrainDrive plugin contract.
"""

def __init__(self, plugin_id: str, plugin_path: str):
"""
Initialize the lifecycle manager.

Args:
plugin_id: Unique identifier for this plugin instance
plugin_path: Filesystem path to the plugin directory
"""
self.plugin_id = plugin_id
self.plugin_path = plugin_path

async def install_plugin(self, user_id: str, db) -> dict:
"""
Called when a user installs the plugin.

Args:
user_id: The ID of the user installing the plugin
db: Database session for plugin setup

Returns:
dict with 'success' (bool) and optional 'message' (str)
"""
# Initialize plugin resources, create tables, seed data
return {"success": True, "message": "Plugin installed successfully"}

async def delete_plugin(self, user_id: str, db) -> dict:
"""
Called when a user uninstalls the plugin.

Args:
user_id: The ID of the user uninstalling
db: Database session for cleanup

Returns:
dict with 'success' (bool) and optional 'message' (str)
"""
# Clean up plugin resources, remove data
return {"success": True, "message": "Plugin uninstalled successfully"}

async def get_plugin_status(self, user_id: str, db) -> dict:
"""
Check if the plugin is properly installed for a user.

Args:
user_id: The user to check
db: Database session

Returns:
dict with 'installed' (bool) and optional metadata
"""
return {"installed": True, "version": "1.0.0"}

def get_plugin_info(self) -> dict:
"""
Return plugin metadata for the Plugin Manager UI.

Returns:
Plugin metadata dictionary (see Plugin Manifest Format)
"""
return {
"name": "My Plugin",
"slug": "my-plugin",
"version": "1.0.0",
"description": "What this plugin does",
"author": "Your Name",
"components": [...]
}

Optional Methods

class LifecycleManager:
# ... required methods ...

async def repair_plugin(self, user_id: str, db) -> dict:
"""
Repair/reinstall plugin without losing user data.

Returns:
dict with 'success' (bool) and optional 'message' (str)
"""
return {"success": True}

async def upgrade_plugin(self, user_id: str, db, from_version: str, to_version: str) -> dict:
"""
Handle version upgrades with data migration.

Args:
from_version: Previous installed version
to_version: New version being installed

Returns:
dict with 'success' (bool) and optional 'message' (str)
"""
return {"success": True}

def get_routes(self) -> list:
"""
Register custom FastAPI routes for this plugin.

Returns:
List of FastAPI route definitions
"""
return []

def get_settings_definitions(self) -> list:
"""
Define plugin settings that appear in the Settings UI.

Returns:
List of setting definition dictionaries
"""
return []

Plugin Manifest Format

The plugin manifest is returned by get_plugin_info() and defines how the plugin appears in BrainDrive.

Full Schema

{
"name": "My Plugin",
"slug": "my-plugin",
"version": "1.0.0",
"description": "Brief description of what this plugin does",
"author": "Developer Name",
"author_url": "https://github.com/developer",
"repository": "https://github.com/org/plugin-repo",
"license": "MIT",
"icon": "puzzle-piece",
"category": "ai | utility | integration | widget",
"tags": ["ai", "chat", "productivity"],
"min_braindrive_version": "1.0.0",
"components": [
{
"id": "my-component",
"name": "My Component",
"description": "What this component does",
"category": "widgets",
"icon": "widget-icon",
"default_config": {
"title": "Default Title",
"showHeader": true
},
"config_schema": {
"type": "object",
"properties": {
"title": { "type": "string", "title": "Title" },
"showHeader": { "type": "boolean", "title": "Show Header" }
}
}
}
],
"dependencies": {
"plugins": ["other-plugin-slug"],
"services": ["ollama", "openai"]
},
"permissions": ["api", "settings", "events", "state"]
}

Required Fields

FieldTypeDescription
namestringHuman-readable plugin name
slugstringURL-safe unique identifier (lowercase, hyphens)
versionstringSemantic version (e.g., "1.0.0")
descriptionstringBrief description for Plugin Manager
componentsarrayList of UI components exposed by this plugin

Optional Fields

FieldTypeDescription
authorstringDeveloper/organization name
author_urlstringLink to author's website or profile
repositorystringSource code repository URL
licensestringLicense identifier (e.g., "MIT")
iconstringIcon name for Plugin Manager
categorystringPlugin category for filtering
tagsarrayTags for search/discovery
min_braindrive_versionstringMinimum compatible BrainDrive version
dependenciesobjectRequired plugins or services
permissionsarrayRequested Service Bridge permissions

Module Metadata Format

Each component in the components array defines a draggable UI module.

Component Schema

{
"id": "chat-interface",
"name": "Chat Interface",
"description": "Interactive AI chat component",
"category": "ai",
"icon": "message-square",
"default_size": {
"width": 400,
"height": 600,
"minWidth": 300,
"minHeight": 400
},
"default_config": {
"model": "default",
"systemPrompt": "",
"showHistory": true
},
"config_schema": {
"type": "object",
"properties": {
"model": {
"type": "string",
"title": "AI Model",
"enum": ["default", "gpt-4", "claude"],
"default": "default"
},
"systemPrompt": {
"type": "string",
"title": "System Prompt",
"format": "textarea"
},
"showHistory": {
"type": "boolean",
"title": "Show Chat History",
"default": true
}
}
},
"events": {
"emits": ["chat:message-sent", "chat:response-received"],
"listens": ["user:settings-changed"]
}
}

Component Fields

FieldTypeDescription
idstringUnique component identifier within this plugin
namestringDisplay name in Page Builder
descriptionstringTooltip/description for component
categorystringCategory in Page Builder sidebar
iconstringIcon name for Page Builder
default_sizeobjectInitial dimensions when dropped
default_configobjectDefault configuration values
config_schemaobjectJSON Schema for config panel
eventsobjectEvents this component emits/listens to

Config Schema Format

The config_schema follows JSON Schema with BrainDrive extensions:

{
"type": "object",
"properties": {
"textField": {
"type": "string",
"title": "Text Field",
"description": "Help text shown below field",
"default": "default value"
},
"numberField": {
"type": "number",
"title": "Number Field",
"minimum": 0,
"maximum": 100,
"default": 50
},
"selectField": {
"type": "string",
"title": "Select Field",
"enum": ["option1", "option2", "option3"],
"enumNames": ["Option 1", "Option 2", "Option 3"]
},
"booleanField": {
"type": "boolean",
"title": "Toggle",
"default": false
},
"colorField": {
"type": "string",
"title": "Color",
"format": "color"
},
"textareaField": {
"type": "string",
"title": "Long Text",
"format": "textarea"
}
},
"required": ["textField"]
}

REST API Endpoints

The installation, removal, and management of plugins are handled by the core backend API. These endpoints are what the BrainDrive UI calls when you interact with the Plugin Manager.

For complete details on all plugin-related endpoints, see the Backend REST API Reference (» Plugins).


Frontend Module Federation

Plugins use Webpack Module Federation to expose React components to BrainDrive at runtime.

webpack.config.js Setup

const { ModuleFederationPlugin } = require('webpack').container;

const PLUGIN_SCOPE = 'MyPlugin';
const MODULE_NAME = 'MyPluginModule';

module.exports = {
// ... other config
plugins: [
new ModuleFederationPlugin({
name: PLUGIN_SCOPE, // Must match plugin_data.scope from lifecycle_manager.py
filename: 'remoteEntry.js',
exposes: {
// Expose modules by their module name from lifecycle_manager.py
[`./${MODULE_NAME}`]: './src/index',
},
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
},
}),
],
};

Component Export Format

Each exposed component receives Service Bridges via props:

// src/components/MyComponent.tsx
import React from 'react';

interface MyComponentProps {
// Service Bridges (injected by BrainDrive)
bridges: {
api: APIBridge;
events: EventBridge;
theme: ThemeBridge;
settings: SettingsBridge;
pageContext: PageContextBridge;
pluginState: PluginStateBridge;
};
// Component configuration (from Page Builder)
config: {
title?: string;
showHeader?: boolean;
// ... matches config_schema
};
// Page context
pageId: string;
componentId: string;
}

const MyComponent: React.FC<MyComponentProps> = ({ bridges, config, pageId }) => {
const [data, setData] = React.useState(null);

React.useEffect(() => {
// Load saved state
bridges.pluginState.load().then(setData);
}, []);

return (
<div>
<h2>{config.title || 'My Component'}</h2>
{/* Component content */}
</div>
);
};

export default MyComponent;

Build Output

After running npm run build, your plugin should produce:

dist/
├── remoteEntry.js # Module Federation entry point (required)
├── main.js # Main bundle
├── [hash].js # Chunk files
└── assets/ # Static assets (images, fonts)

The remoteEntry.js file is what BrainDrive loads to access your plugin's components.