Manifest reference
manifest.json sits at the root of a .macroDeckPlugin artifact, at the root of an installed version
directory and, during development, at the plugin’s content root, where the SDK reads it at startup.
Example
Section titled “Example”What macrodeck-plugin new generates:
{ "$schema": "https://schemas.macro-deck.app/plugin-manifest-v1.schema.json", "manifestVersion": 1, "id": "com.example.hue-lights", "name": "Hue Lights", "version": "1.0.0", "description": "Control Hue lights from Macro Deck.", "icon": "Assets/icon.svg", "entrypoints": { "win-x64": { "executable": "runtimes/win-x64/HueLights.exe" }, "osx-arm64": { "executable": "runtimes/osx-arm64/HueLights" }, "linux-x64": { "executable": "runtimes/linux-x64/HueLights" } }, "publisher": { "name": "Example Publisher" }, "license": "MIT", "compatibility": { "macroDeck": ">=3.0.0-0" }, "repository": "https://github.com/example/hue-lights", "homepage": "https://example.com/hue-lights"}- Schema:
plugin-manifest-v1.schema.json($idhttps://schemas.macro-deck.app/plugin-manifest-v1.schema.json). Name it in$schemafor editor validation and completion. - Property names are camelCase.
- Unknown properties are ignored everywhere, so an older host reads a newer manifest as it did before. Do not validate with a schema that rejects unknown properties; the host accepts them.
Fields
Section titled “Fields”Requirement is the category that decides when a field is required.
| Field | Type | Requirement | Meaning |
|---|---|---|---|
manifestVersion |
integer | runtime | Must be exactly 1. |
id |
string | runtime | Reverse-domain plugin id; must match the install directory. |
name |
string | runtime | Display name, 1-128 characters, no control characters. |
version |
string | runtime | SemVer 2.0; must match the install directory. |
entrypoints |
object | runtime | At least one launch target, keyed by runtime identifier. |
description |
string | publication | Human-readable description. |
icon |
string | publication | Relative path to the plugin icon. |
publisher |
object | publication | The Creator or Organization account that owns the listing. |
license |
string | publication | SPDX identifier by convention, carried verbatim and never parsed. |
repository |
string | publication | Absolute http/https URL. Informational. |
compatibility |
object | publication | SDK, protocol and Macro Deck ranges the plugin supports. |
homepage |
string | recommended | Absolute http/https URL. Informational. |
additionalLinks |
object[] | recommended | Further links shown in the Store. See additionalLinks. |
shutdown |
object | recommended | Graceful shutdown timeout. |
health |
object | recommended | Health probe settings. |
permissions |
string[] | recommended | Host capabilities the plugin declares it uses. |
languages |
string[] | recommended | BCP-47 tags of the plugin’s own strings. Normally derived by the tooling. |
ai |
object | recommended | Self-declaration about AI use, shown in the Store. See ai. |
dependencies |
object[] | recommended | Plugins this one needs. |
conflicts |
object[] | recommended | Plugins this one cannot run beside. |
iconPacks |
object[] | recommended | Icon packs this one references. |
bundledIconPacks |
object[] | recommended | Icon packs shipped inside the plugin’s own package. See Bundled icon packs. |
files |
object[] | generated | Per-file digests of the payload. Written by pack. |
signature |
object | generated | Creator signature. Written by the signer. |
The five runtime fields are the schema’s top-level required array.
Identity
Section titled “Identity”"manifestVersion": 1,"id": "com.example.hue-lights","name": "Hue Lights","version": "1.0.0"manifestVersionother than1is rejected before the rest is parsed, so a future manifest reports exactly that (unsupported-manifest-version).name: the no-control-characters rule is enforced by the host; the schema cannot express it.idandversionlocate the install:<dataRoot>/plugins/<id>/versions/<version>/. A manifest whoseidorversiondisagrees with that directory is rejected.
Package-ID rules
Section titled “Package-ID rules”^[a-z][a-z0-9]*(-[a-z0-9]+)*(\.[a-z][a-z0-9]*(-[a-z0-9]+)*)+$| Rule | Valid | Invalid |
|---|---|---|
| Lowercase letters, digits, hyphens, dots only | com.example.hue-lights |
com.Example.hue_lights |
| At least two dot-separated segments | com.example |
myplugin |
| Each segment starts with a letter; hyphens only between letters/digits | my-plugin2 |
-my, my--plugin, my- |
| At most 128 characters |
The same pattern validates publisher.id and every id in dependencies, conflicts and iconPacks.
Because an underscore is illegal, the _staging and _cache directories can never be taken for a plugin.
Entrypoints
Section titled “Entrypoints”"entrypoints": { "win-x64": { "executable": "runtimes/win-x64/HueLights.exe", "arguments": ["--quiet"] }, "osx-arm64": { "executable": "runtimes/osx-arm64/HueLights" }, "linux-x64": { "executable": "runtimes/linux-x64/HueLights.dll", "runtime": { "kind": "FrameworkDependent", "dotnetVersion": "10.0" } }}| Field | Type | Default | Requirement | Rules |
|---|---|---|---|---|
executable |
string | - | runtime | Relative to the version directory and inside it: no .., no absolute path. Never a script: .sh, .bat, .cmd, .ps1, .command are rejected whatever the runtime. |
arguments |
string[] | none | recommended | Passed to the executable in order. |
runtime.kind |
string | SelfContained |
recommended | SelfContained or FrameworkDependent, case-insensitive. Omitting runtime means self-contained. |
runtime.dotnetVersion |
string | - | recommended | major.minor, e.g. "10.0". Required when kind is FrameworkDependent, ignored otherwise. |
Reader-only cross-field rule: FrameworkDependent requires executable to end in .dll; self-contained
requires it not to.
The runtimes/<rid>/ layout that build and pack expect is described once, in
Staging layout. build and validate --level package judge it with one
shared rule (entrypoint-layout-invalid). build treats the entrypoint keys as the list of platforms to
build (or one with --rid) and fails when a declared entrypoint is missing from the output.
Runtime
Section titled “Runtime”Prefer FrameworkDependent with dotnetVersion "10.0" for a .NET plugin; it is what
new generates. Packaged Macro Deck ships a .NET runtime
(Microsoft.NETCore.App and Microsoft.AspNetCore.App 10.0, the patch its own release was built and
tested on) and runs the host itself on it, so a framework-dependent plugin carries no runtime: about
0.7 MB compressed per platform for the template plugin, against about 43 MB self-contained.
The host launches a framework-dependent entrypoint with dotnet <executable> and picks the runtime as
follows:
- The bundled runtime, when it has every framework the plugin’s
<Name>.runtimeconfig.json(beside the.dll) asks for, under that file’s roll-forward policy. Without a readable runtimeconfig the requirement isMicrosoft.NETCore.AppatdotnetVersion. - Otherwise a system-installed
dotnetthat has them, for example forMicrosoft.WindowsDesktop.Appor another .NET major. Installed runtimes are read once per host process; restart Macro Deck after installing one. - A system
dotnetwhose runtimes could not be listed is launched anyway; when nothing satisfies the requirement the plugin stays stopped (see troubleshooting).
Later Macro Deck releases add a new .NET major beside the existing one instead of replacing it, and do not roll a plugin forward onto a major it did not ask for.
Stay self-contained (omit runtime) when the plugin needs a runtime Macro Deck does not ship, pins a
specific runtime patch, or is not .NET at all. Self-contained entrypoints are launched directly.
An osx-x64 framework-dependent entrypoint that an osx-arm64 host falls back to (see
below) runs on the bundled arm64 runtime: managed code works, x64-only
native libraries do not load. Declare osx-arm64 for a framework-dependent plugin.
Runtime identifier resolution
Section titled “Runtime identifier resolution”| Host RID | Uses |
|---|---|
| Exact key present | That key |
osx-arm64 without its own key |
osx-x64 |
win-arm64 without its own key |
win-x64 |
Anything else, including linux-musl-* |
Nothing - there is no "any" key and no other fallback |
An artifact with no entrypoint for the host still installs and activates; the installer adds an advisory warning and does not start it. Only the entrypoint for the current RID is checked for existence on disk.
"icon": "Assets/icon.svg"- Forward-slash path relative to the version directory: no
..segment, no absolute path. - Lets a listing show an icon for a plugin that is not running; a running plugin’s icon still travels over the asset pipeline.
- Not checked for existence at Development level, so a missing icon never stops a working plugin. At
Package level and above,
validate,buildandpackreporticon-declared-not-present. - When
files[]is present, list the icon there like any other payload file.
Timing settings
Section titled “Timing settings”"shutdown": { "gracefulTimeoutSeconds": 10 },"health": { "path": "/_macrodeck/health", "intervalSeconds": 15, "timeoutSeconds": 2, "unhealthyThreshold": 3}Numeric values are clamped, never rejected.
| Field | Type | Default | Clamped to | Meaning |
|---|---|---|---|---|
shutdown.gracefulTimeoutSeconds |
integer | 10 | 1-60 | Time to exit after session.goodbye and the WebSocket close, before a process-tree kill. |
health.path |
string | /_macrodeck/health |
- | SDK health route the probe calls. |
health.intervalSeconds |
integer | 15 | 5-120 | Seconds between probes. |
health.timeoutSeconds |
integer | 2 | 1-10 | Seconds before one probe counts as failed. |
health.unhealthyThreshold |
integer | 3 | 2-10 | Consecutive failures before the plugin is unhealthy. The floor of 2 means one missed probe never restarts a plugin. |
permissions
Section titled “permissions”"permissions": ["host:variables", "net:outbound"]Recommended. Array of unique strings. Known vocabulary, one per host callback surface:
| Group | Permissions |
|---|---|
| Host | host:variables, host:user-variables, host:config, host:deck, host:scripts, host:widgets, host:notifications, host:action-interactions, host:devices, host:variable-values, host:layouts, host:folder-views, host:widget-types, host:event-bindings, host:screensavers, host:adb, host:messaging, host:video-streams |
| Other | events:publish, assets:upload, net:outbound, fs:user-files, process:spawn, device:usb |
- Unknown permission: warning (
unknown-permission), still installs. Not an enum on purpose. - Duplicate: rejected.
- Declared, validated, persisted and exposed. The host enforces only
host:adb: an installed plugin that does not declare it cannot use theadbhost API, see Android devices. Every other permission is enforced nowhere. See the security model.
languages
Section titled “languages”"languages": ["en", "de", "zh-Hant-TW"]Recommended. Array of unique BCP-47 tags.
- Normally not hand-written.
buildandpackderive it fromLocalization/*.resx: unsuffixedStrings.resxisen, each culture-suffixed sibling adds its tag. A hand-written value survives only when there is nothing to derive from; when both exist and disagree, the derived list wins andpacksays so. See the manifest languages field. - Full tags, never truncated:
zh-Hans/zh-Hantandpt-BR/pt-PTstay distinct. - Shape: 2-3 letter language, optional 4-letter script, optional 2-letter or 3-digit region - the shape MDLOC005 checks.
- Unrecognised tag: not an error. Blank or duplicate (case-insensitive,
de=DE): rejected. - For stores and update listings before install only. A running plugin’s localization capability is the authority; nothing in the host resolves text against this list.
"ai": { "interaction": true, "generatedContent": false, "generatedAssets": false, "services": ["OpenAI"]}Recommended. The plugin’s self-declaration about artificial intelligence. The Store shows it on the package page under AI.
| Field | Type | Default | Meaning |
|---|---|---|---|
interaction |
boolean | false |
Users interact with an AI system through the plugin: a chatbot, a voice assistant, a conversational agent. |
generatedContent |
boolean | false |
The plugin generates images, audio, video or text with AI while it runs. |
generatedAssets |
boolean | false |
The plugin ships icons, images, sounds or texts that were created or substantially changed with AI. |
services |
string[] | none | Display names of the external AI services the plugin uses. At most 16 names of at most 64 characters, shown as plain text. |
- Omitted means “not declared”, and the Store says exactly that. It never reads as “uses no AI”. To
state that the plugin uses no AI, declare the object with every flag
falseand noservices. Naming a service without setting a flag still counts as using AI. - Declarative only. The host never enforces or checks it, and a malformed value never stops a plugin from
installing or running. A flag that is not
trueorfalse(includingnull), or aservicesvalue that is not an array or has no readable name left, makes the whole declaration read as not declared, never as “uses no AI”. Otherwise blank, over-long or repeated names are dropped.validatestill reports a shape the schema does not allow. - Icon packs and the Store registry use the same object, so every package kind is labelled the same way.
- A plugin that uses AI must declare it accurately to be listed in the Store. The declaration does not replace your own legal obligations, for example under the EU AI Act.
Publication metadata
Section titled “Publication metadata”"description": "Control Hue lights from Macro Deck.","license": "MIT","repository": "https://github.com/example/hue-lights","homepage": "https://example.com/hue-lights","publisher": { "name": "Example Publisher", "id": "com.example", "email": "plugins@example.com", "url": "https://example.com"}homepage, repository and publisher.url must be absolute http/https URLs.
On the package’s Store page, Links starts with homepage as Homepage, then repository. The Store
links only https addresses, and lists a homepage that equals repository once.
additionalLinks
Section titled “additionalLinks”Resources beyond homepage and repository, shown in declared order under Links on the package’s
Store page, after the repository.
"additionalLinks": [ { "type": "documentation", "url": "https://docs.example.com" }, { "type": "issues", "url": "https://github.com/example/hue-lights/issues" }, { "type": "community", "url": "https://discord.gg/example" }, { "type": "custom", "label": "Setup Guide", "url": "https://example.com/setup" }]type |
Shown as (English) |
|---|---|
documentation |
Documentation |
wiki |
Wiki |
issues |
Report an issue |
support |
Support |
community |
Community |
donate |
Donate |
privacy |
Privacy policy |
terms |
Terms of service |
changelog |
Changelog |
license |
License |
custom |
Its own label |
Macro Deck labels the standard types in the viewer’s language. The constants are
PluginManifestLinkTypes in MacroDeck.Plugin.Packaging.
| Field | Type | Rules |
|---|---|---|
type |
string | Required. |
url |
string | Required. Absolute http/https URL. |
label |
string | Required for custom, at most 128 characters, no control characters, shown as written. Not allowed on a standard type. null is the same as absent. |
- No two links may share a URL. URLs are compared after normalising scheme and host case; the path, query
and fragment must match exactly, so
docs#setupanddocs#faqare different links. - No standard type may appear twice. Two
communitylinks would both read “Community”; give the second one acustomlabel instead. - No two
customlabels may be equal, ignoring case and surrounding spaces. - An unknown
typeis a warning (unknown-link-type), never an error. A type added in a later release still installs on an older Macro Deck, which simply does not show that link.
validate, build and pack report a broken link as invalid-additional-link. The host itself never refuses to install or run a plugin because of additionalLinks: an invalid
link is not shown. pack rewrites each entry with only type, url and label. Tools can apply the same
rules with PluginManifestLinks.Validate, and pick the entries safe to show with
PluginManifestLinks.Displayable.
Older Macro Deck versions ignore the field.
publisher
Section titled “publisher”| Field | Type | Requirement | Rules |
|---|---|---|---|
name |
string | publication | Required, non-empty, whenever the block is present. |
id |
string | recommended | Reverse-domain id when present. |
email |
string | recommended | Contact email. |
url |
string | recommended | Absolute http/https URL. |
Locally publisher is an unchecked claim. At upload the Creator Portal checks that publisher.name
matches the authenticated Creator/Organization account and that publisher.id, when present, is that
account’s id - so publisher.id stays recommended. Signing, not this field, authenticates an artifact:
see signature, Publishing to the Store and
the security model.
compatibility
Section titled “compatibility”"compatibility": { "sdk": ">=1.0.0,<2.0.0", "protocol": { "minimum": 1, "maximum": 1 }, "macroDeck": ">=3.0.0-0"}The block is publication-required: declare at least one member. An absent member declares nothing, never “incompatible”.
| Field | Type | Requirement | At install |
|---|---|---|---|
sdk |
version range | recommended | Recorded, not checked - the host learns the SDK only on connect. |
protocol |
{ minimum, maximum } |
recommended | Outside the host’s range rejects. Inclusive range of protocol majors; minimum >= 1, maximum >= minimum, both runtime-required once protocol is present. Same type as the wire handshake. |
macroDeck |
version range | recommended | Outside the range rejects. Skipped on a development host build (0.0.0-dev). |
A failed compatibility check is a rejection, never a warning.
Version range grammar
Section titled “Version range grammar”Used by compatibility.sdk, compatibility.macroDeck and every versionRange:
* any version>=1.2.0 one comparator>=1.2.0,<2.0.0 comma means AND- Comparators:
=,>,>=,<,<=. No caret, tilde,||or wildcard. - Plain SemVer 2.0 precedence:
>=1.0.0is not satisfied by1.0.0-beta.1. - To accept prereleases of the lower bound, end it with
-0, the lowest prerelease of any version:>=3.0.0-0is satisfied by3.0.0-beta.1,3.0.0-rc.1,3.0.0and everything after. This is whatmacrodeck-plugin newwrites forcompatibility.macroDeck. - Whitespace around comparators and commas is trimmed:
">= 1.0.0, < 2.0.0"is accepted.
Dependencies
Section titled “Dependencies”"dependencies": [ { "id": "com.example.core", "versionRange": ">=1.0.0,<2.0.0" }, { "id": "com.example.extras", "optional": true }],"conflicts": [{ "id": "com.example.legacy" }],"iconPacks": [{ "id": "com.example.icons", "versionRange": ">=1.0.0", "optional": true }]dependencies, conflicts and iconPacks are arrays of:
| Field | Type | Default | Requirement |
|---|---|---|---|
id |
string | - | runtime - reverse-domain id |
versionRange |
string | any version | recommended - grammar |
optional |
boolean | false |
recommended - false makes a dependency hard |
A duplicate id within one array, or an id in both dependencies and conflicts, is rejected.
| Declaration | When | Severity | Effect |
|---|---|---|---|
dependency, optional: false |
Missing or out of range | Blocking | Installs and activates; not auto-started. |
dependency, optional: true |
Missing or out of range | Advisory | Installs, activates, starts. |
| conflict | Named plugin installed and its active version satisfies the conflict’s versionRange |
Blocking | Installs and activates; not auto-started, whatever optional says. Outside the range: no warning at all. |
| icon pack | Always | Advisory | Parsed and exposed only - icon packs have database ids minted on import, so resolution cannot succeed today. |
Blocking never fails install or activation; it only withholds the automatic start.
Bundled icon packs
Section titled “Bundled icon packs”"bundledIconPacks": [ { "key": "logos", "path": "icon-packs/logos.macroDeckIconPack" }, { "key": "status", "path": "icon-packs/status.macroDeckIconPack" }]Icon packs the plugin ships inside its own .macroDeckPlugin, such as logos of the services it controls.
The host imports each one as a read-only pack owned by the plugin, so users can put its icons on any button
right after installing the plugin, and keeps it in step on update and uninstall. Add them with
macrodeck-plugin icon-pack add rather than by hand.
| Field | Type | Requirement | Rules |
|---|---|---|---|
key |
string | runtime | Identifies the pack within this plugin: lowercase letters, digits and inner hyphens, at most 64 characters. Keep it stable across versions: an update that keeps the key replaces the installed pack and keeps its icons by name, so buttons keep their icons. |
path |
string | runtime | Forward-slash path to a .macroDeckIconPack file, relative to the version directory: no .. segment, no absolute path. The extension is compared case-insensitively. |
- A pack is identified by the plugin id plus its key, never by a global pack id, and its icons by name. Names must be unique within a pack (compared case-insensitively); the same name may appear in two packs of one plugin.
- At most 32 entries. A repeated
key, or a repeatedpath(case-insensitive), is rejected by the reader (invalid-bundled-icon-pack). - The reader checks the shape only, never that the file exists.
validatewarnsbundled-icon-pack-missingfor a declared file that is not there, and for a packed manifestbundled-icon-pack-not-in-filesfor a pathfiles[]does not list. - List each pack in
files[]like any other payload file, whichbuildandpackdo for you. The host skips a pack its signed file list does not cover. - Separate from
iconPacks, which keeps its meaning: references to packs the plugin would like available, not packs it carries. - Compatibility: a host that predates this field ignores it and installs the plugin without the packs. The plugin still runs; its icon references then resolve to no icon.
"files": [ { "path": "runtimes/win-x64/HueLights.exe", "sha256": "sha256:b512f83e009ab0fcdda47e89a16013fa8bdf0baeb4b10e3343fc7ceca3cf6f3a", "size": 204800 }]Generated by macrodeck-plugin pack, which recomputes it from disk and discards any authored value.
| Field | Type | Rules |
|---|---|---|
path |
string | Required. Forward-slash, relative to the version directory. Duplicates rejected case-insensitively. |
sha256 |
string | Required. sha256: plus exactly 64 lowercase hex characters. |
size |
integer | Required. Bytes, >= 0. |
- Present: the installer verifies every entry and rejects any extracted file not listed.
- Absent: the installer records an advisory warning.
- Hand-authored in an unbuilt source tree:
validate,buildandpackwarngenerated-field-authored(a packed artifact or extracted install legitimately carries it).
signature
Section titled “signature”"signature": { "algorithm": "ed25519", "keyId": "macro-deck-store-2026", "value": "MEUCIQDx8p6...base64...==", "signedAt": "2026-01-15T12:00:00Z"}Generated: written by the Creator Portal for a Store artifact, or by macrodeck-plugin sign outside the
Store. Signs the format’s canonical digest, never re-serialised manifest JSON. Embedded here, with
certificate.json and certificate.sig at the archive root, plus issuer.json and issuer.sig when an
issuer certificate signed the certificate; no detached signature file. The certificate files are never
listed in files[]. issuer.json and issuer.sig are reserved only in a package whose certificate names
an issuer; a package signed directly under the root may declare files of those names like any other.
Exact shape:
package signature schema.
| Field | Type | Rules |
|---|---|---|
algorithm |
string | Required, non-blank. Only ed25519 is understood. |
keyId |
string | Required, non-blank. The signing certificate’s certificateId; verification fails if it names another certificate than the one carried. |
value |
string | Required, non-blank. Base64 signature bytes. |
signedAt |
string | RFC 3339 date-time. The certificate’s validity is evaluated at this instant, so a package stays verifiable after its certificate expires. |
- The host verifies before writing the install and on every launch. Every outcome except “unsigned” refuses; unsigned installs only on explicit confirmation for a file the user selected or uploaded. A present signature that does not verify is a failure, not a weaker unsigned.
- Sign after packing:
packrecomputesfiles[], so an earlier signature no longer matches.packpasses an existingsignaturethrough untouched;signrefuses to replace one. - Hosts older than the issuer chain refuse an artifact signed under an issuer certificate.
macrodeck-plugin verifyruns the same check (chain, validity atsignedAt, canonical digest, every declared file) - gate CI on it. Seesign,verifyand the signing verdict table.
Requirement categories
Section titled “Requirement categories”| Category | Required when |
|---|---|
runtime |
Always. The host’s reader rejects a manifest missing one. |
publication |
Before acceptance into the public Macro Deck plugin ecosystem. Never for local development. |
recommended |
Never. |
generated |
Never hand-authored; produced by build/pack/signing (files, signature). |
Categories feed three cumulative levels, Development ⊂ Package ⊂ Publication. A manifest valid at a
level stays valid at that level.
| Level | Checks | Run by |
|---|---|---|
| Development | Every runtime field, manifest/entrypoint/compatibility shape. Never gets stricter. |
The host at install - the only level it enforces. validate --manifest/--directory by default. |
| Package | Development, plus packaged content (entrypoints and icon present, valid multi-RID layout), plus missing publication fields as warnings. |
build, pack, validate --level package; validate --artifact by default. |
| Publication | Package, with missing publication fields as errors. |
validate --level publication, the Creator Portal at upload. |
Each schema property carries a non-standard x-macrodeck-requirement annotation ("runtime",
"publication", "recommended" or "generated"). Validators ignore it; tooling can read categories from
the schema instead of hardcoding this table.
MacroDeck.Plugin.Packaging.Manifest.PluginManifestRequirements reads the same annotations from the
schema embedded in that package.
See validate --level, Publishing to the Store and
Plugin hosting.
Validation
Section titled “Validation”macrodeck-plugin validate --manifest manifest.jsonmacrodeck-plugin validate --manifest manifest.json --level publicationvalidate runs the real reader, the embedded schema, the permission vocabulary and, when files[] is
present, the digests against real bytes, reporting every independent problem in one run. inspect
describes an artifact without judging it. See the CLI guide.
Actual output for broken variants of the example:
| Change | Diagnostic |
|---|---|
"manifestVersion": 2 |
error unsupported-manifest-version: Manifest version 2 is not supported; only 1 is understood. |
"id": "MyPlugin" |
error invalid-plugin-id: 'MyPlugin' is not a valid plugin id. |
name removed |
error schema:required: Required properties ["name"] are not present [] |
"version": "1.0" |
error invalid-version: '1.0' is not a valid SemVer version. [/version] |
"entrypoints": {} |
error no-entrypoints: Manifest declares no entrypoints. |
"executable": "../x" |
error entrypoint-outside-version-directory: Entrypoint 'linux-x64' executable '../x' escapes the version directory. |
"executable": "run.sh" |
error invalid-entrypoint-runtime: Entrypoint 'linux-x64' executable 'run.sh' looks like a script, which the artifact format forbids. |
FrameworkDependent, executable x |
error invalid-entrypoint-runtime: Entrypoint 'linux-x64' is framework-dependent but its executable does not end in '.dll'. |
No runtime, executable x.dll |
error invalid-entrypoint-runtime: Entrypoint 'linux-x64' is self-contained but its executable ends in '.dll'. |
"icon": "../icon.svg" |
error invalid-icon: Icon path '../icon.svg' is not a safe relative path. |
Missing icon file, --level package |
error icon-declared-not-present: 'Assets/nope.svg' is declared as 'icon' but is not present in the packaged content. [/icon] (package) |
"homepage": "example.com" |
error schema:pattern: The string value is not a match for the indicated regular expression [/homepage] |
{ "type": "custom", "url": "https://example.com/setup" } |
error invalid-additional-link: Link 0 is a custom link and must declare a label. [/additionalLinks/0/label] |
{ "type": "wiki", "label": "Our wiki", ... } |
error invalid-additional-link: Link 0 is a 'wiki' link, which Macro Deck labels itself; remove its label. [/additionalLinks/0/label] |
Two links with the same url |
error invalid-additional-link: Link 1 url 'https://docs.example.com' is already declared by another link. [/additionalLinks/1/url] |
{ "type": "roadmap", ... } |
warning unknown-link-type: Link 0 has the unknown type 'roadmap' and will not be shown. [/additionalLinks/0/type] |
| Permission listed twice | error invalid-permission: Permission 'host:variables' is declared more than once. |
"permissions": ["host:teleport"] |
warning unknown-permission: 'host:teleport' is not a known permission. [/permissions/0] |
"languages": ["de", "DE"] |
error invalid-language: Language 'DE' is declared more than once. |
"macroDeck": "^3.0.0" |
error invalid-compatibility: Compatibility.MacroDeck '^3.0.0' is not a valid version range. |
"protocol": { "minimum": 2, "maximum": 1 } |
error invalid-compatibility: Compatibility.Protocol range [2, 1] is invalid. |
"protocol": { "minimum": 1 } |
error schema:required: Required properties ["maximum"] are not present [/compatibility/protocol] |
Same id in dependencies and conflicts |
error invalid-dependency: 'com.example.core' cannot be both a dependency and a conflict. |
"publisher": { "id": "com.example" } |
error schema:required: Required properties ["name"] are not present [/publisher] |
description removed, --level package |
warning publication-metadata-missing: 'description' is required to publish to the Macro Deck plugin ecosystem. It is not required to develop or run this plugin locally. [/description] (publication) |
compatibility removed, --level publication |
error publication-metadata-missing: 'compatibility' is required to publish to the Macro Deck plugin ecosystem: declare at least one of 'sdk', 'protocol' or 'macroDeck'. ... |
"health": { "unhealthyThreshold": 1 } |
No diagnostic - clamped to 2. |
See also
Section titled “See also”- The raw schema - machine-checkable, with per-field descriptions.
- Plugin hosting - the artifact, the installer’s rules and the on-disk layout.
- Plugin CLI -
build,validate,inspectandpack. - Security model - what signing and permissions do and do not guarantee.