Quick start
Goal: within 15 minutes, get a minimal plugin to appear in the Extension Workshop, be enableable, and speak in the log.
1. What the smallest plugin looks like
A plugin = one standalone folder whose root must contain mod.json:
my_tool/
├── mod.json # required (or manifest.json)
├── my_tool.py # Python entry point (not needed for data plugins)
├── locales/ # recommended: plugin self-contained i18n strings
│ ├── zh-CN.json
│ └── en-US.json
├── icon.svg # recommended; icon.png/webp/jpg are auto-detected too
└── README.md # optional, shown in the hub listingMinimal mod.json:
{
"id": "myteam.tool.hello",
"name": "Hello Tool",
"version": "1.0.0",
"target_app_version": "0.2",
"author": "MyTeam",
"description": "最小示例:按热键把一句话送进字幕",
"type": "tool",
"entrypoint": "my_tool.py:HelloTool"
}⚠️
target_app_versionis mandatory: without it the plugin never even shows up in the Extension Workshop (log:[registry] 拒绝识别…未适配 0.2.0). See Compatibility & version gates.
my_tool.py:
from transbox.plugins.base import BasePlugin
class HelloTool(BasePlugin):
def initialize(self, config=None) -> None:
super().initialize(config)
self.host.register_plugin_hotkey(self.id, "run", "Alt+T", name="我的工具")
self.host.log("info", "Hello Tool 已就绪")
def action_run(self, **kwargs) -> dict:
ok = self.host.feed_direct_caption("hello", "auto", tts=False, drop_noise=False)
return {"ok": ok}
def shutdown(self) -> None:
self.host.unregister_plugin_hotkeys(self.id)
super().shutdown()2. Make the host find it
The host scans these directories (the 4th one only in the self-published build):
| Scan root | Who puts it there | Notes |
|---|---|---|
<install dir>/extensions/ | Shipped with the app | Official built-ins / examples |
%APPDATA%/transbox/extensions/ | The user | The most convenient place while developing |
Steam Workshop content/<AppID>/ | Steam subscription | Synced automatically by the Steam client |
<data dir>/workshop/<id>/ | Web Plugin Hub | Self-published build only; only a root-level mod.json is recognised |
Recommended development loop:
- Drop the whole
my_tool/folder into%APPDATA%/transbox/extensions/ - Open Settings → Extension Workshop → Refresh
- Flip the switch on the plugin card to enable it
- Engine types (
asr/mt/tts/theme/interpretation) must also be selected as the active engine on their own settings page
Source priority when ids collide: local > steam > web; a bundled plugin shipped with the app is only overridden when the workshop version has a higher semver.
3. Where to look when something breaks
Settings → Extension Workshop: card status, error messages,missing prerequisite pluginand the like all live here- Application log:
<install dir>/logs/app.log(lines prefixed[registry],[plugin:xxx]) - The plugin speaking for itself:
self.host.log("info", "…") - User-facing notice:
self.host.show_toast("…")
The host never silently swallows a load failure: a module import error, a missing entry class, a too-new min_app_version and a missing prerequisite dependency all leave a trace in the log and on the hub card.
See Hot debugging.
4. Hand the whole doc set to an AI
If you want a large model to write a compliant plugin without access to the main program's source, paste Layout & mod.json, the card for the matching type from Type overview, and Provider signatures into the AI, and require it to obey:
- Compliant layout: one standalone folder + a valid root
mod.json, a globally uniqueid,builtin.*forbidden; - Complete contract inheritance: a Python plugin inherits the matching base class from
transbox.plugins.base, implements every abstract method, and matches the signatures exactly; - Thread safety: network requests / inference / expensive computation must use
self.run_in_background(), events are dispatched withself.emit_event(), and blocking the Qt main thread is strictly forbidden; - Configure with
config_schema; when you need "get a key / test connection" style UX, shipui_extensions.settings_view; always read config viaself._config.get(key), never hard-code private keys or personal paths; - Self-contained i18n:
locales/zh-CN.json+locales/en-US.json, keys prefixedplugin.<plugin_id>.*, and never modify the host's core string tables; - Visual rules: QML uses
ThemeTokensandPluggableWindowBackgroundto adapt to the theme automatically; Emoji / character icons are forbidden, icons must be vector SVG; - MT plugins must declare
target_langs: list every language the model can translate into (including Chinese and English); do not rely onsupported_langsalone; see Language codes & translatable languages. - Local-service plugins follow the Local-service engine contract (lazy startup / port fallback / kill child processes in shutdown).
- Output: the complete directory tree + the complete
mod.json+ the complete source (never elide core logic with an ellipsis) + local testing and publishing instructions.
