Skip to main content
This guide walks you through creating a Mudstack plugin from scratch using the official template and the @mudstack/plugins package.

Prerequisites

  • Node.js 16 or newer (for running and building your plugin).
  • Mudstack desktop app (plugins run inside the app).
  • Familiarity with JavaScript or TypeScript (the examples use CommonJS for the entry point, which is typical for plugins loaded by Mudstack).

Step 1: Get the template

Start from the mudstack-plugins repo:
  1. Fork the repo on GitHub, or use Use this template if the repo is set up as a template.
  2. Clone your fork locally.
The root of the repo is the plugin template. It already contains:
  • package.json – name, main entry, and dependency on @mudstack/plugins
  • manifest.json – plugin id, name, version, main file, and optional subscriptions/registrations
  • index.js – a class extending MudstackPlugin with activate() and deactivate()

Step 2: Rename and describe your plugin

Edit manifest.json and package.json so they identify your plugin (not the generic template). manifest.json – Update at least:
  • id – Unique plugin ID (e.g. com.yourcompany.my-plugin). Use a reverse-DNS style.
  • name – Display name (e.g. My Pipeline Plugin).
  • description – Short description of what the plugin does.
  • author – Your name or team.
package.json – Update:
  • name – npm-style package name (e.g. my-mudstack-plugin).
  • description – Same or similar to manifest.
  • author – Same as manifest.
Example manifest.json (excerpt):
{
  "id": "com.studio.asset-validator",
  "name": "Asset Validator",
  "version": "1.0.0",
  "description": "Validates assets on upload and adds status.",
  "author": "Your Studio",
  "main": "index.js",
  "enabled": true,
  "dependencies": [],
  "subscriptions": [],
  "registrations": []
}

Step 3: Install dependencies

In the plugin folder (repo root when using the template):
yarn install
# or
npm install
This installs @mudstack/plugins, which provides the MudstackPlugin base class and types.

Step 4: Implement your plugin logic

Your entry point (e.g. index.js) must export a single class that extends MudstackPlugin. The runtime will:
  1. Load your module.
  2. Instantiate the class with the Plugin API: new YourPlugin(api).
  3. Call activate() when the plugin is enabled, and deactivate() when it is disabled or the app shuts down.

Minimal example (JavaScript, CommonJS)

const { MudstackPlugin } = require('@mudstack/plugins');

class MyPlugin extends MudstackPlugin {
  async activate() {
    await super.activate();
    this.api.log('info', 'MyPlugin activated');
  }

  async deactivate() {
    this.api.log('info', 'MyPlugin deactivating');
    await super.deactivate();
  }
}

module.exports = MyPlugin;

Using the API

Inside your class you have this.api with:
  • this.api.log(level, message, payload?) – Log to Mudstack (e.g. 'info', 'warn', 'error', 'debug').
  • this.api.events.on(eventType, handler) – Subscribe to events (e.g. file.created, plugin.activated). Returns an unsubscribe function; you only need to call it for subscriptions you add in code (not for manifest-declared subscriptions).
  • this.api.events – Use off() if you need to remove a handler by reference.
  • this.api.sendEvent(eventType, payload) – Emit an event to the app and other plugins.
  • this.api.db – Access to account, workspace, library, tag, asset, and asset version APIs (read/update data).
  • this.api.configgetConfig(), setConfig(), getSchema(), validateConfig(), getDefaultConfig() for plugin settings.
  • this.api.hasDependency(pluginId, version?) – Check if another plugin (or dependency) is available.
  • this.api.requestFromPlugin(targetPluginId, methodName, payload?) – Call another plugin; that plugin responds with api.respond(requestId, result) or api.respondWithError(requestId, error).
  • this.api.executeNodeScript(), executeCommand(), executePythonScript(), etc. – Run scripts or binaries (with timeout, cwd, env).
See the Plugin API reference for full details.

Adding a context menu command

To add a right-click menu item that runs your code:
  1. In manifest.json, add a contextMenuCommands array (if not present) and an entry, e.g.:
"contextMenuCommands": [
  {
    "id": "com.studio.asset-validator.run",
    "title": "Run validation",
    "description": "Validate selected assets",
    "eventType": "com.studio.asset-validator.run"
  }
]
  1. In manifest.json, add a subscriptions entry so the runtime calls a method on your class when the event is emitted:
"subscriptions": [
  { "event": "com.studio.asset-validator.run", "handler": "handleRunValidation" }
]
  1. In your class, implement the handler. The message includes a request id and payload (e.g. selected asset ids):
async handleRunValidation(message) {
  const { id: requestId, payload } = message || {};
  this.api.log('info', 'Run validation requested', payload);
  // e.g. call api.db, api.executePythonScript(), then api.respond(requestId, result)
}
You do not need to manually subscribe with this.api.events.on() for events listed in subscriptions; the runtime wires those for you.

Step 5: Declare dependencies (optional)

If your plugin depends on another plugin (e.g. a thumbnailer that requires a specific runtime), add it to manifest.json:
"dependencies": [
  { "id": "com.example.thumbnailer-base", "version": "^1.0.0" }
]
  • id – Plugin ID (or dependency id).
  • version – Optional semver range (e.g. ^1.0.0).
  • optional – If true, the plugin can run when the dependency is missing (e.g. with reduced features).
The runtime will resolve and load dependencies before activating your plugin. Use this.api.hasDependency(pluginId, version?) or this.api.getDependency(dependencyId) in code when needed.

Step 6: Config schema (optional)

To expose settings (e.g. API keys, paths), define a config.schema in manifest.json. The runtime will validate and merge with defaults, and your plugin can read/write via this.api.config:
"config": {
  "schema": {
    "apiKey": {
      "type": "string",
      "required": false,
      "description": "API key for external service"
    },
    "timeoutMs": {
      "type": "number",
      "default": 30000,
      "min": 1000,
      "max": 120000
    }
  }
}
In activate() you can call this.api.config.getConfig() and use the values.

Step 7: Install the plugin in Mudstack

  1. Copy the plugin folder (the whole directory containing manifest.json, package.json, and index.js) into Mudstack’s plugins directory:
    • Windows: Documents\Mudstack\plugins\
    • macOS: ~/Documents/Mudstack/plugins/
    • Or the path configured in the app for user plugins.
  2. Ensure node_modules is present (run yarn install or npm install inside the plugin folder).
  3. Restart Mudstack (or use the app’s refresh/plugin discovery if available). Your plugin should appear in the list and activate if enabled.

Step 8: Debug and iterate

  • Use this.api.log(‘info’, …) or this.api.log(‘debug’, …) to inspect behavior. Logs are written to the Mudstack plugin log location for your plugin.
  • Check the app’s plugin management UI for enable/disable and any error state.
  • For examples of subscriptions and context menu commands, see the mudstack-plugins examples (e.g. hello-world, context-menu-example).

Summary checklist

  • Clone or fork mudstack-plugins (use root as plugin).
  • Rename id, name, description, author in manifest.json and package.json.
  • Run yarn install or npm install in the plugin folder.
  • Implement a class extending MudstackPlugin with activate() and deactivate() in index.js (or the file set in main).
  • Add contextMenuCommands and subscriptions in the manifest if you need context menu actions.
  • Add dependencies and config.schema in the manifest if needed.
  • Copy the plugin folder into Mudstack’s plugins directory and restart or refresh.
For more detail on the lifecycle, architecture, and API, see Plugin lifecycle, Plugin system architecture, and Plugin API.