Plugin publishing guide
The marketplace uses GitHub distribution: plugin bytes live entirely in your
own GitHub repository, and the registry records one entry pointing at it.
Shipping a new version needs nothing but a tag — no PR per release.
1. Create a repo from the template
Generate your plugin repo from
plugin-template (one
plugin = one repo). Once the plugin works, make sure the root hasmanifest.json and the entry file main.js:
{
"id": "example.my-plugin",
"name": "My Plugin",
"version": "0.1.0",
"author": "Your name",
"description": "One sentence about what the plugin does",
"main": "main.js",
"trust": "safe",
"permissions": ["canvas.registerNodeDef"],
"categories": ["node"]
}
id: lowercase letters/digits/dots/hyphens; immutable after listing, and
part of the install archive nameversion: semver (e.g. 0.1.0), bumped on every releasetrust:safe(canvas only) /trusted(includes nodeEntry — main-process
access, reviewed more strictly)
2. Tag, and the release packs itself
Pushing a v* tag triggers the template's release workflow, which zips the
built manifest.json and main.js, recomputes the manifest integrity field,
and uploads three assets:
git tag v0.1.0 && git push origin v0.1.0
<id>-<version>.zip— versioned archive (for pinned entries)<id>.zip— versionless alias, always the latest stable releasemanifest.json— versionless alias, used by the desktop app to detect updates
Packing recomputes the SHA-256 of every entry file and injects integrity;
the desktop app enforces it at install time. The release must be a full
release (not a draft or prerelease) or releases/latest will not see it.
3. Open a PR against the registry
Open a PR against poly-creator/plugins
adding one entry to plugins.json:
{
"id": "example.my-plugin",
"name": "My Plugin",
"author": "Your name",
"repo": "your-user/your-plugin-repo",
"description": "One sentence about what the plugin does"
}
CI verifies the repo exists, that the latest release carries all three assets,
and that the in-zip manifest matches the entry. Once merged, the plugin shows
up in the marketplace and in the desktop app's Market tab. After that, every
release is just a tag — the registry entry stays put.
To pin a specific version (byte-level replay protection), add both tag andsha256 to the entry (they must come as a pair); the hash is verified on
install.
Rules
- One plugin per repo — multi-plugin repos break the
<id>.zipalias
convention and CI rejects them - zip ≤ 30 MiB; path-traversal entries (
../, absolute paths) are rejected trustedplugins that use nodeEntry get a stricter manual review- Unlisting = removing the entry from
plugins.json(already-installed users
keep working)