Skip to content

fix(packaging): ship bundled plugin manifests - #82977

Closed
JoaoMarcos44 wants to merge 1 commit into
NousResearch:mainfrom
JoaoMarcos44:agent/fix-82916-plugin-manifests
Closed

JoaoMarcos44 wants to merge 1 commit into
NousResearch:mainfrom
JoaoMarcos44:agent/fix-82916-plugin-manifests

Conversation

@JoaoMarcos44

@JoaoMarcos44 JoaoMarcos44 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #82916.

Hermes 2026.8.3 could install bundled plugin Python modules without their runtime manifests. Platform adapters then existed on disk but were invisible to plugin discovery, so Feishu, Discord, Slack, Teams and other platform plugins never registered.

This PR fixes the packaging contract at its source and adds artifact-level regression coverage.

User-visible failure

On the affected installation:

HERMES_PLUGINS_DEBUG=1 hermes gateway run
[plugins] DEBUG bundled/platforms: 0 manifest(s)
WARNING gateway.run: No adapter available for feishu

The gateway is not missing a Feishu implementation. It is missing the metadata that tells Hermes to discover and defer-load that implementation.

Root cause

Bundled plugin layout:

plugins/platforms/<name>/
├── __init__.py       # register(ctx) entry point
├── adapter.py        # platform implementation
└── plugin.yaml       # discovery manifest

Packaging flow before this PR:

plugins.* package discovery
        │
        ├── Python files included
        └── plugin.yaml/plugin.yml omitted by package-data allowlist
                                      │
                                      ▼
                         installed wheel/sdist has no manifests
                                      │
                                      ▼
PluginManager._scan_directory() skips plugin directories
                                      │
                                      ▼
_register_deferred_platform() never runs
                                      │
                                      ▼
platform_registry remains empty
                                      │
                                      ▼
gateway.run._create_adapter() returns no adapter

Infographic :

infographic

The specific metadata gap was in [tool.setuptools.package-data]: plugins.* was listed for Python package discovery, but no plugins data entry covered YAML manifests.

This regression appeared when packaging configuration was simplified in #68217. It reintroduced the same packaging failure class previously fixed by #34034 and #28149.

Fix

pyproject.toml now declares:

[tool.setuptools.package-data]
plugins = ["**/plugin.yaml", "**/plugin.yml"]

This keeps manifest selection beside the package metadata that controls artifact contents. No gateway fallback, adapter duplication, import workaround, or platform-specific branch was added.

Regression protection

tests/test_packaging_build_guard.py now:

  1. Builds a real PEP 517 wheel.
  2. Builds a real PEP 517 sdist.
  3. Enumerates every plugin.yaml and plugin.yml under the source plugins/ tree.
  4. Verifies every source manifest exists in the generated artifact.
  5. Continues testing the existing non-Nix build guard.

This catches both:

  • Python code present but manifest absent.
  • A future glob that matches only a subset of nested plugin categories.

Validation evidence

Pre-fix reproduction

Built from the affected packaging configuration:

wheel plugin manifests: 0
sdist plugin manifests: 0

The new regression test failed with all bundled manifests reported missing.

Fixed artifacts

wheel plugin manifests: 97
sdist plugin manifests: 97

A clean extracted-wheel smoke test then executed the real scanner:

platform manifests discovered: 22
required manifests discovered: feishu-platform, discord-platform

Local tests

pytest tests/test_packaging_build_guard.py
4 passed

pytest tests/test_project_metadata.py tests/test_packaging_metadata.py
13 passed

pytest tests/hermes_cli/test_plugins.py        tests/hermes_cli/test_plugin_scanner_recursion.py        tests/providers/test_plugin_discovery.py
57 passed

Combined focused validation
74 passed

Ruff passed for changed files.

GitHub CI

PR checks completed successfully:

  • 34 checks passed
  • 0 failed
  • Python test slices passed
  • Python E2E passed
  • Windows-only tests passed
  • macOS-only tests passed
  • Ruff/type checks passed
  • uv.lock validation passed
  • OSV/supply-chain checks passed
  • Docker build/test workflow passed

Scope and non-goals

  • Preserves existing plugin discovery and deferred-loading behavior.
  • Preserves the non-Nix wheel/sdist build guard.
  • Does not re-enable Homebrew/PyPI as officially supported distribution methods.
  • Does not modify gateway adapter selection.
  • Does not alter plugin manifests or platform code.
  • Does not change unrelated bundled assets such as dashboard/sidecar files.

The fix makes generated artifacts complete for the manifest contract without resurrecting removed distribution-policy paths.

Files changed

  • pyproject.toml: include bundled plugin manifests in setuptools package data.
  • tests/test_packaging_build_guard.py: verify wheel and sdist contents against the complete source manifest set.

Release note

The fix takes effect in artifacts built from the merged commit. Existing 2026.8.3 installations remain broken until upgraded to a release containing this change.

Related: #82916, #34034, #28149, #68217.

@JoaoMarcos44
JoaoMarcos44 marked this pull request as ready for review August 10, 2026 06:13
@JoaoMarcos44
JoaoMarcos44 requested a review from a team August 10, 2026 06:13
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/plugins Plugin system and bundled plugins area/install-update Installer, updater, packaging, wheels, doctor sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 10, 2026
@egilewski

Copy link
Copy Markdown
Contributor

looks mergeable

The package-data declaration matches the runtime discovery boundary: every bundled plugin.yaml / plugin.yml must survive the source-to-artifact transition at the same relative path.

Security evidence:

  • trust boundary: Bundled plugin manifests cross from the source tree into installed wheel/sdist contents consumed by PluginManager.
  • source/sink/invariant: All 97 source manifests must ship in both artifacts so platform adapters remain discoverable without eager optional-SDK imports.
  • current-main reproduction: The current-main wheel and sdist built successfully but each contained 0 of 97 source manifests.
  • PR-head or patch-replay validation: The current-main replay built both artifacts with exactly 97 of 97 manifests and no missing or unexpected manifest paths; the focused packaging and metadata tests passed.
  • positive/negative cases: The extracted wheel discovered 22 platform manifests and registered Discord, Feishu, Slack, and Teams lazily while leaving their optional SDKs unloaded.
  • residual bypass search: Both .yaml and .yml manifest spellings are covered without broadening package data to unrelated YAML files.
  • reviewer validation: Independent source, artifact, runtime-discovery, and focused-test review found no actionable issue.

Not checked:

  • CodeRabbit review

Signed: GPT-5.6-sol-xhigh in Codex

@teknium1

Copy link
Copy Markdown
Collaborator

Merged via PR #86670. Your commit was cherry-picked onto current main with your authorship preserved in git log — thank you for the fix and the thorough artifact-level regression test.

@teknium1 teknium1 closed this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/plugins Plugin system and bundled plugins P1 High — major feature broken, no workaround sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 2026.8.3 packaging omits all plugin.yaml manifests — platform plugins fail to register

4 participants