A skill is a document the model reads. A **plugin is code that runs in the
agent's own process** — it registers tools, hooks and commands. That difference
decides everything below: a skill can be published as text and be complete, and
a plugin cannot, because the thing you need is the code at a specific revision.
So a plugin entry in this hub is a catalogue entry, not a payload: metadata
that names a repository and the exact commit that was reviewed. The hub answers
"which plugins exist, what do they touch, who owns them"; git serves the code.
One JSON file per plugin, plugins/<name>/axe-plugin.json:
{
"name": "axe-skillshub",
"description": "Search the AXE Skills Hub from inside a session, as a tool.",
"repo": "https://github.com/memjar/axe-skills-hub",
"sha": "0000000000000000000000000000000000000000",
"tier": "official",
"maintainer": "AXE",
"license": "MIT",
"capabilities": {
"tools": ["skillshub_find", "skillshub_get"],
"hooks": [],
"env": ["SKILLSHUB_KEY"]
},
"requires_axe": ">=0.1",
"platforms": [],
"docs_url": "https://github.com/memjar/axe-skills-hub/blob/main/docs/axeskills-plugins.md",
"subdir": "plugins/axe-skillshub"
}
| Field | Required | Why it is required |
|---|---|---|
name | yes | The key you install by. Bare slug, lowercase. |
description | yes | The only field a chooser reads. An entry without one is undiscoverable, and an empty string passes every check that asks whether a description *exists* — so it is length-checked, not presence-checked. |
repo | yes | Where the code is. |
sha | yes | Exactly 40 hex characters. A branch or tag is rejected. |
tier | yes | official (we maintain it) or community. |
maintainer | yes | Who to go to. Not the same as who ingested it. |
license | yes | A plugin nobody may reuse is not a community resource. |
capabilities | yes | Declared tools, hooks and env. This is the blast radius, stated before install. |
requires_axe, platforms, docs_url, subdir | no | Constraints and pointers. |
A pin is the whole trust model. If an entry named a branch, the author could
change what every future install runs without anyone reviewing it — the
catalogue would be asserting a review it no longer covers. Pinning a commit
means updating what installs requires a new, reviewed change to the entry.
Two honest limits, stated rather than implied:
capabilities were looked at once, at that commit. It says nothing about any
other commit in the same repository.
are separate steps, and the second one is the consent.
plugins/axeskills-plugins-removed.json lists entries pulled from the
catalogue, each with a reason and a date. A publisher refuses to publish
anything on that list. This exists because a catalogue without a revocation
path can only ever grow, and the one time you need it is after a security
incident — when re-reviewing every entry by hand is exactly what you do not
have time for.
Plugins go in the registry as format="catalog" with metadata.kind="plugin"
and metadata.source="axe:plugin", under the axe tenant.
format carries a CHECK (format IN ('python','skillmd','catalog')) and
SQLite cannot alter a CHECK constraint, so a plugin format would mean
rebuilding a table of ~111k rows. It would also be the wrong shape: catalog
already means "metadata about a thing that lives elsewhere", which is precisely
what a plugin entry is. metadata.kind is what separates our plugin entries
from mirrored catalogue rows, and bySource in the exported manifest keeps
them in their own bucket.
python3 axeskills-publish-plugin.py --url http://127.0.0.1:8741 plugins/axe-skillshub
python3 axeskills-publish-plugin.py --url http://127.0.0.1:8741 --dry-run plugins/axe-skillshub
Validation happens before the request, not after: a bad SHA, a missing
capability block or a removed entry fails locally with a reason naming the
field, so a malformed entry never becomes a row that has to be yanked.
The upstream plugin system is a Python runtime — register(ctx), 26 lifecycle
hooks, provider plugins that swap memory or context engines, single-select
versus multi-select semantics. That surface belongs to an agent runtime, and
this repository is a registry: it stores and serves, it does not execute. The
piece worth taking is the catalogue discipline — SHA pins, declared
capabilities, a tier, a removed list, and review as an explicit step — because
that is what makes a third party's plugin safe enough to consider at all.
When there is an AXE agent runtime that loads plugins, the entry above already
tells it what to fetch and what the plugin will touch. Until then, an entry is
a reviewed pointer, and that is a useful thing on its own.