Skip to content

The salieno.json manifest

A complete field-by-field reference for salieno.json — the manifest that names your panel, wires its Server form, and sets the credential rules Core generates accounts from.

8 min readUpdated Aug 15, 2026
On this page

Every panel extension ships two things: a driver class and a salieno.json manifest that sits next to it. The manifest is how Core learns your panel exists before it ever loads a line of your code — it names the panel, points at the driver class, states which Core versions it targets, and declares the two things Core renders generically: the Server connection form and the credential rules it pre-generates accounts from. This article documents every field.

For where the manifest fits in the package, see Your first panel. For the driver methods it points at, see The driver contract.

A complete manifest#

Here is the real cPanel manifest, annotated. The comments are for reading only — the file on disk must be strict, comment-free JSON.

json
{
  "schema": "salieno.panel/1",              // manifest format version — always this string
  "kind": "panel",                          // this is a hosting panel (not a theme or other extension)
  "slug": "cpanel",                         // unique id: server group value AND marketplace product slug
  "name": "cPanel / WHM",                   // shown in the group picker, Extensions library, service pages
  "version": "1.0.0",                       // YOUR panel's semver
  "namespace": "Salieno\\Panel\\Cpanel\\",  // your PSR-4 root
  "driver": "Cpanel",                       // the class in that namespace implementing the contract
  "entry": "Cpanel.php",                    // the driver file, relative — must end in .php
  "requires_core": ">=1.0.0 <2.0.0",        // the CORE version window you support (not your version)

  "capabilities": [                         // informational; driver capabilities() is authoritative
    "create","suspend","unsuspend","terminate","change_package","change_password",
    "account_summary","packages","sync","login_account","login_server",
    "quick_actions","reseller"
  ],

  "connection": {                           // renders the Server form's connection fields
    "label": "cPanel / WHM",
    "port": "2087",
    "auth": "token",
    "username_label": "WHM username (root or reseller)",
    "password_label": "WHM password",
    "token_label": "WHM API token",
    "token_help": "Create in WHM » Development » Manage API Tokens...",
    "docs": "https://api.docs.cpanel.net/whm/tokens/"
  },

  "credentials": {                          // rules Core uses to pre-generate account credentials
    "username_max_length": 8
  },

  "description": "cPanel & WHM hosting panel driver for Salieno Core..."
}

Top-level fields#

schema#

Always "salieno.panel/1". Core compares this exactly; anything else is rejected at install with "a manifest format this Salieno version does not understand." It is how a future manifest revision can change shape without breaking installs of the current one.

kind#

Always "panel". It distinguishes a hosting-panel extension from other marketplace extension kinds. A wrong value is refused as "not a hosting panel."

slug#

The panel's unique identifier, lowercase, [a-z0-9] start then [a-z0-9_-]. This one string does double duty, and that is the sharpest edge in the whole manifest:

  • It is the marketplace product slug — the id of the listing a buyer is entitled to.
  • It is what a server group stores to remember which panel backs it. Every provisioned account is keyed to this slug in the database.

On install, Core checks that the manifest slug matches the product it was fetched as; a mismatch fails with "that panel package does not match the product it was fetched as." Because provisioned accounts are keyed by slug, it is also the value an update must never change — changing it would orphan every existing account. Pick it once, at creation, and leave it.

name#

The human label shown in the server-group panel picker, the admin Extensions library, and the client and admin service pages. Free text — "cPanel / WHM", "Plesk".

version#

Your panel's own semantic version, e.g. "1.0.0". This is the number the marketplace tracks for update badges: to publish an update you increment this, and its semver must be strictly greater than the currently published version. It is stored on the installed row and shown next to your panel in the Extensions library. Do not confuse it with requires_core below.

namespace#

Your PSR-4 root, written as a PHP namespace with a trailing backslash — "Salieno\\Panel\\Cpanel\\". In JSON each backslash is escaped, so a single \ is written \\. Core maps this namespace onto your package files through a scoped autoloader that is unlocked only after the security gate passes, so your namespace should be distinctive to your panel. It is validated for a conservative namespace shape at install.

driver#

The class within that namespace that implements the contract — "Cpanel". Core resolves the fully qualified class as namespace + driver, so here Salieno\Panel\Cpanel\Cpanel. If your driver lives in a sub-namespace you may write "Drivers\\Cpanel", and Core will look for the class at Salieno\Panel\Cpanel\Drivers\Cpanel. The resolved class must be instanceof App\HostingModule\Server\HostingManagerInterface; extending AbstractPanel satisfies that automatically (see The driver contract).

entry#

The driver file's path relative to the package root — "Cpanel.php". It must end in `.php`; the marketplace requires it when you submit. It should point at the same file Core derives from namespace + driver (strip the namespace root off the class, turn \ into /, add .php), and at install time Core confirms that file actually exists in the package, failing with "that panel does not contain the driver it declares." For a driver in a sub-namespace, entry follows suit — "Drivers/Cpanel.php".

requires_core#

A Core version range, e.g. ">=1.0.0 <2.0.0". This is the single most-misread field: it declares which versions of Salieno Core your panel is compatible with, not anything about your panel's own version. Both worked examples target the 1.x line. Use a range that excludes the next major (<2.0.0) so a breaking Core release does not silently run an untested panel against it.

capabilities#

An informational array of capability slugs, mirroring what your driver actually supports. The marketplace and library can show it so buyers see at a glance what the panel does. It is not authoritative at runtime — Core decides which controls to render by calling your driver's capabilities() method, never by reading this array. Keep the two in sync out of good hygiene, but understand that the driver method is the source of truth. The full list of slugs and what each lights up in the UI is in Capabilities and the UI.

description#

Optional. A one-line human blurb for the marketplace listing. Purely informational; Core does not act on it.

The connection block#

connection is the manifest's first big payoff: it is what lets a brand-new panel render its own Server form with no changes to Core. When an operator adds a server under your panel's group, Core reads this block to build the connection fields, apply the default port, and decide which credential inputs are required. Every key:

KeyWhat it does
labelA short name for the connection profile, shown on the Server form.
portThe panel's API port as a string ("2087", "8443"). Selecting the group pre-fills this and forces the https:// protocol.
authThe credential scheme. One of "token", "password", or "token-or-password" — this drives which fields Core requires (see below).
username_labelLabel for the admin/username field ("WHM username (root or reseller)").
password_labelLabel for the password field.
token_labelLabel for the API-token field ("WHM API token", or "API secret key (optional)" when it is one of two accepted credentials).
token_helpInline help under the token field — where to create it, how it is sent.
docsA URL to the panel vendor's API docs, linked from the form.

How auth shapes the form#

The auth value decides what a new server must provide:

  • "token" — the API token is the credential; Core marks the token field required. cPanel/WHM uses this.
  • "password" — the admin password is required.
  • "token-or-password" — either satisfies the form; each field is required only when the other is empty. Plesk uses this, accepting an API secret key or the admin login + password.

The values your form collects arrive on $server inside the driver — $server->username, $server->password, $server->api_token, $server->verify_ssl, and so on. The full connection-profile walkthrough, including the "Test connection" probe, is in The Server connection form.

The credentials block#

credentials is the one place Core reads your rules for pre-generating an account's login before it calls create(). Today it carries a single documented key:

KeyWhat it does
username_max_lengthThe maximum username length the panel accepts. cPanel is 8; Plesk is 16.

Core generates a username within this cap so the value it hands your driver is one the real panel will accept. Without the block, a panel silently inherits the conservative legacy default (8 characters), which would needlessly truncate usernames on a panel that allows longer ones. Set it to your panel's real limit.

This governs only the value Core pre-generates. Your create() may always return the real username and password in its data payload, and those returned values win over anything Core generated — so a panel whose API assigns its own username can simply echo it back. That interplay is covered in The driver contract.

Sharp edges, in one place#

  • `slug` is the marketplace product slug and the server-group key at once. Choose it at creation and never change it — an update that changes the slug orphans every provisioned account.
  • `entry` must end in `.php` and should point at the same file namespace + driver resolves to; install fails if that file is not in the package.
  • `requires_core` is the Core version window, not your panel's version. Your version lives in version.
  • `connection` renders the Server form; `credentials` feeds account pre-generation. These two blocks are why adding a panel needs no Core edits.
  • The manifest `capabilities` array is informational. Runtime always trusts the driver's capabilities() method.

With the manifest in hand, move on to The driver contract to implement the methods it points at, or The security and trust model to understand why a hand-copied folder with a perfect manifest still will not load.

panelsmanifestreference
Was this article helpful?
Still stuck?Contact support
The salieno.json manifest