{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://termix.site/schemas/plugin-manifest.schema.json", "title": "Termix Plugin Manifest v2", "type": "object", "additionalProperties": false, "required": [ "id", "name", "version", "description", "author", "license", "engine", "category", "capabilities" ], "properties": { "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,39}$", "description": "Unique plugin id. Lowercase, starts with a letter, 2-40 characters. Must equal the plugin's directory name." }, "name": { "type": "string", "minLength": 1 }, "version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$", "description": "Semver version string." }, "description": { "type": "string", "minLength": 1 }, "author": { "type": "object", "additionalProperties": false, "required": ["name"], "properties": { "name": { "type": "string", "minLength": 1 }, "url": { "type": "string", "minLength": 1 } } }, "license": { "type": "string", "minLength": 1 }, "repository": { "type": "string", "minLength": 1 }, "category": { "type": "string", "enum": [ "Terminal", "Files & Transfer", "Infrastructure", "Monitoring", "Networking", "Access & Security", "Productivity" ] }, "icon": { "type": "string", "minLength": 1, "description": "A Lucide icon name, or a relative path to an icon.svg in the plugin root." }, "engine": { "type": "object", "additionalProperties": false, "required": ["termix", "api"], "properties": { "termix": { "type": "string", "minLength": 1, "description": "Display string only. Never enforced." }, "api": { "type": "string", "pattern": "^[0-9]+$", "description": "Plugin SDK major version. The real compatibility gate." } } }, "capabilities": { "type": "array", "description": "Catalog capability ids this plugin's code needs. See the SDK capability catalog.", "items": { "type": "string", "enum": [ "credentials:read", "ssh:connect", "process:spawn", "users:write", "auth:provide", "system:tls", "device:serial", "hosts:write", "credentials:use", "network:outbound", "network:serve", "users:read", "events:core", "notify:send", "audit:read", "desktop:window", "hosts:read", "db:own", "kv:own", "secrets:own", "settings:read-core", "ui:surface" ] } }, "dependencies": { "type": "object", "description": "Plugin ids this plugin cannot run without, mapped to a semver range.", "additionalProperties": { "type": "string", "minLength": 1 }, "propertyNames": { "pattern": "^[a-z][a-z0-9-]{1,39}$" } }, "optionalDependencies": { "type": "object", "description": "Plugin ids this plugin uses when present. It must keep working without them.", "additionalProperties": { "type": "string", "minLength": 1 }, "propertyNames": { "pattern": "^[a-z][a-z0-9-]{1,39}$" } }, "provides": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["service", "version", "permission"], "properties": { "service": { "type": "string", "pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+$" }, "version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$" }, "permission": { "type": "string", "minLength": 1 } } } }, "requires": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["service", "versionRange"], "properties": { "service": { "type": "string", "pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+$" }, "versionRange": { "type": "string", "minLength": 1 }, "optional": { "type": "boolean" } } } }, "providesSecret": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["key", "permission"], "properties": { "key": { "type": "string", "pattern": "^[a-z0-9-]+$" }, "permission": { "type": "string", "minLength": 1 }, "descriptionKey": { "type": "string", "minLength": 1 } } } }, "requiresSecret": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["plugin", "key"], "properties": { "plugin": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,39}$" }, "key": { "type": "string", "pattern": "^[a-z0-9-]+$" }, "optional": { "type": "boolean" } } } }, "contributes": { "type": "object", "additionalProperties": false, "properties": { "tabs": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "titleKey", "icon", "openFrom"], "properties": { "id": { "type": "string", "minLength": 1 }, "titleKey": { "type": "string", "minLength": 1 }, "icon": { "type": "string", "minLength": 1 }, "openFrom": { "type": "array", "minItems": 1, "items": { "type": "string", "enum": ["rail", "host-context-menu", "palette"] } } } } }, "guest": { "type": "boolean" }, "auth": { "type": "object", "additionalProperties": false, "properties": { "sshAuthTypes": { "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]{0,63}$" } }, "loginMethods": { "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]{0,63}$" } }, "secondFactors": { "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]{0,63}$" } } } }, "panels": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "titleKey"], "properties": { "id": { "type": "string", "minLength": 1 }, "titleKey": { "type": "string", "minLength": 1 }, "icon": { "type": "string", "minLength": 1 } } } }, "dashboardCards": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "titleKey"], "properties": { "id": { "type": "string", "minLength": 1 }, "titleKey": { "type": "string", "minLength": 1 }, "icon": { "type": "string", "minLength": 1 } } } }, "actions": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "titleKey", "handler"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9-]+(\\.[a-zA-Z0-9-]+)+$" }, "titleKey": { "type": "string", "minLength": 1 }, "handler": { "type": "string", "pattern": "^[A-Za-z_$][A-Za-z0-9_$]*$" }, "icon": { "type": "string", "minLength": 1 }, "permission": { "type": "string", "minLength": 1 }, "slot": { "type": "string", "minLength": 1 }, "kind": { "type": "string", "enum": ["button", "component"] } } } }, "actionSlots": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "accepts"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9-]+(\\.[a-zA-Z0-9-]+)+$" }, "accepts": { "type": "array", "minItems": 1, "items": { "type": "string", "enum": ["button", "component"] } }, "descriptionKey": { "type": "string", "minLength": 1 } } } }, "permissions": { "type": "array", "description": "Role permissions this plugin contributes. Core registers each as ..", "items": { "type": "object", "additionalProperties": false, "required": ["name", "titleKey", "descriptionKey"], "properties": { "name": { "type": "string", "description": "Plugin-relative name. May contain dots. Must not start with a core group or this plugin's id.", "pattern": "^[a-z0-9_-]+(\\.[a-z0-9_-]+)*$" }, "titleKey": { "type": "string", "minLength": 1 }, "descriptionKey": { "type": "string", "minLength": 1 }, "defaultRoles": { "type": "array", "description": "System roles that hold this the first time it is seen.", "items": { "type": "string", "enum": ["admin", "user"] } } } } }, "settings": { "type": "object", "description": "Settings fields core renders on the plugin's settings page and in the host editor.", "additionalProperties": false, "properties": { "admin": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["key", "type"], "properties": { "key": { "type": "string", "description": "Storage key, unique within its scope.", "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$" }, "type": { "type": "string", "enum": [ "boolean", "string", "number", "select", "multiselect", "secret", "textarea", "json", "custom" ] }, "labelKey": { "type": "string", "minLength": 1, "description": "Required for every type except \"custom\"." }, "descriptionKey": { "type": "string", "minLength": 1 }, "placeholderKey": { "type": "string", "minLength": 1 }, "default": { "description": "Value used until one is written." }, "options": { "type": "array", "description": "select and multiselect only.", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["value", "labelKey"], "properties": { "value": { "type": "string", "minLength": 1 }, "labelKey": { "type": "string", "minLength": 1 } } } }, "min": { "type": "number", "description": "number fields only." }, "max": { "type": "number", "description": "number fields only." }, "requires": { "type": "string", "description": "Key of a boolean field in the same scope that must be on." }, "permission": { "type": "string", "minLength": 1, "description": "Permission needed to write it. Admin fields default to admin.plugins.manage." }, "group": { "type": "string", "minLength": 1, "description": "Section heading this field sits under." }, "component": { "type": "string", "minLength": 1, "description": "Registered component id. Required when type is \"custom\"." } } } }, "user": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["key", "type"], "properties": { "key": { "type": "string", "description": "Storage key, unique within its scope.", "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$" }, "type": { "type": "string", "enum": [ "boolean", "string", "number", "select", "multiselect", "secret", "textarea", "json", "custom" ] }, "labelKey": { "type": "string", "minLength": 1, "description": "Required for every type except \"custom\"." }, "descriptionKey": { "type": "string", "minLength": 1 }, "placeholderKey": { "type": "string", "minLength": 1 }, "default": { "description": "Value used until one is written." }, "options": { "type": "array", "description": "select and multiselect only.", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["value", "labelKey"], "properties": { "value": { "type": "string", "minLength": 1 }, "labelKey": { "type": "string", "minLength": 1 } } } }, "min": { "type": "number", "description": "number fields only." }, "max": { "type": "number", "description": "number fields only." }, "requires": { "type": "string", "description": "Key of a boolean field in the same scope that must be on." }, "permission": { "type": "string", "minLength": 1, "description": "Permission needed to write it. Admin fields default to admin.plugins.manage." }, "group": { "type": "string", "minLength": 1, "description": "Section heading this field sits under." }, "component": { "type": "string", "minLength": 1, "description": "Registered component id. Required when type is \"custom\"." } } } }, "host": { "type": "object", "additionalProperties": false, "required": ["fields"], "properties": { "enableKey": { "type": "string", "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$", "description": "Boolean rendered first, gating the rest of the section." }, "enableLabelKey": { "type": "string", "minLength": 1 }, "fields": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["key", "type"], "properties": { "key": { "type": "string", "description": "Storage key, unique within its scope.", "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{0,63}$" }, "type": { "type": "string", "enum": [ "boolean", "string", "number", "select", "multiselect", "secret", "textarea", "json", "custom" ] }, "labelKey": { "type": "string", "minLength": 1, "description": "Required for every type except \"custom\"." }, "descriptionKey": { "type": "string", "minLength": 1 }, "placeholderKey": { "type": "string", "minLength": 1 }, "default": { "description": "Value used until one is written." }, "options": { "type": "array", "description": "select and multiselect only.", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["value", "labelKey"], "properties": { "value": { "type": "string", "minLength": 1 }, "labelKey": { "type": "string", "minLength": 1 } } } }, "min": { "type": "number", "description": "number fields only." }, "max": { "type": "number", "description": "number fields only." }, "requires": { "type": "string", "description": "Key of a boolean field in the same scope that must be on." }, "permission": { "type": "string", "minLength": 1, "description": "Permission needed to write it. Admin fields default to admin.plugins.manage." }, "group": { "type": "string", "minLength": 1, "description": "Section heading this field sits under." }, "component": { "type": "string", "minLength": 1, "description": "Registered component id. Required when type is \"custom\"." } } } } } } } }, "hostCapability": { "description": "A host-editor checkbox backed by a boolean column on the host record. Reshaped by a later step.", "oneOf": [ { "$ref": "#/$defs/hostCapability" }, { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/hostCapability" } } ] } } }, "backend": { "type": "string", "minLength": 1, "description": "Built backend entry, relative to the plugin root. Defaults to dist/backend.js." }, "frontend": { "type": "string", "minLength": 1, "description": "Built frontend entry, relative to the plugin root. Defaults to dist/frontend.js." }, "locales": { "type": "string", "minLength": 1, "description": "Locales directory, relative to the plugin root. Defaults to locales." }, "platforms": { "type": "array", "minItems": 1, "items": { "type": "string", "enum": ["linux", "win32", "darwin"] } }, "nativeDependencies": { "type": "array", "minItems": 1, "description": "Bare npm package names this plugin depends on that carry a native (.node) binding. The build never bundles them: they stay a real dependency in the plugin's own package.json and are resolved from node_modules at runtime, the same as a host-provided package, so the compiled native binary is never copied into the JS bundle.", "items": { "type": "string", "minLength": 1 } } }, "$defs": { "hostCapability": { "type": "object", "additionalProperties": false, "required": ["key", "labelKey", "editorTab"], "properties": { "key": { "type": "string", "minLength": 1 }, "labelKey": { "type": "string", "minLength": 1 }, "editorTab": { "type": "string", "minLength": 1 } } } } }