Hot debugging
Edit a file → refresh → read the log. The host never silently swallows a load failure.
Development loop
- Put the plugin folder into a scan directory (
%APPDATA%/transbox/extensions/is recommended during development) - Settings → Extension Workshop → Refresh (re-scan)
- Open the plugin switch to enable it
- For engine types, also go to Settings → ASR / MT / TTS and select it as the active engine
- Change code / QML → reload:
- QML: during development you can use the host's hot reload (
TRANSBOX_QML_RELOAD=1, saving any.qmlrebuilds it automatically); in a release environment just disable and re-enable the plugin to reload - Python: disable → enable (it reloads through
importlib). Once the module has been imported, editing the file of the same name does not always take effect — restart the app if needed
- QML: during development you can use the host's hot reload (
Where to look when something breaks
| Symptom | Look at first |
|---|---|
| The plugin does not appear at all | Is mod.json valid, is id empty, is it in the right directory, did the refresh pick it up |
| It appears but cannot be enabled | The hint on the workshop card (prerequisite plugin / runtime / min_app_version), the [registry] lines in the log |
| It is enabled but nothing happens | For engine types, is it already selected as the active engine on the settings page; did hotkey registration succeed (a conflict returns False) |
| The UI does not refresh | Does the QML listen to pluginConfigChanged (see UI slots) |
| You want evidence | self.host.log("info", "…", key=value) |
Log location: <install dir>/logs/app.log (including lines prefixed with [registry], [plugin:xxx]). There is also errors.log and faulthandler.log.
Use host.show_toast() / host.show_error() for user-facing hints, and never throw an exception stack at the user.
Common self-checks
python
def initialize(self, config=None):
super().initialize(config)
self.host.log("info", "插件初始化", plugin_dir=self.host.plugin_dir(self.id))
self.host.log("info", "能力", caps=self.host.get_plugin_config(self.id))- Print
self.host.plugin_dir(self.id)to confirm the actual install directory. - Print
self._configto confirm the config keys and values are what you expect (config_schemadefaults are filled in). - To know which channel you are on:
host.get_app_version()/host.get_locale(); the distribution form is visible in the environment variableTRANSBOX_DISTRIBUTION(selfpub/ steam).
Do not forget
- An external plugin's
initialize()runs on a background thread; the host callswait_async_init()before it needs the plugin. toolplugins get their instance preloaded during the scan phase, so do not do heavy work ininitialize().- Log and toast text must make the problem locatable ("service port 18080 is taken, please pick another one" rather than "startup failed").
