Packaging & size limit
A plugin is just a folder plus a
mod.json. Packaging = zipping the whole folder.
What goes into the package
The root of the zip must be mod.json directly (no extra wrapping folder):
text
my_mod.zip
├── mod.json ← at the root
├── my_mod.py
├── locales/
├── icon.svg
└── *.qmlThe client's built-in export feature packages by this rule; when packaging by hand, take care not to zip an outer folder in as well.
Size limit: 20 MB (hard limit)
| Stage | Limit |
|---|---|
| Client pre-check before upload | 20 MB (anything bigger is stopped locally, not a single byte is sent) |
| Server (Pages Function) | 20 MB |
The Plugin Hub runs on a Cloudflare Pages Function, and packages from 45 MB up get cut off mid-upload by the platform (the client only sees a write failure, with no useful hint) — so we block up front at 20 MB.
What to do with big data
| Thing | How to distribute it |
|---|---|
| Model weights (hundreds of MB to a few GB) | model_artifacts in mod.json → the host downloads them from HF / ModelScope into the user data directory. See Model artifacts |
Native runtimes (.dll / .exe, tens of MB) | requires_runtime → the host downloads, verifies and unpacks on demand. See Host runtimes |
| Lightweight Python dependencies | Ship them in libs/ or vendor/ with the package (see Runtime environment) |
| Tens of MB of your own binary and there is no matching official runtime | Contact the official team for a separate distribution channel (do not stuff it into the .tbmod) |
Lesson from the field: an author once packed an 88 MB llama runtime into a package and the upload was bound to fail. The runtime components we have today exist for exactly this scenario.
Version number
versioninmod.jsonmust be a semanticx.y.zversion.- It is required when publishing to the Plugin Hub, and a new version must be higher than the highest online version (you can edit it directly on the publish page).
- Local loading accepts it being absent (defaults to
1.0.0). version(your own release number) andtarget_app_version(the client generation you adapt to, must be0.2) are two different things — see Compatibility & version gates.
Pre-packaging self-check
- [ ] The zip root is
mod.jsondirectly (notmy_mod/mod.json) - [ ]
mod.jsondeclares"target_app_version": "0.2"(without it the plugin cannot be installed, see Compatibility & version gates) - [ ]
idis globally unique and the author segment is not a reserved name (transbox/official/builtin/community/example/workshop/steam/system/admin/root/support/web/test/tbmod) - [ ]
versionisx.y.zand higher than the highest online version - [ ] The file
entrypointpoints to and the class name really exist - [ ] The package contains no
__pycache__/.git/ temporary files - [ ] Total size < 20 MB; no big binaries or weights
- [ ]
locales/has both the Chinese and the English file (see i18n) - [ ] The icon is a vector SVG, not Emoji / characters
