feat(plugin): register spec-defined extension points in PluginManager #939

Closed
opened 2026-03-14 01:16:56 +00:00 by freemo · 6 comments
Owner

Background and Context

The specification defines 30 named extension points across the system (spec §Architecture > Extensibility, §Extension Points). These are the hooks where plugins and custom implementations can be registered to extend system behavior: context strategies, pipeline components, tool providers, output renderers, validation runners, skill providers, etc.

The current implementation in src/cleveragents/infrastructure/plugins/ (~40% complete) has:

  • PluginLoader — discovers and loads plugin modules from entry points
  • PluginManager — manages plugin lifecycle (register/unregister/list)
  • PluginDescriptor — plugin metadata model
  • ExtensionPointRegistry — generic registry for extension points

However, zero of the 30 spec-defined extension points are actually registered in the ExtensionPointRegistry. The infrastructure exists but no extension points are declared, meaning plugins have nowhere to hook into. The PluginManager.register_extension() method exists but is never called by the system to declare what can be extended.

Affected files

  • src/cleveragents/infrastructure/plugins/registry.pyExtensionPointRegistry
  • src/cleveragents/infrastructure/plugins/manager.pyPluginManager
  • Various subsystems that should declare extension points (context, output, validation, tools, skills, etc.)

Expected Behavior

All 30 spec-defined extension points must be declared in the ExtensionPointRegistry with proper typing, and the relevant subsystems must query the registry for plugin-provided implementations.

Acceptance Criteria

  • All 30 spec-defined extension points registered in ExtensionPointRegistry:
    • Context: context.strategy, context.pipeline_component (x10), context.storage_backend
    • Output: output.renderer, output.materializer, output.format
    • Validation: validation.runner, validation.rule_provider
    • Tools: tool.provider, tool.middleware
    • Skills: skill.provider, skill.template
    • Resources: resource.resolver, resource.type_handler
    • A2A: a2a.transport, a2a.extension_method
    • Events: event.handler, event.filter
    • Config: config.source, config.validator
    • Safety: safety.guardrail
  • Each extension point has a typed protocol/interface definition
  • Subsystems query the registry for plugin-provided implementations at initialization
  • Plugin authors can register implementations via Python entry points
  • Extension point discovery: plugin list-extension-points CLI command

Metadata

  • Commit message: feat(plugin): register spec-defined extension points in PluginManager
  • Branch: feature/plugin-extension-points
  • Parent Epic: None (standalone feature)
  • Blocks: None
  • Blocked by: None

Subtasks

  • Define typed Protocol interfaces for each extension point category
  • Register all 30 extension points in ExtensionPointRegistry at app bootstrap
  • Wire context subsystem to query context.* extension points
  • Wire output subsystem to query output.* extension points
  • Wire validation subsystem to query validation.* extension points
  • Wire tool/skill/resource subsystems to query their extension points
  • Wire A2A subsystem to query a2a.* extension points
  • Implement plugin list-extension-points CLI command
  • Add documentation strings to each registered extension point
  • Tests (Behave): Add scenarios for plugin registration through entry points
  • Tests (Unit): Add tests for each extension point registration and lookup
  • Verify coverage >=97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when all 30 spec-defined extension points are registered, typed, and discoverable, and at least one subsystem (context or output) queries the registry for plugin implementations.

## Background and Context The specification defines 30 named extension points across the system (spec §Architecture > Extensibility, §Extension Points). These are the hooks where plugins and custom implementations can be registered to extend system behavior: context strategies, pipeline components, tool providers, output renderers, validation runners, skill providers, etc. The current implementation in `src/cleveragents/infrastructure/plugins/` (~40% complete) has: - `PluginLoader` — discovers and loads plugin modules from entry points - `PluginManager` — manages plugin lifecycle (register/unregister/list) - `PluginDescriptor` — plugin metadata model - `ExtensionPointRegistry` — generic registry for extension points However, **zero** of the 30 spec-defined extension points are actually registered in the `ExtensionPointRegistry`. The infrastructure exists but no extension points are declared, meaning plugins have nowhere to hook into. The `PluginManager.register_extension()` method exists but is never called by the system to declare what can be extended. ### Affected files - `src/cleveragents/infrastructure/plugins/registry.py` — `ExtensionPointRegistry` - `src/cleveragents/infrastructure/plugins/manager.py` — `PluginManager` - Various subsystems that should declare extension points (context, output, validation, tools, skills, etc.) ## Expected Behavior All 30 spec-defined extension points must be declared in the `ExtensionPointRegistry` with proper typing, and the relevant subsystems must query the registry for plugin-provided implementations. ## Acceptance Criteria - [ ] All 30 spec-defined extension points registered in `ExtensionPointRegistry`: - Context: `context.strategy`, `context.pipeline_component` (x10), `context.storage_backend` - Output: `output.renderer`, `output.materializer`, `output.format` - Validation: `validation.runner`, `validation.rule_provider` - Tools: `tool.provider`, `tool.middleware` - Skills: `skill.provider`, `skill.template` - Resources: `resource.resolver`, `resource.type_handler` - A2A: `a2a.transport`, `a2a.extension_method` - Events: `event.handler`, `event.filter` - Config: `config.source`, `config.validator` - Safety: `safety.guardrail` - [ ] Each extension point has a typed protocol/interface definition - [ ] Subsystems query the registry for plugin-provided implementations at initialization - [ ] Plugin authors can register implementations via Python entry points - [ ] Extension point discovery: `plugin list-extension-points` CLI command ## Metadata - **Commit message**: `feat(plugin): register spec-defined extension points in PluginManager` - **Branch**: `feature/plugin-extension-points` - **Parent Epic**: None (standalone feature) - **Blocks**: None - **Blocked by**: None ## Subtasks - [ ] Define typed Protocol interfaces for each extension point category - [ ] Register all 30 extension points in `ExtensionPointRegistry` at app bootstrap - [ ] Wire context subsystem to query `context.*` extension points - [ ] Wire output subsystem to query `output.*` extension points - [ ] Wire validation subsystem to query `validation.*` extension points - [ ] Wire tool/skill/resource subsystems to query their extension points - [ ] Wire A2A subsystem to query `a2a.*` extension points - [ ] Implement `plugin list-extension-points` CLI command - [ ] Add documentation strings to each registered extension point - [ ] Tests (Behave): Add scenarios for plugin registration through entry points - [ ] Tests (Unit): Add tests for each extension point registration and lookup - [ ] Verify coverage >=97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when all 30 spec-defined extension points are registered, typed, and discoverable, and at least one subsystem (context or output) queries the registry for plugin implementations.
freemo added this to the v3.6.0 milestone 2026-03-14 01:18:23 +00:00
Member

Implementation Notes — @CoreRasurae

Design Decisions

  1. Protocol-based extension points: All 21 extension point interfaces are defined as @runtime_checkable Protocol classes in extension_protocols.py. This allows both static type checking (Pyright) and runtime isinstance() checks for plugin validation.

  2. Catalog pattern: Extension point definitions are centralized in extension_catalog.py with a single register_all_extension_points() function called during app bootstrap. This keeps registration declarative and discoverable.

  3. Optional PluginManager wiring: The ACMS pipeline accepts an Optional[PluginManager] parameter to maintain backward compatibility with existing code that doesn't inject a plugin manager.

Files Created/Modified

File Purpose
infrastructure.plugins.extension_protocols 21 Protocol classes for extension point categories
infrastructure.plugins.extension_catalog Registration catalog with 30 extension point definitions
infrastructure.plugins.__init__ New exports
application.container Wired register_all_extension_points() at bootstrap
application.services.acms_service Context subsystem extension point queries
features/plugin_extension_points.feature 38 Behave scenarios
features/steps/plugin_extension_points_steps.py Step definitions with 21 stub implementations

Extension Point Categories (30 total)

  • Context: 12 (strategy, 10 pipeline components, storage backend)
  • Output: 3 (renderer, materializer, format)
  • Validation: 2 (runner, rule provider)
  • Tools: 2 (provider, middleware)
  • Skills: 2 (provider, template)
  • Resources: 2 (resolver, type handler)
  • A2A: 2 (transport, extension method)
  • Events: 2 (handler, filter)
  • Config: 2 (source, validator)
  • Safety: 1 (guardrail)

Quality Gate Results

  • lint: Passed (all checks passed)
  • typecheck: Passed (0 errors, 0 warnings)
  • unit_tests: Passed (13,023 scenarios, 0 failures)
  • coverage: 97.0% — COVERAGE OK

Commit

Branch: feature/plugin-extension-points
Commit: 3f5ca4e8feat(plugin): register spec-defined extension points in PluginManager

## Implementation Notes — @CoreRasurae ### Design Decisions 1. **Protocol-based extension points:** All 21 extension point interfaces are defined as `@runtime_checkable` Protocol classes in `extension_protocols.py`. This allows both static type checking (Pyright) and runtime isinstance() checks for plugin validation. 2. **Catalog pattern:** Extension point definitions are centralized in `extension_catalog.py` with a single `register_all_extension_points()` function called during app bootstrap. This keeps registration declarative and discoverable. 3. **Optional PluginManager wiring:** The ACMS pipeline accepts an `Optional[PluginManager]` parameter to maintain backward compatibility with existing code that doesn't inject a plugin manager. ### Files Created/Modified | File | Purpose | |------|---------| | `infrastructure.plugins.extension_protocols` | 21 Protocol classes for extension point categories | | `infrastructure.plugins.extension_catalog` | Registration catalog with 30 extension point definitions | | `infrastructure.plugins.__init__` | New exports | | `application.container` | Wired `register_all_extension_points()` at bootstrap | | `application.services.acms_service` | Context subsystem extension point queries | | `features/plugin_extension_points.feature` | 38 Behave scenarios | | `features/steps/plugin_extension_points_steps.py` | Step definitions with 21 stub implementations | ### Extension Point Categories (30 total) - Context: 12 (strategy, 10 pipeline components, storage backend) - Output: 3 (renderer, materializer, format) - Validation: 2 (runner, rule provider) - Tools: 2 (provider, middleware) - Skills: 2 (provider, template) - Resources: 2 (resolver, type handler) - A2A: 2 (transport, extension method) - Events: 2 (handler, filter) - Config: 2 (source, validator) - Safety: 1 (guardrail) ### Quality Gate Results - **lint**: Passed (all checks passed) - **typecheck**: Passed (0 errors, 0 warnings) - **unit_tests**: Passed (13,023 scenarios, 0 failures) - **coverage**: 97.0% — COVERAGE OK ### Commit Branch: `feature/plugin-extension-points` Commit: `3f5ca4e8` — `feat(plugin): register spec-defined extension points in PluginManager`
freemo self-assigned this 2026-04-02 06:13:59 +00:00
Author
Owner

PR #1217 reviewed, approved, and merged.

All 30 spec-defined extension points are now registered in the ExtensionPointRegistry with typed Protocol interfaces. The ACMSPipeline context subsystem integration is wired and tested. 38 Behave scenarios pass covering registration, lookup, protocol conformance, and entry point discovery.

Minor follow-up items noted in the review (non-blocking):

  • Step file plugin_extension_points_steps.py exceeds 500-line guideline (787 lines) — stub classes could be extracted to features/mocks/
  • Two # noqa: E501 suppressions in extension_protocols.py could be resolved by wrapping long signatures
  • TOTAL_EXTENSION_POINTS constant could be derived from len(_EXTENSION_POINT_DEFS) instead of hardcoded
PR #1217 reviewed, approved, and merged. All 30 spec-defined extension points are now registered in the `ExtensionPointRegistry` with typed Protocol interfaces. The ACMSPipeline context subsystem integration is wired and tested. 38 Behave scenarios pass covering registration, lookup, protocol conformance, and entry point discovery. Minor follow-up items noted in the review (non-blocking): - Step file `plugin_extension_points_steps.py` exceeds 500-line guideline (787 lines) — stub classes could be extracted to `features/mocks/` - Two `# noqa: E501` suppressions in `extension_protocols.py` could be resolved by wrapping long signatures - `TOTAL_EXTENSION_POINTS` constant could be derived from `len(_EXTENSION_POINT_DEFS)` instead of hardcoded
Author
Owner

Dependency notice: Issue #1292fix(plugin): validate entry point module paths against allowlist before loading — has been created as a child of this Epic. It addresses a security vulnerability in PluginLoader.load_from_entry_points where ep.load() is called before validating the module path against the _allowed_prefixes allowlist.

Per project conventions, #1292 blocks this Epic (#939).

**Dependency notice**: Issue #1292 — *fix(plugin): validate entry point module paths against allowlist before loading* — has been created as a child of this Epic. It addresses a security vulnerability in `PluginLoader.load_from_entry_points` where `ep.load()` is called before validating the module path against the `_allowed_prefixes` allowlist. Per project conventions, #1292 **blocks** this Epic (#939).
Author
Owner

PR #1217 reviewed, approved, and merge scheduled (will merge when CI checks pass).

Two independent reviews confirmed spec alignment (all 30 extension points), type safety, test quality (38 Behave scenarios), and correctness. Non-blocking follow-up items noted: step file size (787 lines, recommend extracting stubs to features/mocks/) and hardcoded TOTAL_EXTENSION_POINTS constant.

PR #1217 reviewed, approved, and merge scheduled (will merge when CI checks pass). Two independent reviews confirmed spec alignment (all 30 extension points), type safety, test quality (38 Behave scenarios), and correctness. Non-blocking follow-up items noted: step file size (787 lines, recommend extracting stubs to `features/mocks/`) and hardcoded `TOTAL_EXTENSION_POINTS` constant.
Author
Owner

PR #1217 reviewed, approved, and merged. All 30 spec-defined extension points are now registered in the ExtensionPointRegistry with typed Protocol interfaces, and the context subsystem is wired to query context.* extension points.

PR #1217 reviewed, approved, and merged. All 30 spec-defined extension points are now registered in the `ExtensionPointRegistry` with typed Protocol interfaces, and the context subsystem is wired to query `context.*` extension points.
Author
Owner

PR #1217 reviewed, approved, and merged. All 30 spec-defined extension points are now registered in the ExtensionPointRegistry with typed Protocol interfaces, completing the plugin extension infrastructure.

PR #1217 reviewed, approved, and merged. All 30 spec-defined extension points are now registered in the `ExtensionPointRegistry` with typed Protocol interfaces, completing the plugin extension infrastructure.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#939
No description provided.