> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mudstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugin Lifecycle

> Plugin states, activate and deactivate flow, cleanup, and process teardown.

This page describes the lifecycle of a Mudstack plugin: from discovery to active use and deactivation.

## Plugin states

The runtime tracks each plugin in one of these states:

| State            | Description                                                                        |
| ---------------- | ---------------------------------------------------------------------------------- |
| **registered**   | Discovered and in the registry; not yet loaded.                                    |
| **loading**      | Dependency resolution and child process creation in progress.                      |
| **loaded**       | Child process is up; plugin module loaded; not yet activated.                      |
| **activating**   | Main process has sent activate command; waiting for plugin to finish `activate()`. |
| **active**       | Plugin has completed `activate()` and is running. Can receive events and requests. |
| **deactivating** | Main process has sent deactivate command; plugin is running `deactivate()`.        |
| **inactive**     | Plugin has completed `deactivate()`; may still be in memory or process.            |
| **unloading**    | Process is being torn down (e.g. plugin disabled or app shutdown).                 |
| **unloaded**     | Child process has been destroyed; plugin is no longer running.                     |
| **failed**       | Error during load, activation, or health check; plugin is not active.              |

Transitions (simplified): **registered** → **loading** → **loaded** → **activating** → **active**. On disable or shutdown: **active** → **deactivating** → **inactive** → **unloading** → **unloaded**. Errors can move the plugin to **failed**.

## Activation flow

1. **Load decision** – The app decides to load the plugin (e.g. it’s enabled and its dependencies are satisfied). Plugin state moves to **loading**.
2. **Dependencies** – All manifest dependencies (other plugins, optional executables) are resolved. If a required dependency is missing or fails to load, this plugin does not activate (and may be marked failed or skipped).
3. **Child process** – The runtime spawns a Node.js child process for this plugin, passing `PLUGIN_ID` and `PLUGIN_PATH`. The child loads the plugin loader script, which then loads your **main** module and instantiates your class with the **Plugin API**. State becomes **loaded**.
4. **Activate command** – The main process sends an activate message to the child with plugin id and path. The child calls **activate()** on your plugin instance (with timeout and error handling so a bad `activate()` doesn’t hang the process).
5. **Your activate()** – You should:
   * Call **await super.activate()** first.
   * Set up any **in-process** state (e.g. subscribe to events with **this.api.events.on()** if not using manifest subscriptions only).
   * Optionally read **this.api.config.getConfig()**, **this.api.hasDependency()**, or **this.api.getTempDirectory()** (if available in the child).
   * Return (or resolve the promise). If you throw or reject, activation is reported as failed and the plugin moves to **failed**.
6. **Active** – The child signals activation success to the main process. State becomes **active**. The plugin now receives events (including manifest subscriptions) and can be called by other plugins via **requestFromPlugin** / **respond**.

Activation has a timeout (e.g. 30 seconds). If **activate()** does not complete in time, the plugin is treated as failed.

## Deactivation flow

1. **Deactivate trigger** – The user disables the plugin, or the app is shutting down, or the plugin is being unloaded for reload. State moves to **deactivating**.
2. **Deactivate command** – The main process sends a deactivate message to the child. The child calls **deactivate()** on your plugin instance.
3. **Your deactivate()** – You should:
   * Release resources (e.g. unsubscribe from events you added in **activate()** with the function returned from **api.events.on()**). Note: subscriptions declared in the manifest are managed by the runtime; you don’t need to unsubscribe from those.
   * Close handles, clear timers, etc.
   * Call **await super.deactivate()**.
   * Return (or resolve). The runtime will not wait forever; there is a deactivation timeout.
4. **Inactive / Unload** – The child signals deactivation success. The main process may then tear down the child process (state **unloading** → **unloaded**). If the plugin is only being disabled (not unloaded), it may remain **inactive** until the process is later destroyed.

If a plugin has **dependents** (other plugins that depend on it), the app typically will not deactivate it until those dependents are deactivated first.

## Cleanup and best practices

* **Subscriptions in code** – If you call **this.api.events.on(...)** in **activate()**, store the returned unsubscribe function and call it in **deactivate()**. For **subscriptions** in the manifest, the runtime cleans up when the plugin is deactivated; you don’t need to unsubscribe manually.
* **No mandatory unsub for plugin.activated** – Subscriptions to system events like **plugin.activated** are also cleaned up when the plugin is deactivated; you don’t have to unsubscribe explicitly.
* **Avoid long work in activate/deactivate** – Keep both methods relatively fast. Do heavy or long-running work asynchronously after activation (e.g. in response to an event or context menu).
* **Errors** – If **activate()** or **deactivate()** throws, the runtime catches it, logs it, and reports failure. The plugin may end up in **failed** or **unloaded** state; the app may retry loading later (e.g. on health check or user “reload”).

## Health checks and reload

The app may run a periodic **health check** on active plugins (e.g. ping the child process). If the plugin process dies or stops responding, the app may mark it **failed** and optionally attempt to **reload** it (unload then load again). After a limited number of reload retries, the plugin may stay in **failed** until the user intervenes.

## Summary

* **States**: registered → loading → loaded → activating → **active** → deactivating → inactive → unloading → unloaded (or **failed** on error).
* **activate()**: Call **super.activate()**, set up listeners and state, return. Don’t block too long.
* **deactivate()**: Clean up listeners you added in code, release resources, call **super.deactivate()**.
* Manifest **subscriptions** and system events like **plugin.activated** are cleaned up by the runtime; you only need to unsubscribe for **api.events.on()** you add yourself.

For the exact API surface available during lifecycle, see [Plugin API](/developer/plugin-api).
