Plugin System Documentation
Plugin System Documentation
Section titled “Plugin System Documentation”The architecture analyzer uses a plugin-based system for metrics computation. This allows you to add new metrics without modifying the core system.
Plugin Interface
Section titled “Plugin Interface”All metric plugins implement the MetricPlugin trait:
#[async_trait]pub trait MetricPlugin: Send + Sync { fn id(&self) -> &str; fn version(&self) -> &str; fn requires(&self) -> Vec<DataRequirement>; async fn compute(&self, ctx: &MetricContext) -> anyhow::Result<MetricResult>;}Required Methods
Section titled “Required Methods”id(): Returns a unique identifier for the plugin (e.g.,"scc","propagation_cost")version(): Returns the plugin version stringrequires(): Lists the data artifacts this plugin needs (e.g.,ImportGraph,SccDag,Reachability)compute(): Computes the metric and returns aMetricResult
Creating a Plugin
Section titled “Creating a Plugin”Step 1: Create Plugin Module
Section titled “Step 1: Create Plugin Module”Create a new directory under crates/arxo-engine/src/metrics/:
crates/arxo-engine/src/metrics/ └── your_metric/ ├── mod.rs └── plugin.rsStep 2: Implement the Plugin
Section titled “Step 2: Implement the Plugin”Example plugin structure:
use async_trait::async_trait;use std::collections::HashMap;use crate::core::types::{DataRequirement, MetricContext, MetricPlugin, MetricResult};
pub struct YourMetricPlugin;
#[async_trait]impl MetricPlugin for YourMetricPlugin { fn id(&self) -> &str { "your_metric" }
fn version(&self) -> &str { "1.0.0" }
fn requires(&self) -> Vec<DataRequirement> { vec![DataRequirement::ImportGraph] }
async fn compute(&self, ctx: &MetricContext) -> anyhow::Result<MetricResult> { // Access data through context let graph = ctx.data.import_graph().await?;
// Compute your metric let value = compute_your_metric(&graph);
// Return result let mut values = HashMap::new(); values.insert("your_metric.value".to_string(), value);
Ok(MetricResult { id: self.id().to_string(), version: self.version().to_string(), values, details: None, }) }}Step 3: Register the Plugin
Section titled “Step 3: Register the Plugin”Add your plugin to the registry in crates/arxo-engine/src/core/registry.rs:
use crate::metrics::your_metric::plugin::YourMetricPlugin;
impl PluginRegistry { fn register_defaults(&mut self) { self.register(Box::new(SccMetricPlugin)); self.register(Box::new(YourMetricPlugin)); // Add your plugin }}Step 4: Export the Module
Section titled “Step 4: Export the Module”Add to crates/arxo-engine/src/metrics/mod.rs:
pub mod scc;pub mod your_metric; // Add your moduleAvailable Data Artifacts
Section titled “Available Data Artifacts”Plugins can request these data artifacts through DataRequirement:
ImportGraph: The dependency graph with nodes and edgesSccDag: Strongly connected components (cycles) and condensed DAGReachability: Transitive reachability matrix (future)ExportsIndex: Public API surface analysis (future)
Example: SCC Plugin
Section titled “Example: SCC Plugin”The SCC (Strongly Connected Components) plugin demonstrates the pattern:
pub struct SccMetricPlugin;
#[async_trait]impl MetricPlugin for SccMetricPlugin { fn id(&self) -> &str { "scc" } fn version(&self) -> &str { "1.0.0" }
fn requires(&self) -> Vec<DataRequirement> { vec![DataRequirement::SccDag] }
async fn compute(&self, ctx: &MetricContext) -> anyhow::Result<MetricResult> { let scc_dag = ctx.data.scc_dag().await?;
let mut values = HashMap::new(); values.insert("scc.component_count".to_string(), scc_dag.component_count() as f64); values.insert("scc.cycle_count".to_string(), scc_dag.cycle_count() as f64); values.insert("scc.max_cycle_size".to_string(), scc_dag.max_cycle_size() as f64); values.insert("scc.total_nodes_in_cycles".to_string(), scc_dag.total_in_cycles() as f64);
Ok(MetricResult { id: self.id().to_string(), version: self.version().to_string(), values, details: None, }) }}Metric Result Format
Section titled “Metric Result Format”The MetricResult contains:
id: Plugin identifierversion: Plugin versionvalues: HashMap of metric keys to values (e.g.,"scc.cycle_count"→5.0)details: Optional additional diagnostic information
Metric keys follow the pattern: {plugin_id}.{metric_name} (e.g., scc.cycle_count, scc.max_cycle_size, propagation_cost.system.ratio).
Configuration
Section titled “Configuration”Plugins are enabled/disabled in the YAML configuration:
metrics: - id: scc enabled: true - id: your_metric enabled: trueBest Practices
Section titled “Best Practices”- Idempotency: Plugins should produce consistent results for the same input
- Error Handling: Use
anyhow::Resultfor proper error propagation - Performance: Cache expensive computations in the
MetricContext.cacheif needed - Naming: Use descriptive metric keys that include the plugin ID
- Versioning: Update version when plugin behavior changes
Future Extensions
Section titled “Future Extensions”The plugin system is designed to support:
- Dynamic plugin loading (future)
- Plugin dependencies
- Plugin-specific configuration from YAML
- Parallel metric computation