Plugin ManifestNEW
The manifest.json format for Sophon plugins.
Overview
Every plugin requires a manifest.json at the plugin project root. It declares which core interface the plugin implements and what settings it needs, and it ships inside the .sophon-plugin archive produced by sophon dev build.
Schema
{
"name": "acme-chat-adapter",
"version": "1.0.0",
"description": "Channel adapter for the Acme in-house chat system",
"author": "Your Name",
"type": "plugin",
"pluginInterface": "ChannelAdapter",
"entrypoint": "AcmeChatAdapter.dll",
"channelType": "acme-chat",
"recipientMetadataKey": "channel",
"settings": [
{
"name": "serverUrl",
"displayName": "Server URL",
"type": "string",
"required": true
},
{
"name": "apiToken",
"displayName": "API Token",
"type": "secret",
"required": true
}
]
}Required Fields
Strictly speaking, only pluginInterface is enforced by the Gateway's manifest parser — without it the manifest is not recognized as a plugin at all (skipped, not an error). name and version are read leniently (a missing name falls back to the plugin's directory name; a missing version falls back to "0.0.0"). But sophon dev validate and sophon dev build require name, version, and description — treat all of these as required in practice.
| Field | Type | Description |
|---|---|---|
name | string | Unique plugin identifier. Also the key used for Sophon:Plugins:Allow allowlist matching (case-insensitive) and duplicate detection across scan directories. |
version | string | SemVer version, e.g. "1.0.0". |
pluginInterface | string | Which core interface the plugin implements — see the values table below. Legacy I-prefixed spellings (IChannelAdapter, …) are also accepted. |
pluginInterface Values
| Value | Status |
|---|---|
ChannelAdapter | Wired — registered as a live channel type, appears in the add-channel wizard |
DocumentExtractor | Wired — registered into the dynamic extractor registry for its supportedExtensions |
ModelProvider | Accepted, not yet consumed by the runtime — coming |
EmbeddingProvider | Accepted, not yet consumed by the runtime — coming |
VaultBackend | Accepted, not yet consumed by the runtime — coming |
Tool | Refused at parse time — custom tools belong to skills or MCP |
For the accepted-but-not-yet-consumed interfaces, the plugin process starts and runs, but the Gateway logs a one-time warning that it does not yet consume the interface.
Optional Fields
| Field | Type | Description |
|---|---|---|
channelType | string | ChannelAdapter only: the channel type identifier. Always normalized (trimmed + lowercased) and must match ^[a-z][a-z0-9-]{1,31}$ after normalization — an invalid value rejects the whole manifest. Derived from name if omitted. |
providerType | string | ModelProvider only: the provider type identifier. |
supportedExtensions | string[] | DocumentExtractor only: file extensions to claim, e.g. [".epub"]. Built-in formats always win ties; a plugin that declares no extensions is skipped. |
recipientMetadataKey | string | ChannelAdapter only: metadata key for outbound routing (default "chatId"). |
metadata | object | Arbitrary key-value metadata, surfaced verbatim in GET /api/plugins/{id}. |
entrypoint | string | Required by sophon dev validate/sophon dev build, but ignored by the Gateway — it auto-discovers the DLL by convention (<directory-name>.dll, then publish/, then any .dll with a matching runtimeconfig.json). |
The settings Array
Each entry declares one user-configurable setting. For ChannelAdapter plugins these drive the dynamic settings form in the add-channel wizard (surfaced via GET /api/channels/types):
| Field | Type | Description |
|---|---|---|
name | string | Canonical key for the setting. key is accepted as a legacy alias. |
type | string | "string" (default) or "secret". Any other value is coerced to "string" with a warning — there are no numeric or boolean setting types. |
displayName | string | Human-readable label shown in the setup UI. |
required | boolean | Enforced before the plugin connects — a missing or blank required setting fails fast. |
default | string | Default value pre-filled in the setup UI. |
Settings of type "secret" are stored in the credential vault and masked in the UI — the value is stripped from the persisted channel config and re-hydrated in memory just before connect. The declaration only applies while the plugin is registered, so also pick a name the built-in secret-name heuristic recognizes (keys containing token, secret, password, apikey, and similar — apiToken, not authCode) as a fallback for configs saved while the plugin is stopped.
Never put a real secret in default. Defaults are visible to any authenticated user via the listing endpoints (e.g. GET /api/channels/types) — only configured "secret" values are masked, not their defaults.
Validation and Refusal Rules
"pluginInterface": "Tool"is refused at parse time with a warning — the plugin never starts. This is intentional: custom agent tools belong to skills (sandboxed) or MCP servers, not full-trust plugins.- An invalid
channelType(fails the regex after normalization) rejects the whole manifest with a warning — it is not silently dropped. - The
Sophon:Plugins:Allowallowlist matches the manifest'snamefield, case-insensitive. An empty allowlist permits every discovered plugin onceSophon:Plugins:Enabledistrue. - Malformed
settingsentries degrade gracefully: a bad entry is skipped with a warning rather than rejecting the manifest.
Related
- Plugins — what plugins are, the trust gate, lifecycle, and building your first plugin
- Publishing Packages — distributing plugins through the Marketplace
- Skill Manifest — the manifest format for sandboxed skills