Skip to content

Platform plugin discovery drops platforms/ namespace from keys #27548

@kh-mitya

Description

@kh-mitya

Bug Description

Bundled gateway platform plugins under plugins/platforms/<name>/ are discovered with keys like teams-platform instead of the path-derived key platforms/teams.

This is inconsistent with the plugin manager's key model for namespaced plugins (image_gen/openai, web/tavily, etc.) and breaks config/UI code that uses canonical plugin keys for plugins.enabled / plugins.disabled.

Root Cause

In PluginManager.discover_and_load(), bundled top-level plugins are scanned with platforms skipped, then platform plugins are scanned separately:

bundled = self._scan_directory(
    repo_plugins,
    source="bundled",
    skip_names={"memory", "context_engine", "platforms", "model-providers"},
)
...
bundled_platforms = self._scan_directory(
    repo_plugins / "platforms", source="bundled"
)

Because the second scan starts at plugins/platforms with an empty prefix, _parse_manifest() computes:

key = f"{prefix}/{plugin_dir.name}" if prefix else name

For platform manifests whose name is e.g. teams-platform, the key becomes teams-platform instead of platforms/teams.

Steps to Reproduce

Run plugin discovery from a clean HERMES_HOME on current HEAD:

HERMES_HOME=$(mktemp -d) python - <<'PY'
from hermes_cli.plugins import get_plugin_manager, discover_plugins
pm = get_plugin_manager()
discover_plugins(force=True)
for p in sorted(pm.list_plugins(), key=lambda x: x.get('key','')):
    if p.get('kind') == 'platform':
        print((p.get('key'), p.get('name'), p.get('enabled'), p.get('error')))
PY

Actual Behavior

('google_chat-platform', 'google_chat-platform', True, None)
('irc-platform', 'irc-platform', True, None)
('line-platform', 'line-platform', True, None)
('simplex-platform', 'simplex-platform', True, None)
('teams-platform', 'teams-platform', True, None)

Expected Behavior

Platform plugin keys should include the platforms/ namespace, while the display/manifest name can remain whatever the manifest declares:

('platforms/google_chat', 'google_chat-platform', True, None)
('platforms/irc', 'irc-platform', True, None)
('platforms/line', 'line-platform', True, None)
('platforms/simplex', 'simplex-platform', True, None)
('platforms/teams', 'teams-platform', True, None)

Impact

  • plugins.disabled / plugins.enabled entries using canonical keys like platforms/teams do not affect the discovered platform plugin if discovery reports teams-platform.
  • Downstream tooling that displays plugin state by key can show platform plugins as neutral/not blocked even when config intended to disable them.
  • The bug is specific to plugins/platforms/* because other category plugins are scanned with a category prefix and already get keys like web/tavily or image_gen/openai.

Candidate Fix

Scan bundled platform plugins with _scan_directory_level() and prefix="platforms" instead of _scan_directory() from inside the platforms directory:

bundled_platforms = self._scan_directory_level(
    repo_plugins / "platforms",
    source="bundled",
    skip_names=None,
    prefix="platforms",
    depth=0,
)

I verified this minimal local patch produces the expected platforms/* keys.

Verification Performed

  • Reproduced on a clean detached worktree at HEAD: platform keys are *-platform.
  • Applied the minimal local patch above: platform keys become platforms/*.
  • Ran relevant plugin tests locally after the patch:
python -m pytest tests/hermes_cli/test_plugins.py tests/hermes_cli/test_plugins_cmd.py -q -o 'addopts='
137 passed in 6.39s

Environment

  • Repo: NousResearch/hermes-agent
  • Component: plugin discovery / bundled gateway platform plugins

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/pluginsPlugin system and bundled pluginstype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions