---
title: "List a plugin"
description: "Prepare and submit a plugin listing for hub review."
canonical_url: "https://docs.oz0.ai/build/plugins/list-a-plugin"
---
# List a plugin

> Prepare and submit a plugin listing for hub review.

For: plugin authors.

Submit a listing to a plugin hub so tenants can find and install your plugin by name. A hub such as `orchestrator-zero/hub` (source access coming soon) keeps one file per plugin and builds a signed [plugin index](https://docs.oz0.ai/build/plugins/indexes).

The listing supplies sources, versions, maintainers and links. The hub uses the plugin's `README.md` as its documentation. Its CI runs `plugin inspect` on the pinned source with a pinned engine release to discover the plugin's contents, requirements and capabilities.

<note>

oz0 Hub (coming soon) is not public yet. Everything on this page works against a checkout of a hub repository, and a company can run a hub of its own in the same format.

</note>

## Before you list

- `plugin lint` passes, apart from a [size budget](https://docs.oz0.ai/build/parts/tools/definitions#the-size-budget) error (`tools.budget`), which the hub only warns about, and the plugin installs from its source.
- Its `README.md` is within the [README's limits](https://docs.oz0.ai/build/plugins/limits/documentation#the-readme-its-images-and-its-diagrams) and says what the plugin does, how to set it up and its limits: the hub's page shows it as the plugin's documentation ([below](https://docs.oz0.ai/build/plugins/list-a-plugin/review#the-readme-is-the-documentation)). `plugin lint`, `plugin pack` and `hub submit` fail on a README past them.
- It has a licence file, and `license:` in `oz0-plugin.yaml` declares the licence as an SPDX identifier, such as `MIT` ([the licence checks](https://docs.oz0.ai/build/plugins/limits/documentation#the-licence)). `hub submit` refuses a plugin without a licence file (`licence.missing`), and lint fails when the file reads as another licence than the one declared. A text the engine does not recognise is not refused: a maintainer reads it at review.
- You have a namespace you can prove, which becomes the first half of the plugin's name, `<namespace>/<manifest name>`:
  - `io.github.<account>`, proven by your GitHub account; for an organisation's namespace, a maintainer confirms its owners once and records the accounts that may list for it;
  - `com.example` for a domain you own, proven by a TXT record at `_oz0-hub.example.com` that names your key: `v=oz0hub1; k=ed25519; p=<your key in base64>`. Hosting domains such as `github.io` prove nothing;
  - with only a signing key, a namespace the hub's maintainers give you.
- Your tool IDs and agent and flow names start with your plugin's name or its first dash-separated part: plugin `acme-risk` may have the tools `acme_risk` and `acme_fetch` and the agent `acme-risk`. A tool ID, an agent or flow name and a plugin name each belong to one plugin of a tenant, so a generic `github` or `fetch` cannot be installed next to anyone else's.<br />

The prefixes `oz0_` and `oz0-` belong to the verified plugins of the publisher `ai.oz0`, and the hub refuses a new name that takes one of them or only looks like one (`ozo_`, `0z0-`, an `oz0` with a Cyrillic `о`), or a tool ID or agent name of a verified plugin; `plugin lint` warns of both.<br />

Their plugin names (`github`, `slack`, `web` and the rest) are theirs too: name yours `acme-github`, not `github`.
- Your signing key is an Ed25519 key. The OpenSSH key you sign release tags with (`ssh-ed25519 AAAA...`) is the easiest: the same key signs tags, submissions and the DNS record.

## By pull request

```bash [Terminal]
oz0 hub submit https://github.com/alice/github-tools --ref v1.2.0 \
  --publisher io.github.alice --hub ../oz0-hub --maintainer "Alice <alice@example.com>" --tag github
```

```text [Output]
Wrote ../oz0-hub/listings/io.github.alice/github-tools.yaml (io.github.alice/github-tools 1.2.0). Commit it on a branch and open a pull request:

Add io.github.alice/github-tools 1.2.0
...
```

`hub submit` inspects the plugin at the commit `--ref` resolves to, as `plugin inspect` does, and writes the listing: a new file, or a new version of the one there, keeping the rest of it, comments included. It pins the commit, the SHA-256 of the packed content and the forge's repository ID; never a tag. The pull request's text lists the source, the contents, everything the code may do and its requirements; `--pr-text <file>` writes it to a file instead.

On our hub, a maintainer approves every listing's pull request before it merges, a new version's too. The hub's checks run first and decide what the maintainer must look at: a pull request they block needs a maintainer's review in the listing as well.

`hub submit` and `plugin inspect` fetch a remote source as the edge does: public addresses over `https://` only, pinned to the addresses the host resolved to, with no redirect followed. A repository or registry on a private network needs `--allow-net <network>`; one you serve yourself on this machine, at any of its addresses (inside a network `--allow-net` lists too) or over plain `http://`, needs `--allow-local`. A folder, a bundle file and a `file://` repository are read as they are.

Bundles and OCI artifacts list the same way: `hub submit team-1.2.0.tar.gz --url https://example.com/team-1.2.0.tar.gz`, or `hub submit oci://ghcr.io/alice/team@sha256:...`. Their pages have no Repository link, since nothing ties the bytes to a repository.

`hub submit` runs the same README and licence checks as `plugin lint`, and fails on their errors before it writes anything; there a missing licence file is an error too. It has no `--documentation` flag and asks for no repository link: the README is the documentation, and the hub computes the Repository link from the source it verified.

For a new version of a listed plugin, `hub submit` adds only the version. Flags that describe the plugin (`--summary`, `--maintainer`, the links, `--tag`, `--track`) are refused then: edit the listing file instead.

### Check it before the pull request

```bash [Terminal]
oz0 hub submit https://github.com/alice/github-tools --ref v1.2.0 \
  --publisher io.github.alice --hub ../oz0-hub --check --pr-author alice
```

With `--check`, `hub submit` writes the listing and then runs the checkout's own checks on it, as the hub's pull request CI runs them: the checkout's `hubtool check`, built with `go build` when `bin/hubtool` is missing or older than its code, against the commit the pull request goes into, with the engine release its `engine.lock` pins. The findings are the ones the pull request will get, and the command fails when they block the listing until a maintainer reviews it, as for a first plugin or a growth in permissions.

- `--pr-author` is the forge account that will open the pull request (default `$HUB_PR_AUTHOR`), for the check of who changed the listing; without it that check only notes it was not done.
- `--base <commit>` is the commit the pull request goes into, which the checks diff against. By default it is where your branch left the hub's default branch (the merge base of `HEAD` with `origin/HEAD` or `origin/main`), so listings you committed on a branch count as changed, as they will in the pull request; a checkout without `origin` uses `HEAD`.
- The pinned engine comes from the hub's cache (`~/.cache/oz0-hub`, or `$HUB_CACHE`), or `$HUB_ENGINE`. When neither has it, `--engine-source <engine checkout>` builds it once with the hub's `scripts/engine.sh`; without one the check runs with your own binary and says the findings may differ from the CI's.
- DNS records and forge accounts are asked of the network, as the CI does. Set `HUB_FIXTURES=fixtures` to answer them from the hub's offline fixtures instead, as the hub's own Makefile does for local runs.

### Signing a pull request

The hub ties every change to its publisher, not only the first listing: each new version, a change to the summary, maintainers or links, and a status change. A pull request by the account that owns an `io.github.<account>` namespace, or by an account the publisher's file names as a member, proves itself. For a namespace proven by a domain or only a key, add `--sign-key`:

```bash [Terminal]
oz0 hub submit https://git.example.com/alice/team --ref v1.3.0 --publisher com.example \
  --hub ../oz0-hub --sign-key ~/.ssh/id_ed25519
```

It writes `submissions/com.example/team/1.3.0.json` next to the listing: a copy of that version signed with your key, which the hub's checks verify against the key your namespace's DNS record names. Commit both. The copy binds the version exactly as written (its source, when it was added and by what), and for a new plugin its summary, maintainers and links too, so a listing that differs from it is refused: edit the listing before you sign, or sign again. A change nobody can tie to the publisher is blocked until a maintainer reviews it in the listing.

The proof decides whether the checks block, not whether a maintainer looks: every listing's pull request still needs a maintainer's approval.

## Without GitHub

```bash [Terminal]
oz0 hub submit https://git.example.com/alice/team --ref v1.2.0 --publisher com.example \
  --bundle submission.json --sign-key ~/.ssh/id_ed25519
```

The bundle is one signed file: the listing's version, what your engine found and the pull request's text, signed with your key (an unencrypted OpenSSH ed25519 key, or an engine key file from `index keygen`).

For a new version of a plugin that is listed already, add `--new-version`, so the pull request's text says so. Send it to the hub's maintainers.

They import it with the hub's own script, which checks the signature against the key the hub has for your namespace, or records it for a first submission, keeps the bundle as the version's proof, and the same checks run as for a pull request.

## List a set

A [set](https://docs.oz0.ai/build/plugins/sets) is listed, signed and kept in custody like any plugin: submit its folder as you would a plugin's. Its listing carries its members under `generated.members`, each plugin with its exact version and its pinned source. When the index is signed, each member from the same index (a `hub:` source) gets the commit and content digest its pinned version is listed at, and the set is refused while a member's version is not listed, or is withdrawn or quarantined, or is a set itself.

The set's clashes are its members' (two members that clash refuse it), and the hub's filters find it by its members' facets, with the kind `set`.

A set's page states its evals and the date they last passed, instead of a claim about the combination: a set says
which versions its evals ran on, and nothing more.

## Related tasks

- [Hub review checks](https://docs.oz0.ai/build/plugins/list-a-plugin/review): Understand what the hub checks before accepting a listing.
- [Maintain a listing](https://docs.oz0.ai/build/plugins/list-a-plugin/maintain): Update maintainers, ownership, names and signed releases.

<legacy-sections>

- <span id="advisories-in-the-index">

Section

</span>

: [advisories in the index](https://docs.oz0.ai/build/plugins/list-a-plugin/review#advisories-in-the-index)
- <span id="co-maintain-hand-over-or-move-a-plugin">

Section

</span>

: [co maintain hand over or move a plugin](https://docs.oz0.ai/build/plugins/list-a-plugin/maintain#co-maintain-hand-over-or-move-a-plugin)
- <span id="links-and-the-repository">

Section

</span>

: [links and the repository](https://docs.oz0.ai/build/plugins/list-a-plugin/review#links-and-the-repository)
- <span id="new-versions-from-signed-tags">

Section

</span>

: [new versions from signed tags](https://docs.oz0.ai/build/plugins/list-a-plugin/maintain#new-versions-from-signed-tags)
- <span id="reference">

Section

</span>

: [reference](https://docs.oz0.ai/build/plugins/list-a-plugin/maintain#reference)
- <span id="the-licence">

Section

</span>

: [the licence](https://docs.oz0.ai/build/plugins/list-a-plugin/review#the-licence)
- <span id="the-readme-is-the-documentation">

Section

</span>

: [the readme is the documentation](https://docs.oz0.ai/build/plugins/list-a-plugin/review#the-readme-is-the-documentation)
- <span id="used-by-and-the-graph">

Section

</span>

: [used by and the graph](https://docs.oz0.ai/build/plugins/list-a-plugin/review#used-by-and-the-graph)
- <span id="what-a-listing-shows">

Section

</span>

: [what a listing shows](https://docs.oz0.ai/build/plugins/list-a-plugin/review#what-a-listing-shows)
- <span id="what-the-hub-checks">

Section

</span>

: [what the hub checks](https://docs.oz0.ai/build/plugins/list-a-plugin/review#what-the-hub-checks)

</legacy-sections>


## Sitemap

See the full [sitemap](https://docs.oz0.ai/sitemap.md) for all pages.
