Plugin Metadata

Warning

Pre-implementation. This page describes proposed contracts. Class signatures, parameter types, config field names, and behavior are subject to change before code lands. Once implementation exists, content here will be regenerated from docstrings or sourced from running tests.

Every plugin package distributed for the framework declares standardized metadata. This serves three purposes:

  1. The CLI (rfgen list-emitters, list-channels, etc.) prints unified, machine-readable plugin information across first-party and third-party plugins.

  2. A future plugin hub (analog of HuggingFace Hub) can index packages without inspecting their code.

  3. SemVer compatibility between a plugin and the core framework is checkable before install.

This page is normative. All plugin packages, including first-party plugins shipped under rfgen.emitters.*, must conform.

Plugin metadata schema

# rfgen/core/plugin_metadata.py
from pydantic import BaseModel, Field
from typing import Literal


class PluginMetadata(BaseModel):
    name: str                                     # PyPI distribution name, e.g. "rfgen-myradar"
    plugin_kind: Literal[
        "emitter", "channel", "scene_composer",
        "labeler", "annotator", "store",
        "executor", "annotation_orchestrator",
        "time_placement", "freq_placement",
        "llm_client", "credentials_provider",
        "log_sink",
    ]
    version: str                                  # SemVer of this plugin

    # What it provides (kind-dependent fields)
    families: list[str] = Field(default_factory=list)         # for emitters: ["radar"]
    classes: list[str] = Field(default_factory=list)          # for emitters: ["pulsed.barker.b13", ...]
    backends: list[str] = Field(default_factory=list)         # for channels: ["awgn", "tdl_a"]

    # Compatibility
    rfgen_compat: str                             # SemVer range, e.g. ">=0.5,<0.7"
    python_compat: str = ">=3.11"

    # Provenance
    license: str                                  # SPDX identifier
    homepage: str | None = None
    description: str = Field(max_length=200)
    maintainers: list[str] = Field(default_factory=list)

    # Optional rich content
    docs_url: str | None = None
    plugin_card_url: str | None = None            # URL to PLUGIN_CARD.md
    example_config_url: str | None = None
    benchmarks_url: str | None = None

Plugin registration

Every plugin package exposes a PLUGIN attribute on its top-level module:

# rfgen_myradar/__init__.py
from rfgen.core.plugin_metadata import PluginMetadata

PLUGIN = PluginMetadata(
    name="rfgen-myradar",
    plugin_kind="emitter",
    version="0.2.1",
    families=["radar"],
    classes=["pulsed.barker.b13", "pulsed.barker.b11", "fmcw.up", "fmcw.down"],
    rfgen_compat=">=0.5,<0.7",
    license="Apache-2.0",
    description="High-fidelity polyphase pulsed radar emitter for rfgen.",
    homepage="https://github.com/myorg/rfgen-myradar",
    maintainers=["Jane Doe <jane@example.com>"],
)

# Concrete plugin classes self-register via the decorator (existing mechanism)
from rfgen.emitters.base import BaseEmitter
from rfgen.core.registry import register_emitter
from rfgen.enums import EmitterFamily

@register_emitter(family=EmitterFamily.RADAR)
class BarkerB13Emitter(BaseEmitter):
    ...

Entry-point group names

Plugins register concrete classes under stable Python entry-point groups. The group name identifies which API contract the class implements.

Plugin kind

Entry-point group

API contract

emitter

rfgen.emitters

BaseEmitter

channel

rfgen.channels

BaseChannel

scene_composer

rfgen.scene_composers

BaseSceneComposer

labeler

rfgen.labelers

BaseLabeler

annotator

rfgen.annotators

BaseAnnotator

store

rfgen.stores

BaseStore

executor

rfgen.executors

BaseDistributedExecutor

annotation_orchestrator

rfgen.annotation_orchestrators

BaseBatchAnnotationOrchestrator

time_placement

rfgen.time_placement

BaseTimePlacement

freq_placement

rfgen.freq_placement

BaseFrequencyPlacement

inference_client

rfgen.inference_clients

BaseInferenceClient

credentials_provider

rfgen.credentials

BaseCredentialsProvider

log_sink

rfgen.log_sinks

BaseLogSink

Plugin Card convention (PLUGIN_CARD.md)

Mirrors HuggingFace’s data and model cards. Every plugin package ships a PLUGIN_CARD.md at its repo root with the following fields. The framework does not parse these; they are for human reviewers and a future hub.

---
name: rfgen-myradar
plugin_kind: emitter
version: 0.2.1
license: Apache-2.0
rfgen_compat: ">=0.5,<0.7"
---

# rfgen-myradar

## What it does
One-paragraph summary. Concrete enough that a reader knows whether to install.

## Supported classes
Bullet list of `taxonomy_path` leaves this plugin produces.

## Parameters
Pydantic schema or table of supported `params` keys with ranges and defaults.

## Citations
Standards documents, papers, reference datasets the implementation derives from.

## Validation status
- Round-trip cross-checked against: <reference implementation>
- Bandwidth audited within ±5% of: <spec>
- PAES on caption set N=1000: <score>

## Known limitations
What this plugin does not model.

## Changelog
Recent versions and what changed.

Discovery and listing

The framework’s CLI scans installed packages for PLUGIN attrs and emits a unified table:

rfgen list-emitters
# NAME                FAMILY    CLASSES                            VERSION   RFGEN_COMPAT
# torchsig_adapter    comms     bpsk, qpsk, 16qam, ofdm, ...       2.1.1     >=0.5,<2.0
# rfgen-myradar       radar     pulsed.barker.b13, fmcw.up, ...    0.2.1     >=0.5,<0.7
# rfgen-bigsignal     iot       lora.css.sf12_bw250                0.4.0     >=0.4,<0.7

rfgen list-emitters --remote
# Queries the configured remote registry (default: official rfgen plugin index)
# in addition to installed packages. Includes plugins NOT yet installed.

Validation sandbox

rfgen plugin validate DIST runs plugin behavior checks in a child process. On Linux, the validator advertises FULL isolation only after this harmless preflight succeeds:

unshare --user --map-root-user --net -- true

The FULL profile isolates the child in user and network namespaces, applies the documented resource limits, sanitizes its environment, and uses a temporary working directory. It does not require a private procfs mount.

If the preflight fails, validation fails closed with SANDBOX_UNAVAILABLE and exit code 6; plugin code is not started. A Debian 12 GCP probe verified the minimal preflight. The earlier --mount-proc variant failed with EPERM, so it is not part of the supported profile.

Plugin package naming convention

Tier

Naming pattern

Maintained by

First-party (in rfgen core)

rfgen.emitters.<family>, etc.

Core team

Official extension

rfgen-<short-name>

Core team or appointed maintainer

Community

rfgen-<short-name>-<scope> (e.g. rfgen-myradar-defense)

Anyone

Private / corporate

Any name; not on the public index

Internal

The rfgen- prefix is convention only, not enforced. The framework discovers plugins by entry point regardless of package name.

SemVer compatibility check

When a plugin loads, the framework reads its rfgen_compat field and compares against the running framework version. Incompatible plugins are listed but not loaded:

rfgen list-emitters
# ...
# rfgen-old-radar    radar     ...                              0.1.0     >=0.3,<0.4
#                    INCOMPATIBLE: rfgen 0.5.2 not in >=0.3,<0.4

The CLI emits a warning at startup if any installed plugin is incompatible. The framework never silently ignores or auto-disables an incompatible plugin.

Future hub readiness

The schema above is sufficient to power a future hub website. The hub would aggregate:

  • All PLUGIN declarations from PyPI packages with the rfgen- keyword.

  • All PLUGIN_CARD.md files from those packages’ GitHub repos.

  • Download counts, last-release dates, GitHub stars (from PyPI and GitHub APIs).

  • Optional: PAES benchmarks, validation badges, signed-by-author markers.

No code in the framework needs to change for a hub to launch. The hub is a static site generator that consumes PyPI metadata. The framework’s only contribution is the schema.

Implementation timing

This page specifies what plugins must declare as of v0.5. First-party plugins (e.g. rfgen.emitters.comms.torchsig_adapter) ship PLUGIN declarations from day one. Third-party plugins published before v0.5 are exempt from PLUGIN requirement; later versions must add it.

See Also