pluggable

Crates.iopluggable
lib.rspluggable
version0.1.0
created_at2025-08-04 17:48:37.392798+00
updated_at2025-08-04 17:48:37.392798+00
descriptionA comprehensive, async plugin system for Rust applications with dependency management and security
homepagehttps://github.com/tomerlichtash/pluggable
repositoryhttps://github.com/tomerlichtash/pluggable
max_upload_size
id1780990
size319,631
Tomer Lichtash (tomerlichtash)

documentation

https://docs.rs/pluggable

README

Pluggable

Crates.io Documentation CI License

A comprehensive, async plugin system for Rust applications with dependency management, security, and extensibility.

Features

  • ๐Ÿš€ Async-first: Built from the ground up with async/await support
  • ๐Ÿ”— Dependency Management: Automatic plugin dependency resolution and execution ordering
  • ๐Ÿ”’ Security: Capability-based permission system with sandboxing support
  • โšก Performance: Parallel plugin execution where dependencies allow
  • ๐Ÿงช Testing: Comprehensive testing framework with mocks and harnesses
  • ๐Ÿ“Š Observability: Event system with lifecycle hooks and logging
  • ๐Ÿ›  Developer Experience: Clean APIs, auto-discovery, and rich configuration

Quick Start

Add to your Cargo.toml:

[dependencies]
pluggable = "0.1.0"

Basic Plugin Example

use pluggable::prelude::*;

#[derive(Default)]
pub struct HelloPlugin {
    metadata: PluginMetadata,
}

impl HelloPlugin {
    pub fn new() -> Self {
        Self {
            metadata: PluginMetadata::new("hello", "1.0.0"),
        }
    }
}

#[async_trait]
impl Plugin for HelloPlugin {
    fn metadata(&self) -> &PluginMetadata {
        &self.metadata
    }

    fn schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "name": { "type": "string", "default": "World" }
            }
        })
    }

    async fn initialize(
        &mut self,
        _config: serde_json::Value,
        _context: &PluginContext,
    ) -> PluginResult<()> {
        Ok(())
    }

    async fn execute(&mut self, _context: &mut PluginContext) -> PluginResult<PluginOutput> {
        Ok(PluginOutput::success(json!({
            "message": "Hello, World!"
        })))
    }

    async fn cleanup(&mut self, _context: &PluginContext) -> PluginResult<()> {
        Ok(())
    }
}

// Auto-register the plugin
pluggable::register_plugin!(HelloPlugin, "hello", "1.0.0", "A simple greeting plugin");

Running a Plugin Pipeline

use pluggable::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create plugin registry and discover plugins
    let mut registry = PluginRegistry::new();
    let mut discovery = PluginDiscovery::new();
    discovery.auto_register_all(&mut registry)?;

    // Set up workspace and executor
    let workspace = std::path::PathBuf::from("./workspace");
    let executor = PluginExecutor::new(registry, workspace);

    // Execute the pipeline with automatic dependency resolution
    let results = executor.execute_pipeline().await?;

    println!("Pipeline completed with {} plugins", results.plugin_outputs.len());
    Ok(())
}

Key Concepts

Plugin System

  • Plugin Trait: Core trait that all plugins implement
  • Auto-Discovery: Plugins are automatically discovered and registered
  • Lifecycle Management: Initialize โ†’ Execute โ†’ Cleanup phases

Dependency Management

  • Automatic Resolution: Dependencies are resolved and executed in correct order
  • Parallel Execution: Independent plugins run concurrently
  • Output Passing: Plugin outputs are available to dependent plugins

Security

  • Permission-Based: Plugins declare required permissions
  • Capability System: Fine-grained access control
  • Sandboxing: Optional isolation for untrusted plugins

Configuration

  • JSON Schema: Type-safe configuration with validation
  • Flexible Loading: Support for TOML, YAML, and JSON
  • Environment Integration: Environment variable expansion

Examples

The repository includes several comprehensive examples:

  • Text Processor: Multi-plugin text processing pipeline
  • Plugin Testing: Comprehensive testing framework usage
  • Security: Permission system and sandboxing

Run examples with:

cargo run --example text_processor

Architecture

The plugin system is built around several core components:

  • Registry: Manages plugin discovery and registration
  • Executor: Handles plugin lifecycle and dependency resolution
  • Context: Provides plugins with workspace access and communication
  • Security Manager: Enforces permission-based access control
  • Event System: Enables plugin communication and observability

For detailed architecture information, see ARCHITECTURE.md.

Testing

Pluggable includes a comprehensive testing framework:

use pluggable::testing::*;

#[tokio::test]
async fn test_my_plugin() {
    let mut harness = PluginTestHarness::new().unwrap();
    
    let plugin = MyPlugin::new();
    harness = harness.with_plugin(plugin).unwrap();
    
    let output = harness.execute("my-plugin").await.unwrap();
    
    harness.assert_success(&output).unwrap();
    harness.assert_output_contains(&output, "result", &json!("expected")).unwrap();
}

Performance

  • Parallel Execution: Independent plugins run concurrently
  • Efficient Dependencies: Topological sorting for optimal execution order
  • Minimal Overhead: Zero-cost abstractions where possible
  • Resource Management: Automatic cleanup and memory management

Contributing

Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.

License

This project is licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Commit count: 0

cargo fmt