Publishing a plugin
Built a plugin with the Plugin SDK? You can publish it in two modes:
- Private (for yourself) — side-load into your instance. The artifact never leaves it.
- Public (for everyone) — submit to the curated official AiHummer catalog via a PR.
Analogy: installing a .vsix by hand (private) vs publishing to the VS Code
Marketplace (public); a private npm registry vs the public one.
Private mode — side-load into your instance
Use this when only you need the plugin: an internal connector, a custom integration, a test build.
Steps
- Package and sign the bundle:
aihummer plugin package ./my-plugin aihummer plugin sign --key author.key --manifest ./my-plugin/manifest.json my-plugin-1.0.0.tar.gz - Upload it to the instance one of two ways:
- Admin UI → Plugins → “Upload plugin” — drag the bundle; or
- CLI:
aihummer plugin publish --private --instance https://your-instance \ --token <admin-token> my-plugin-1.0.0.tar.gz
- Under the hood this is
POST /v1/admin/modules/upload(multipart,integrations:write): the artifact lands in the instance blob store (AIHUMMER_BLOB_DIR) under ablob:ref, and a catalog row is registered withorigin = local-private,visibility = private. - The plugin appears in the marketplace tagged Private and installs via the normal path — sandboxed systemd unit + health gate.
Trust: the pinned key and the trust store
Private artifacts must be signed. When you upload a plugin signed with an unknown key, the Admin UI prompts you to approve the author’s key into the instance trust store (one click). Once approved, the signature is verified on every install and update.
- Artifacts from the official source verify against the registry key pinned in core — trusted by default, no extra step.
- Private artifacts verify against keys in the instance trust store.
- Unsigned bundles are rejected — except in dev mode for local iteration:
AIHUMMER_PLUGIN_DEV_UNSIGNED=1.
[!WARNING]
AIHUMMER_PLUGIN_DEV_UNSIGNED=1disables signature verification and is meant only for local development. Never enable it on an externally reachable instance.
Public mode — the public registry
To make a plugin available to every instance, submit it to the public
registry
AiHummer/marketplace-catalog
via a PR: automated checks + review, and on approval AiHummer counter-signs the
release.
Steps
- One-time — register the publisher. Generate a key and reserve the
namespace:
This reserves theaihummer plugin keygen # prints the public key (base64) and key id@younamespace. Keep the private key to yourself — it signs every submission. - Host the artifact at a stable HTTPS URL (the artifact is hosted by the author, not by AiHummer).
- Open a PR to the catalog:
aihummer plugin publish --public --dir ./my-plugin --key author.key \ --artifact-url https://you.example.com/my-plugin-1.0.0.tar.gz \ --publisher you --description "What the plugin does" --icon https://you.example.com/icon.svg \ [--screenshot https://you.example.com/1.png ...] [--channel stable|beta] \ [--register-key author.pub]--register-keyaddspublishers/<you>.json(needed only on your first submission). - CI gates validate the submission (see below), AI review posts a risk verdict, and an AiHummer maintainer reviews and merges manually.
- On merge the release is counter-signed with the pinned registry key and
published to a separate
community-catalog.jsonon the CDN. Every instance that has added this source sees the plugin; core trusts it via the pinned key — no per-operator trust step needed.
The submission contract
A PR adds two files (the form is generated by publish --public and is
stable):
publishers/<publisher>.json — one-time registration:
{
"publisher": "acme",
"public_key": "<base64 std ed25519 public key>",
"key_id": "<sha256(public_key)[:16] in hex>",
"contact": "you@example.com"
}
catalog/<publisher>/<slug>/plugin.json — a submission (one per version line):
{
"publisher": "acme",
"slug": "hello-tool",
"namespaced_slug": "@acme/hello-tool",
"version": "1.0.0",
"channel": "stable",
"artifact_url": "https://acme.example.com/hello-tool-1.0.0.tar.gz",
"license": "MIT",
"publisher_key_id": "bd68f2deedad25b1",
"signature": "<base64 ed25519 over the release identity>",
"manifest": { "...the full Manifest object..." }
}
namespaced_slugmust equal@<publisher>/<slug>.channel∈stable | beta.artifact_urlis the.tar.gzhosted by the author.publisher_key_idmust match the registered publisher’skey_id.- The release identity signed = the bytes
slug \x00 version \x00 artifact_url. - For a public submission the embedded
manifestmust carrydescription,icon(and optionallyscreenshots) — see store-page fields.
[!TIP]
aihummer plugin publish --publicassembles these files in the right shape and opens the PR for you — there’s no need to hand-edit the JSON.
Moderation
Every submission goes through an automated check (the submission contract, signature and a security scan), then an advisory AI risk review, and finally a mandatory human review by the AiHummer team. Neither automation nor the AI ever merges on its own — the decision is always a maintainer’s, and nothing reaches the catalog without their approval. A published plugin later found to be malicious or broken can be revoked and dropped from the catalog on the next sync.
The community catalog as an extra source
Public plugins are published to a separate community-catalog.json that does
not overwrite the curated first-party catalog. An instance adds it as an extra
source in Plugins → Sources (or POST /v1/admin/modules/catalog/sources). See
Install & updates and
Overview & tiers.
Where next
- Plugin SDK — manifest fields and the
aihummer plugincommands. - Install & updates — multi-source, the trust model, signed updates, ranking.
- Marketplace: overview & tiers — official vs community registry.