Skip to main content
A manifest is the block of metadata that describes an addon. Every plugin, theme, and icon pack ships one. All addon kinds use the same shape, and the same manager validates it before the addon loads. This page documents the full shape. The page for each addon kind covers only what is specific to that kind.
Fonts are the exception. A font is a single file placed in the Fonts folder, with no manifest and no folder of its own. See Fonts below.

Required fields

Each of these must be present and not undefined. Otherwise the addon is rejected when it loads.
string
required
A unique identifier for the addon. It is the addon’s key in every manager operation and its storage namespace, so keep it the same across versions.
string
required
The human-readable name shown in settings.
string
required
A short summary of what the addon does.
AddonAuthor[]
required
A non-empty array of authors. An empty array fails validation, the same as a missing field.
string
required
The addon’s version. Increase it on every release so clients can detect updates.
string
required
The entry point the bundle is built from. Themes ignore this field. See Themes below.

Optional fields

Used for display and updates. You can leave them out.
string | { uri: string }
The addon’s icon: an asset name, or an object with a uri for a remote image.
string
A URL Unbound checks to discover newer versions.
string
Where the addon’s bundle is hosted.

Example

manifest.json
The manifest is validated as soon as the addon loads. The addon is rejected if any required field is missing or undefined, or if authors is empty.
You reference the id in several places:
  • Manager calls such as plugins.toggle('my-plugin').
  • Your storage store name.
  • The addon’s entry in the enabled-state map.
Choose it once and don’t change it.

Per-addon details

Every kind uses the same manifest shape, but each needs different files on disk and uses different fields.
  • At startup, the loader scans the Plugins, Themes, and Fonts folders.
  • Icon packs are installed by the client under Unbound/Icons.
See iOS for where these folders are on the device.
A plugin is a directory inside Plugins that contains a manifest.json. The loader skips entries that aren’t directories or have no manifest.main is required and must resolve to a real file. It resolves in one of two ways:
  • A value starting with / is treated as an absolute path and used as-is.
  • Anything else resolves relative to the plugin’s own folder.
In both cases the resolved path must exist and must not be a directory. Otherwise the plugin is skipped. Unbound reads that file and evaluates it to create your plugin’s running instance. See Creating an Addon.
A theme is a directory that contains both a manifest.json and a bundle.json. The bundle file name is fixed. The loader looks for exactly bundle.json next to the manifest, and skips the theme if that file is missing or isn’t a JSON object.
Themes ignore main entirely. Manifest validation still requires the field, but the loader never reads it when locating a theme’s bundle. Pointing main at a file with a different name does nothing. Rename the file to bundle.json instead.
While a theme is active, its id is stored as applied. Only one theme is applied at a time, and this value is how Unbound remembers which one. The palette and background live in bundle.json, not in the manifest. See Theme Types.
An icon pack is a folder of image files with the same layout as Discord’s asset tree, installed under Unbound/Icons/<id>. It uses the shared manifest above, plus two fields of its own:
'icon-pack'
Marks the manifest as an icon pack. If the field is present at install time, it must be 'icon-pack', or the install is rejected.
'github' | 'other'
How the pack’s files are fetched. If omitted, it is inferred from main: a github.com URL means github, and anything else means other.
How main is used depends on source:
  • github: main is the repo URL, optionally with a /tree/<branch>/<path> suffix. Unbound downloads the images in that tree into the pack folder.
  • other: the pack installs through the shared bundle path, like any other addon.
See Icon Packs.
A font has no manifest and no folder. It is a single font file placed directly in the Fonts directory. The loader registers it under the full name stored inside the font file, not under its file name.Registering a font does not apply it. A font only takes effect through the unbound.font-states setting, which maps a font family name to the name of the font to use in its place. See Settings for that key.
The key "*" in font-states is a wildcard. It overrides every font request in the app, whatever family was requested. If a wildcard entry is set, per-family entries never take effect.