Skip to content

Cross-Plugin Orchestration

As the FCC ecosystem grows beyond the core framework, plugins from different packages need to coordinate. The CrossPluginOrchestrator manages dependencies between plugins, tracks persona interactions across plugin boundaries, and monitors ecosystem health. This tutorial explains the orchestration model and shows how to use it.

The Plugin Dependency Model

FCC plugins can depend on each other in three ways:

Dependency Type Description Example
provides_llm One plugin supplies LLM capabilities to another PAOM provides LLM access to FCC
provides_taxonomy One plugin supplies classification structures CONSTEL provides taxonomy to AOME
provides_metadata One plugin supplies metadata or configuration FCC provides persona specs to PAOM

These dependencies form a directed graph. The CrossPluginOrchestrator lets you declare, query, and validate this graph.

Setting Up the Orchestrator

from fcc.plugins.orchestration import (
    CrossPluginOrchestrator,
    PluginDependency,
    PluginInteraction,
    PluginHealthStatus,
)

# Declare plugin dependencies
dependencies = [
    PluginDependency(
        source_plugin="paom",
        target_plugin="fcc-core",
        dependency_type="provides_metadata",
        description="PAOM consumes FCC persona specifications",
    ),
    PluginDependency(
        source_plugin="aome",
        target_plugin="constel",
        dependency_type="provides_taxonomy",
        description="AOME uses CONSTEL taxonomy for archetype classification",
    ),
    PluginDependency(
        source_plugin="constel",
        target_plugin="fcc-core",
        dependency_type="provides_metadata",
        description="CONSTEL reads persona dimension profiles from FCC",
    ),
]

orchestrator = CrossPluginOrchestrator(dependencies=dependencies)
print(f"Registered dependencies: {orchestrator.dependency_count}")

Resolving Dependencies

Query what a plugin depends on (forward dependencies) or what depends on it (reverse dependencies):

# What does PAOM depend on?
paom_deps = orchestrator.resolve_dependencies("paom")
for dep in paom_deps:
    print(f"  PAOM -> {dep.target_plugin} ({dep.dependency_type})")

# What depends on fcc-core?
fcc_consumers = orchestrator.reverse_dependencies("fcc-core")
for dep in fcc_consumers:
    print(f"  {dep.source_plugin} -> fcc-core ({dep.dependency_type})")

Expected output:

  PAOM -> fcc-core (provides_metadata)
  paom -> fcc-core (provides_metadata)
  constel -> fcc-core (provides_metadata)

Cross-Plugin Persona Interactions

Personas from different plugins can interact. The orchestrator tracks these cross-boundary interactions:

# Define cross-plugin persona interactions
interactions = [
    PluginInteraction(
        source_persona="RC",
        source_plugin="fcc-core",
        target_persona="PAOM-RA",
        target_plugin="paom",
        interaction_type="downstream",
        description="Research Crafter feeds findings to PAOM Research Analyst",
    ),
    PluginInteraction(
        source_persona="STE",
        source_plugin="fcc-core",
        target_persona="CONSTEL-TE",
        target_plugin="constel",
        interaction_type="peer",
        description="Taxonomy engineers coordinate classification standards",
    ),
    PluginInteraction(
        source_persona="PAOM-RA",
        source_plugin="paom",
        target_persona="AOME-AA",
        target_plugin="aome",
        interaction_type="downstream",
        description="PAOM analysis feeds AOME archetype assessment",
    ),
]

# Add interactions to the orchestrator
for interaction in interactions:
    orchestrator.add_interaction(interaction)

print(f"Total interactions: {orchestrator.interaction_count}")

Querying the Interaction Matrix

The interaction matrix groups interactions by source plugin for a bird's-eye view:

matrix = orchestrator.get_interaction_matrix()
for plugin_id, plugin_interactions in matrix.items():
    print(f"\n{plugin_id}:")
    for ix in plugin_interactions:
        print(f"  {ix.source_persona} -> {ix.target_persona} "
              f"({ix.interaction_type})")

Expected output:

fcc-core:
  RC -> PAOM-RA (downstream)
  STE -> CONSTEL-TE (peer)

paom:
  PAOM-RA -> AOME-AA (downstream)

You can also query interactions for a specific persona:

# Find all interactions involving the Research Crafter
rc_interactions = orchestrator.get_interactions_for_persona("RC")
for ix in rc_interactions:
    direction = "sends to" if ix.source_persona == "RC" else "receives from"
    other = ix.target_persona if ix.source_persona == "RC" else ix.source_persona
    print(f"  RC {direction} {other} ({ix.interaction_type})")

Validating Interactions

The orchestrator can validate that all interactions reference known plugins:

errors = orchestrator.validate_interactions()
if errors:
    for err in errors:
        print(f"  Validation error: {err}")
else:
    print("All interactions are valid")

Ecosystem Health Monitoring

The orchestrator aggregates health status from individual plugins into an ecosystem-wide report:

# Collect health status from each plugin
statuses = [
    PluginHealthStatus(
        plugin_id="fcc-core",
        healthy=True,
        persona_count=84,
    ),
    PluginHealthStatus(
        plugin_id="paom",
        healthy=True,
        persona_count=12,
    ),
    PluginHealthStatus(
        plugin_id="aome",
        healthy=False,
        persona_count=8,
        error="Missing taxonomy dependency",
    ),
]

report = orchestrator.check_health(statuses)
print(f"Total plugins: {report.total_plugins}")
print(f"Healthy: {report.healthy_plugins}")
print(f"Unhealthy: {report.unhealthy_plugins}")
print(f"Total personas: {report.total_personas}")

# Drill into unhealthy plugins
for status in report.statuses:
    if not status.healthy:
        print(f"\n  Plugin {status.plugin_id}: {status.error}")

Expected output:

Total plugins: 3
Healthy: 2
Unhealthy: 1
Total personas: 104

  Plugin aome: Missing taxonomy dependency

The Plugin Registry

The PluginRegistry discovers plugins via Python entry points. It scans all fcc.plugins.* entry-point groups at startup:

from fcc.plugins.registry import PluginRegistry
from fcc.plugins.base import PluginType

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

print(f"Discovered: {result.discovered}")
print(f"Loaded: {result.loaded}")
if result.errors:
    for err in result.errors:
        print(f"  Error: {err}")

# List plugins by type
for plugin_type_name, count in registry.plugins_by_type().items():
    if count > 0:
        print(f"  {plugin_type_name}: {count}")

Next Steps