Skip to main content

Plugin System Overview

MoFA implements a dual-layer plugin architecture that combines the performance of compile-time plugins with the flexibility of runtime plugins, enabling extreme extensibility without compromising performance.

Architecture

The plugin system consists of two complementary layers:
┌─────────────────────────────────────────────────────────────┐
│                    Business Layer                           │
│              (Your Agents & Workflows)                      │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│              Runtime Plugin Layer (Rhai)                    │
│  • Hot-reloadable scripts                                   │
│  • Dynamic business logic                                   │
│  • Workflow orchestration                                   │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│         Compile-time Plugin Layer (Rust/WASM)               │
│  • LLM integration                                          │
│  • Tool execution                                           │
│  • Storage & memory                                         │
│  • Native system integration                                │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│              MoFA Microkernel                               │
│  • Plugin lifecycle management                              │
│  • Communication bus                                        │
│  • Metadata system                                          │
└─────────────────────────────────────────────────────────────┘

Plugin Types

MoFA supports multiple plugin types for different use cases:

LLM Plugins

Integrate language models for text generation, chat, and embeddings

Tool Plugins

Execute custom tools and function calls from agents

Storage Plugins

Provide persistent key-value storage backends

Memory Plugins

Manage agent memory and retrieval systems

Monitor Plugins

Track metrics, alerts, and observability

Custom Plugins

Implement domain-specific functionality

Plugin Lifecycle

All plugins follow a standard lifecycle:
1

Unloaded

Plugin is registered but not yet loaded into memory
2

Loading

Plugin is being loaded and configured
3

Loaded

Plugin is loaded but not yet initialized
4

Running

Plugin is active and processing requests
5

Paused

Plugin is temporarily stopped but can be resumed
6

Unloaded

Plugin is shut down and resources are released

Plugin Manager

The PluginManager coordinates all plugin operations:
mofa-plugins/src/lib.rs
use mofa_plugins::{
    PluginManager, LLMPlugin, ToolPlugin, StoragePlugin
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create plugin manager
    let manager = PluginManager::new("my_agent");

    // Register plugins
    manager.register(LLMPlugin::new("llm_001")).await?;
    manager.register(ToolPlugin::new("tools_001")).await?;
    manager.register(StoragePlugin::new("storage_001")).await?;

    // Initialize all plugins
    manager.load_all().await?;
    manager.init_all().await?;
    manager.start_all().await?;

    // Execute plugin
    let result = manager.execute(
        "llm_001",
        "What is the capital of France?".to_string()
    ).await?;

    println!("Result: {}", result);

    // Cleanup
    manager.stop_all().await?;
    manager.unload_all().await?;

    Ok(())
}

Core Plugin Trait

All plugins implement the AgentPlugin trait:
mofa-kernel/src/plugin/mod.rs
#[async_trait::async_trait]
pub trait AgentPlugin: Send + Sync {
    /// Get plugin metadata
    fn metadata(&self) -> &PluginMetadata;

    /// Get current plugin state
    fn state(&self) -> PluginState;

    /// Load plugin with context
    async fn load(&mut self, ctx: &PluginContext) -> PluginResult<()>;

    /// Initialize plugin
    async fn init_plugin(&mut self) -> PluginResult<()>;

    /// Start plugin execution
    async fn start(&mut self) -> PluginResult<()>;

    /// Stop plugin execution
    async fn stop(&mut self) -> PluginResult<()>;

    /// Unload plugin and release resources
    async fn unload(&mut self) -> PluginResult<()>;

    /// Execute plugin with input
    async fn execute(&mut self, input: String) -> PluginResult<String>;

    /// Get plugin statistics
    fn stats(&self) -> HashMap<String, serde_json::Value>;

    /// Type casting support
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
    fn into_any(self: Box<Self>) -> Box<dyn Any>;
}

Plugin Metadata

Every plugin has associated metadata:
mofa-kernel/src/plugin/mod.rs
pub struct PluginMetadata {
    /// Unique plugin identifier
    pub id: String,
    /// Human-readable name
    pub name: String,
    /// Plugin type
    pub plugin_type: PluginType,
    /// Version string
    pub version: String,
    /// Description
    pub description: String,
    /// Plugin capabilities
    pub capabilities: Vec<String>,
    /// Execution priority
    pub priority: i32,
    /// Plugin dependencies
    pub dependencies: Vec<String>,
}

impl PluginMetadata {
    pub fn new(id: &str, name: &str, plugin_type: PluginType) -> Self {
        Self {
            id: id.to_string(),
            name: name.to_string(),
            plugin_type,
            version: "1.0.0".to_string(),
            description: String::new(),
            capabilities: Vec::new(),
            priority: 0,
            dependencies: Vec::new(),
        }
    }

    pub fn with_description(mut self, desc: &str) -> Self {
        self.description = desc.to_string();
        self
    }

    pub fn with_capability(mut self, capability: &str) -> Self {
        self.capabilities.push(capability.to_string());
        self
    }
}

Plugin Context

Plugins receive a shared context for state and configuration:
use mofa_plugins::{PluginContext, PluginConfig};

// Create context
let ctx = PluginContext::new("my_agent");

// Set shared state
ctx.set_state("counter", 42i32).await;
ctx.set_state("session_id", "abc123".to_string()).await;

// Get shared state
let counter: Option<i32> = ctx.get_state("counter").await;
let session: Option<String> = ctx.get_state("session_id").await;

// Configure plugin
let mut config = PluginConfig::new();
config.set("timeout", 30);
config.set("enabled", true);
config.set("api_key", "sk-...");
The plugin context is thread-safe and can be shared across plugins for inter-plugin communication.

Health Checks

Monitor plugin health:
// Check all plugins
let health = manager.health_check_all().await;
for (id, healthy) in &health {
    println!("Plugin {}: {}", id,
        if *healthy { "✓ Healthy" } else { "✗ Unhealthy" }
    );
}

// Get plugin statistics
let stats = manager.stats("llm_001").await;
if let Some(stats) = stats {
    println!("Call count: {}", stats["call_count"]);
    println!("Total tokens: {}", stats["total_tokens"]);
}

Plugin Discovery

List and filter plugins:
// List all plugins
let plugins = manager.list_plugins().await;
for plugin in &plugins {
    println!("- {} ({}): {}", plugin.name, plugin.id, plugin.description);
}

// Get plugins by type
let llm_plugins = manager.get_by_type(PluginType::LLM).await;
let tool_plugins = manager.get_by_type(PluginType::Tool).await;

println!("LLM plugins: {:?}", llm_plugins);
println!("Tool plugins: {:?}", tool_plugins);

Next Steps

Compile-time Plugins

Build high-performance Rust/WASM plugins

Runtime Plugins

Create flexible Rhai runtime plugins

Rhai Scripting

Learn the Rhai scripting language

WASM Plugins

Develop sandboxed WebAssembly plugins

Build docs developers (and LLMs) love