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

# Extension catalog and registry

> Where operators browse extensions, how agents install and auto-update from the catalog, the registry API, and how submission works.

<Warning>
  The catalog is live in Mission Control's **Extensions** tab and on altnautica.com/extensions, and agents check it daily for updates. Third-party submission is not open, and there is no `ados plugin search`.
</Warning>

## Where the catalog appears

* **Mission Control.** A node's **Extensions** tab shows a searchable grid of catalog extensions with category filters (drivers, ui, ai, telemetry, tools) and an installed marker. **Install** on a card hands the archive URL and its sha256 pin to the agent (see [URL install](/developers/distribution-url-install)).
* **The agent.** Each agent ships a bundled first-party catalog, served at `GET /api/v1/plugins/catalog` and shown in the agent dashboard.
* **The website.** altnautica.com/extensions lists published extensions.

<Frame caption="The catalog grid in a node's Extensions tab.">
  <img src="https://mintcdn.com/altnautica/2ehvmPY4A5RpSNa5/images/developers/registry-browse.png?fit=max&auto=format&n=2ehvmPY4A5RpSNa5&q=85&s=5418c2f6e052670836349cb7745b0355" alt="Extensions tab catalog grid with search box, category filters and an installed marker" width="1600" height="1000" data-path="images/developers/registry-browse.png" />
</Frame>

## Install by id

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
ados plugin install com.altnautica.mavlink-gimbal-v2
ados plugin info com.altnautica.mavlink-gimbal-v2
```

`ados plugin install <id>` installs a built-in plugin or a first-party catalog entry by id, at the catalog's version. There is no `@version` syntax. `ados plugin info <id>` prints the manifest summary and runtime state.

## Automatic updates

Once a day the agent compares every enabled install with the newest version the registry publishes:

| Outcome | When |
| - | - |
| Silent install | Patch or minor bump, unchanged permissions and code surface, still-supported board, same signer, not pinned, auto-update on. The new archive must be pinned by sha256 and passes every install check; a refused archive rolls back to the installed version. |
| Notify | Major bump, permission change, change to what the plugin can run (risk, services, spawn allowlist, binaries, payloads), a dropped board, or a different signer. The operator gets an `update_available` notice; a signer change needs a remove and a fresh install. |
| Skipped | Pinned, auto-update off, nothing newer, or no registry row. |
| Failed | Registry, download, archive, install or enable error, recorded on the install and retried at the next daily check. |

The whole cycle is deferred while the vehicle counts as armed (unknown or stale state counts as armed). Control it per plugin:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
ados plugin pin com.example.my-plugin 1.2.0
ados plugin unpin com.example.my-plugin
ados plugin auto-update com.example.my-plugin off
```

The same daily cycle fetches the registry's revocation list and merges it into the agent's local list; see [Revocation and incidents](/developers/revocation-and-incidents).

## Registry API

The registry is served from the Convex backend's HTTP routes:

| Route | Purpose |
| - | - |
| `GET /v1/plugins` | List catalog entries. Query: `category`, `license`, `signed_only`, `verified_only`, `q`, `limit`. |
| `GET /v1/plugins/:id` | One plugin and its versions. |
| `GET /v1/plugins/:id/:version` | One version. |
| `GET /v1/plugins/:id/:version/download` | 302 redirect to the archive. |
| `GET /v1/revoked.json` | Revoked signer keys and plugin versions. |
| `POST /v1/plugins/submit` | Submit a signed archive (see below). |

`/v1/revoked.json` returns:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "signer_keys": ["example-2025-X"],
  "plugin_versions": ["com.example.my-plugin@1.0.3"],
  "generated_at": 1767225600000
}
```

A self-hosted Convex backend serves its own catalog; see [Self-hosting](/developers/self-hosting/overview).

## Submit a plugin

Third-party submission is not open. This section describes the endpoint as it ships.

`POST /v1/plugins/submit` takes a `multipart/form-data` body and a bearer token that resolves to a registry user. Required fields: `archive`, `plugin_id`, `version`, `category`, `manifest_yaml`, `signature`, `signer_key_id`, `payload_hash` and `agent_min_version`. Optional: `archive_sha256`, `name`, `description`, `license`, `homepage_url`, `repo_url`, `agent_max_version`, `gcs_min_version`. `category` must be one of `drivers`, `ui`, `ai`, `telemetry` or `tools`; anything else returns 400.

`scripts/submit.sh` in ADOSExtensions derives every required field from a signed archive and sends it:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
ADOS_REGISTRY_URL=https://cloud.example.com \
ADOS_REGISTRY_TOKEN=<token> \
  ./scripts/submit.sh extensions/my-plugin/dist/com.example.my-plugin-1.0.0.signed.adosplug \
  --category drivers --repo-url https://github.com/acme/acme-extensions
```

The equivalent `curl`:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://cloud.example.com/v1/plugins/submit \
  -H "Authorization: Bearer <token>" \
  -F archive=@com.example.my-plugin-1.0.0.signed.adosplug \
  -F plugin_id=com.example.my-plugin \
  -F version=1.0.0 \
  -F category=drivers \
  -F manifest_yaml=@manifest.yaml \
  -F signature=<base64 signature> \
  -F signer_key_id=acme-2026-A \
  -F payload_hash=<sha256 hex> \
  -F agent_min_version=0.100.0 \
  -F license=GPL-3.0-or-later
```

The manifest fields the registry reads are top-level: `id`, `license`, `homepage`.

### Review

The registry scans the first 256 KiB of the archive for a short list of dangerous patterns (`eval(`, `exec(`, `__import__(`, `subprocess` calls, `os.system(`) and scores it at 100 minus 20 per finding. Run [`ados plugin lint`](/developers/linting) locally for the fuller check.

| Status | Meaning |
| - | - |
| `pending` | Clean scan (score 80 or more, no findings) and an OSS licence. Ready for review. |
| `queued_for_review` | Anything else. Queued for closer review. |
| `approved` | Published by the registry operator. |
| `rejected` | Declined by the registry operator. |

Every submission waits for the registry operator; nothing auto-publishes. The registry stores your signature as submitted; it is verified on each agent at install against that agent's trusted keys. The verified-publisher badge is set by the registry operator. To pull a version, contact the registry operator.

## Next steps

<CardGroup cols={2}>
  <Card title="Revocation and incidents" href="/developers/revocation-and-incidents">
    Revoke a signer, an archive or a release.
  </Card>

  <Card title="Legal and licensing" href="/developers/legal-and-licensing">
    Licences and distribution channels.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.