plugin package

Reviewed against commit 8a2cb42ad on 2026-10-23.

Reference: generated package page orchestrata_ultimate.plugin (14 modules, 3,882 lines of code); key modules sdk, manager, loader, context, governance. In the orchestrata overview this package sits in layer 5 (Interface) beside the gateway, and plugin is one of the ten components of the planned split. Not to be confused with the separate Claude Code plugin that the overview describes under tooling.

The story

Orchestrata ships with a fixed cast of Volks — the Concierge, Analyst, Architect, QA, and their peers — but SPEC-015 demanded that the system be extensible without editing its core. orchestrata_ultimate.plugin is the answer: a Plugin SDK that lets first- and third-party packages contribute new Volk types, tools, LLM providers, messaging channels, Prolog governance rules, and knowledge-graph schema extensions. A plugin is an ordinary Python package that ships a plugin.yaml manifest declaring who it is, what it depends on, and — crucially — which capabilities it needs (di_access, redis, neo4j (the capability identifier and its "Direct Neo4j access" docstring are unchanged in the code at 8a2cb42ad, although Neo4j itself was retired on 2026-07-27), network, filesystem, prolog, event_bus, provider, gateway). Nothing a plugin does happens outside that declaration: the manifest is the contract, and the runtime holds it to that contract.

The life of a plugin flows through a small set of collaborators. PluginLoader finds candidates from two sources — local directories scanned for plugin.yaml files, and pip-installed packages exposing the orchestrata_plugin entry-point group — and imports the module, but only after _validate_module_path confirms the dotted path starts with an allowed prefix and contains no blocked segment (os, subprocess, ctypes, and friends). topological_sort orders manifests so dependencies load before dependents, raising PluginCircularDependencyError on a cycle and PluginDependencyError on a missing edge. Before any of that, manifest.py parses and validates the YAML — kebab-case name, semver version, known capabilities only — into a PluginManifest, and PluginGovernance authorizes the load through an allowlist/blocklist check driven by PluginConfig (open mode admits any non-blocklisted plugin; explicit mode requires an allowlist entry). PluginManager is the conductor: it drives discover → validate → load → initialize → start → stop → unload, recording every instance, manifest, context, and status in the thread-safe PluginRegistry, which is the single source of truth for what is loaded.

The plugin author's world is the PluginContext handed to their initialize() method. It carries the plugin's id, config, manifest, and directory, and exposes the registration API — register_volk, register_tool, register_provider, register_channel, register_rules, register_kg_schema, plus subscribe_event/emit_event — whose real logic lives in registration.py. resolve() reaches into the DI container but only if the manifest declared di_access, otherwise it raises CapabilityDeniedError; PluginGovernance likewise refuses attempts to claim a reserved core Volk alias (U:Ox, U:PS, U:Qa, …) or a reserved system tool (system.shell, system.eval, system.exec). Each register_volk call lands in a concrete VolkRegistry — an in-memory IVolkRegistry keyed by alias — so a plugin-registered Volk becomes a real, queryable entity rather than a silent no-op.

To the rest of the codebase the package presents PluginSDK, a simplified facade over PluginManager for discovering, loading, querying, enabling, installing, and starting plugins. It is the composition root for operators: it constructs the concrete VolkRegistry and wires it into the manager so plugin Volk registrations actually go somewhere. Its neighbours are the packages a plugin extends — the kernel that would project registered Volks into its dispatch table, governance behind the capability checks, di for the container PluginContext scopes, and core, which contributes the BaseError root of the exception hierarchy and the @traces decorators that thread SPEC-015 traceability through every module here.

Key responsibilities

Class diagram

Lifecycle orchestration

PluginSDK wraps PluginManager, which owns a PluginRegistry, drives a PluginLoader, and consults PluginGovernance on every load.

Diagram projects-orchestrata-ultimate-modules-plugin-1

The plugin author's surface

PluginContext is what a plugin sees during initialize(); it reads the PluginManifest, and registers into the concrete VolkRegistry. The register path in registration.py does not consult PluginGovernance: register_volk refuses only an alias the same plugin already registered, and register_rules / register_kg_schema only record the request and log it.

Diagram projects-orchestrata-ultimate-modules-plugin-2

Protocols, enums, and the exception hierarchy

The SDK is defined against Protocols (so any registry can be swapped in) and roots every failure in core's BaseError, giving callers one catchable PluginError family.

Diagram projects-orchestrata-ultimate-modules-plugin-3

Module map

Module Role
__init__.py Package facade (SPEC-015) — re-exports the SDK, manager, loader, registries, manifest, governance, config, interfaces and exceptions.
sdk.py PluginSDK — public facade + composition root that wires VolkRegistry.
manager.py PluginManager — full lifecycle orchestrator (IPluginManager).
loader.py PluginLoader — local + pip discovery, safe import, topological_sort.
discovery.py Module-level discover/install/enable/disable/reload/unload helpers.
registry.py PluginRegistry — thread-safe store of instances, manifests, contexts, infos.
context.py PluginContext — the author-facing registration + DI surface.
registration.py The concrete registration logic behind each PluginContext.register_*.
registries.py VolkRegistry / RegisteredVolk — concrete in-memory IVolkRegistry.
manifest.py PluginManifest, KGSchemaExtension — plugin.yaml parsing + validation.
governance.py PluginGovernance — allowlist/blocklist, reserved aliases/tools, resource limits.
config.py PluginConfig, PluginResourceLimits — manager behaviour + limits.
interfaces.py Protocols (IPlugin, IPluginManager, registries, IEventBus), enums, PluginInfo.
exceptions.py PluginError hierarchy rooted in core.BaseError.

Notes

Class map (generated)

Generated from the live source AST by scripts/gen-module-class-diagrams.py — do not hand-edit. Abstract classes have a green border; members listed are those defined on the class itself (inherited members excluded). Solid empty-triangle arrows = in-package inheritance; dashed arrows into dashed boxes = external/stdlib/cross-package bases; filled diamond = composition (constructed in __init__); open diamond = aggregation (annotated/injected reference); diamond edge labels name the owning attribute.

plugin class map