Skip to content

Migration Guide — Phase 7: Plug & Play

This guide walks you through migrating existing XYBEROS code to use the Phase 7 patterns: entry-point discovery, capability-based provider selection, and graceful degradation.


Table of Contents

  1. Why Migrate?
  2. Migration: Provider → Capability-Aware Provider
  3. Migration: Manager → Graceful Degradation
  4. Migration: Registry → Entry-Point Discovery
  5. Migration: Pipeline → Phase-Gated Pipeline
  6. Checklist

Why Migrate?

Pattern Before (Phase 0-6) After (Phase 7)
Provider selection Always uses .default() Capability-gated .best() or .fallback()
Failure handling Raises immediately Graceful degradation across providers
Plugin registration Manual registry.register() Auto-discovery via entry points
Input gating No built-in mechanism can_handle() on each provider

Migration: Provider → Capability-Aware Provider

Before

from xyberos.common.provider import Provider


class MyProvider(Provider):
    @property
    def name(self) -> str:
        return "my_provider"

    def process(self, input: str) -> str:
        return input.upper()

After

from xyberos.common import Provider, ProviderCapability
from xyberos.common.capabilities import nlp_capability


class MyProvider(Provider):
    @property
    def name(self) -> str:
        return "my_provider"

    @property
    def capability(self) -> ProviderCapability:
        return nlp_capability(
            languages=("en",),
            description="NLP-based uppercase transformer",
        )

    def can_handle(self, input: str) -> bool:
        """Only handle English text under 10KB."""
        return (
            isinstance(input, str)
            and len(input) < 10_000
        )

    def process(self, input: str) -> str:
        return input.upper()

What changed

  1. Added capability property — declares this is an NLP (Phase 2) provider that handles English with ~50ms latency.
  2. Added can_handle() — prevents the provider from being selected for inputs it cannot process (e.g. non-string or oversized).

Migration: Manager → Graceful Degradation

Before

class MyManager:
    def __init__(self, registry):
        self._registry = registry

    def detect(self, text: str) -> tuple[str, float]:
        provider = self._registry.default()
        return provider.detect(text)

After

import logging

logger = logging.getLogger(__name__)

class MyManager:
    def __init__(self, registry):
        self._registry = registry

    def detect(self, text: str) -> tuple[str, float]:
        """Detect with graceful degradation."""
        return self._registry.fallback(
            text,
            "detect",
            default_result=("unknown", 0.0),
        )

    def detect_fast(self, text: str) -> tuple[str, float]:
        """Fast path — default provider only, no fallback."""
        return self._registry.default().detect(text)

What changed

  1. detect() now uses registry.fallback() — tries each provider in priority order. On failure, logs and tries the next.
  2. Added detect_fast() — direct default provider call for when you want the old behavior (fast, no fallback).
  3. No try/except needed — fallback() handles it.

Migration: Registry → Entry-Point Discovery

Before

registry = MyRegistry()
registry.register("my_provider", MyProvider(), default=True)

After

registry = MyRegistry()

# Option A: Auto-discover from entry points
registry.discover("xyberos.providers")

# Option B: Manual with entry-point helper
from xyberos.common.registry import discover_and_register
discover_and_register(registry, "xyberos.providers", default_name="my_provider")

# Option C: Manual (unchanged)
registry.register("my_provider", MyProvider(), default=True)

Adding entry points to your package

In your pyproject.toml:

[project.entry-points."xyberos.providers"]
my_provider = "my_package.providers:MyProvider"

See docs/plugins.md for details.


Migration: Pipeline → Phase-Gated Pipeline

Before

from xyberos.common.pipeline import Pipeline

pipeline = Pipeline([stage1, stage2, stage3])
result = pipeline.execute(input)

After (phase-limited execution)

from xyberos.brain.perception.perceiver import CognitivePerceiver
from xyberos.brain.perception.models import PerceptionInput

perceiver = CognitivePerceiver()

# Only run deterministic + NLP processors (phases 1-2)
observation = perceiver.perceive_with_capability(
    PerceptionInput(content="Hello"),
    max_phase=2,
)

After (graceful degradation)

from xyberos.brain.perception.perceiver import GracefulPerceiver

perceiver = GracefulPerceiver(fallback_phase=2)

# If full pipeline fails, falls back to phase 1-2 only
# On total failure, returns minimal Observation (never crashes)
observation = perceiver.perceive(PerceptionInput(content="Hello"))

Checklist

Use this checklist when migrating a module to Phase 7:

  • [ ] Provider: Added capability property with appropriate phase
  • [ ] Provider: Added can_handle() with input validation
  • [ ] Manager: Uses registry.fallback() instead of registry.default()
  • [ ] Manager: Added _fast() variant for direct default access
  • [ ] Registry: Calls registry.discover() during initialization
  • [ ] Entry Points: Added pyproject.toml entry point for each provider
  • [ ] Pipeline: Considered GracefulPerceiver for perception
  • [ ] Tests: Added tests for fallback behavior
  • [ ] Tests: Added tests for can_handle() gating
  • [ ] Tests: Added tests for capability-based selection