Skip to content

Plugin manifest (plugin.json) β€” A.3 reference ​

Every Phlix plugin ships a plugin.json at the root of its package. This file is the source of truth for the loader (A.4), the admin UI (A.5), and the signature verifier (A.7+). A.3 defines:

  • The schema β€” schemas/manifest.schema.json in detain/phlix-shared (JSON Schema draft 2020-12). IDEs and CI lint manifests against this file. The runtime validator (Phlix\Plugins\Manifest\ManifestSchema) loads it from vendor/detain/phlix-shared/schemas/manifest.schema.json on installs of phlix-shared β‰₯ 0.6.0.
  • The parser β€” Phlix\Shared\Plugin\Manifest, an immutable PHP value object (shipped in the detain/phlix-shared Composer package). Parses plugin.json into typed properties. The validator (Phlix\Plugins\Manifest\ManifestSchema) stays in phlix-server and emits Phlix\Shared\Plugin\ManifestValidationError instances. The legacy Phlix\Plugins\Manifest and Phlix\Plugins\ManifestValidationError FQCNs remain available as deprecated aliases through 0.11.x.

Scope reminder. A.3 ships the spec and the parser only. The loader, sandbox, signature verification, and event-alias→FQCN resolution all live in A.4.

Canonical example ​

json
{
    "name": "phlix-plugin-lastfm",
    "version": "1.0.0",
    "phlix_min_server_version": "0.10.0",
    "type": "scrobbler",
    "entry": "Phlix\\Plugins\\Lastfm\\Plugin",
    "events": ["phlix.playback.started", "phlix.playback.stopped"],
    "settings": {
        "api_key": { "type": "string", "required": true, "secret": true },
        "api_secret": { "type": "string", "required": true, "secret": true }
    },
    "signature": "sha256:..."
}

This is the same example as PHLIX_EXPANSION_PLAN.md Β§5 β€” keep them in sync. The two valid-*.json fixtures under tests/Fixtures/Plugins/ are minimal, working manifests you can copy to bootstrap a new plugin.

Field reference ​

Required ​

FieldTypeConstraints
namestringKebab-case. Must start with phlix-plugin-. Max 64 chars. Single hyphens only (no leading/trailing/doubled). Regex ^phlix-plugin-[a-z0-9]+(-[a-z0-9]+)*$.
versionstringPlugin semver (optional prerelease and/or build metadata). Regex ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$.
phlix_min_server_versionstringMinimum supported Phlix server semver. Same regex.
typestringOne of the eleven values below.
entrystringFully-qualified entry class name. Regex ^[A-Z][A-Za-z0-9_]*(?:\\[A-Z][A-Za-z0-9_]*)+$.

Plugin types (type enum) ​

Mirrors PHLIX_EXPANSION_PLAN.md Β§5 and Phlix\Shared\Plugin\ManifestType:

ValuePurpose
metadata-providerPulls media metadata (e.g. an alternative TMDb).
subtitle-providerDownloads or generates subtitles.
auth-providerAuthenticates users (OIDC, LDAP, SSO, …).
library-typeAdds a brand-new library kind.
notifierSends notifications (push, email, chat).
scrobblerReports playback to an external service.
tunerLive-TV tuner backend.
transcoder-hookAdjusts the transcoder pipeline.
ui-themeRestyles the web portal.
arr-integrationIntegrates with *arr stack (Sonarr, Radarr).
analytics-sinkExports analytics to external systems.

Optional ​

events ​

An array of manifest aliases. Each alias is a dotted string of the form phlix.<area>.<verb>(.<sub>)* (regex ^phlix\.[a-z]+(?:\.[a-z_]+)+$; segments after <area> may contain underscores, e.g. phlix.user.logged_in). The canonical alias list lives in docs/dev/event-reference.md. The A.4 loader resolves these aliases to event FQCNs at install time.

settings ​

A keyed object describing the settings the plugin exposes to operators via the admin UI. Each value is an object:

KeyTypeNotes
typestringOne of string, int, bool, float, array. Required.
requiredbooleanWhether the operator must set a value. Default false.
secretbooleanHides the value in UI/logs and stores it encrypted. Default false.
defaultanyDefault value when the operator leaves the field blank.

signature ​

Either null (unsigned plugin) or a string matching ^sha256:[0-9a-f]{64}$. Signature verification lives in A.7; A.3 only validates the format.

Parsing and validating in PHP ​

php
use Phlix\Plugins\Manifest\ManifestSchema;
use Phlix\Shared\Plugin\Manifest;
use Phlix\Shared\Plugin\ManifestType;
use RuntimeException;

try {
    $manifest = Manifest::fromJson(file_get_contents('plugin.json'));
} catch (RuntimeException $e) {
    // Hard parse failure β€” the file isn't even valid JSON.
    throw $e;
}

$errors = (new ManifestSchema())->validate($manifest);
if ($errors !== []) {
    foreach ($errors as $error) {
        printf("[%s] %s β€” %s\n", $error->code, $error->field, $error->message);
    }
    return;
}

assert($manifest->manifestType() instanceof ManifestType);

Error codes returned by validate() ​

The code field on ManifestValidationError mirrors the JSON Schema constraint that failed (required, pattern, enum, type, additionalProperties, …), plus a Phlix-specific unknown_field code for top-level keys that the schema does not allow.

Authoring checklist ​

  1. Copy tests/Fixtures/Plugins/valid-lastfm.json (scrobbler) or valid-oidc.json (auth provider) into your plugin's root.
  2. Replace name, entry, events, and settings to match your plugin.
  3. Lint your plugin.json against the schema (optional β€” the loader will validate again at install time):
    sh
    # If you have phlix-shared checked out next to phlix-server:
    npx ajv-cli validate -s ../phlix-shared/schemas/manifest.schema.json -d plugin.json
    # …or from a phlix-server install:
    npx ajv-cli validate -s vendor/detain/phlix-shared/schemas/manifest.schema.json -d plugin.json
  4. Commit the manifest alongside your PHP entry class. Wiring the plugin into the runtime arrives in A.4.

See also ​

  • docs/plugins/developer-guide.md β€” top-level plugin authoring guide (stub; expanded in A.7).
  • docs/dev/event-reference.md β€” canonical alias β†’ FQCN table for events.
  • PHLIX_EXPANSION_PLAN.md Β§5 (internal planning doc, not published here) β€” the master plan that defines the manifest fields and the eleven types.

BSD-3-Clause