{ "$id": "https://raw.githubusercontent.com/vicinaehq/vicinae/refs/heads/main/extra/schemas/extension.json", "type": "object", "$defs": { "keywords": { "type": "array", "items": { "type": "string", "pattern": "^[^,\\r\\n\\t]+$", "maxLength": 25, "minLength": 1 }, "title": "Searchable terms", "maxItems": 12, "minItems": 0, "description": "String values helping Vicinae display the extension's entry point when such terms are searched for.", "uniqueItems": true }, "arguments": { "type": "array", "maxItems": 3, "items": { "required": ["type", "name", "placeholder"], "type": "object", "allOf": [ { "if": { "properties": { "type": { "const": "dropdown" } } }, "then": { "required": ["data"], "properties": { "data": { "type": "array", "items": { "type": "object", "required": ["title", "value"], "properties": { "title": { "type": "string", "title": "The dropdown item display name", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 1 }, "value": { "type": "string", "title": "The dropdown item value" } }, "additionalProperties": false }, "title": "Dropdown values", "minItems": 1, "description": "Only valid for dropdowns. It specifies all the values to be displayed in the dropdown", "uniqueItems": true } } } } ], "properties": { "name": { "type": "string", "title": "The argument's name/identifier", "pattern": "^[a-zA-Z0-9-._~]*$", "maxLength": 255, "minLength": 2, "description": "The key for accessing the launch argument value." }, "placeholder": { "type": "string", "title": "The human-friendly name of the argument", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 1, "description": "The placeholder will be shown in the Vicinae search bar argument field." }, "type": { "enum": ["text", "password", "dropdown"], "type": "string", "title": "The argument type", "description": "Currently only 'text', 'password' and 'dropdown' are supported." }, "required": { "type": "boolean", "title": "Argument existence requirement", "description": "Indicates whether the value is required and must be entered by the user before the command is usable" } } }, "uniqueItems": true }, "preferences": { "type": "array", "items": { "type": "object", "allOf": [ { "if": { "properties": { "type": { "const": "textfield" } } }, "then": { "properties": { "default": { "type": "string", "title": "The optional default value for the textfield" } } } }, { "if": { "properties": { "type": { "const": "checkbox" } } }, "else": { "required": ["title"], "properties": { "title": { "type": "string", "title": "The human-friendly property's name", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 2, "description": "The property title will be displayed in Preferences." } } }, "then": { "required": ["label"], "properties": { "label": { "type": "string", "title": "Checkbox label", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 1, "description": "The label of the checkbox. Shown next to the checkbox." }, "title": { "type": "string", "title": "Checkbox title", "pattern": "^$|^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 0, "description": "Shown as a section title above the checkbox itself. If you want to group multiple checkboxes into a single section, set the title of the first checkbox and leave the title of the other checkboxes empty." }, "default": { "type": "boolean", "title": "The optional default value for the checkbox" } } } }, { "if": { "properties": { "type": { "const": "dropdown" } } }, "then": { "required": ["data"], "properties": { "data": { "type": "array", "items": { "type": "object", "required": ["title", "value"], "properties": { "title": { "type": "string", "title": "The dropdown item display name", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 1 }, "value": { "type": "string", "title": "The dropdown item value" } }, "additionalProperties": false }, "title": "Dropdown values", "minItems": 1, "description": "Only valid for dropdowns. It specifies all the values to be displayed in the dropdown", "uniqueItems": true }, "default": { "type": "string", "title": "The optional default value for the dropdown", "description": "This value must be one of the values specified within 'data'." } } } }, { "if": { "properties": { "type": { "const": "appPicker" } } }, "then": { "properties": { "default": { "type": "string", "title": "The optional default value for the appPicker", "description": "This value must be an application name, a bundle ID or a path" } } } }, { "if": { "properties": { "type": { "const": "file" } } }, "then": { "properties": { "default": { "type": "string", "title": "The optional default value for the file picker", "description": "This value must be a path to a file" } } } }, { "if": { "properties": { "type": { "const": "directory" } } }, "then": { "properties": { "default": { "type": "string", "title": "The optional default value for the file picker", "description": "This value must be a path to a directory" } } } } ], "required": ["name", "description", "type", "required"], "properties": { "name": { "type": "string", "title": "The property's name/identifier", "pattern": "^[a-zA-Z0-9-._~]*$", "maxLength": 255, "minLength": 2, "description": "The slugged property's name used internally." }, "type": { "enum": ["textfield", "password", "checkbox", "dropdown", "appPicker", "file", "directory"], "type": "string", "title": "The preference type", "description": "Currently only 'textfield', 'password' (for secure entry), 'checkbox', 'dropdown', 'appPicker', 'file', and 'directory' are supported." }, "required": { "type": "boolean", "title": "Preference existence requirement", "description": "Indicates whether the value is required and must be entered by the user before the extension is usable" }, "description": { "type": "string", "title": "The property's description", "pattern": "^[^\\s]+(\\s+[^\\s]+)*$", "maxLength": 1024, "minLength": 8, "description": "It helps users understand what the preference does. It will be displayed as a tooltip when hovering over it." }, "placeholder": { "type": "string", "title": "Optional placeholder text", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "description": "Text displayed in the preference's field when no value has been input." } } }, "uniqueItems": true } }, "$schema": "https://json-schema.org/draft/2020-12/schema", "required": ["name", "title", "description", "icon", "author", "license", "commands", "dependencies"], "properties": { "icon": { "type": "string", "title": "The extension's icon", "pattern": "^[^\\s]+(?:[ ]*[^\\s]+)*$", "description": "A 512x512 icon representing the extension. It will be displayed in the Store and in Preferences. If any of the extension's commands doesn't have an icon, it will 'inherit' the extension's icon. Please note that light and dark themes are supported; just append '@dark' to the filename for the dark theme and the correct icon will be picked at run-time. For example, set for this property 'icon.png' and put in the assets folder the 'icon.png' and 'icon@dark.png' files.", "contentMediaType": "image/png" }, "name": { "type": "string", "title": "The extension's name/identifier", "pattern": "^(@workaround/)?[a-z0-9-~][a-z0-9-_~]*$", "maxLength": 255, "minLength": 3, "description": "The slugged extension's name used internally as identifier and in the store as part of the URL." }, "debug": { "type": "object", "title": "Options used during the extension debugging", "properties": { "reloadShortcut": { "type": "object", "title": "Reload keyboard shortcut", "required": ["modifiers", "key"], "properties": { "key": { "type": "string", "title": "Keyboard key", "maxLength": 2, "minLength": 1, "description": "The keyboard key pressed with the modifier to trigger an action (e.g. ⌘ + B)" }, "modifiers": { "type": "array", "items": { "enum": ["command", "option", "control", "shift"], "type": "string" }, "title": "Keyboard modifier", "maxItems": 4, "minItems": 1, "description": "Such as the command modifier (⌘), option modifier (⌥), control modifier (⌃), or shift modifier (⇧).", "uniqueItems": true } }, "description": "Keyboard shortcut used to refresh/reload a command while the Vicinae window is focused.", "additionalProperties": false } }, "description": "Compilation and run-time options to improve development experience." }, "owner": { "type": "string", "title": "The extension's owner/maintainer", "pattern": "^[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*$", "maxLength": 75, "minLength": 2, "description": "User ultimately responsible for the extension. The extension's store URL is composed of the owner username and the extension's name." }, "title": { "type": "string", "title": "The human-friendly extension's name", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 2, "description": "The extension title will be displayed in the Store and in Preferences." }, "access": { "enum": ["public", "private"], "type": "string", "title": "Extension's discoverability", "description": "Public extensions are downloadable by anybody, while private extensions can only be downloaded by a member of a given organization." }, "author": { "type": "string", "title": "The extension's current author", "pattern": "^[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*$", "maxLength": 75, "minLength": 2, "description": "User currently contributing the most to the extension." }, "license": { "const": "MIT", "title": "The extension's license", "description": "Currently only MIT is accepted, although more licenses will probably be available in the future." }, "platforms": { "type": "array", "items": { "enum": ["macOS", "Windows"], "type": "string" }, "title": "The extension's supported platforms", "description": "Currently only `macOS` and `Windows` are accepted. If not present, the extension is assumed to be available on all platforms.", "minItems": 1, "uniqueItems": true }, "commands": { "type": "array", "items": { "type": "object", "required": ["name", "title", "description", "mode"], "properties": { "icon": { "type": "string", "title": "The command's icon", "pattern": "^[^\\s]+(?:[ ]*[^\\s]+)*$", "description": "A 512x512 icon representing the command. It will be displayed in Preferences and Vicinae root search. If a command doesn't have an icon, it will 'inherit' the extension's icon. Please note that light and dark themes are supported; just append '@dark' or '@light' to the icons name and the correct icon will be picked at run-time. For example, write for this property 'icon.png' and have in the assets folder the 'icon@light.png' and 'icon@dark.png' assets.", "contentMediaType": "image/png" }, "mode": { "enum": ["view", "no-view", "menu-bar"], "type": "string", "title": "The type of run-time command", "description": "A value of 'view' indicates that the command will show a main view when performed. 'no-view' means that the command does not push a view to the main navigation stack in Vicinae. The latter is handy for directly opening URL or other API functionality that doesn't require a user interface. 'menu-bar' renders an extra item in the macOS system menu bar at the top of the screen." }, "name": { "type": "string", "title": "The command's name/identifier", "pattern": "^[a-z0-9-~][a-zA-Z0-9-._~]*$", "maxLength": 255, "minLength": 2, "description": "The name directly maps to the entry point file for the command. So a command named 'index' would map to 'src/index.ts' (or any other supported TypeScript or JavaScript file extension such as .tsx, .js, .jsx)." }, "title": { "type": "string", "title": "The human-friendly command's name", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 2, "description": "The command title will be displayed in the Store, Preferences, and in Vicinae's root search." }, "keywords": { "$ref": "#/$defs/keywords" }, "subtitle": { "type": "string", "title": "Additional command descriptor", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 2, "description": "The subtitle (if any) will be displayed next to the command name in the root search. It helps user differentiate potentially similar commands. For example, a Google Suite extension may define 2 commands titled 'Create Document'. To differentiate them, one of the subtitle can be 'Google Docs' while the other can be 'Google Sheets'." }, "description": { "type": "string", "title": "The command's description", "pattern": "^[^\\s]+(\\s+[^\\s]+)*$", "maxLength": 2048, "minLength": 0, "description": "It helps users understand what the command does. It will be displayed in the Store and in Preferences." }, "interval": { "type": "string", "title": "The command's background scheduling interval", "pattern": "^(\\d+)(s|m|h|d)$", "description": "The value specifies that a no-view or menu-bar command should be launched in the background every X seconds (s), minutes (m), hours (h) or days (d). Examples: 90s, 1m, 12h, 1d. The minimum value is 10 seconds (10s)." }, "preferences": { "$ref": "#/$defs/preferences", "description": "Commands can optionally contribute preferences that are shown in Vicinae Preferences > Extensions when selecting the command. You can use preferences for configuration values and passwords or personal access tokens. Commands automatically \"inherit\" extension preferences and can also override entries with the same `name`." }, "arguments": { "$ref": "#/$defs/arguments", "description": "An optional array of arguments that are requested from user when the command is called" }, "disabledByDefault": { "type": "boolean", "title": "Whether the command should be enabled by default or not", "description": "Defaults to `false`" } }, "additionalProperties": true }, "title": "Executable extension's commands", "maxItems": 100, "minItems": 1, "description": "List of all commands vended by this extensions. An extension must contain at least one command.", "uniqueItems": true }, "tools": { "type": "array", "items": { "type": "object", "required": ["name", "title", "description"], "properties": { "icon": { "type": "string", "title": "The tool's icon", "pattern": "^[^\\s]+(?:[ ]*[^\\s]+)*$", "description": "A 512x512 icon representing the tool. It will be displayed in various places across Vicinae. If a tool doesn't have an icon, it will 'inherit' the extension's icon. Please note that light and dark themes are supported; just append '@dark' or '@light' to the icons name and the correct icon will be picked at run-time. For example, write for this property 'icon.png' and have in the assets folder the 'icon@light.png' and 'icon@dark.png' assets.", "contentMediaType": "image/png" }, "name": { "type": "string", "title": "The tool's name/identifier", "pattern": "^[a-z0-9-][a-zA-Z0-9-_]*$", "maxLength": 64, "minLength": 2, "description": "The name directly maps to the entry point file for the tool. So a tool named 'index' would map to 'src/tools/index.ts' (or any other supported TypeScript or JavaScript file extension such as .tsx, .js, .jsx)." }, "title": { "type": "string", "title": "The human-friendly tool's name", "pattern": "^[^\\s]+(?: [^\\s]+)*$", "maxLength": 255, "minLength": 2, "description": "The tool title will be displayed in the Store, Preferences, and any other places the tool might be referenced in the Vicinae UI." }, "keywords": { "$ref": "#/$defs/keywords" }, "description": { "type": "string", "title": "The tool's description", "pattern": "^[^\\s]+(\\s+[^\\s]+)*$", "maxLength": 2048, "minLength": 12, "description": "It helps users (and other actors like AI) understand what the tool does. It will be displayed in the Store and in Preferences." }, "functionalities": { "type": "array", "title": "Limits the tool to the specified functionalities", "description": "Limits the tool to the specified functionalities. If not specified, the tool can be used in any context (if it matches the requirements for each of them).", "items": { "enum": ["AI attachment provider", "AI tool"], "type": "string" } }, "preferences": { "$ref": "#/$defs/preferences", "description": "Tools can optionally contribute preferences that are shown in Vicinae Preferences > Extensions when selecting the AI Extension item. You can use preferences for configuration values and passwords or personal access tokens. Tools automatically \"inherit\" extension preferences and can also override entries with the same `name`." } }, "additionalProperties": true }, "title": "Extension's tools", "maxItems": 100, "minItems": 0, "description": "List of all tools that the AI can use to interact with this extension.", "uniqueItems": true }, "ai": { "type": "object", "title": "AI-related information", "description": "Additional information related to the AI capabilities of the extension", "properties": { "instructions": { "type": "string", "description": "Additional system instructions added when the tools are used in AI" }, "evals": { "type": "array", "items": { "type": "object", "properties": { "input": { "type": "string", "description": "The prompt to evaluate" }, "usedAsExample": { "type": "boolean", "description": "Whether the eval can be used as an example in Vicinae (default `true`)" } }, "required": ["input"] }, "description": "List of tests to evaluate the reliability of the tools when used in AI" } } }, "keywords": { "$ref": "#/$defs/keywords" }, "description": { "type": "string", "title": "The extension's description", "pattern": "^[^\\s]+(\\s+[^\\s]+)*$", "maxLength": 2048, "minLength": 16, "description": "It helps users understand what the extension does. It will be displayed in the Store and in Preferences." }, "preferences": { "$ref": "#/$defs/preferences", "description": "Extensions can contribute preferences that are shown in Vicinae Preferences > Extensions. You can use preferences for configuration values and passwords or personal access tokens." }, "categories": { "type": "array", "items": { "type": "string" } }, "contributors": { "type": "array", "items": { "type": "string", "pattern": "^[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*$", "maxLength": 75, "minLength": 2 }, "title": "The extension's list of contributors", "minItems": 0, "description": "Users who have meaningfully contributed to the extension's commands.", "uniqueItems": true }, "pastContributors": { "type": "array", "items": { "type": "string", "pattern": "^[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*$", "maxLength": 75, "minLength": 2 }, "title": "The extension's list of past contributors", "minItems": 0, "description": "Users who have meaningfully contributed to the extension's commands but do not maintain it anymore.", "uniqueItems": true }, "dependencies": { "type": "object", "title": "The extension's source dependencies", "required": ["@vicinae/api"], "properties": { "@vicinae/api": { "type": "string", "title": "Vicinae API dependency", "description": "The Vicinae API version used by this extension." } }, "description": "Source dependencies following the npm package.json dependency format." }, "external": { "type": "array", "title": "Dependencies that shouldn't be bundled", "items": { "type": "string" }, "description": "An Array of package or file names that should be excluded from the build. The package will not be bundled, but the import is preserved and will be evaluated at runtime." } } }