Skip to content

Plugin Architecture

The FCC framework provides a plugin system with 10 plugin types, entry-point discovery via importlib.metadata, a central PluginRegistry, and a CrossPluginOrchestrator for dependency resolution and interaction management across the ecosystem.

flowchart TD
    EP[setuptools entry points] --> PR[PluginRegistry]
    PR --> |discover| D{10 Plugin Types}
    D --> P1[PersonaPlugin]
    D --> P2[EnginePlugin]
    D --> P3[TemplatePlugin]
    D --> P4[ScorerPlugin]
    D --> P5[ValidatorPlugin]
    D --> P6[ProviderPlugin]
    D --> P7[GovernancePlugin]
    D --> P8[ScenarioPlugin]
    D --> P9[WorkflowPlugin]
    D --> P10[EventSubscriberPlugin]
    PR --> CPO[CrossPluginOrchestrator]
    CPO --> Health[EcosystemHealthReport]

Plugin Types

Each plugin type corresponds to a setuptools entry-point group under fcc.plugins.*:

Plugin Type Entry-Point Group Purpose ABC
Personas fcc.plugins.personas Contribute additional persona YAML definitions PersonaPlugin
Engines fcc.plugins.engines Provide custom simulation engines EnginePlugin
Templates fcc.plugins.templates Supply Jinja2 doc templates TemplatePlugin
Scorers fcc.plugins.scorers Implement custom quality scoring ScorerPlugin
Validators fcc.plugins.validators Add custom validation rules ValidatorPlugin
Providers fcc.plugins.providers Provide data or AI services ProviderPlugin
Governance fcc.plugins.governance Extend governance frameworks GovernancePlugin
Scenarios fcc.plugins.scenarios Contribute simulation scenarios ScenarioPlugin
Workflows fcc.plugins.workflows Add custom workflow graphs WorkflowPlugin
Subscribers fcc.plugins.subscribers Register event bus subscribers EventSubscriberPlugin

PluginMeta

Every plugin exposes metadata through the plugin_meta() method, returning a frozen PluginMeta dataclass:

Field Type Description
id str Unique plugin identifier
name str Human-readable plugin name
version str Semantic version string
plugin_type PluginType One of the 10 plugin types
description str Plugin description
author str Plugin author
source_package str Python package providing this plugin
tags tuple[str, ...] Categorization tags

Plugin ABCs

Each plugin type has an abstract base class defining its contract. Here are the key ABCs:

PersonaPlugin

class PersonaPlugin(ABC):
    @abstractmethod
    def plugin_meta(self) -> PluginMeta: ...

    @abstractmethod
    def get_persona_paths(self) -> list[Path]:
        """Return paths to YAML files containing persona definitions."""

    def get_dimension_paths(self) -> list[Path]:
        """Return paths to dimension profile YAML files (optional)."""
        return []

    def get_cross_reference_paths(self) -> list[Path]:
        """Return paths to cross-reference YAML files (optional)."""
        return []

EnginePlugin

Contributes a custom simulation engine class that the framework can use in place of the default engine.

EventSubscriberPlugin

The 10th plugin type, connecting the plugin system with the event bus. Subscriber plugins register callbacks for specific event types during framework initialization.

PluginRegistry

The PluginRegistry is the central registry for discovering, loading, and accessing plugins.

Discovery

from fcc.plugins.registry import PluginRegistry

registry = PluginRegistry()
result = registry.discover()

print(result.discovered)   # Total entry points found
print(result.loaded)       # Successfully loaded
print(result.errors)       # List of error messages

Discovery scans all fcc.plugins.* entry-point groups using importlib.metadata.entry_points(). Each entry point is loaded, instantiated, and validated against the appropriate ABC. Plugins that fail to load are recorded as errors but do not block other plugins.

Querying Plugins

from fcc.plugins.base import PluginType

# Get all plugins of a specific type
persona_plugins = registry.get_plugins(PluginType.PERSONAS)

# Get a specific plugin by ID
plugin = registry.get_plugin("paom-personas")

# Check if a plugin exists
exists = registry.has_plugin("paom-personas")

Entry-Point Registration

Plugins register through pyproject.toml or setup.cfg:

[project.entry-points."fcc.plugins.personas"]
my-personas = "my_package.fcc_plugin:MyPersonaPlugin"

[project.entry-points."fcc.plugins.subscribers"]
my-subscriber = "my_package.fcc_plugin:MySubscriberPlugin"

CrossPluginOrchestrator

The CrossPluginOrchestrator manages interactions between ecosystem plugins, providing dependency resolution, interaction matrix querying, and health monitoring.

Dependencies

from fcc.plugins.orchestration import CrossPluginOrchestrator, PluginDependency

orchestrator = CrossPluginOrchestrator()

# Add a dependency
orchestrator.add_dependency(PluginDependency(
    source_plugin="constel",
    target_plugin="paom",
    dependency_type="provides_taxonomy",
    description="CONSTEL provides taxonomy data to PAOM",
))

# Resolve dependencies for a plugin
deps = orchestrator.resolve_dependencies("constel")

# Find reverse dependencies (who depends on this plugin?)
rdeps = orchestrator.reverse_dependencies("paom")

Interactions

Cross-plugin persona interactions track how personas from different plugins collaborate:

from fcc.plugins.orchestration import PluginInteraction

orchestrator.add_interaction(PluginInteraction(
    source_persona="STE",
    source_plugin="fcc-core",
    target_persona="OA",
    target_plugin="constel",
    interaction_type="peer",
    description="Taxonomy alignment between STE and OA",
))

# Query interaction matrix grouped by source plugin
matrix = orchestrator.get_interaction_matrix()

# Get all interactions for a specific persona
interactions = orchestrator.get_interactions_for_persona("STE")

# Validate all interactions reference known plugins
errors = orchestrator.validate_interactions()

Ecosystem Health

from fcc.plugins.orchestration import PluginHealthStatus

statuses = [
    PluginHealthStatus(plugin_id="fcc-core", healthy=True, persona_count=24),
    PluginHealthStatus(plugin_id="paom", healthy=True, persona_count=30),
    PluginHealthStatus(plugin_id="constel", healthy=False, error="Missing dep"),
]

report = orchestrator.check_health(statuses)
print(report.total_plugins)     # 3
print(report.healthy_plugins)   # 2
print(report.unhealthy_plugins) # 1
print(report.total_personas)    # 54

Data Files

Plugin ecosystem configuration is stored in src/fcc/data/ecosystem/:

  • plugin_dependencies.yaml -- Declares inter-plugin dependencies with types and descriptions
  • plugin_interactions.yaml -- Maps cross-plugin persona interactions with directions

Error Handling

The plugin system defines three specific error types in fcc.plugins.errors:

Error When Raised
PluginLoadError Plugin fails to load or instantiate
PluginConflictError Two plugins register the same ID
PluginNotFoundError Requested plugin ID does not exist