> For the complete documentation index, see [llms.txt](https://docs.getvenora.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.getvenora.tech/plugin-api/plugin-lifecycle.md).

# Plugin lifecycle

Part of the [Community Plugin API specification](/plugin-api.md). The key words MUST, SHOULD, and MAY are used as in RFC 2119.

A plugin has two independent kinds of state:

* **Installation state** is stored in extension storage and lasts across page loads: whether the plugin is installed, and whether it is enabled.
* **Runtime state** is per page and lasts only while the Fermo tab is open: whether the plugin is running right now.

## Installation state

```
                 install (validated, confirmed)
 not installed ───────────────────────────────▶ installed, enabled
       ▲                                           │      ▲
       │ uninstall                       disable   │      │ enable
       │ (imported only)                           ▼      │
       └────────────────────────────────────── installed, disabled
```

* Bundled plugins are always installed and cannot be uninstalled. `required: true` bundled plugins cannot be disabled.
* An installed plugin that fails its [compatibility check](/plugin-api/plugin-manifest.md#compatibility) stays installed but is **not started**. Its card shows why.

## Runtime state

```
            load                  started
 stopped ─────────▶ starting ─────────────▶ running
    ▲                  │                       │  │
    │                  │ failed / timeout      │  │ terminated
    │                  ▼                       │  ▼
    │               failed ◀───────────────────┘ failed
    │                                          │
    │                                     stop │
    └───────────────── stopping ◀──────────────┘
```

| State      | Meaning                                                                      | API available?                             |
| ---------- | ---------------------------------------------------------------------------- | ------------------------------------------ |
| `stopped`  | No frame exists for the plugin on this page                                  | No                                         |
| `starting` | The frame exists, the module is loading, and the default export is running   | **Yes**                                    |
| `running`  | The default export finished successfully                                     | **Yes**                                    |
| `stopping` | The cleanup function is running                                              | No: requests reject with `runtime_stopped` |
| `failed`   | Startup failed, or Venora terminated the plugin. The frame has been removed. | No                                         |

There is at most one running instance of a plugin per page. These states are shown on the plugin's card (for example "Running in sandbox", or "Failed to run: …").

## When plugin code runs

Plugins run only on Fermo's own top-level `https://fermo.sbar.fyi/channels/…` page, never in a framed copy of Fermo or on another origin (see [plugin-security.md](/plugin-api/plugin-security.md), SEC-11). Fermo navigates without reloading the page, so the same tab can start and stop a plugin many times.

Plugin code runs in a dedicated worker inside its sandboxed frame, so it has no `window` or `document` (see [plugin-api.md §7](/plugin-api.md#7-the-plugins-environment)).

1. **Load.** When a `/channels/` page is reached, Venora starts every plugin that is installed, enabled, compatible, and has valid permissions. Each one gets a **new** sandboxed frame. Plugins start in parallel, and their start order is not specified.
2. **Module evaluation.** Venora imports the entry script, and its top-level code runs. The `venora` object is **not** available at the top level. Top-level code SHOULD only define things.
3. **Initialization.** Venora calls the module's default export with `venora`. This is the plugin's initialization, and the API can be used from here on: requests made while `starting` are served.
4. **Running.** The plugin becomes `running` when the default export returns, or when the promise it returns resolves. If it returns a function, that function is the plugin's **cleanup handler**.
5. **Stop.** On a stop (see the trigger table below), Venora:
   1. stops accepting requests;
   2. calls the cleanup handler and waits for it, including any promise it returns;
   3. rejects the plugin's pending requests with `runtime_stopped`;
   4. removes the frame;
   5. removes everything it added to the page for the plugin: CSS, notices, avatars, and its commands.

Each start is a fresh module instance, and no JavaScript state survives a stop. Use [`venora.storage`](/plugin-api/plugin-settings-storage.md#storage) for data that must persist.

### Time limits

| Phase                          | Limit      | If exceeded                                                  |
| ------------------------------ | ---------- | ------------------------------------------------------------ |
| Module load and initialization | 10 seconds | `failed` with `TimeoutError`; the frame is removed           |
| Cleanup handler                | 2 seconds  | The frame is removed anyway                                  |
| Each request                   | 30 seconds | The request rejects with `timeout`; the plugin keeps running |

Initialization SHOULD do only setup, such as reading settings, subscribing to events, and showing a first notice. Long-running work SHOULD be started without awaiting it, so the 10-second limit is not reached.

## Failures

| What happens                                                                                      | Result                                                                                                                     |
| ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| A syntax error, a missing default export, or the default export throws or rejects                 | The plugin goes to `failed`. The error's name and message are shown on its card. Its frame and page additions are removed. |
| Initialization does not finish within 10 seconds                                                  | `failed` (`TimeoutError`)                                                                                                  |
| An uncaught error or unhandled rejection **after** startup, including in an event listener        | Reported to Venora and logged. The plugin keeps running. At most 20 errors per run are reported.                           |
| The plugin sends more than 20 malformed messages                                                  | Venora terminates it, and it goes to `failed`                                                                              |
| The plugin's worker does not answer Venora's ping within 5 seconds (for example, stuck in a loop) | `failed` ("The plugin stopped responding."). Its frame and worker are removed.                                             |
| More than 200 of its requests are rejected with `rate_limited` within 10 seconds                  | `failed` ("The plugin kept making requests over its limits.")                                                              |
| It sends a message larger than the size limits                                                    | `failed` at once                                                                                                           |

* A failed plugin is **not retried** while the page stays on `/channels/`.
* It is tried again the next time plugins load, after navigating away and back or reloading the page.
* **Repeated problems.** A plugin stopped 3 times on the same page for the last four reasons in the table (malformed messages, not responding, over its limits, oversized messages) is not started again until the page is reloaded. Its card says "Stopped after repeated problems on this page."
* One plugin's failure never affects another plugin. Resource limits are per plugin; see [plugin-api.md §12](/plugin-api.md#12-resource-limits).

## Cleanup handlers

* **Optional.** Return a function from the default export to register a cleanup handler. It may be `async`. It can register no more than one.
* **What it is for.** Use it to release resources the plugin created itself, such as timers. It does not need to remove page changes or subscriptions, because Venora removes those.
* **No API calls.** The API is unavailable while it runs. Calls reject with `runtime_stopped`, so the handler MUST NOT rely on them, for example to save data. Save data when it changes instead.
* **Errors are contained.** An error thrown by the handler is reported, and the stop continues.
* **Not guaranteed to run.** It does **not** run when:

  * the tab or page is closed or reloaded;
  * the browser exits;
  * Venora terminates the plugin (`failed`);
  * the stop takes longer than 2 seconds (it is cut short).

  In those cases the frame is destroyed, which ends all plugin code at once. Venora's page additions disappear with the page or are removed by Venora. Plugins MUST NOT depend on the cleanup handler for correctness or persistence.

## What triggers a stop

| Trigger                                                                                                                                    | Cleanup runs?                                           | Then                                                                                                                                                                             |
| ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Navigating from `/channels/…` to another Fermo route                                                                                       | Yes                                                     | Requests made after the navigation are refused with `runtime_stopped` straight away, before the plugin has stopped. The plugin starts again when a `/channels/` page is reached. |
| Fermo's document is replaced (for example with `document.open()`)                                                                          | No; the plugin frames are removed with the old document | Venora stops its plugins and its UI on that page and acts on nothing in the new document. A page reload restores it.                                                             |
| Uninstalling the plugin                                                                                                                    | Yes                                                     | Its record, enabled state, settings, and storage are deleted, and the page reloads                                                                                               |
| Disabling or enabling a plugin, or installing or updating one, on the Plugins page                                                         | No; the page reloads                                    | The new state applies after the reload                                                                                                                                           |
| Turning safe mode on, or disabling or uninstalling a plugin, from the Venora toolbar popup (or turning safe mode on from the Plugins page) | Yes                                                     | Open Fermo tabs apply the change at once, without a reload. Turning safe mode off, or enabling a plugin, starts it at once.                                                      |
| Venora is updated or reloaded while Fermo is open                                                                                          | Yes, best effort                                        | The old Venora stops its plugins and removes its UI; the new Venora runs after a page reload                                                                                     |
| Page reload, tab close, or browser exit                                                                                                    | No                                                      |                                                                                                                                                                                  |
| Startup failure, timeout, too many malformed messages, not responding, staying over its limits, or an oversized message                    | No                                                      | `failed`                                                                                                                                                                         |

## Install, update, uninstall

**Install.**

* The ZIP is validated in full ([plugin-manifest.md](/plugin-api/plugin-manifest.md#packaging)).
* If the plugin declares sensitive permissions, the user confirms them.
* Only then is it stored, as enabled. The page reloads, and the plugin starts on the next `/channels/` page.

**Update.** Choose **Add plugin** and select a ZIP with the same `id` and a higher `version`. Updates are manual: Venora has no plugin registry and does not check for new versions.

* Venora shows the current and new versions and the new version's release notes, and replaces the plugin only if the user chooses **Update**.
* The new version goes through the full install validation, including the sensitive-permission warning.
* A ZIP with the same, a lower, or an invalid version is rejected.
* If anything fails or the user cancels, the installed version is left untouched.
* On success, the page reloads, and the new version starts in a fresh frame.

What carries over:

* The plugin's enabled state, settings, and storage are **kept**.
* There is no migration hook in version 1. If a plugin changes the format of its stored data, it SHOULD store a schema version and migrate during initialization.
* Bundled plugins can only be updated by updating Venora.

**Uninstall.** Imported plugins only. Venora:

1. stops the plugin, running its cleanup handler;
2. deletes its stored files, enabled state, settings, and its `venora.storage` data;
3. reloads the page.

Nothing belonging to an uninstalled plugin remains.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.getvenora.tech/plugin-api/plugin-lifecycle.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
