The descriptor
Every plugin describes itself in atai-plugin.yml file at the repository root,
shipped inside the built wheel as well. It is the single artifact the registry
reads — the registry never downloads or unpacks the package to learn what it
contains.
tai-plugin.yml
Each entry in
provides carries a kind (tool, agent, extension,
connector, channel, backend, storage, monitoring, webhook-verifier,
config, identity, studio-plugin, router, or middleware), a name, the
module that registers it, and a one-line description. The kind is what tells
an installer which manifest field the item wires into — see
the plugin descriptor.
The parser is strict on purpose: unknown keys, YAML anchors, duplicate keys, a
file over 256 KiB, or a non-UTF-8 file are all rejected rather than
interpreted.
permissions is declarative metadata shown to installers — it is
not a sandbox.Cut a release
The registry resolves a version’s artifact from PyPI when the distribution is there, so the release order is: publish the distribution, then push the tag the registry watches.- Bump
versionin bothpyproject.tomlandtai-plugin.ymlto the same value. - Push tag
v<version>. The shipped release workflow asserts the tag matches the project version, builds withuv build, and uploads to PyPI. - The registry normalises the tag by stripping one leading
v, sov0.2.0must matchversion: 0.2.0in the descriptor.
What the registry does with it
A registered repository’s tag push reaches the registry as a GitHub webhook, and the whole publish happens inside that one request — there is no queue, no worker, and no scheduled crawl.1
Verify the delivery
The HMAC signature is checked against the registry’s webhook secret before
anything else is read. A push that is not a tag is acknowledged and ignored.
2
Resolve the listing
The repository URL is matched to a registered listing. An unknown repository
is rejected — this is where “curated” is enforced.
3
Read the descriptor at the tag
tai-plugin.yml is fetched at the pushed tag and validated. The registry
then cross-checks that its namespace, name, and package still match the
listing, so a registered repository cannot publish into someone else’s
namespace.4
Resolve the artifact
The distribution is looked up on PyPI. When it is there, the version’s
artifact reference and its SHA-256 are recorded and the listing’s source is
pypi; when it is not, the source is github and the version carries no
artifact pointer.5
Render and store
The README is rendered to sanitised HTML, the version row is written with its
items and its full descriptor, and the listing’s displayed metadata follows
if this version is now the latest.
contract is not a parseable specifier
set, when the tag does not normalise to the descriptor’s version, or when that
version has been killed. A killed version is terminal: re-pushing the tag does
not resurrect it. A distribution absent from PyPI is not a refusal — the version
is simply recorded as a github source.
Advisories
An advisory marks a version range of a listing as unsafe. Filing one is a registry-administrator action, and there is no reporting route for publishers or users — report a problem to the registry’s maintainers. An advisory carries the listing ref, anaffected_versions specifier set, a
severity of low, medium, high, or critical, and a one-line summary.
Withdrawing one keeps the row and stamps it withdrawn, so consumers that already
saw it also see the withdrawal.
Servers poll the public advisories feed and surface matches against what they
have installed — Advisories covers the client side and
its poll setting. A kill switch is the sharper tool: it marks a version
unpublishable rather than merely warning about it.
See also
- The marketplace model — listings, items, versions, advisories.
- The plugin descriptor — writing
tai-plugin.yml. - Install a plugin — the consumer side.

