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

# Publishing and versions

> Upload a plugin through the Portal or the management API, how version activation works, and how to roll back.

Uploading a plugin adds a **version** to a capability. Versions are integers
the platform assigns; exactly one is active at a time, and every agent and
gateway bound to the plugin calls that one.

## Uploading

### Portal

**Plugins → New plugin** creates the capability and its first version.
**Plugins → your plugin → Versions → Upload version** adds a version to an
existing one.

Either way you choose between two modes:

* **WASM component** — a `.wasm` file, with an optional `.wit` file for tool
  descriptions.
* **.npack archive** — the packaged output of `noorle plugin build`, carrying
  the component, `noorle.yaml`, the WIT file, and any `.env` defaults.

Limits:

|                            |                 |
| -------------------------- | --------------- |
| Plugin name                | 2–50 characters |
| Archive decompressed total | 256 MB          |

An upload larger than the accepted size is rejected before anything is stored.
Plugin components are typically well under it; if you are close enough to
wonder, see [Size](/docs/build/plugins/project-structure#size).

### Management API

`POST /v1/capabilities/upload` accepts a `.npack` archive. A request whose body
exceeds the accepted size is rejected with `413`.

## What happens on upload

1. The archive is unpacked and the component is validated — Component Model
   binary, imports inside the nine allowed WASI prefixes, at least one
   exported function. Failure returns the errors and writes nothing.
2. The component bytes are stored content-addressed by SHA-256.
3. A **dormant** version row is appended, and the per-version metadata
   (`noorle.yaml`, environment defaults, WIT) is stored alongside it.
4. One transaction records the integrity digests and flips the new version to
   active.

Because step 4 is a single commit, a successful upload is immediately live —
there is no separate activation step for a normal upload.

If step 4 fails, the version stays dormant and **the previously active version
keeps serving**. A dormant version shows in the Portal with a **No artifact**
badge and cannot be activated: its component never landed in durable storage.
Re-upload it.

## Versions in the Portal

**Plugins → your plugin → Versions** lists every version, newest first. Each
card shows:

* the version number, an **Active** badge where applicable, and a **Builder**
  badge on versions produced by Plugin Builder;
* the tools it exports, with their descriptions;
* a read-only summary of its policy — allowed network hosts, storage
  permissions, environment variable keys, timeout and memory limits;
* **Edit configuration**, which opens the per-version policy and credential
  drawer;
* **Set as active** on any non-active version that has an artifact.

## Rolling back

Open **Versions** and choose **Set as active** on the version you want.

The switch is account-wide and immediate: there is one active version per
plugin, and every agent, gateway, and workflow bound to it picks up the change.
There is no per-binding version pin — `agent_capability` carries no version
column — so you cannot run version 3 for one agent and version 2 for another.

To stage a change, upload to a **separate plugin** and bind that one to a test
agent.

## Configuration changes without a rebuild

Policy and credentials are per-version data, not baked into the component. Use
**Edit configuration** on a version to change allowed hosts, environment keys
and values, timeout, memory, and credential values. See the
[noorle.yaml reference](/docs/build/plugins/configuration#editing-configuration-after-upload).

## Deleting

Deleting a plugin in the Portal removes the capability **and all of its
versions**, permanently. Bindings to agents and gateways go with it.

## Before you upload

* The component builds and its tools carry doc comments in the WIT file —
  those become the descriptions a model reads.
* `noorle.yaml` names only the hosts you actually call, with `path_prefix` and
  `methods` where the API allows it.
* Secrets are declared as `credentials`, not hardcoded and not shipped in
  `.env`.
* The timeout you request is realistic; the default is 30 seconds and the
  ceiling is 120.
* You have somewhere to roll back to, or you accept that this upload goes live
  for every binding the moment it succeeds.

## Next

* [Permissions](/docs/build/plugins/permissions)
* [noorle.yaml reference](/docs/build/plugins/configuration)
