AiHummer
English
Sign inAccount
v1.2.x
{ }Swagger

Plugin SDK

v1.2.x · updated 2026-06-27

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 slug comes 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 validate before 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