Sophon 1.15 is here
Sophon Docs
API Reference

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.

FieldTypeDescription
namestringUnique plugin identifier. Also the key used for Sophon:Plugins:Allow allowlist matching (case-insensitive) and duplicate detection across scan directories.
versionstringSemVer version, e.g. "1.0.0".
pluginInterfacestringWhich core interface the plugin implements — see the values table below. Legacy I-prefixed spellings (IChannelAdapter, …) are also accepted.

pluginInterface Values

ValueStatus
ChannelAdapterWired — registered as a live channel type, appears in the add-channel wizard
DocumentExtractorWired — registered into the dynamic extractor registry for its supportedExtensions
ModelProviderAccepted, not yet consumed by the runtime — coming
EmbeddingProviderAccepted, not yet consumed by the runtime — coming
VaultBackendAccepted, not yet consumed by the runtime — coming
ToolRefused 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

FieldTypeDescription
channelTypestringChannelAdapter 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.
providerTypestringModelProvider only: the provider type identifier.
supportedExtensionsstring[]DocumentExtractor only: file extensions to claim, e.g. [".epub"]. Built-in formats always win ties; a plugin that declares no extensions is skipped.
recipientMetadataKeystringChannelAdapter only: metadata key for outbound routing (default "chatId").
metadataobjectArbitrary key-value metadata, surfaced verbatim in GET /api/plugins/{id}.
entrypointstringRequired 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):

FieldTypeDescription
namestringCanonical key for the setting. key is accepted as a legacy alias.
typestring"string" (default) or "secret". Any other value is coerced to "string" with a warning — there are no numeric or boolean setting types.
displayNamestringHuman-readable label shown in the setup UI.
requiredbooleanEnforced before the plugin connects — a missing or blank required setting fails fast.
defaultstringDefault 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:Allow allowlist matches the manifest's name field, case-insensitive. An empty allowlist permits every discovered plugin once Sophon:Plugins:Enabled is true.
  • Malformed settings entries degrade gracefully: a bad entry is skipped with a warning rather than rejecting the manifest.
  • 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