Plugin SDK
A plugin is described by one manifest.json. The contract that validates the
manifest during development is the same one the platform enforces at install
time, so a manifest that passes validate is a manifest the marketplace will
accept. The aihummer plugin CLI covers the whole lifecycle: from scaffold to
signing and publishing.
One manifest, one contract
A plugin has exactly one source of truth — its manifest.json. It declares the
plugin kind (kind), how it is configured (config[]), its capabilities, and —
for host-native services — the install[] steps and start command that the
SystemdDeployer runs. Because development
and installation use the same validation contract, “valid manifest” and
“installable plugin” mean the same thing.
[!NOTE] The manifest describes a plugin’s contract, not its store-page name. The machine
slugcomes from the directory/bundle name (private side-load) or from the submission you fill in «My plugins» when publishing a community plugin — see Publishing a plugin.
CLI
aihummer plugin bundles the development, packaging and publishing commands:
# Scaffold a manifest (kind: connector | service | openapi | mcp)
aihummer plugin init <kind> [dir]
# Validate a manifest against the install contract
aihummer plugin validate <manifest.json>
# Generate an ed25519 author key (writes <prefix>.key and <prefix>.pub)
aihummer plugin keygen [--out <prefix>]
# Build and package the plugin into a release tarball + .sha256
aihummer plugin package <dir> [--out <file>] [--slug <slug>] [--build "<cmd>"]
# Sign the release identity (slug\0version\0source_ref); with --manifest the
# signature is embedded into the manifest.signature field
aihummer plugin sign --key <priv> [--manifest <m.json>] <bundle|dir>
# Upload a private plugin into your own instance (side-load)
aihummer plugin publish --private --instance <url> --token <admin> <bundle.tar.gz>
To publish a community plugin for everyone, you do not use a CLI command — you upload the packaged, signed artifact from your My Plugins in the personal cabinet (upload → AI review → moderation). See Submit a plugin.
| Command | What it does |
|---|---|
init <kind> [dir] |
Writes a starter manifest.json for the chosen kind. |
validate <m.json> |
Validates the manifest with the same contract as install. |
keygen |
Generates the author key pair: .key (private, keep secret) and .pub, prints the key id. |
package <dir> |
Builds (opt. --build) and packs into <slug>-<version>.tar.gz with a --strip-components=1 layout, writes .sha256. Never packs .env, *.key, node_modules, .git. |
sign --key <priv> |
Signs the release identity; prints the signature and key id; with --manifest embeds the signature into the manifest. |
publish --private |
Uploads a bundle to your instance’s POST /v1/admin/modules/upload. |
Both publishing paths — private side-load and community publishing via the personal cabinet — are detailed on Publishing a plugin.
Manifest fields
Whether a field is required depends on the kind and on whether the plugin is public. Base and identity fields:
| Field | Type | Required | Purpose |
|---|---|---|---|
kind |
string | always | Kind: connector | service | openapi | mcp. |
version |
string | yes | Plugin version (semver), e.g. 1.0.0. |
contract |
string | for channels | Contract ID, e.g. aihummer.channel.v1. |
scope |
string | no | Access model: shared (default) or personal. |
capabilities |
string[] | no | Declared capabilities. |
config |
object[] | no | Config form fields; each needs key, plus label, secret, required. |
oauth |
object | no | OAuth2 (authorize_url, token_url, scopes[]) to connect a user’s account. |
signature |
string | when signed | base64 ed25519 signature over the release identity (embedded by sign). |
Kind-specific fields — exactly one block is filled depending on kind:
| Field | For kind | Required | Purpose |
|---|---|---|---|
host_native.exec_start |
connector, service | yes | Command that runs the long-lived service. |
host_native.runtime |
connector, service, mcp | no | node | python | binary. |
host_native.install |
connector, service, mcp | no | Install steps (array of shell commands), run on the host after extraction. |
host_native.port |
connector, service | no | Preferred TCP port (the deployer may reassign via $PORT). |
host_native.health_path |
connector, service | no | Health-check path (default /healthz). |
openapi.spec_url |
openapi | yes | URL of the OpenAPI 3.x spec. |
openapi.base_url |
openapi | no | Override servers[0].url. |
openapi.allowed_hosts |
openapi | no | Egress allowlist for the synthesized tools. |
openapi.auth |
openapi | no | Map securityScheme → secret name. |
openapi.tool_prefix |
openapi | no | Tool-name prefix. |
mcp.transport |
mcp | yes | stdio or http. |
mcp.command / mcp.args |
mcp (stdio) | yes for stdio | Server executable and arguments. |
mcp.url |
mcp (http) | yes for http | MCP endpoint URL. |
mcp.auth_header / mcp.secret_token_key |
mcp (http) | no | Header and secret key for the bearer token. |
Store-page and identity fields (for community plugins)
The manifest can also carry publisher identity and store-page fields. For a community plugin these are what the catalog shows, but you normally enter them in the «My plugins» store page in your personal cabinet at submission time (name, descriptions, icon, screenshots, category, donation link) rather than by hand in the manifest. A private side-load needs none of them — such a plugin is trusted at the instance level.
| Field | Type | Required | Purpose |
|---|---|---|---|
visibility |
string | no | public | private | unlisted. Empty = legacy/first-party (no identity requirement). |
publisher |
string | for public | Publisher namespace, ^[a-z0-9][a-z0-9-]{1,38}$. Public slugs are named @publisher/slug. |
publisher_key_id |
string | for public | key id of the key the artifact is signed with. |
description |
string | for public | Store-page blurb in the catalog. |
icon |
string | for public | Plugin icon: an https:// URL or a data: URI. |
screenshots |
string[] | no | Store-page screenshots (array of https:// URLs; each non-empty). |
[!TIP] Run
aihummer plugin validatebefore you submit. The install and validation contract are identical, so a manifest that passes locally will be accepted both by the marketplace deployer and by the marketplace review in your personal cabinet.
Minimal manifests
A service scaffold (what aihummer plugin init service writes):
{
"version": "1.0.0",
"kind": "service",
"scope": "shared",
"contract": "aihummer.channel.v1",
"host_native": {
"runtime": "node",
"install": ["npm ci --omit=dev"],
"exec_start": "node dist/main.js",
"port": 8800,
"health_path": "/healthz"
},
"config": [
{ "key": "api_token", "label": "API token", "secret": true, "required": true }
]
}
A zero-code openapi manifest is even shorter — it just points at the spec:
{
"version": "1.0.0",
"kind": "openapi",
"scope": "shared",
"openapi": {
"spec_url": "https://api.example.com/openapi.json",
"tool_prefix": "example_",
"allowed_hosts": ["api.example.com"],
"auth": { "bearerAuth": "api_token" }
},
"config": [
{ "key": "api_token", "label": "API token", "secret": true, "required": true }
]
}
An mcp manifest (stdio transport):
{
"version": "1.0.0",
"kind": "mcp",
"scope": "shared",
"host_native": { "runtime": "node", "install": ["npm ci --omit=dev"] },
"mcp": { "transport": "stdio", "command": "node", "args": ["server.js"] }
}
From manifest to marketplace
After validation, a plugin is packaged (package), signed (sign) and published
in one of two ways:
- Private (for yourself) — side-load into your instance via the Admin UI or
publish --private. The artifact never leaves the instance. - Community (for everyone) — upload the packaged, signed artifact from the My Plugins in your personal cabinet; after AI review and human moderation it is signed and published to the community catalog.
See Publishing a plugin for the full walkthrough.
Where next
- Publishing a plugin — private side-load and community publishing via the personal cabinet, review and moderation.
- Zero-code integrations — the
openapiandmcpkinds in detail. - Install & updates — what drives
install[], the health gate, trust and signed updates. - Marketplace: overview & tiers — where each kind lives and how the official catalog differs from community.