Publishing to the Marketplace
About 1156 wordsAbout 4 min
The extension marketplace is maintained in the UniBot.Market repository. The repository holds a registry extensions.json that is automatically read by the bot; users submit their extensions via Pull Request, and the bot can then search and one-click install them from the WebUI.
Overall Flow
Publishing a marketplace extension consists of three steps:
Package the extension
Compress the extension source code into a zip, making sure the root directory contains
Extension.toml, see 1. Package the Extension.Publish a Release
Upload the zip as an asset to the extension repository's GitHub Release, see 2. Publish a Release.
Register metadata
Register the metadata in the marketplace's
extensions/<id>.jsonand submit a PR, see 3. Create Metadata.Merge into the registry
After the workflow validation passes and the PR is merged,
extensions.jsonis generated automatically and the bot can discover your extension.
1. Package the Extension
Tip
It is recommended to use the Extension.Example template repository directly: it already ships with a complete packaging workflow (.github/workflows/release.yml) that automatically packages the extension into a zip and uploads it as a Release asset when a GitHub Release is published, so no manual configuration is needed. Just develop your own extension on top of the template.
Extensions are distributed as source zips (not via PyPI), and the zip root must contain Extension.toml. Refer to the packaging workflow of Extension.Example; the zip structure should be:
Extension.toml# Manifest (must be at the root)
__init__.py# Entry point (required for code extensions)
Commands.py# Command definitions (optional)
Services.py# Service definitions (optional)
...
Important
The zip root must be the extension content itself; it must not contain an extra nested Extension/ directory. Otherwise UniBot cannot find the Extension.toml at the root after extraction, and the installation fails.
2. Publish a Release
Upload the packaged zip to the extension repository's GitHub Release. It is recommended to name the asset <id>-<version>.zip (for example Placeholder-1.0.0.zip) so the registry script can identify it automatically.
3. Create Metadata
Create <extension-id>.json (for example Example.json) under the marketplace's extensions/ directory:
{
"id": "Example",
"name": "Example Extension",
"repo": "Minecraft-UniBot/Extension.Example",
"description": "An example extension that demonstrates the UniBot extension development workflow.",
"official": false
}Field Reference
| Field | Required | Description |
|---|---|---|
id | Yes | The extension's unique identifier; must be alphanumeric with underscores and must match the id in the Extension.toml inside the package |
name | Yes | Display name |
repo | Yes | The extension's source repository, in owner/repo format |
description | No | Extension description |
official | No | Whether it is an official release (boolean, default false); reviewed and set by repository maintainers, third-party extensions cannot declare it themselves |
Metadata Fields
Note
Metadata files starting with an underscore (e.g. _EXAMPLE.json) are skipped by the build script and used as documentation templates.
4. Submit a PR
Submit the new metadata file to the UniBot.Market repository and create a Pull Request:
- The workflow automatically validates the metadata format on the PR and pulls Releases from your extension repository to verify it can be built.
- After validation passes, the repository maintainer merges it, and
extensions.jsonis generated automatically.
SHA-256 Security Mechanism
Why is sha256 not required?
The SHA-256 checksum is computed at build time by the marketplace repository's workflow to prevent download tampering. User-submitted metadata does not contain and does not accept a sha256 field, which guarantees security. When installing through the WebUI, the downloaded zip is verified against the SHA-256 provided by the registry, and installations are rejected if the checksum fails.
Automatic Updates
- On PR / push:
build.ymlrebuilds the registry and fetches the latest Release assets for each extension, recomputing the SHA-256 checksums. - Every day at 9:00 / 15:00 / 21:00 (Beijing time):
update.ymlautomatically checks each extension repository for new Releases, updates the version numbers and SHA-256 checksums, and commits the changes back tomain.
Installation Flow (Triggered from WebUI)
Download
Select a version from the registry and download the Release asset zip.
Verify
Verify the SHA-256 checksum provided by the registry.
Security check
Verify that the zip root matches the
idin the manifest; reject absolute paths,../paths and symbolic links.Atomic replacement
Extract to a temporary directory; after all checks pass, atomically replace
Extensions/<id>/.Restart to take effect
Takes effect after restart.
Installation is a rollback-able transaction: download, verification, extraction, and manifest validation all happen in a temporary directory, and a failure at any step must not change the current version. Upgrading downloads the new version and atomically replaces the directory; uninstalling deletes the directory (both done in the WebUI).
Version Compatibility and Switching
Every marketplace Release carries a unibot_version constraint (taken from the extension package's [compatibility].unibot and recorded by the registry builder). Installation picks a version accordingly:
| Scenario | Behavior |
|---|---|
| The latest version supports the current core version | Installs the latest version directly |
| The latest version is incompatible, but a compatible older release exists | Falls back to the latest compatible release and explains the fallback in the task log |
| No release supports the current core version | Installation is rejected with "this extension does not support the current UniBot version" |
| The admin explicitly picks a version | Installs that exact version (useful for rolling back; compatibility is not re-checked) |
Version selection rules
The WebUI extension market offers a version switcher menu:
- Click the version icon on a card to list every available release (newest first); each is marked as compatible or not.
- Choosing a compatible release installs it; incompatible releases cannot be selected.
- A "latest → version to install" hint on the card means the latest release does not support the current core version.
- Extensions with no compatible release at all are marked "unsupported" and their install button is disabled.
Upgrades only ever move to "the latest release that supports the current core version", so an older core will never be upgraded to an incompatible extension release.
Local Build (Optional)
You can build against an existing Release without a GitHub Token (the public API is rate-limited); requires Python 3.11+:
python3 scripts/build_registry.pyStrict validation mode (equivalent to the PR check):
python3 scripts/build_registry.py --validate