Compatibility & version gates
target_app_version(required since 0.2), the naming migration table, deprecated types, and themin_app_versionrules. Read this page before touching an old plugin.
target_app_version: the adaptation gate (required since 0.2.0)
It answers one question for the host: which client generation was this plugin written for? Missing = unknown = incompatible.
{ "target_app_version": "0.2" }| Plugin source | Must declare? | When missing |
|---|---|---|
Engine built-ins (is_builtin) | No | Always compatible |
extensions/ shipped with the installer (bundled) | No | Not subject to this gate |
| Your own plugins / Steam Workshop / Web Plugin Hub | Yes | Judged incompatible and refused outright |
Accepted values: 0.2 / 0.2.0 / 0.2.x / >=0.2 / ^0.2 (the rule: it starts with 0.2).
The legacy aliases
target_version/host_apiare still accepted, but do not use them — writetarget_app_version.
It is enforced at three gates
| Stage | Behaviour | Log |
|---|---|---|
| Scan / registration | Never enters the plugin list (users think "it isn't installed") | [registry] 拒绝识别外部插件 <id>: 缺少 target_app_version 字段(未适配 0.2.0),判定版本不匹配 |
| Instance creation | Returns None; enabling / selecting as engine fails | [registry] 拒绝加载 <id>: 缺少 target_app_version 或版本不匹配 |
| Hub install | Throws InstallError; the package never lands on disk | 插件 <id> 未声明 target_app_version 字段(未适配 0.2.0 版本),直接判定版本不匹配,已拒绝安装 |
Why it is this strict
A 0.1.x plugin on 0.2.0 does not just "misbehave slightly" — it breaks outright: the SPI was renamed (camelCase → snake_case), runtimes are now host-provided, and config_schema.type spellings were tightened. Refusing before load/install beats letting users stare at a traceback.
Migrating an old plugin (start with this one line)
- Add
"target_app_version": "0.2"tomod.json; - Follow Naming migration and Deprecation and migration to switch to snake_case;
- If you depend on a runtime, switch to
requires_runtime+host.runtime_dir(); - Verify locally: no more
拒绝加载lines in the log, and the settings page can select your plugin as the engine.
How the two version fields divide the work
| Field | The question it answers | Default | When omitted |
|---|---|---|---|
target_app_version | Which client generation you adapted to | none | Refused (must declare 0.2) |
min_app_version | The lowest client version you require | 1.0.0 | No restriction |
In practice write both: target_app_version marks the generation, and add min_app_version once you actually use a new API.
Naming migration (camelCase → snake_case)
| Old spelling | Canonical name | Status |
|---|---|---|
host.feedDirectCaption | feed_direct_caption | Both names coexist for ≥ 1 minor version |
host.registerPluginHotkey | register_plugin_hotkey | Same |
host.unregisterPluginHotkeys | unregister_plugin_hotkeys | Same |
host.getPluginHotkeys | get_plugin_hotkeys | Same |
camelCase config APIs such as host.getPluginConfig | get_plugin_config / set_plugin_config_value / save_plugin_config | Same |
host.getRecentConversation | get_recent_conversation | Same |
translate(..., source=) reaching straight into the layer below | Adapted inside the implementation | Community Hunyuan already fixed |
New code uses the snake_case names only.
Deprecation and migration
| Current state | Canonical | Migration |
|---|---|---|
type: middleware + action_* | type: tool | Change the manifest metadata (tools / text sources should not hang under middleware) |
type: audio_filter | — | Deprecated; the host does not recognise it |
type: bundle | — | Deprecated; the host does not recognise it |
| Undocumented methods on the bridge | — | Always treat them as unstable; use the Host SPI instead |
Glossary format: there is only one form, an array of objects (src / tgt / src_lang / tgt_lang). Flat dictionaries, tgt as an object/array, language-pair grouping, and terms.txt / tsv all load as an empty table — stop teaching those formats. See glossary.
The min_app_version gate
- The default value
1.0.0is treated as "no restriction" (it is not taken as a real lower bound).""/"0"/"0.0.0"are likewise treated as no restriction. - When a real lower bound is declared, the host compares it before creating the instance: current app version <
min_app_version→ loading is refused and a line is left in the log ([registry] 拒绝加载 <id>: 需要应用版本 >= x.y.z,当前 a.b.c). - Therefore: local loading may omit it; when publishing to the Plugin Hub
versionis mandatory, whilemin_app_versionshould only be written when you actually use a new API.
Suggested lower bounds
| What you used | Suggestion |
|---|---|
| Basic Providers / data plugins | Can be omitted (= no restriction) |
Outbound events handle_host_event, feed_caption | >= 0.3.0 (go by the version that actually shipped) |
Model artifacts model_artifacts | See the change notes for the corresponding version |
requires_plugins / requires_runtime | See the change notes for the corresponding version |
Reserved id segments
The first segment of a plugin id (the author segment) must not use a reserved name:
transbox official builtin community example workshop
steam system admin root support web test tbmodThe server rejects them with reserved_id; local loading is not restricted, but follow the rule anyway, otherwise publishing will always fail.
Recommended format: <your name>.<type>.<name>, for example myteam.mt.deeplx.
Version number rules
versioninmod.json: a semanticx.y.zversion.- When publishing to the Plugin Hub: mandatory, and it must be higher than the highest online version (otherwise 409 / a prompt to submit a new version).
- Local client loading may omit it (defaults to
1.0.0). - The consuming side decides whether an update exists from "installed receipt version vs the online latest".
Related
- Packaging & size limit
- Publish channels
- Host implementation status
- Layout & mod.json — the
target_app_version/min_app_version/versionfields
