Files
Ewald 625920846c feat(plugins): introduce Blueprint manifest format (Phase 3.3)
Adds a declarative blueprint.{yaml,json} manifest layer on top of the existing dynamic-module plugin loader. Each plugin can now ship as a self-contained package with a manifest describing name, version, author, type, entrypoint class, and capabilities. The legacy flat .py plugin format remains fully supported.

Manifest schema v1 with fields: schema_version, name (slug), version (semver), author, type (metadata_extractor), entrypoint.{module,class}, optional capabilities/tags/license/homepage/description/min_majoor_version. Path-traversal and module-name injection are rejected at parse time. YAML manifests require PyYAML (already shipped by ComfyUI core); JSON manifests need no extra deps.

Loader: PluginLoader.discover_plugins now treats subdirectories with a blueprint manifest as blueprint packages (taking precedence over plain Python-package scanning). New PluginLoader.blueprints property and get_stats[blueprints] field expose loaded manifests for listing endpoints.

Migrated bundled examples to blueprint layout: plugins/examples/wanvideo/, plugins/examples/custom_node_template/, plugins/examples/rgthree/ (YAML variant).

Tests: 11 new tests in tests/features/test_blueprint_plugins.py covering manifest parsing edge cases (bad name, bad semver, unknown type, path traversal, schema mismatch), YAML support, discovery skipping invalid manifests, and loader integration including a missing-entrypoint warning path.
2026-05-21 22:31:15 +02:00
..

Majoor Assets Manager - Plugin Examples

This directory contains example metadata extractor plugins for the Majoor Assets Manager.

Two plugin layouts are supported:

  1. Blueprint format (recommended) — a directory containing a declarative blueprint.yaml (or blueprint.json) manifest plus the entrypoint module.
  2. Flat module format (legacy) — a single *.py file dropped into a plugin directory. Still supported; new plugins should use the blueprint format.

Blueprint Layout

my_plugin/
    blueprint.yaml          # or blueprint.json
    my_extractor.py         # entrypoint module

Manifest fields (v1):

Field Required Notes
schema_version yes Currently 1
name yes Lowercase slug [a-z][a-z0-9_]+
version yes Semver, e.g. 1.2.0
author yes Free text
type yes Only metadata_extractor for now
entrypoint.module yes Filename without .py, inside the package
entrypoint.class yes Class implementing MetadataExtractorPlugin
description, license, homepage, min_majoor_version, tags, capabilities no Informational

See examples/wanvideo/blueprint.json and examples/rgthree/blueprint.yaml for working manifests.

Available Examples

1. WanVideo Extractor (examples/wanvideo/)

Extracts WanVideo custom node metadata from PNG/WebP files. Priority 100.

2. Custom Node Template (examples/custom_node_template/)

Documented template for creating custom extractors. Priority 50.

3. rgthree Skeleton (examples/rgthree/)

Minimal blueprint demonstrating the YAML manifest variant. Priority 50.

Installation

Option 1: Copy to Global Plugin Directory

# Windows (PowerShell)
Copy-Item wanvideo_extractor.py ~/.comfyui/majoor_plugins/extractors/

# Linux/macOS
cp wanvideo_extractor.py ~/.comfyui/majoor_plugins/extractors/

Option 2: Copy to Local Plugin Directory

# Copy to ComfyUI output directory
cp wanvideo_extractor.py <ComfyUI>/output/_mjr_plugins/extractors/

Option 3: Use Bundled Plugins Directory

# Copy to extension's plugins directory
cp wanvideo_extractor.py <ComfyUI>/custom_nodes/ComfyUI-Majoor-AssetsManager/plugins/

Usage

After installing plugins:

  1. Restart ComfyUI or reload plugins via API:

    curl -X POST http://localhost:8188/mjr/am/plugins/reload
    
  2. List installed plugins:

    curl http://localhost:8188/mjr/am/plugins/list
    
  3. Enable/Disable plugins via Assets Manager UI:

    • Open Settings → Plugins tab
    • Toggle plugins on/off

Creating Your Own Plugin

See custom_node_extractor.py for a complete template with documentation.

Quick Start

from mjr_am_backend.features.metadata.plugin_system.base import (
    MetadataExtractorPlugin,
    ExtractionResult,
)

class MyExtractor(MetadataExtractorPlugin):
    @property
    def name(self): return "my_extractor"

    @property
    def supported_extensions(self): return ['.png']

    @property
    def priority(self): return 50

    async def extract(self, filepath: str) -> ExtractionResult:
        # Your extraction logic here
        data = {"key": "value"}
        return self._create_success_result(data)

Troubleshooting

Plugin Not Loading

  1. Check logs for validation errors
  2. Verify file is in correct directory
  3. Ensure plugin inherits from MetadataExtractorPlugin
  4. Check for syntax errors

Extraction Fails

  1. Enable debug logging: MJR_PLUGIN_LOG_LEVEL=DEBUG
  2. Check file permissions
  3. Verify file format is supported

Performance Issues

  1. Reduce plugin priority to run later
  2. Implement caching in plugin
  3. Use pre_extract() for quick rejections

Security Notes

Plugins are validated before loading. The following are blocked:

  • eval() / exec() usage
  • os.system() / subprocess calls
  • Network access (socket, requests)
  • Unsafe deserialization (pickle, marshal)

See PLUGIN_SYSTEM_DESIGN.md for complete security model.

License

All example plugins are provided under the MIT license.


For complete documentation, see:

  • docs/PLUGIN_SYSTEM_DESIGN.md - Architecture and design
  • docs/PLUGIN_DEVELOPMENT_GUIDE.md - Development guide (TODO: create)