Orchestrata Ultimate / Specs / 015-plugin-sdk

015-plugin-sdk: Plugin SDK

The Plugin SDK is the extensibility framework for Orchestrata. It defines a public API surface and runtime for third-party and first-party plugins that extend the system with new Volk types, tools, LLM providers, channel adapters, governance rules, and knowledge graph extensions — all installable and loadable at runtime without modifying the monorepo or rebuilding the system.

At a glance

Item Value
Spec directory specs/015-plugin-sdk/
Status line in the spec Implemented
Requirement IDs defined 210
With a @traces citation in src/ 95 (45.2%)
With a @traces citation in tests/ 0 (0.0%)
Tracked files 6
RTM page 015-plugin-sdk

Reading this spec

The Plugin SDK is the extensibility framework of Orchestrata. It defines a public API and runtime for first-party and third-party plugins that add new Volk types, tools, LLM providers, channel adapters, governance rules and knowledge graph extensions, installable and loadable at runtime without modifying the monorepo. The problem it solves is that the system's packages are tightly coupled workspace dependencies, all components are imported statically at startup, and the existing Volk types are hardcoded.

The scope is twelve user stories: installing and loading a plugin, developing Volk, tool and provider plugins, discovery and listing, configuration, isolation and security, and lifecycle management (priority 1), then governance rule plugins, knowledge graph extension plugins, event hooks and channel adapter plugins (priority 2). Requirement IDs use the REQ-015- prefix.

The key decisions are an IPluginManager interface registered as ComponentType.PLUGIN_MANAGER; plugins as Python packages with a plugin.yaml manifest declaring capabilities, dependencies and entry points; discovery by a local directory scan plus pip-installed packages in the orchestrata_plugin entry point group; and a lifecycle of discover, validate, load, initialize, start, stop and unload. The SDK exposes IPlugin, PluginContext and registration of tools, Volks, providers and governance rules. PAM++ governance controls which plugins are allowed, what they can access and their resource limits, and all plugin operations are audit logged.

In the code, the package is orchestrata_ultimate/plugin. The largest tracers are orchestrata_ultimate/plugin/interfaces, orchestrata_ultimate/plugin/manager, orchestrata_ultimate/plugin/sdk, orchestrata_ultimate/plugin/context and orchestrata_ultimate/plugin/discovery. The per-requirement view is on the RTM page.

The spec's status line reads Implemented. It tracks 6 files and defines 210 requirement IDs. The full text follows below.

Measured coverage is 95 of 210 requirements cited by at least one @traces in src/ (45.2%), spread over 29 modules; the module citing the most of them is orchestrata_ultimate/plugin/interfaces (35 requirements). In tests/, 0 requirements are cited by a test-side @traces.

Coverage gaps: 115 requirements have no citing symbol. The largest untraced groups are REQ-015-* (115). Untraced means no @traces names the ID; the behaviour may still exist in code that was never annotated. Test-side citations are thinner than code-side ones (0 against 95).

Requirements

Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.

ID Done Requirement Traced by
REQ-015-001 no Install plugin from pip package spec (orchestrata plugins install orchestrata-plugin-browser) 1
REQ-015-002 no Install plugin from local directory path (orchestrata plugins install ./my-plugin) 4
REQ-015-003 no Install plugin from git URL (orchestrata plugins install git+https://...) 4
REQ-015-004 no Installation validates manifest before completing 3
REQ-015-005 no Installation checks Python dependency compatibility none
REQ-015-006 no Discover plugins from configurable local directories 5
REQ-015-007 no Discover plugins via importlib.metadata entry point group orchestrata_plugin 2
REQ-015-008 no Discover plugins from pip packages with orchestrata-plugin- prefix 1
REQ-015-009 no Deduplicate discovered plugins by name (local takes precedence) 2
REQ-015-010 no Log all discovered plugins with source and version none
REQ-015-011 no Load plugin Python module via importlib 3
REQ-015-012 no Instantiate plugin entry point class from manifest none
REQ-015-013 no Pass PluginContext to plugin on instantiation none
REQ-015-014 no Load plugins in dependency order (topological sort) 1
REQ-015-015 no Detect and reject circular plugin dependencies 1
REQ-015-016 no Plugin calls context.register_volk(alias, capabilities, handler) 4
REQ-015-017 no Registered Volk appears in kernel Volk registry 11
REQ-015-018 no Registered Volk is routable via CXP packets 1
REQ-015-019 no Volk alias validated for uniqueness (conflict detection) 1
REQ-015-020 no Volk alias cannot override core Volks (U:Ox, U:PS, U:KR reserved) 1
REQ-015-021 no Plugin Volk receives CXP packets via handler function 6
REQ-015-022 no Plugin Volk responds via standard CXP protocol 1
REQ-015-023 no Plugin Volk participates in PAM++ governance none
REQ-015-024 no Plugin Volk has access to PluginContext for DI resolution none
REQ-015-025 no Plugin Volk can declare capabilities (reasoning, coding, etc.) 1
REQ-015-026 no Plugin Volks auto-deregistered on plugin stop none
REQ-015-027 no In-flight CXP packets to plugin Volk handled gracefully on stop none
REQ-015-028 no Plugin Volk health monitored by kernel health system none
REQ-015-029 no Plugin Volk errors isolated from other Volks none
REQ-015-030 no Plugin Volk registration logged to audit trail none
REQ-015-031 no Plugin calls context.register_tool(name, description, schema, handler) 5
REQ-015-032 no Tool name namespaced: plugin.<plugin_name>.<tool_name> none
REQ-015-033 no Tool parameters validated against JSON Schema on invocation none
REQ-015-034 no Tool registered in central tool registry accessible to all Volks 2
REQ-015-035 no Tool name validated for uniqueness none
REQ-015-036 no Tool handler invoked asynchronously with validated parameters none
REQ-015-037 no Tool results returned to calling Volk via CXP none
REQ-015-038 no Tool invocation authorized by PAM++ before execution none
REQ-015-039 no Tool execution timeout enforced (configurable per tool) none
REQ-015-040 no Tool errors returned as structured error responses none
REQ-015-041 no Plugin tools auto-deregistered on plugin stop none
REQ-015-042 no In-flight tool invocations completed or cancelled on plugin stop none
REQ-015-043 no Tool invocation count tracked per plugin none
REQ-015-044 no Tool execution time tracked per invocation none
REQ-015-045 no Tool registration logged to audit trail none
REQ-015-046 no Plugin calls context.register_provider(name, provider, config) 3
REQ-015-047 no Provider implements IProvider protocol (SPEC-011) none
REQ-015-048 no Provider registered with IProviderManager via DI 1
REQ-015-049 no Provider participates in fallback chains none
REQ-015-050 no Provider participates in cost tracking and rate limiting none
REQ-015-051 no Provider config loaded from plugin config section none
REQ-015-052 no Provider API keys loaded from environment variables none
REQ-015-053 no Provider model metadata declared (capabilities, pricing, context window) none
REQ-015-054 no Provider rate limits declared in config none
REQ-015-055 no Provider health monitored by ProviderManager 2
REQ-015-056 no Plugin providers auto-deregistered on plugin stop none
REQ-015-057 no In-flight provider requests completed or cancelled on stop 2
REQ-015-058 no Provider deregistration triggers fallback chain update none
REQ-015-059 no Provider registration logged to audit trail none
REQ-015-060 no Provider errors isolated from other providers none
REQ-015-061 no Plugin calls context.register_rules(rule_files) 2
REQ-015-062 no Rule files are relative paths within plugin directory none
REQ-015-063 no Rules loaded into Prolog knowledge base on initialize none
REQ-015-064 no Rules unloaded from Prolog knowledge base on stop none
REQ-015-065 no Rule predicate conflicts detected and reported none
REQ-015-066 no Plugin rules cannot override core PAM++ predicates none
REQ-015-067 no Plugin rules validated against constitutional articles none
REQ-015-068 no Plugin rules namespaced to prevent collisions none
REQ-015-069 no Rule loading failures do not crash Prolog engine none
REQ-015-070 no Rule audit trail records loaded/unloaded predicates none
REQ-015-071 no Plugin calls context.register_kg_schema(node_types, rel_types, indexes) 3
REQ-015-072 no Node types namespaced with plugin prefix: Plugin_<name>_<NodeType> none
REQ-015-073 no Schema applied to Neo4j on plugin initialize none
REQ-015-074 no Schema migrations versioned per plugin 1
REQ-015-075 no Schema conflicts with core or other plugins detected none
REQ-015-076 no Plugin can create nodes of its declared types none
REQ-015-077 no Plugin can create relationships of its declared types none
REQ-015-078 no Plugin KG operations scoped to its namespace none
REQ-015-079 no Core KG nodes not modifiable by plugins none
REQ-015-080 no KG schema extension logged to audit trail none
REQ-015-081 no orchestrata plugins list shows all plugins with status none
REQ-015-082 no List output includes: name, version, status, capabilities, source 1
REQ-015-083 no orchestrata plugins info <name> shows full manifest details none
REQ-015-084 no Info output includes: registered components, config schema, resource usage 1
REQ-015-085 no orchestrata plugins enable <name> activates a disabled plugin 4
REQ-015-086 no orchestrata plugins disable <name> deactivates without uninstalling 4
REQ-015-087 no Disable stops the plugin and deregisters its components 1
REQ-015-088 no orchestrata plugins uninstall <name> removes completely 5
REQ-015-089 no Uninstall cleans up Redis state, Neo4j audit, and files none
REQ-015-090 no Plugin status visible via Gateway RPC plugins.list (SPEC-014) none
REQ-015-091 no orchestrata plugins doctor <name> runs health check on plugin none
REQ-015-092 no Doctor checks: manifest validity, dependencies, config, capability access none
REQ-015-093 no Doctor reports errors with remediation suggestions none
REQ-015-094 no Error plugins include error message and stack trace in listing 1
REQ-015-095 no Plugin logs accessible via orchestrata plugins logs <name> none
REQ-015-096 no Plugin config loaded from configs/monolithic.yaml under plugins.<name> 1
REQ-015-097 no Config validated against schema declared in manifest (JSON Schema) none
REQ-015-098 no Environment variable interpolation supported in plugin config none
REQ-015-099 no Config accessible via PluginContext.config 1
REQ-015-100 no Invalid config prevents plugin load with validation error 1
REQ-015-101 no Default config values from manifest applied when keys missing none
REQ-015-102 no Config changes detectable for hot-reload notification none
REQ-015-103 no Plugin notified of config changes via on_config_changed() callback none
REQ-015-104 no New config validated before applying (rollback on rejection) none
REQ-015-105 no Config changes logged to audit trail none
REQ-015-106 no Plugins declare required capabilities in manifest none
REQ-015-107 no DI container scoped to declared capabilities only 1
REQ-015-108 no Undeclared capability access raises CapabilityDeniedError 2
REQ-015-109 no Capability access logged for security audit none
REQ-015-110 no Capability types: di_access, redis, neo4j, network, filesystem, prolog, event_bus, provider, gateway 1
REQ-015-111 no Prolog queried for plugin_allowed(name) before loading none
REQ-015-112 no Prolog queried for plugin_capability_granted(name, cap) per capability none
REQ-015-113 no Plugin allowlist configurable in monolithic.yaml 1
REQ-015-114 no Plugin blocklist overrides allowlist 1
REQ-015-115 no Governance decisions logged to audit trail 1
REQ-015-116 no Memory usage tracked per plugin 2
REQ-015-117 no API call count tracked per time window 2
REQ-015-118 no Events emitted tracked per time window 2
REQ-015-119 no Resource limits configurable per plugin in monolithic.yaml 2
REQ-015-120 no Plugin throttled or disabled on resource limit breach 1
REQ-015-121 no Plugin exceptions caught and logged (never crash core) 1
REQ-015-122 no Plugin marked "error" after consecutive failures (configurable threshold) 2
REQ-015-123 no Auto-disable on persistent error state (configurable) 1
REQ-015-124 no Other plugins unaffected by one plugin's failure none
REQ-015-125 no Plugin errors include full traceback and plugin context none
REQ-015-126 no Lifecycle order: discover → validate → load → initialize → start 2
REQ-015-127 no Shutdown order: stop → unload (reverse dependency order) 2
REQ-015-128 no initialize() called after load, before any other method 2
REQ-015-129 no start() called after all plugins initialized 3
REQ-015-130 no stop() called on shutdown or disable 5
REQ-015-131 no Plugin declares dependencies on other plugins in manifest none
REQ-015-132 no Load order computed via topological sort on dependency graph 1
REQ-015-133 no Circular dependencies detected and rejected with clear error 1
REQ-015-134 no Missing dependency prevents plugin load with clear error 1
REQ-015-135 no Dependency version constraints validated none
REQ-015-136 no Hot-reload executes: stop → unload → load → initialize → start 1
REQ-015-137 no Hot-reload preserves other plugins' state none
REQ-015-138 no Hot-reload re-registers all plugin components none
REQ-015-139 no Hot-reload validates manifest changes before applying none
REQ-015-140 no Hot-reload logged to audit trail none
REQ-015-141 no All lifecycle transitions emit events to EventBus none
REQ-015-142 no Events: plugin.discovered, plugin.loaded, plugin.initialized, plugin.started, plugin.stopped, plugin.unloaded, plugin.error none
REQ-015-143 no Events include plugin name, version, and transition details none
REQ-015-144 no All lifecycle events logged to Neo4j audit trail none
REQ-015-145 no Gateway subscribers receive plugin lifecycle events (SPEC-014) none
REQ-015-146 no Plugin calls context.subscribe_event(topic, handler) 3
REQ-015-147 no Subscription supports wildcard topics (cxp.*, session.*) 1
REQ-015-148 no Subscriptions auto-unsubscribed on plugin stop none
REQ-015-149 no Subscription returns subscription_id for manual unsubscribe 2
REQ-015-150 no Event handler receives full event payload 1
REQ-015-151 no Plugin calls context.emit_event(event_type, payload) 3
REQ-015-152 no Custom events namespaced: plugin.<name>.<event_type> 1
REQ-015-153 no Custom events visible to other plugins and gateway subscribers 1
REQ-015-154 no Event emission rate tracked per plugin (resource limit) 1
REQ-015-155 no Event handler errors do not crash EventBus or other subscribers 2
REQ-015-156 no Plugin calls context.register_channel(channel_id, inbound, outbound) 3
REQ-015-157 no Channel registered with kernel channel registry 2
REQ-015-158 no Channel_id validated for uniqueness 1
REQ-015-159 no Inbound handler converts external messages to CXP packets none
REQ-015-160 no Outbound handler converts CXP packets to channel-native messages 1
REQ-015-161 no Inbound messages routed through kernel like any CXP packet 1
REQ-015-162 no Outbound messages dispatched to channel via outbound handler none
REQ-015-163 no Channel configuration loaded from plugin config (tokens, webhooks) none
REQ-015-164 no Channel health monitored by kernel health system none
REQ-015-165 no Channel errors isolated from other channels none
REQ-015-166 no Plugin channels auto-deregistered on plugin stop none
REQ-015-167 no In-flight channel messages handled gracefully on stop none
REQ-015-168 no Channel registration logged to audit trail 1
REQ-015-169 no Channel message throughput tracked per plugin 1
REQ-015-170 no Channel reconnection handled by plugin (not core) 1
REQ-015-171 no SDK published as orchestrata-plugin-sdk pip package none
REQ-015-172 no SDK includes: IPlugin, PluginContext, PluginManifest, PluginCapability 2
REQ-015-173 no SDK includes type stubs for all public interfaces 1
REQ-015-174 no SDK is version-pinned to Orchestrata compatibility range none
REQ-015-175 no SDK has zero runtime dependencies on Orchestrata core (interface-only) 1
REQ-015-176 no orchestrata plugins scaffold <name> generates plugin template none
REQ-015-177 no Template includes: plugin.yaml, pyproject.toml, src/, tests/, README.md none
REQ-015-178 no Template includes working example (minimal Volk or tool) 1
REQ-015-179 no SDK documentation with examples for each registration type none
REQ-015-180 no Plugin testing utilities provided (test harness, mock context) none
REQ-015-181 no SDK API follows semantic versioning 1
REQ-015-182 no Breaking changes require major version bump 1
REQ-015-183 no Deprecation warnings for API changes 1
REQ-015-184 no SDK changelog maintained 1
REQ-015-185 no Compatibility matrix published (SDK version ↔ Orchestrata version) 1
REQ-015-186 no IPluginManager registered with ComponentType.PLUGIN_MANAGER none
REQ-015-187 no IPluginManager resolvable from DI container none
REQ-015-188 no PluginManager implements IComponent lifecycle 1
REQ-015-189 no PluginManager initializes after kernel and before Volks none
REQ-015-190 no PluginManager stops before kernel on shutdown none
REQ-015-191 no list_plugins() returns all plugins with status 4
REQ-015-192 no get_plugin(name) returns plugin info or None 4
REQ-015-193 no load_plugin(name) loads and initializes a discovered plugin 5
REQ-015-194 no unload_plugin(name) stops and unloads a plugin 4
REQ-015-195 no reload_plugin(name) hot-reloads a plugin 4
REQ-015-196 no Query plugins by status (active, disabled, error) 1
REQ-015-197 no Query plugins by capability (which plugins provide network access?) none
REQ-015-198 no Query registered components by plugin (which Volks does plugin X provide?) none
REQ-015-199 no Query plugin resource usage none
REQ-015-200 no Query plugin health 1
REQ-015-201 no Plugin install/uninstall events recorded none
REQ-015-202 no Plugin lifecycle events recorded (load, init, start, stop, unload) none
REQ-015-203 no Plugin registration events recorded (volk, tool, provider, channel, rules) none
REQ-015-204 no Plugin governance decisions recorded (allow, deny, capability grant) none
REQ-015-205 no Plugin errors recorded with traceback none
REQ-015-206 no Audit records stored as Neo4j (:PluginAudit) nodes none
REQ-015-207 no Audit records linked to (:Plugin) nodes via relationships none
REQ-015-208 no Audit records include timestamp, plugin_name, event_type, details none
REQ-015-209 no Audit records immutable after write none
REQ-015-210 no Audit queryable by time range, plugin name, event type none

Code that traces this spec

Module Symbols Requirements
orchestrata_ultimate/core/protocols/base 1 1
orchestrata_ultimate/core/protocols/decoupling 4 2
orchestrata_ultimate/core/protocols/providers 1 1
orchestrata_ultimate/kernel/cli_main 3 3
orchestrata_ultimate/kernel/event_bus 3 3
orchestrata_ultimate/kernel/pipeline 3 4
orchestrata_ultimate/knowledge_graph/nodes 4 4
orchestrata_ultimate/knowledge_graph/prolog_bridge 7 7
orchestrata_ultimate/knowledge_graph/relationships 2 2
orchestrata_ultimate/knowledge_graph/schema 2 2
orchestrata_ultimate/knowledge_graph/temporal 4 4
orchestrata_ultimate/knowledge_graph/types 6 6
orchestrata_ultimate/knowledge_graph/types_enums 2 2
orchestrata_ultimate/orchestrator/engine 1 1
orchestrata_ultimate/orchestrator/orchestrator 1 1
orchestrata_ultimate/plugin/config 3 3
orchestrata_ultimate/plugin/context 11 12
orchestrata_ultimate/plugin/discovery 8 9
orchestrata_ultimate/plugin/exceptions 6 6
orchestrata_ultimate/plugin/governance 3 3
orchestrata_ultimate/plugin/interfaces 29 35
orchestrata_ultimate/plugin/loader 9 7
orchestrata_ultimate/plugin/manager 16 17
orchestrata_ultimate/plugin/manifest 4 4
orchestrata_ultimate/plugin/registration 8 8
orchestrata_ultimate/plugin/registries 7 4
orchestrata_ultimate/plugin/registry 7 7
orchestrata_ultimate/plugin/sdk 14 13
orchestrata_ultimate/providers/provider_manager 3 2

Checklists

checklists/README.md

Plugin SDK Checklists

Project: Orchestrata Plugin SDK (Spec 015) Component: Plugin SDK Status: Planning Phase Owner: Architecture Team


Overview

The Plugin SDK is the extensibility framework for Orchestrata. It defines the public API surface and runtime for third-party and first-party plugins that extend the system with new Volk types, tools, LLM providers, channel adapters, governance rules, and knowledge graph extensions — all installable and loadable at runtime without modifying the monorepo.


Checklist Summary
Checklist Total Items Completed Progress
Requirements 220+ 0 0%
Constitutional Compliance 110+ 0 0%
Testing Plan 380+ 0 0%
TOTAL 710+ 0 0%

Key Responsibilities
1. Plugin Discovery and Loading
2. Plugin SDK (Public API)
3. Plugin Lifecycle Management
4. Isolation and Security
5. Plugin Management CLI

Performance Targets
Metric Target Critical Threshold
Plugin Discovery <500ms for 50 plugins <1s
Plugin Validation <100ms per plugin <200ms
Plugin Initialization <2s per plugin <5s
Full Startup (50 plugins) <10s <20s
Tool Invocation Overhead <5ms p95 <10ms
Volk Routing Overhead <10ms p95 <20ms
Capability Check <1ms p95 <5ms

Checklist Files
1. requirements.md

Functional requirements organized by user stories:

2. constitutional.md

Compliance with all 11 constitutional articles:

3. testing.md

Comprehensive testing strategy:


Integration Points
Upstream Dependencies
Downstream Consumers

References

Last Updated: 2026-03-27 Version: 1.0.0 Maintained By: Architecture Team

checklists/constitutional.md

Plugin SDK - Constitutional Compliance

Component: Plugin SDK Spec: 015-plugin-sdk Status: Compliance Review Total Compliance Items: 120+


Overview

This document tracks compliance of the Plugin SDK with all 11 articles of the Orchestrata Constitution. The plugin system is the primary extensibility mechanism — it must enforce constitutional boundaries rigorously to prevent third-party code from violating system invariants.


Article I: Agent Autonomy

Principle: Volks (agents) retain autonomy; plugins extend but do not override agent behavior.

Compliance Requirements
Autonomy Preservation

Priority: Critical Verification: Integration tests + manual review


Article II: Prolog as Single Source of Truth

Principle: All governance rules are defined in Prolog; plugin governance queries Prolog.

Compliance Requirements
Prolog Integration

Priority: Critical Verification: Prolog integration tests + policy compliance tests


Article III: Session Isolation

Principle: Sessions are isolated; plugin state does not leak between sessions.

Compliance Requirements
State Isolation

Priority: Critical Verification: Session isolation tests + state leak detection


Article IV: Hooks for Extensibility

Principle: The system provides extension points for customization.

Compliance Requirements
Extension Points

Priority: High Verification: Hook registration tests + extension tests


Article V: Minimal Core, Maximal Extension

Principle: Core is minimal; the plugin system is how features are added.

Compliance Requirements
Minimal Core

Priority: High Verification: Core size metrics + extension loading tests


Article VI: Python 3.14t Implementation

Principle: Plugin SDK is implemented in Python 3.14t with modern async patterns.

Compliance Requirements
Python Version
Code Quality

Priority: High Verification: CI/CD checks + static analysis


Article VII: Testing Without Mocks

Principle: Tests use real implementations, not mocks.

Compliance Requirements
Real Systems Testing

Priority: Critical Verification: Test code review + mock detector


Article VIII: Metrics and Observability

Principle: All operations are observable and measurable.

Compliance Requirements
Metrics Collection
Observability

Priority: High Verification: Metrics tests + observability review


Article IX: Graceful Degradation

Principle: System degrades gracefully under failure, does not crash.

Compliance Requirements
Failure Handling
Recovery

Priority: High Verification: Failure injection tests + chaos tests


Article X: Version Compatibility

Principle: APIs are versioned; breaking changes are avoided.

Compliance Requirements
API Versioning

Priority: Medium Verification: Compatibility tests + version migration tests


Article XI: Documentation First

Principle: Documentation precedes implementation.

Compliance Requirements
Design Documentation

Priority: High Verification: Documentation review + doc tests


Summary Statistics
Article Total Items Completed Percentage
Article I (Autonomy) 10 0 0%
Article II (Prolog) 10 0 0%
Article III (Isolation) 10 0 0%
Article IV (Hooks) 10 0 0%
Article V (Minimal Core) 10 0 0%
Article VI (Python 3.14t) 20 0 0%
Article VII (No Mocks) 10 0 0%
Article VIII (Observability) 20 0 0%
Article IX (Degradation) 20 0 0%
Article X (Versioning) 10 0 0%
Article XI (Documentation) 10 0 0%
TOTAL 140 0 0%

Last Updated: 2026-03-27 Version: 1.0.0 Maintained By: Architecture Team

checklists/requirements.md

The requirement list above comes from this file; 0 of 210 checkbox items are ticked.

checklists/testing.md

Plugin SDK - Testing Plan

Component: Plugin SDK Spec: 015-plugin-sdk Status: Test Planning Phase Total Test Cases: 381+


Overview

This document defines the comprehensive testing strategy for the Plugin SDK. All tests follow the strict "no mocking" policy and use real implementations including real plugin loading, real Redis, real Neo4j, real Prolog for governance, and real kernel integration.


Test Categories Summary
Category Test Count Purpose Priority
Unit Tests 140+ Core logic validation Critical
Integration Tests 100+ System integration Critical
Contract Tests 40 Interface compliance High
Performance Tests 50+ Loading & runtime overhead High
Compliance Tests 11 Constitutional compliance Critical
Failure Scenario Tests 40+ Error handling & recovery High
TOTAL 381+

Unit Tests (140+)
Plugin Discovery Tests (15 tests)
Plugin Validation Tests (15 tests)
Plugin Loading Tests (20 tests)
Plugin Lifecycle Tests (15 tests)
PluginContext Tests (20 tests)
Capability Enforcement Tests (15 tests)
Plugin Configuration Tests (15 tests)
Resource Limit Tests (10 tests)
CLI Command Tests (15 tests)

Integration Tests (100+)
Kernel Integration (20 tests)
Prolog Integration (15 tests)
Redis Integration (15 tests)
Neo4j Integration (15 tests)
End-to-End Tests (35 tests)

Contract Tests (40)
IPlugin Protocol Compliance (10 tests)
Manifest Schema Compliance (10 tests)
PluginContext API Compliance (10 tests)
IComponent Compliance (10 tests)

Performance Tests (50+)
Discovery and Loading Performance (20 tests)
Runtime Performance (20 tests)
CLI Performance (10 tests)

Compliance Tests (11)

Failure Scenario Tests (40+)
Plugin Load Failures (10 tests)
Plugin Runtime Failures (15 tests)
Dependency Failures (10 tests)
Hot-Reload Failures (5 tests)

Summary Statistics
Category Test Count Completed Percentage
Unit Tests 140 0 0%
Integration Tests 100 0 0%
Contract Tests 40 0 0%
Performance Tests 50 0 0%
Compliance Tests 11 0 0%
Failure Scenario Tests 40 0 0%
TOTAL 381 0 0%

Last Updated: 2026-03-27 Version: 1.0.0 Maintained By: Architecture Team

Other tracked files

Full spec text

Verbatim from specs/015-plugin-sdk/spec.md; headings are pushed down two levels.

SPEC-015: Plugin SDK

Metadata



Overview

What

The Plugin SDK is the extensibility framework for Orchestrata. It defines a public API surface and runtime for third-party and first-party plugins that extend the system with new Volk types, tools, LLM providers, channel adapters, governance rules, and knowledge graph extensions — all installable and loadable at runtime without modifying the monorepo or rebuilding the system.

Why
How


User Scenarios

US-001: Install and Load a Plugin (P1)

As a system operator I want to install a plugin from a package or local directory So that I can extend Orchestrata with new capabilities without modifying core code

Acceptance Criteria:


US-002: Develop a Custom Volk Plugin (P1)

As a plugin developer I want to create a new specialized Volk (agent) as a plugin So that I can add domain-specific agent capabilities to Orchestrata

Acceptance Criteria:


US-003: Develop a Tool Plugin (P1)

As a plugin developer I want to create new tools that Volks can invoke So that agents gain new capabilities (web search, browser automation, code execution, etc.)

Acceptance Criteria:


US-004: Develop a Provider Plugin (P1)

As a plugin developer I want to add a new LLM provider as a plugin So that Orchestrata can use additional model backends without core changes

Acceptance Criteria:


US-005: Develop a Governance Rule Plugin (P2)

As a plugin developer I want to add custom Prolog governance rules as a plugin So that I can extend PAM++ policies without modifying core rule files

Acceptance Criteria:


US-006: Develop a Knowledge Graph Extension Plugin (P2)

As a plugin developer I want to extend the knowledge graph with new node types and relationships So that the graph captures domain-specific knowledge

Acceptance Criteria:


US-007: Plugin Discovery and Listing (P1)

As a system operator I want to list, inspect, enable, and disable plugins So that I can manage the extension ecosystem

Acceptance Criteria:


US-008: Plugin Configuration (P1)

As a system operator I want to configure plugins via the standard configuration system So that plugin behavior is customizable without code changes

Acceptance Criteria:


US-009: Plugin Isolation and Security (P1)

As a security administrator I want to control what plugins can access and do So that untrusted plugins cannot compromise the system

Acceptance Criteria:


US-010: Plugin Lifecycle Management (P1)

As the system I want to manage plugin lifecycle through well-defined phases So that plugins are loaded, initialized, started, and stopped cleanly

Acceptance Criteria:


US-011: Plugin Event Hooks (P2)

As a plugin developer I want to hook into system events So that my plugin can react to kernel, session, and CXP events

Acceptance Criteria:


US-012: Channel Adapter Plugin (P2)

As a plugin developer I want to add a new messaging channel (Slack, Telegram, Matrix) as a plugin So that Orchestrata can communicate through additional external surfaces

Acceptance Criteria:



Terminology



Data Models

PluginManifest Schema (plugin.yaml)
{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "PluginManifest",
    "type": "object",
    "required": ["name", "version", "description", "author", "license", "entry_point", "min_orchestrata_version"],
    "properties": {
        "name": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9-]*$",
            "description": "Unique plugin name in kebab-case."
        },
        "version": {
            "type": "string",
            "pattern": "^\\d+\\.\\d+\\.\\d+$",
            "description": "Semantic version of the plugin."
        },
        "description": {
            "type": "string",
            "maxLength": 500
        },
        "author": {
            "type": "string"
        },
        "license": {
            "type": "string",
            "description": "SPDX license identifier."
        },
        "entry_point": {
            "type": "string",
            "pattern": "^[a-z_][a-z0-9_.]*:[A-Z][a-zA-Z0-9]*$",
            "description": "Python import path in module:Class format."
        },
        "capabilities": {
            "type": "array",
            "items": {
                "type": "string",
                "enum": ["di_access", "redis", "neo4j", "network", "filesystem", "prolog", "event_bus", "provider", "gateway"]
            },
            "default": []
        },
        "dependencies": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Other plugin names this plugin depends on."
        },
        "python_dependencies": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Pip package specifications."
        },
        "config_schema": {
            "oneOf": [
                {"type": "object"},
                {"type": "null"}
            ],
            "description": "JSON Schema for plugin-specific configuration."
        },
        "min_orchestrata_version": {
            "type": "string",
            "pattern": "^\\d+\\.\\d+\\.\\d+$"
        },
        "prolog_rules": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Relative paths to Prolog rule files."
        },
        "kg_schema": {
            "oneOf": [
                {
                    "type": "object",
                    "properties": {
                        "node_types": {"type": "array", "items": {"type": "string"}},
                        "relationship_types": {"type": "array", "items": {"type": "string"}},
                        "indexes": {"type": "array", "items": {"type": "string"}},
                        "constraints": {"type": "array", "items": {"type": "string"}},
                        "migration_version": {"type": "integer", "minimum": 1}
                    }
                },
                {"type": "null"}
            ]
        }
    },
    "additionalProperties": false
}
PluginContext Interface Schema
{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "PluginContext",
    "description": "Runtime context provided to plugins during initialization.",
    "type": "object",
    "required": ["config", "logger", "plugin_dir", "manifest"],
    "properties": {
        "config": {
            "type": "object",
            "description": "Plugin-specific configuration validated against manifest config_schema."
        },
        "logger": {
            "type": "object",
            "description": "Plugin-scoped logging.Logger instance."
        },
        "plugin_dir": {
            "type": "string",
            "description": "Absolute path to the plugin's directory on the filesystem."
        },
        "manifest": {
            "$ref": "#/definitions/PluginManifest"
        }
    }
}
PluginInfo Schema
{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "PluginInfo",
    "type": "object",
    "required": ["manifest", "status", "source"],
    "properties": {
        "manifest": {
            "$ref": "#/definitions/PluginManifest"
        },
        "status": {
            "type": "string",
            "enum": ["discovered", "loading", "active", "error", "disabled"]
        },
        "source": {
            "type": "string",
            "pattern": "^(local|pip|git):.*$",
            "description": "Plugin origin (e.g., local:/path, pip:package-name, git:url)."
        },
        "loaded_at": {
            "type": ["string", "null"],
            "format": "date-time"
        },
        "error": {
            "type": ["string", "null"],
            "description": "Error message if status is 'error'."
        },
        "registered_volks": {
            "type": "array",
            "items": {"type": "string"}
        },
        "registered_tools": {
            "type": "array",
            "items": {"type": "string"}
        },
        "registered_providers": {
            "type": "array",
            "items": {"type": "string"}
        },
        "registered_channels": {
            "type": "array",
            "items": {"type": "string"}
        },
        "resource_usage": {
            "type": "object",
            "properties": {
                "memory_bytes": {"type": "integer"},
                "api_calls_last_hour": {"type": "integer"},
                "events_emitted_last_hour": {"type": "integer"},
                "errors_last_hour": {"type": "integer"}
            }
        }
    }
}
Plugin Registration Event Schema
{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "PluginRegistrationEvent",
    "type": "object",
    "required": ["plugin_name", "event_type", "timestamp"],
    "properties": {
        "plugin_name": {"type": "string"},
        "event_type": {
            "type": "string",
            "enum": ["discovered", "loaded", "started", "stopped", "unloaded", "error", "enabled", "disabled"]
        },
        "timestamp": {"type": "string", "format": "date-time"},
        "details": {"type": "object"}
    }
}


Functional Requirements

Core Plugin Framework

FR-001: IPluginManager Interface (P1)

FR-002: Plugin Discovery (P1)

FR-003: Plugin Validation (P1)

FR-004: Plugin Loading (P1)

FR-005: Plugin Lifecycle (P1)

Plugin SDK

FR-006: IPlugin Interface (P1)

FR-007: Volk Registration (P1)

FR-008: Tool Registration (P1)

FR-009: Provider Registration (P1)

FR-010: Governance Rule Registration (P2)

FR-011: Knowledge Graph Extension (P2)

FR-012: Channel Registration (P2)

FR-013: Event Subscription (P2)

Plugin Management CLI

FR-014: Plugin Install (P1)

FR-015: Plugin Uninstall (P1)

FR-016: Plugin List and Info (P1)

Plugin Configuration

FR-017: Plugin Config Schema (P1)

FR-018: Plugin Config Hot-Reload (P2)

Isolation and Security

FR-019: Capability-Based Access Control (P1)

FR-020: PAM++ Plugin Governance (P1)

FR-021: Plugin Resource Limits (P1)

FR-022: Plugin Error Isolation (P1)

Audit Trail

FR-023: Plugin Audit (P1)



Error Conditions

ID Condition Handling
ERR-001 Plugin manifest fails JSON Schema validation Plugin remains in discovered status; PluginInfo.error contains validation error message
ERR-002 Plugin declares dependency on another plugin that is not installed Load fails with PluginDependencyError; dependent plugin remains in discovered status
ERR-003 Plugin declares min_orchestrata_version higher than running version Load fails with PluginVersionError
ERR-004 Plugin entry_point import fails (module not found or class not found) Plugin transitions to error status with ImportError details
ERR-005 Plugin initialize() method raises an exception Plugin transitions to error status; partially registered components are rolled back
ERR-006 Plugin attempts to register a Volk with a reserved alias (U:Ox, U:PS, U:KR) Registration rejected with PluginAuthorizationError
ERR-007 Plugin attempts to access DI service outside declared capabilities Scoped container raises CapabilityDeniedError
ERR-008 Plugin exceeds configured resource limit (memory, API calls, events) Plugin is throttled and warning event is emitted
ERR-009 Plugin reaches error_threshold (default: 5) consecutive errors System auto-disables plugin and emits plugin.auto_disabled event
ERR-010 Two plugins declare conflicting KG schema extensions (same node type or relationship type) Second plugin load fails with PluginConflictError
ERR-011 Plugin Prolog rule file contains syntax errors Rule loading fails; plugin transitions to error status without affecting existing Prolog knowledge base
ERR-012 PAM++ denies plugin load authorization (plugin_allowed(Name) fails) Plugin remains in discovered status with error set to "governance_denied"
ERR-013 Plugin is unloaded while it has active EventBus subscriptions All subscriptions are automatically unsubscribed before unload completes
ERR-014 Plugin hot-reload fails during reload cycle System attempts to restore previous version; if restoration fails, plugin enters error status
ERR-015 Circular dependencies detected between plugins All plugins in the cycle fail to load with PluginCircularDependencyError


API Contracts

Contract: Plugin Manifest Schema (contracts/plugins/manifest-v1.0.0.yaml)
info:
  title: Orchestrata Plugin Manifest Schema
  version: 1.0.0
  spec_id: 015-plugin-sdk
  spec_version: 1.0.0
  maturity: experimental

schemas:
  PluginManifest:
    type: object
    required: [name, version, description, author, license, entry_point, min_orchestrata_version]
    properties:
      name:
        type: string
        pattern: "^[a-z][a-z0-9-]*$"
      version:
        type: string
        pattern: "^\\d+\\.\\d+\\.\\d+$"
      description:
        type: string
        maxLength: 500
      author:
        type: string
      license:
        type: string
      entry_point:
        type: string
        pattern: "^[a-z_][a-z0-9_.]*:[A-Z][a-zA-Z0-9]*$"
      capabilities:
        type: array
        items:
          type: string
          enum: [di_access, redis, neo4j, network, filesystem, prolog, event_bus, provider, gateway]
      dependencies:
        type: array
        items:
          type: string
      python_dependencies:
        type: array
        items:
          type: string
      config_schema:
        oneOf:
          - type: object
          - type: "null"
      min_orchestrata_version:
        type: string
      prolog_rules:
        type: array
        items:
          type: string
      kg_schema:
        oneOf:
          - type: object
          - type: "null"

  PluginInfo:
    type: object
    required: [manifest, status, source]
    properties:
      manifest:
        $ref: "#/schemas/PluginManifest"
      status:
        type: string
        enum: [discovered, loading, active, error, disabled]
      source:
        type: string
      loaded_at:
        type: string
        format: date-time
        nullable: true
      error:
        type: string
        nullable: true
      registered_volks:
        type: array
        items:
          type: string
      registered_tools:
        type: array
        items:
          type: string
      registered_providers:
        type: array
        items:
          type: string
      registered_channels:
        type: array
        items:
          type: string
      resource_usage:
        type: object
        properties:
          memory_bytes:
            type: integer
          api_calls_last_hour:
            type: integer
          events_emitted_last_hour:
            type: integer
          errors_last_hour:
            type: integer

  PluginLifecycleEvent:
    type: object
    required: [plugin_name, event_type, timestamp]
    properties:
      plugin_name:
        type: string
      event_type:
        type: string
        enum: [discovered, loaded, started, stopped, unloaded, error, enabled, disabled]
      timestamp:
        type: string
        format: date-time
      details:
        type: object

rpc_methods:
  plugin.list:
    description: List all discovered plugins with status
    scope_required: read_only
    result:
      type: array
      items:
        $ref: "#/schemas/PluginInfo"

  plugin.install:
    description: Install a plugin from source
    scope_required: admin
    params:
      type: object
      required: [source]
      properties:
        source:
          type: string
    result:
      $ref: "#/schemas/PluginManifest"

  plugin.uninstall:
    description: Uninstall a plugin
    scope_required: admin
    params:
      type: object
      required: [name]
      properties:
        name:
          type: string
    result:
      type: object
      required: [uninstalled]
      properties:
        uninstalled:
          type: boolean

  plugin.enable:
    description: Enable a disabled plugin
    scope_required: admin
    params:
      type: object
      required: [name]
      properties:
        name:
          type: string
    result:
      type: object
      required: [status]
      properties:
        status:
          type: string

  plugin.disable:
    description: Disable an active plugin
    scope_required: admin
    params:
      type: object
      required: [name]
      properties:
        name:
          type: string
    result:
      type: object
      required: [status]
      properties:
        status:
          type: string

performance:
  discovery_p95_ms: 500
  validation_p95_ms: 100
  initialization_p95_ms: 2000
  full_startup_50_plugins_p95_s: 10
  tool_invocation_overhead_p95_ms: 5
  capability_check_p95_ms: 1

security:
  capability_enforcement: true
  governance_authorization: true
  resource_limits: true
  audit_trail: true

observability:
  emits_metrics: true
  metric_names:
    - orchestrata_plugins_active
    - orchestrata_plugin_load_duration_seconds
    - orchestrata_plugin_errors_total
    - orchestrata_plugin_tool_invocations_total
    - orchestrata_plugin_events_emitted_total

spec_traceability:
  spec_id: "015-plugin-sdk"
  spec_version: "1.0.0"
  user_stories:
    - "US-001"
    - "US-002"
    - "US-003"
    - "US-004"
    - "US-005"
    - "US-006"
    - "US-007"
    - "US-008"
    - "US-009"
    - "US-010"


Non-Functional Requirements

Performance

NFR-001: Plugin Loading

NFR-002: Plugin Runtime

PR-001: Plugin discovery - SHALL complete within 500ms for up to 50 plugins at the 95th percentile.

PR-002: Plugin validation - Individual plugin manifest validation SHALL complete within 100ms at the 95th percentile.

PR-003: Plugin initialization - Individual plugin initialization (import + instantiate + initialize()) SHALL complete within 2 seconds at the 95th percentile.

PR-004: Full startup - Full plugin system startup for 50 plugins SHALL complete within 10 seconds at the 95th percentile.

PR-005: Tool invocation - Tool invocation overhead introduced by the plugin SDK layer SHALL be < 5ms at the 95th percentile.

PR-006: CXP routing - CXP message routing to a plugin-registered Volk SHALL add < 10ms overhead at the 95th percentile compared to core Volk routing.

PR-007: Event delivery - Event delivery to plugin event subscribers SHALL add < 50ms overhead at the 95th percentile.

PR-008: Capability checks - Capability permission checks SHALL complete within 1ms at the 95th percentile (cached).

PR-009: Plugin unload - SHALL complete within 5 seconds, including deregistration of all components and EventBus unsubscription.

PR-010: Hot-reload - Plugin hot-reload SHALL complete within 10 seconds (stop + unload + load + initialize + start).

PR-011: Memory overhead - The plugin system SHALL not increase core system memory usage by more than 50MB when no plugins are loaded.

Reliability

NFR-003: Isolation

NFR-004: Data Integrity

Security
Supply Chain

NFR-006: Supply Chain


Technical Design

Architecture
┌──────────────────────────────────────────────────────────────┐
│                    Plugin SDK System                           │
├──────────────────────────────────────────────────────────────┤
│                                                                │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐        │
│  │   Plugin      │  │   Plugin     │  │   Plugin     │        │
│  │   Manager     │──│   Loader     │──│   Registry   │        │
│  │              │  │              │  │              │        │
│  └──────────────┘  └──────────────┘  └──────────────┘        │
│         │                 │                 │                   │
│         ▼                 ▼                 ▼                   │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐        │
│  │   Plugin      │  │  Capability  │  │  Scoped DI   │        │
│  │   Lifecycle   │  │  Enforcer    │  │  Container   │        │
│  └──────────────┘  └──────────────┘  └──────────────┘        │
│         │                 │                 │                   │
│         ▼                 ▼                 ▼                   │
│  ┌─────────────────────────────────────────────────────┐      │
│  │              Plugin SDK (Public API)                  │      │
│  │   IPlugin · PluginContext · register_volk()           │      │
│  │   register_tool() · register_provider()               │      │
│  │   register_channel() · register_rules()               │      │
│  │   subscribe_event() · emit_event()                    │      │
│  └─────────────────────────────────────────────────────┘      │
│         │                 │                 │                   │
│         ▼                 ▼                 ▼                   │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐        │
│  │    Kernel     │  │   Prolog     │  │    Neo4j     │        │
│  │  (Volk Reg,   │  │  (PAM++      │  │  (Audit,     │        │
│  │   EventBus)   │  │   Plugin     │  │   KG Ext)    │        │
│  │              │  │   Rules)     │  │              │        │
│  └──────────────┘  └──────────────┘  └──────────────┘        │
└──────────────────────────────────────────────────────────────┘
Key Interfaces
class IPluginManager(IComponent, ABC):
    """Plugin lifecycle and registry management."""

    @abstractmethod
    async def discover_plugins(self) -> list[PluginManifest]:
        """Discover available plugins from configured sources."""

    @abstractmethod
    async def load_plugin(self, name: str) -> None:
        """Load and initialize a plugin by name."""

    @abstractmethod
    async def unload_plugin(self, name: str) -> None:
        """Stop and unload a plugin by name."""

    @abstractmethod
    async def reload_plugin(self, name: str) -> None:
        """Hot-reload a plugin (stop → unload → load → initialize → start)."""

    @abstractmethod
    def get_plugin(self, name: str) -> PluginInfo | None:
        """Get plugin info by name. Returns None if not found."""

    @abstractmethod
    def list_plugins(self) -> list[PluginInfo]:
        """List all discovered plugins with status."""

    @abstractmethod
    async def enable_plugin(self, name: str) -> None:
        """Enable a disabled plugin."""

    @abstractmethod
    async def disable_plugin(self, name: str) -> None:
        """Disable an enabled plugin without uninstalling."""

    @abstractmethod
    async def install_plugin(self, source: str) -> PluginManifest:
        """Install a plugin from source (pip spec, local path, git URL)."""

    @abstractmethod
    async def uninstall_plugin(self, name: str) -> None:
        """Uninstall a plugin completely (stop, unload, remove)."""


class IPlugin(Protocol):
    """Protocol that all plugins must implement."""

    async def initialize(self, context: PluginContext) -> None:
        """Initialize the plugin. Register components here."""

    async def start(self) -> None:
        """Start the plugin. Called after all plugins initialized."""

    async def stop(self) -> None:
        """Stop the plugin. Clean up resources here."""

    def get_manifest(self) -> PluginManifest:
        """Return the plugin manifest."""


class PluginManifest:
    name: str                              # Unique plugin name (kebab-case)
    version: str                           # Semantic version
    description: str                       # Human-readable description
    author: str                            # Author name or organization
    license: str                           # License identifier (SPDX)
    entry_point: str                       # Python import path to IPlugin class
    capabilities: list[PluginCapability]   # Required capabilities
    dependencies: list[str]               # Other plugin names (load order)
    python_dependencies: list[str]        # pip package specs
    config_schema: dict | None             # JSON Schema for plugin config
    min_orchestrata_version: str           # Minimum compatible version
    prolog_rules: list[str]               # Relative paths to Prolog rule files
    kg_schema: KGSchemaExtension | None   # Knowledge graph schema extension


class PluginCapability(Enum):
    DI_ACCESS = "di_access"           # Access to DI container
    REDIS = "redis"                   # Direct Redis access
    NEO4J = "neo4j"                   # Direct Neo4j access
    NETWORK = "network"               # Outbound network access
    FILESYSTEM = "filesystem"         # Filesystem read/write
    PROLOG = "prolog"                 # Prolog knowledge base access
    EVENT_BUS = "event_bus"           # Kernel EventBus access
    PROVIDER = "provider"             # IProviderManager access
    GATEWAY = "gateway"               # IGatewayServer access


class PluginContext:
    config: dict                      # Plugin-specific configuration
    logger: Logger                    # Plugin-scoped logger
    plugin_dir: Path                  # Plugin directory on filesystem
    manifest: PluginManifest          # Plugin manifest

    async def register_volk(
        self,
        alias: str,
        capabilities: list[str],
        handler: Callable,
    ) -> None:
        """Register a Volk with the kernel."""

    async def register_tool(
        self,
        name: str,
        description: str,
        parameters_schema: dict,
        handler: Callable,
    ) -> None:
        """Register a tool in the tool registry."""

    async def register_provider(
        self,
        name: str,
        provider: IProvider,
        config: ProviderConfig,
    ) -> None:
        """Register an LLM provider with the ProviderManager."""

    async def register_channel(
        self,
        channel_id: str,
        inbound_handler: Callable,
        outbound_handler: Callable,
    ) -> None:
        """Register a messaging channel adapter."""

    async def register_rules(
        self,
        rule_files: list[str],
    ) -> None:
        """Load Prolog rule files into the knowledge base."""

    async def register_kg_schema(
        self,
        node_types: list[str],
        relationship_types: list[str],
        indexes: list[str],
    ) -> None:
        """Extend the knowledge graph schema."""

    async def subscribe_event(
        self,
        topic: str,
        handler: Callable,
    ) -> str:
        """Subscribe to kernel EventBus topic. Returns subscription_id."""

    async def emit_event(
        self,
        event_type: str,
        payload: dict,
    ) -> None:
        """Emit a custom event (namespaced to plugin)."""

    def resolve(self, interface: type) -> Any:
        """Resolve a component from the scoped DI container."""


class PluginInfo:
    manifest: PluginManifest
    status: PluginStatus               # discovered | loading | active | error | disabled
    source: str                        # "local:<path>" | "pip:<package>" | "git:<url>"
    loaded_at: datetime | None
    error: str | None
    registered_volks: list[str]
    registered_tools: list[str]
    registered_providers: list[str]
    registered_channels: list[str]
    resource_usage: PluginResourceUsage


class PluginStatus(Enum):
    DISCOVERED = "discovered"
    LOADING = "loading"
    ACTIVE = "active"
    ERROR = "error"
    DISABLED = "disabled"


class PluginResourceUsage:
    memory_bytes: int
    api_calls_last_hour: int
    events_emitted_last_hour: int
    errors_last_hour: int


class KGSchemaExtension:
    node_types: list[str]
    relationship_types: list[str]
    indexes: list[str]
    constraints: list[str]
    migration_version: int
Plugin Manifest Format (plugin.yaml)
name: orchestrata-plugin-browser
version: 1.0.0
description: Browser automation tool for Orchestrata Volks
author: Mohamed
license: MIT
entry_point: orchestrata_plugin_browser.plugin:BrowserPlugin
min_orchestrata_version: "0.7.0"

capabilities:
  - network
  - di_access
  - event_bus

dependencies: []

python_dependencies:
  - playwright>=1.40.0

config_schema:
  type: object
  properties:
    headless:
      type: boolean
      default: true
    timeout_seconds:
      type: integer
      default: 30
    max_concurrent_pages:
      type: integer
      default: 5
  required: []

prolog_rules: []

kg_schema: null
Plugin Directory Structure
orchestrata-plugin-browser/
├── plugin.yaml                # Plugin manifest
├── pyproject.toml             # Python package metadata
├── src/
│   └── orchestrata_plugin_browser/
│       ├── __init__.py
│       ├── plugin.py          # IPlugin implementation (entry point)
│       ├── browser_tool.py    # Tool implementation
│       └── config.py          # Plugin config model
├── prolog/                    # Optional: Prolog governance rules
│   └── browser_rules.pl
├── tests/
│   ├── test_plugin.py
│   └── test_browser_tool.py
└── README.md
Plugin Loading Sequence
1. PluginManager.discover_plugins()
   ├── Scan plugin_dirs for plugin.yaml files
   ├── Query importlib.metadata for orchestrata_plugin entry points
   └── Deduplicate by name (local > installed)

2. PluginManager.load_plugin(name)
   ├── Validate manifest schema
   ├── Check dependencies (plugins + python packages)
   ├── Query PAM++: plugin_allowed(name) → allow/deny
   ├── Import plugin module via importlib
   ├── Instantiate entry point class
   ├── Create scoped DI container (filtered by capabilities)
   ├── Create PluginContext
   └── Call plugin.initialize(context)
       ├── Plugin registers volks, tools, providers, channels
       ├── Plugin registers Prolog rules
       └── Plugin registers KG schema extensions

3. PluginManager.start_all()
   └── For each loaded plugin (in dependency order):
       └── Call plugin.start()

4. PluginManager.stop_all()
   └── For each active plugin (reverse dependency order):
       ├── Call plugin.stop()
       ├── Auto-deregister all registered components
       ├── Unsubscribe from all EventBus topics
       └── Unload Prolog rules
Redis State Persistence

Plugin registry:

orchestrata:plugin:registry:{name}        — HASH {version, status, loaded_at, source, capabilities}
orchestrata:plugin:registry:active        — SET of active plugin names

TTL: None (persistent). Cleaned on uninstall.

Plugin resource tracking:

orchestrata:plugin:resources:{name}:api   — STRING (int, API calls this hour)
orchestrata:plugin:resources:{name}:evt   — STRING (int, events emitted this hour)
orchestrata:plugin:resources:{name}:err   — STRING (int, errors this hour)

TTL: 3600s (auto-reset hourly).

Neo4j Audit Schema

Nodes:

Relationships:

Configuration
# configs/monolithic.yaml
plugin_manager:
  enabled: true
  plugin_dirs:
    - "~/.orchestrata/plugins"
    - "./plugins"
  auto_discover: true
  allowlist_mode: "explicit"  # "explicit" | "open"
  allowlist:
    - orchestrata-plugin-browser
    - orchestrata-plugin-slack
  blocklist: []
  resource_limits:
    default_memory_bytes: 536870912       # 512MB
    default_api_calls_per_hour: 10000
    default_events_per_hour: 5000
  error_threshold: 5                      # Auto-disable after N consecutive errors

plugins:
  orchestrata-plugin-browser:
    headless: true
    timeout_seconds: 30
    max_concurrent_pages: 5
  orchestrata-plugin-slack:
    bot_token: «redacted»
    signing_secret: «redacted»
    channels:
      - general
      - engineering
Integration Points
Component Integration
orchestrata-core IPluginManager interface, ComponentType.PLUGIN_MANAGER, IPlugin protocol
orchestrata-kernel Volk registry for plugin Volks, EventBus for plugin events
orchestrata-di Scoped DI container for capability-based access control
orchestrata-governance PAM++ plugin authorization predicates
orchestrata-cxp CXP routing for plugin-registered Volks
orchestrata-provider Provider registration for plugin providers (SPEC-011)
orchestrata-knowledge KG schema extension for plugin node/relationship types
orchestrata-session Session-scoped plugin state (future)
orchestrata-gateway Plugin management RPC methods (SPEC-014)
configs/monolithic.yaml Plugin manager and per-plugin configuration

Examples

Example: Minimal Plugin Implementation

plugin.yaml:

name: orchestrata-plugin-hello
version: 1.0.0
description: A minimal example plugin that registers a greeting tool
author: Example Author
license: MIT
entry_point: orchestrata_plugin_hello.plugin:HelloPlugin
min_orchestrata_version: "0.7.0"
capabilities:
  - di_access
  - event_bus
dependencies: []
python_dependencies: []
config_schema:
  type: object
  properties:
    greeting:
      type: string
      default: "Hello from plugin!"
prolog_rules: []
kg_schema: null

plugin.py:

from orchestrata.plugins.sdk import IPlugin, PluginContext, PluginManifest

class HelloPlugin:
    """Minimal plugin demonstrating the IPlugin protocol."""

    def __init__(self) -> None:
        self._context: PluginContext | None = None

    async def initialize(self, context: PluginContext) -> None:
        self._context = context
        greeting = context.config.get("greeting", "Hello from plugin!")
        await context.register_tool(
            name="hello_greet",
            description="Returns a greeting message",
            parameters_schema={
                "type": "object",
                "properties": {
                    "name": {"type": "string"}
                },
                "required": ["name"],
            },
            handler=self._greet,
        )
        context.logger.info("HelloPlugin initialized with greeting: %s", greeting)

    async def start(self) -> None:
        await self._context.emit_event("hello.started", {"status": "ready"})

    async def stop(self) -> None:
        self._context.logger.info("HelloPlugin stopping")

    def get_manifest(self) -> PluginManifest:
        return self._context.manifest

    async def _greet(self, name: str) -> dict:
        greeting = self._context.config.get("greeting", "Hello")
        return {"message": f"{greeting}, {name}!"}
Example: Plugin Discovery and Loading
# System startup sequence
plugin_manager = container.resolve(IPluginManager)

# Discover all available plugins
manifests = await plugin_manager.discover_plugins()
# Returns: [PluginManifest(name="orchestrata-plugin-hello", ...), ...]

# Load a specific plugin
await plugin_manager.load_plugin("orchestrata-plugin-hello")
# Internally: validate → governance check → import → instantiate → initialize

# Query plugin status
info = plugin_manager.get_plugin("orchestrata-plugin-hello")
# Returns: PluginInfo(status=PluginStatus.ACTIVE, registered_tools=["hello_greet"], ...)

# List all plugins
all_plugins = plugin_manager.list_plugins()
# Returns: [PluginInfo(...), ...]
Example: Plugin Error (Capability Denied)
# Plugin declares capabilities: [di_access, event_bus]
# Plugin attempts to access Redis (not declared):
try:
    redis = context.resolve(IRedisClient)
except CapabilityDeniedError as e:
    # e.message: "Plugin 'orchestrata-plugin-hello' does not declare 'redis' capability"
    # e.error_code: "CAPABILITY_DENIED"
    # e.details: {"plugin": "orchestrata-plugin-hello", "capability": "redis"}
    pass
Example: Plugin Volk Registration
async def initialize(self, context: PluginContext) -> None:
    await context.register_volk(
        alias="U:Br",  # Browser agent
        capabilities=["web-scraping", "screenshot", "form-fill"],
        handler=self._handle_browser_task,
    )
    # Volk is now routable via CXP: {"target": "U:Br", ...}


Security

The Plugin SDK implements the following security controls:

Authentication and Authorization
Capability-Based Access Control
Resource Limits
Audit Logging
Error Isolation

Governance

The Plugin SDK integrates with PAM++ (SPEC-007) for governance control:

Plugin Authorization Predicates
%% Plugin load authorization
plugin_allowed(PluginName) :-
    plugin_in_allowlist(PluginName),
    \+ plugin_in_blocklist(PluginName).

plugin_allowed(PluginName) :-
    plugin_allowlist_mode(open),
    \+ plugin_in_blocklist(PluginName).

%% Capability authorization
plugin_capability_granted(PluginName, Capability) :-
    plugin_allowed(PluginName),
    plugin_declares_capability(PluginName, Capability),
    \+ capability_restricted(PluginName, Capability).

%% Resource limits
plugin_resource_limit(PluginName, memory_bytes, Limit) :-
    plugin_memory_limit(PluginName, Limit).
plugin_resource_limit(_, memory_bytes, 536870912).  % Default: 512MB

plugin_resource_limit(PluginName, api_calls_per_hour, Limit) :-
    plugin_api_limit(PluginName, Limit).
plugin_resource_limit(_, api_calls_per_hour, 10000).  % Default: 10K/hour

%% Registration authorization
plugin_can_register_volk(PluginName, VolkAlias) :-
    plugin_capability_granted(PluginName, di_access),
    \+ volk_alias_reserved(VolkAlias).

plugin_can_register_tool(PluginName, ToolName) :-
    plugin_capability_granted(PluginName, di_access),
    \+ tool_name_reserved(ToolName).

%% Reserved aliases (core Volks cannot be overridden)
volk_alias_reserved('U:Ox').
volk_alias_reserved('U:PS').
volk_alias_reserved('U:KR').
Governance Rule Registration


Dependencies



Testing



Success Criteria

  1. SDK Complete: IPlugin, PluginContext, and all registration methods implemented
  2. Discovery: Plugins discovered from local directories and pip packages
  3. Lifecycle: Full lifecycle (discover → validate → load → initialize → start → stop → unload) working
  4. Volk Plugins: Plugin-registered Volks routable via CXP and visible in Volk registry
  5. Tool Plugins: Plugin-registered tools invocable by Volks
  6. Provider Plugins: Plugin-registered providers participating in ProviderManager
  7. Isolation: Plugin errors do not crash core system or other plugins
  8. Governance: PAM++ controls plugin loading, capabilities, and resource limits
  9. CLI: orchestrata plugins list/install/uninstall/enable/disable commands working
  10. Audit: All plugin operations recorded in Neo4j audit trail


Observability

Logging Requirements
  1. Component Logging
    • Log all major operations with appropriate log levels
    • Include correlation IDs for request tracing
    • Log performance metrics for critical operations
    • Log errors with full context for debugging
Metrics Requirements
  1. Performance Metrics
    • Operation duration histograms
    • Request/error rate counters
    • Resource utilization gauges
    • Business metrics relevant to domain
Tracing Requirements
  1. Distributed Tracing
    • Trace propagation across component boundaries
    • Span attributes for domain-specific context
    • Trace sampling based on operational needs
Alerting Requirements
  1. Critical Alerts
    • Error rate spikes
    • Performance degradation
    • Resource exhaustion
    • Business metric anomalies
Dashboard Requirements
  1. Operational Dashboard
    • Real-time system health
    • Performance trends
    • Error analysis
    • Resource monitoring

Revision History

Date Version Author Changes
2026-03-27 1.0.0 Mohamed Initial specification
2026-03-28 1.0.0 Mohamed Added Data Models, Error Conditions, Performance Requirements, Testability, DoD, Terminology, Examples, Contracts sections per spec standard improvements