Identity and loader fields#
| Field | Type / behavior |
|---|---|
id | Stable string. Missing/empty ID falls back to the folder name. Duplicate IDs replace the same map entry; make IDs unique. |
name | Human-readable name for the Plugins panel and log prefix. |
version | Version string displayed in the UI. The loader does not enforce semantic version ranges. |
description | A short explanation of what the plugin does. |
author, icon | Optional author text and icon name. Icons use the app’s existing mappings. |
main | Entry file relative to the directory; missing/empty value falls back to index.js. |
enabled | Controls initialization and hook/action dispatch. Disabled entry files are still evaluated during loading. |
Write a complete manifest even where fallbacks exist. The current loader parses JSON and checks whether the entry file exists; it does not provide a complete JSON Schema validator or a minimum-native-version gate.
Configuration and schema#
| Field | Purpose |
|---|---|
config | Runtime values persisted in plugin.json. Use explicit initial values. |
configSchema | Settings form fields keyed by the same names used in config. |
ui.buttons | Sidebar buttons, including action routing and optional tab opening. |
ui.tabs | Custom panel metadata, content HTML and native action buttons. |
{
"id": "my-plugin",
"name": "My Plugin",
"version": "1.0.0",
"description": "Example settings",
"main": "index.js",
"enabled": true,
"config": {
"threshold": 10,
"mode": "quiet"
},
"configSchema": {
"threshold": {
"label": "Minimum duration (seconds)",
"type": "number",
"default": 10
},
"mode": {
"label": "Mode",
"type": "select",
"options": [
"quiet",
"notify"
],
"default": "quiet"
}
}
}The settings form supports select and boolean controls directly. Other declared types currently use a text input, except password which uses a masked input. A number can therefore arrive as a string. A textarea declaration currently does not produce a multiline editor.
Declare or register UI#
You may place UI declarations in the manifest or register them from onInit. Registering a button/tab with the same ID replaces its entry rather than appending another. Registration is persisted back to plugin.json; dynamic tab content updates are sent to the UI without an immediate manifest write.
Use consistent IDs for openTabId, tab id and action actionId. The configuration editor saves the complete manifest, so keep custom fields compatible with your own loader logic.
Validation and distribution#
Validate JSON before copying a release into the live plugin directory. Comments and trailing commas are invalid JSON. An absent entry file prevents the folder from becoming a loaded plugin. A JavaScript compilation error is logged and yields an empty module, so the manifest may still be listed without working hooks.
The manifest has no implemented permissions prompt, dependency installer or compatibility-range enforcement. Explain required capabilities in your README and test against native 2.0.7. Remove personal configuration values before packaging; a password field masks the form but stores its value as plain text.
Implementation reference: src/types/index.ts; src/main/plugins/PluginManager.ts; PluginManager.tsx · native 2.0.7.