Problem
hermes-plugin-kit gives tools, hooks, middleware, and commands declarative decorators that register_plugin() discovers from a module. Specialized providers use a separate explicit path:
return register_plugin(
ctx,
tools,
memory_providers=(MyMemoryProvider(),),
)
That path is correct for Hermes' lifecycle, but it creates an asymmetry for plugins that combine model-facing tools with a memory provider. The plugin author must maintain decorated module declarations plus a separate provider tuple in register().
The concrete example is hermes-plugin-mempalace: all model-facing operations use @tool, while its private-only MemoryProvider is manually instantiated and passed to register_plugin(). The realm gate also has to be repeated at registration time.
Research
Proposal to explore
Add an optional class-level declaration for specialized providers, while retaining the current instance tuple as the stable low-level API. For example:
@memory_provider(enabled=lambda: not realm_policy().read_only)
class MemPalaceMemoryProvider(MemoryProvider):
...
return register_plugin(ctx, module)
The decorator would mark a provider class or factory for discovery. It would not wrap prefetch, sync_turn, shutdown, generate, or any other provider method. register_plugin() would instantiate the declaration only after its activation predicate passes and would still forward the resulting instance through Hermes' specialized registry.
This should be evaluated against two simpler alternatives:
- Keep the existing explicit tuples and document them as intentionally different from general decorated surfaces.
- Add a typed
plugin_provider(...) declaration/factory rather than a Python decorator, avoiding implicit class construction.
Required boundaries
- Do not expose provider lifecycle methods as model-callable tools.
- Preserve the Hermes
MemoryProvider, ImageGenProvider, and VideoGenProvider ABC contracts.
- Preserve one stateful provider instance per registration.
- Allow runtime activation gates without constructing disabled providers.
- Fail clearly when the active Hermes context does not support that provider kind.
- Detect duplicate provider names across explicit and discovered declarations.
- Keep
memory_providers=, image_gen_providers=, and video_gen_providers= backward compatible.
- Include registration receipts in
RegistrationSummary exactly as the current instance path does.
Definition of done
- Decide whether declarative provider discovery is materially clearer than the explicit tuple contract.
- If accepted, define construction/factory semantics and activation timing before implementation.
- Add tests for enabled/disabled declarations, duplicate names, unsupported contexts, constructor failures, and coexistence with explicit provider tuples.
- Update the specialized-provider guidance without weakening the rule against decorating provider methods as general plugin surfaces.
Problem
hermes-plugin-kitgives tools, hooks, middleware, and commands declarative decorators thatregister_plugin()discovers from a module. Specialized providers use a separate explicit path:That path is correct for Hermes' lifecycle, but it creates an asymmetry for plugins that combine model-facing tools with a memory provider. The plugin author must maintain decorated module declarations plus a separate provider tuple in
register().The concrete example is
hermes-plugin-mempalace: all model-facing operations use@tool, while its private-onlyMemoryProvideris manually instantiated and passed toregister_plugin(). The realm gate also has to be repeated at registration time.Research
register_plugin()already validates provider names and forwards instances throughctx.register_memory_provider,ctx.register_image_gen_provider, orctx.register_video_gen_provider: registration implementation.ctx.register_memory_provider(Mem0MemoryProvider()): Hermes Mem0 registration.hermes-plugin-kitissue covers provider declaration decorators. A search of Hermes issues found only the broader, closed extension-system proposal Feature: Enhanced Extension System with Tool Interception & Lifecycle Events (inspired by Pi) NousResearch/hermes-agent#359.Proposal to explore
Add an optional class-level declaration for specialized providers, while retaining the current instance tuple as the stable low-level API. For example:
The decorator would mark a provider class or factory for discovery. It would not wrap
prefetch,sync_turn,shutdown,generate, or any other provider method.register_plugin()would instantiate the declaration only after its activation predicate passes and would still forward the resulting instance through Hermes' specialized registry.This should be evaluated against two simpler alternatives:
plugin_provider(...)declaration/factory rather than a Python decorator, avoiding implicit class construction.Required boundaries
MemoryProvider,ImageGenProvider, andVideoGenProviderABC contracts.memory_providers=,image_gen_providers=, andvideo_gen_providers=backward compatible.RegistrationSummaryexactly as the current instance path does.Definition of done