Appearance
manifest.json
Every plugin must ship a manifest.json at its root URL. Dissent fetches this when an admin installs a plugin via URL.
Example
json
{
"id": "chess-stats",
"name": "Chess.com Stats",
"version": "1.2.0",
"description": "Live chess rating and recent game history from Chess.com.",
"context": ["sidebar", "profile"],
"tier": 2,
"url": "https://myplugins.example.com/chess-stats/index.html",
"declared_permissions": ["fetch:external"],
"allowed_fetch_domains": ["api.chess.com"],
"config_schema": {
"username": {
"type": "string",
"label": "Chess.com username",
"required": true
}
}
}Fields
id · string · required
Unique stable identifier for your plugin. Use lowercase letters, numbers, and hyphens. Once set, do not change — Dissent uses this to identify the plugin in the registry and across reinstalls.
Example: "chess-stats"
name · string · required
Display name shown in the marketplace and Server Settings.
Example: "Chess.com Stats"
version · string · required
Semantic version string.
Example: "1.2.0"
description · string · required
One or two sentences describing what the plugin does. Shown in the marketplace listing.
Example: "Live chess rating and recent game history from Chess.com."
context · string[] · required
Array of contexts this plugin supports. Valid values: "channel", "sidebar", "profile", "embed", "personal".
A "personal" plugin may declare only the permissions of the personal lane — see Personal Plugins.
A plugin whose context is only ["personal"] cannot be installed on a server: each person adds it from My plugins, and the node refuses a server install of it. List another context as well if it also belongs on servers.
Example: ["sidebar", "profile"]
tier · 1 | 2 | 3 · required
A label: 1 Passive, 2 Interactive, 3 Activity, shown in the marketplace, server settings and on the consent card. It grants no permissions and does not decide whether the consent card appears — declared_permissions does both. See Permissions.
Example: 1
url · string · required
The full URL to the plugin's index.html. This is snapshotted in the database at install time. If your domain changes, the plugin must be reinstalled.
Example: "https://myplugins.example.com/chess-stats/index.html"
config_schema · object · optional
Defines admin-configurable fields. Each key becomes an input in the plugin's config UI inside Server Settings. If null or omitted, the plugin has no admin configuration.
Each value is an object with:
| Property | Type | Description |
|---|---|---|
type | "string" | "number" | "boolean" | Input type |
label | string | Human-readable label shown in the config UI |
required | boolean | Whether the field must be filled before saving |
Values the admin enters are accessible in your plugin as ctx.config.
The key is snake_case. The node reads config_schema and ignores configSchema.
allowed_fetch_domains · string[] · required to use Dissent.fetch()
The hostnames Dissent.fetch() may reach, e.g. ["api.chess.com"]. Matching is exact — example.com does not admit api.example.com — and applies to every redirect hop. Bare hostnames only: no scheme, port or path. With an empty list, every fetch is refused (the node answers domain not in plugin allowlist; the SDK call rejects with fetch failed). Some hosts are further gated by a server-level switch that the server owner must turn on.
declared_permissions · string[] · required for any plugin that uses a permission
The only permissions a user can grant, for every context. Exactly the permissions the plugin uses, e.g. ["storage:user", "game:saves", "overlay:context"]. The user approves this list; a later version that adds one shows Review permissions instead of granting it.
overlay · object · optional (personal plugins)
Panels this plugin adds to the desktop app's game overlay: games (catalog ids) and surfaces (id, title, layer "panel", anchor, size). The node validates it when the plugin is added. See Overlay Panels for every rule.
screenshots · string[] · optional
Array of image URLs shown in the marketplace listing. Recommended size: 1280×800px.
readme_url · string · optional
URL to a Markdown file rendered as the plugin's marketplace "About" page.