Skip to main content
Development preview — this is not a live application; it is still being built.
ProxmoxVEx
↑ ↓ to navigate Enter to open

Plugin API Contract

Current contract version: 1.0.0

Version

Current contract version: 1.0.0

This contract defines the stable interface between ProxmoxVEx core and its plugins. Plugins that conform to this contract can be loaded and managed by the plugin registry.

Interface

File layout

plugins/{plugin-name}/
├── manifest.json       # Required. Machine-readable contract metadata.
├── __init__.py         # Required. Must export a `register(app)` function.
├── ui.html             # Optional. Frontend iframe markup (receives shared plugin-ui.css).
└── config.json         # Optional. Default configuration schema.

manifest.json

{
  "id": "plugin-name",
  "name": "Plugin Name",
  "version": "1.0.0",
  "author": "Author or organization",
  "description": "Human-readable one-line description.",
  "min_ProxmoxVEx": "1.0.0",
  "has_frontend": true,
  "frontend_route": "ui",
  "category": "Tools",
  "min_license_tier": "basic"
}

Fields read by the plugin registry (ProxmoxVEx/api/plugins.py):

  • id — unique plugin identifier (must match the directory name).
  • name, version, author, description — display metadata.
  • min_ProxmoxVEx — minimum core version required.
  • has_frontend / frontend_route — frontend_route: "ui" serves ui.html through the standard plugin-UI route; a custom value maps to the plugin’s own frontend route.
  • category — grouping in the plugin directory.
  • min_license_tier — minimum license tier required to enable the plugin.

__init__.py

def register(app):
    """Register plugin blueprints, handlers, and UI components.

    The plugin loader calls ``register(app)`` — not ``load(app)``.

    Args:
        app: The ProxmoxVEx Flask application instance.
    """
    from . import routes

    app.register_blueprint(routes.bp)

UI rendering and shared stylesheet

Plugins that expose a frontend iframe should ship a ui.html file in the plugin directory. When ProxmoxVEx serves the standard /api/plugins/{plugin_id}/api/ui route, it automatically injects the shared base stylesheet right after the opening <head> tag:

<link rel="stylesheet" href="/static/css/plugin-ui.css" />
  • You do not need to add this <link> manually in plugins/{plugin-name}/ui.html; the core injection adds it automatically and skips the file if it is already present.
  • Native/built-in plugins that are not served through the standard route should include the same <link> directly in their HTML.
  • Plugins may load additional stylesheets or inline <style> blocks after the shared sheet for specific overrides.

In-UI configuration editor

Every plugin UI served through _serve_plugin_ui also receives /static/js/plugin-config.js (after plugin-theme.js, plugin-events.js and plugin-ux.js). It mounts a configuration surface inside the plugin iframe that reads and writes the plugin’s config.json via GET/PUT /api/plugins/{id}/config. The host app’s plugin card “Manage” window stays a routes-only API explorer; the Settings → Plugins JSON editor remains as an admin fallback.

Mounting rules (evaluated on DOMContentLoaded):

Plugin markup Result
<meta name="pvx-config-ui" content="off"> No floating gear; the PVE.config API stays available
any [data-pvx-config] element Click handler bound to each; no floating gear injected
neither of the above Floating settings gear injected at bottom-left
  • PVE.config.open() / PVE.config.close() / PVE.config.mount(el) are exposed (also as PVE.ui.config) so a plugin’s own Settings tab or button can reuse the same modal.
  • When manifest.json declares config_schema (spec 092 shape: {field: {type, label?, description?, required?, secret?, enum?, minimum?, maximum?, default?}}), the editor renders typed, validated fields; otherwise it shows a validated raw-JSON editor. Both views are always reachable via the Form / Raw JSON toggle.
  • The /config endpoint requires the plugins.manage permission; users without it see a permission notice inside the modal.

Stability guarantees

  • Major contract changes break backward compatibility and require a new contract_version.
  • Minor contract changes add capabilities without breaking existing plugins.
  • Patch contract changes are clarifications or fixes to the contract text only.

Deprecation policy

  • Deprecated contract versions are supported for at least one major ProxmoxVEx release.
  • A plugin using a deprecated contract version will log a warning on load.
  • The plugin registry may refuse to load plugins targeting an unsupported contract version.

Security boundaries

  • Plugins run in the same process as ProxmoxVEx core and are therefore trusted by default.
  • Plugins must not import or access the database layer directly; use the public API or core hooks.
  • Plugin frontend iframes are loaded same-origin and must comply with the configured Content-Security-Policy.

Was this page helpful?

ProxmoxVEx Source-Available License
Checking status…

© 2025-2026 ProxmoxVEx contributors