Fonts are the exception. A font is a bare file dropped in the
Fonts folder, with no manifest and no folder of its own. See Fonts below.Required fields
These must be present and defined, or the addon is rejected when it loads.string
required
A unique identifier for the addon. Used as its key in every manager operation and as its storage namespace, so keep it stable 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 just like a missing field.
string
required
The addon’s version. Bump 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. Leaving them out is fine.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
id is the field you reference everywhere else: manager calls like plugins.toggle('my-plugin'), your storage store name, and the addon’s entry in the enabled-state map. Pick it once and never change it.Per-addon details
The shape is shared, but the addon kinds diverge in what they need on disk and which fields actually do anything. The loader scansPlugins, Themes, and Fonts at startup, while icon packs are installed by the client under Unbound/Icons. See iOS for where these live on device.
Plugins
Plugins
A plugin is a directory inside
Plugins containing a manifest.json. Entries that aren’t directories, or that have no manifest, are skipped.main is required and must resolve to a real file. Resolution works 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.
Themes
Themes
A theme is a directory containing 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 it isn’t there or isn’t a JSON object.Besides identifying the theme, its id is the value stored as applied while it’s the active theme. Only one theme is applied at a time, so this is how Unbound remembers which. The palette and background live in bundle.json, not the manifest. See Theme Types.Icon Packs
Icon Packs
An icon pack is a folder of image files mirroring Discord’s asset tree, installed under For a
Unbound/Icons/<id>. It uses the shared manifest above, plus two fields of its own:'icon-pack'
Tags the manifest as an icon pack. When present on install it must match, otherwise the install is rejected.
'github' | 'other'
How the pack’s files are fetched. If omitted, it’s inferred from
main: a github.com URL means github, anything else means other.github pack, main is the repo URL (optionally with a /tree/<branch>/<path> suffix) and Unbound downloads that tree’s images into the pack folder. For other, the pack installs through the shared bundle path like any other addon. See Icon Packs.Fonts
Fonts
A font has no manifest and no folder. It’s a single font file dropped directly into the
Fonts directory, and the loader registers it by reading the font’s own internal full name, not its file name.Registering a font does not apply it. Fonts only take effect through the unbound.font-states setting, which maps a font family name to the name of the font to use instead. See Settings for that key.