Skip to main content
This page is for the native FluffBuzz plugin manifest only. For compatible bundle layouts, see Plugin bundles. Compatible bundle formats use different manifest files:
  • Codex bundle: .codex-plugin/plugin.json
  • Claude bundle: .claude-plugin/plugin.json or the default Claude component layout without a manifest
  • Cursor bundle: .cursor-plugin/plugin.json
FluffBuzz auto-detects those bundle layouts too, but they are not validated against the fluffbuzz.plugin.json schema described here. For compatible bundles, FluffBuzz currently reads bundle metadata plus declared skill roots, Claude command roots, Claude bundle settings.json defaults, Claude bundle LSP defaults, and supported hook packs when the layout matches FluffBuzz runtime expectations. Every native FluffBuzz plugin must ship a fluffbuzz.plugin.json file in the plugin root. FluffBuzz uses this manifest to validate configuration without executing plugin code. Missing or invalid manifests are treated as plugin errors and block config validation. See the full plugin system guide: Plugins. For the native capability model and current external-compatibility guidance: Capability model.

What this file does

fluffbuzz.plugin.json is the metadata FluffBuzz reads before it loads your plugin code. Everything below must be cheap enough to inspect without booting plugin runtime. Use it for:
  • plugin identity, config validation, and config UI hints
  • auth, onboarding, and setup metadata (alias, auto-enable, provider env vars, auth choices)
  • activation hints for control-plane surfaces
  • shorthand model-family ownership
  • static capability-ownership snapshots (contracts)
  • QA runner metadata the shared fluffbuzz qa host can inspect
  • channel-specific config metadata merged into catalog and validation surfaces
Do not use it for: registering runtime behavior, declaring code entrypoints, or npm install metadata. Those belong in your plugin code and package.json.

Minimal example

Rich example

Top-level field reference

providerAuthChoices reference

Each providerAuthChoices entry describes one onboarding or auth choice. FluffBuzz reads this before provider runtime loads.

commandAliases reference

Use commandAliases when a plugin owns a runtime command name that users may mistakenly put in plugins.allow or try to run as a root CLI command. FluffBuzz uses this metadata for diagnostics without importing plugin runtime code.

activation reference

Use activation when the plugin can cheaply declare which control-plane events should activate it later.

qaRunners reference

Use qaRunners when a plugin contributes one or more transport runners beneath the shared fluffbuzz qa root. Keep this metadata cheap and static; the plugin runtime still owns actual CLI registration through a lightweight runtime-api.ts surface that exports qaRunnerCliRegistrations.
This block is metadata only. It does not register runtime behavior, and it does not replace register(...), setupEntry, or other runtime/plugin entrypoints. Current consumers use it as a narrowing hint before broader plugin loading, so missing activation metadata usually only costs performance; it should not change correctness while legacy manifest ownership fallbacks still exist.
Current live consumers:
  • command-triggered CLI planning falls back to legacy commandAliases[].cliCommand or commandAliases[].name
  • channel-triggered setup/channel planning falls back to legacy channels[] ownership when explicit channel activation metadata is missing
  • provider-triggered setup/runtime planning falls back to legacy providers[] and top-level cliBackends[] ownership when explicit provider activation metadata is missing

setup reference

Use setup when setup and onboarding surfaces need cheap plugin-owned metadata before runtime loads.
Top-level cliBackends stays valid and continues to describe CLI inference backends. setup.cliBackends is the setup-specific descriptor surface for control-plane/setup flows that should stay metadata-only. When present, setup.providers and setup.cliBackends are the preferred descriptor-first lookup surface for setup discovery. If the descriptor only narrows the candidate plugin and setup still needs richer setup-time runtime hooks, set requiresRuntime: true and keep setup-api in place as the fallback execution path. Because setup lookup can execute plugin-owned setup-api code, normalized setup.providers[].id and setup.cliBackends[] values must stay unique across discovered plugins. Ambiguous ownership fails closed instead of picking a winner from discovery order.

setup.providers reference

setup fields

uiHints reference

uiHints is a map from config field names to small rendering hints.
Each field hint can include:

contracts reference

Use contracts only for static capability ownership metadata that FluffBuzz can read without importing the plugin runtime.
Each list is optional: Provider plugins that implement resolveExternalAuthProfiles should declare contracts.externalAuthProviders. Plugins without the declaration still run through a deprecated compatibility fallback, but that fallback is slower and will be removed after the migration window.

mediaUnderstandingProviderMetadata reference

Use mediaUnderstandingProviderMetadata when a media-understanding provider has default models, auto-auth fallback priority, or native document support that generic core helpers need before runtime loads. Keys must also be declared in contracts.mediaUnderstandingProviders.
Each provider entry can include:

channelConfigs reference

Use channelConfigs when a channel plugin needs cheap config metadata before runtime loads.
Each channel entry can include:

modelSupport reference

Use modelSupport when FluffBuzz should infer your provider plugin from shorthand model ids like gpt-5.5 or claude-sonnet-4.6 before plugin runtime loads.
FluffBuzz applies this precedence:
  • explicit provider/model refs use the owning providers manifest metadata
  • modelPatterns beat modelPrefixes
  • if one non-bundled plugin and one bundled plugin both match, the non-bundled plugin wins
  • remaining ambiguity is ignored until the user or config specifies a provider
Fields: Legacy top-level capability keys are deprecated. Use fluffbuzz doctor --fix to move speechProviders, realtimeTranscriptionProviders, realtimeVoiceProviders, mediaUnderstandingProviders, imageGenerationProviders, videoGenerationProviders, webFetchProviders, and webSearchProviders under contracts; normal manifest loading no longer treats those top-level fields as capability ownership.

Manifest versus package.json

The two files serve different jobs: If you are unsure where a piece of metadata belongs, use this rule:
  • if FluffBuzz must know it before loading plugin code, put it in fluffbuzz.plugin.json
  • if it is about packaging, entry files, or npm install behavior, put it in package.json

package.json fields that affect discovery

Some pre-runtime plugin metadata intentionally lives in package.json under the fluffbuzz block instead of fluffbuzz.plugin.json. Important examples: Manifest metadata decides which provider/channel/setup choices appear in onboarding before runtime loads. package.json#fluffbuzz.install tells onboarding how to fetch or enable that plugin when the user picks one of those choices. Do not move install hints into fluffbuzz.plugin.json. fluffbuzz.install.minHostVersion is enforced during install and manifest registry loading. Invalid values are rejected; newer-but-valid values skip the plugin on older hosts. Exact npm version pinning already lives in npmSpec, for example "npmSpec": "@wecom/wecom-fluffbuzz-plugin@1.2.3". Pair that with expectedIntegrity when you want update flows to fail closed if the fetched npm artifact no longer matches the pinned release. Interactive onboarding offers trusted registry npm specs, including bare package names and dist-tags. When expectedIntegrity is present, install/update flows enforce it; when it is omitted, the registry resolution is recorded without an integrity pin. Channel plugins should provide fluffbuzz.setupEntry when status, channel list, or SecretRef scans need to identify configured accounts without loading the full runtime. The setup entry should expose channel metadata plus setup-safe config, status, and secrets adapters; keep network clients, gateway listeners, and transport runtimes in the main extension entrypoint. Runtime entrypoint fields do not override package-boundary checks for source entrypoint fields. For example, fluffbuzz.runtimeExtensions cannot make an escaping fluffbuzz.extensions path loadable. fluffbuzz.install.allowInvalidConfigRecovery is intentionally narrow. It does not make arbitrary broken configs installable. Today it only allows install flows to recover from specific stale bundled-plugin upgrade failures, such as a missing bundled plugin path or a stale channels.<id> entry for that same bundled plugin. Unrelated config errors still block install and send operators to fluffbuzz doctor --fix. fluffbuzz.channel.persistedAuthState is package metadata for a tiny checker module:
Use it when setup, doctor, or configured-state flows need a cheap yes/no auth probe before the full channel plugin loads. The target export should be a small function that reads persisted state only; do not route it through the full channel runtime barrel. fluffbuzz.channel.configuredState follows the same shape for cheap env-only configured checks:
Use it when a channel can answer configured-state from env or other tiny non-runtime inputs. If the check needs full config resolution or the real channel runtime, keep that logic in the plugin config.hasConfiguredState hook instead.

Discovery precedence (duplicate plugin ids)

FluffBuzz discovers plugins from several roots (bundled, global install, workspace, explicit config-selected paths). If two discoveries share the same id, only the highest-precedence manifest is kept; lower-precedence duplicates are dropped instead of loading beside it. Precedence, highest to lowest:
  1. Config-selected — a path explicitly pinned in plugins.entries.<id>
  2. Bundled — plugins shipped with FluffBuzz
  3. Global install — plugins installed into the global FluffBuzz plugin root
  4. Workspace — plugins discovered relative to the current workspace
Implications:
  • A forked or stale copy of a bundled plugin sitting in the workspace will not shadow the bundled build.
  • To actually override a bundled plugin with a local one, pin it via plugins.entries.<id> so it wins by precedence rather than relying on workspace discovery.
  • Duplicate drops are logged so Doctor and startup diagnostics can point at the discarded copy.

JSON Schema requirements

  • Every plugin must ship a JSON Schema, even if it accepts no config.
  • An empty schema is acceptable (for example, { "type": "object", "additionalProperties": false }).
  • Schemas are validated at config read/write time, not at runtime.

Validation behavior

  • Unknown channels.* keys are errors, unless the channel id is declared by a plugin manifest.
  • plugins.entries.<id>, plugins.allow, plugins.deny, and plugins.slots.* must reference discoverable plugin ids. Unknown ids are errors.
  • If a plugin is installed but has a broken or missing manifest or schema, validation fails and Doctor reports the plugin error.
  • If plugin config exists but the plugin is disabled, the config is kept and a warning is surfaced in Doctor + logs.
See Configuration reference for the full plugins.* schema.

Notes

  • The manifest is required for native FluffBuzz plugins, including local filesystem loads. Runtime still loads the plugin module separately; the manifest is only for discovery + validation.
  • Native manifests are parsed with JSON5, so comments, trailing commas, and unquoted keys are accepted as long as the final value is still an object.
  • Only documented manifest fields are read by the manifest loader. Avoid custom top-level keys.
  • channels, providers, cliBackends, and skills can all be omitted when a plugin does not need them.
  • Exclusive plugin kinds are selected through plugins.slots.*: kind: "memory" via plugins.slots.memory, kind: "context-engine" via plugins.slots.contextEngine (default legacy).
  • Env-var metadata (providerAuthEnvVars, channelEnvVars) is declarative only. Status, audit, cron delivery validation, and other read-only surfaces still apply plugin trust and effective activation policy before treating an env var as configured.
  • For runtime wizard metadata that requires provider code, see Provider runtime hooks.
  • If your plugin depends on native modules, document the build steps and any package-manager allowlist requirements (for example, pnpm allow-build-scripts + pnpm rebuild <package>).

Building plugins

Getting started with plugins.

Plugin architecture

Internal architecture and capability model.

SDK overview

Plugin SDK reference and subpath imports.