Skip to content

feat: Phase 2 plugin architecture with entry point discovery#115

Draft
ChristopherJHart wants to merge 5 commits into
mainfrom
worktree-plugin-architecture-phase2
Draft

feat: Phase 2 plugin architecture with entry point discovery#115
ChristopherJHart wants to merge 5 commits into
mainfrom
worktree-plugin-architecture-phase2

Conversation

@ChristopherJHart
Copy link
Copy Markdown
Contributor

Summary

  • Introduces a PluginRegistry with entry point discovery (importlib.metadata) for all four plugin types: brokers, inventory, reporters, and hooks
  • Registers built-in implementations (SSH/HTTP/NETCONF brokers, FileInventoryPlugin, HTMLReporterPlugin) as entry points in pyproject.toml
  • Defines HookPlugin protocol with influencing event semantics (hooks can request SKIP at select lifecycle points)
  • Defines ReporterPlugin protocol enabling multiple simultaneous reporters or zero-reporter configuration
  • Makes RuntimeBroker registry-driven while maintaining full backward compatibility with existing test injection patterns
  • CLI reads [tool.huginn.plugins] from project pyproject.toml for plugin configuration

This is Phase 2 of the plugin architecture roadmap: clean internal separation within the same repository, with the ability for third-party plugins to be installed and wired in via standard Python entry points.

Test plan

  • All 449 existing + new tests pass (pytest tests/)
  • Entry point discovery verified: importlib.metadata.entry_points(group='huginn.brokers') returns {ssh, http, netconf}
  • Backward compatibility: running without [tool.huginn.plugins] produces identical behavior
  • Ruff lint passes on all modified files

🤖 AI Generation Metadata

  • AI Generated: Yes
  • AI Tool: claude-code
  • AI Model: opus-4.6
  • AI Contribution: ~90%
  • AI Reason: plugin architecture phase 2 implementation
  • Human Oversight: Design decisions reviewed and approved by user before implementation

🤖 Generated with Claude Code

ChristopherJHart and others added 5 commits May 22, 2026 10:39
Adds a clean internal boundary between the core framework and plugin
implementations, enabling third-party plugins via Python entry points
while keeping built-in plugins automatically active by default.

New modules:
- huginn.plugin_registry: Central PluginRegistry with entry point
  discovery for brokers, inventory, reporters, and hooks
- huginn.hooks: HookPlugin protocol, HookEvent enum, HookDispatcher
  with influencing event semantics (SKIP/CONTINUE signals)
- huginn.reporting.protocol: ReporterPlugin protocol definition

Key changes:
- Built-in brokers (SSH, HTTP, NETCONF), FileInventoryPlugin, and
  HTMLReporterPlugin registered as entry points in pyproject.toml
- RuntimeBroker accepts optional PluginRegistry for broker resolution,
  with backward-compatible fallback to direct instantiation
- Runner iterates reporter plugins instead of hardcoding HTML reporter
- Inventory plugin spec parsing delegates to registry for third-party
  plugin discovery
- CLI reads [tool.huginn.plugins] from pyproject.toml to configure
  plugin filtering and per-plugin options
- normalize_broker_key passes through unknown protocol strings to
  support future third-party broker types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Format hooks.py and plugin_registry.py with ruff
- Add return type annotations to test helpers
- Remove tomli fallback (Python 3.11+ always has tomllib)
- Add PluginRegistry to TYPE_CHECKING import in cli.py
- Widen broker type annotations from set[BrokerType] to set[str]
  throughout runner.py and runtime_broker.py to match the new
  string-based routing
- Remove .value accesses on broker keys (already strings via StrEnum)
- Extract _persist_and_report() from run_test_plan to reduce
  cyclomatic complexity below xenon threshold

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move all plugin-related imports from inside functions to module-level
imports. No circular dependencies exist between these modules, so
lazy imports were unnecessary.

- runtime_broker.py: move SSHBroker, HTTPBroker, NETCONFBroker, and
  PluginRegistry to top-level imports
- cli.py: move tomllib, InjectPlan, PluginConfig, PluginRegistry to
  module level
- inventory_plugins.py: move PluginRegistry and PluginResolutionError
  to module level
- runner.py: move PluginRegistry to module level

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Python 3.11+ supports all modern typing syntax natively. The only
forward reference needed (RuntimeBrokerClient -> RuntimeBroker) is
handled with a quoted string annotation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…istry.py

No forward references exist in this module.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant