Reference for plugin packaging (Documentation Index
Fetch the complete documentation index at: https://docs.fluffbuzz.com/llms.txt
Use this file to discover all available pages before exploring further.
package.json metadata), manifests
(fluffbuzz.plugin.json), setup entries, and config schemas.
Package metadata
Yourpackage.json needs an fluffbuzz field that tells the plugin system what
your plugin provides:
Channel plugin:
fluffbuzz-buzzhub-package.json
compat and build
fields are required. The canonical publish snippets live in
docs/snippets/plugin-publish/.
fluffbuzz fields
| Field | Type | Description |
|---|---|---|
extensions | string[] | Entry point files (relative to package root) |
setupEntry | string | Lightweight setup-only entry (optional) |
channel | object | Channel catalog metadata for setup, picker, quickstart, and status surfaces |
providers | string[] | Provider ids registered by this plugin |
install | object | Install hints: npmSpec, localPath, defaultChoice, minHostVersion, expectedIntegrity, allowInvalidConfigRecovery |
startup | object | Startup behavior flags |
fluffbuzz.channel
fluffbuzz.channel is cheap package metadata for channel discovery and setup
surfaces before runtime loads.
| Field | Type | What it means |
|---|---|---|
id | string | Canonical channel id. |
label | string | Primary channel label. |
selectionLabel | string | Picker/setup label when it should differ from label. |
detailLabel | string | Secondary detail label for richer channel catalogs and status surfaces. |
docsPath | string | Docs path for setup and selection links. |
docsLabel | string | Override label used for docs links when it should differ from the channel id. |
blurb | string | Short onboarding/catalog description. |
order | number | Sort order in channel catalogs. |
aliases | string[] | Extra lookup aliases for channel selection. |
preferOver | string[] | Lower-priority plugin/channel ids this channel should outrank. |
systemImage | string | Optional icon/system-image name for channel UI catalogs. |
selectionDocsPrefix | string | Prefix text before docs links in selection surfaces. |
selectionDocsOmitLabel | boolean | Show the docs path directly instead of a labeled docs link in selection copy. |
selectionExtras | string[] | Extra short strings appended in selection copy. |
markdownCapable | boolean | Marks the channel as markdown-capable for outbound formatting decisions. |
exposure | object | Channel visibility controls for setup, configured lists, and docs surfaces. |
quickstartAllowFrom | boolean | Opt this channel into the standard quickstart allowFrom setup flow. |
forceAccountBinding | boolean | Require explicit account binding even when only one account exists. |
preferSessionLookupForAnnounceTarget | boolean | Prefer session lookup when resolving announce targets for this channel. |
exposure supports:
configured: include the channel in configured/status-style listing surfacessetup: include the channel in interactive setup/configure pickersdocs: mark the channel as public-facing in docs/navigation surfaces
showConfigured and showInSetup remain supported as legacy aliases. Prefer
exposure.
fluffbuzz.install
fluffbuzz.install is package metadata, not manifest metadata.
| Field | Type | What it means |
|---|---|---|
npmSpec | string | Canonical npm spec for install/update flows. |
localPath | string | Local development or bundled install path. |
defaultChoice | "npm" | "local" | Preferred install source when both are available. |
minHostVersion | string | Minimum supported FluffBuzz version in the form >=x.y.z. |
expectedIntegrity | string | Expected npm dist integrity string, usually sha512-..., for pinned installs. |
allowInvalidConfigRecovery | boolean | Lets bundled-plugin reinstall flows recover from specific stale-config failures. |
fluffbuzz.install for install-on-demand
surfaces. If your plugin exposes provider auth choices or channel setup/catalog
metadata before runtime loads, onboarding can show that choice, prompt for npm
vs local install, install or enable the plugin, then continue the selected
flow. Npm onboarding choices require trusted catalog metadata with a registry
npmSpec; exact versions and expectedIntegrity are optional pins. If
expectedIntegrity is present, install/update flows enforce it. Keep the “what
to show” metadata in fluffbuzz.plugin.json and the “how to install it”
metadata in package.json.
If minHostVersion is set, install and manifest-registry loading both enforce
it. Older hosts skip the plugin; invalid version strings are rejected.
For pinned npm installs, keep the exact version in npmSpec and add the
expected artifact integrity:
allowInvalidConfigRecovery is not a general bypass for broken configs. It is
for narrow bundled-plugin recovery only, so reinstall/setup can repair known
upgrade leftovers like a missing bundled plugin path or stale channels.<id>
entry for that same plugin. If config is broken for unrelated reasons, install
still fails closed and tells the operator to run fluffbuzz doctor --fix.
Deferred full load
Channel plugins can opt into deferred loading with:setupEntry during the pre-listen startup
phase, even for already-configured channels. The full entry loads after the
gateway starts listening.
If your setup/full entry registers gateway RPC methods, keep them on a
plugin-specific prefix. Reserved core admin namespaces (config.*,
exec.approvals.*, wizard.*, update.*) stay core-owned and always resolve
to operator.admin.
Plugin manifest
Every native plugin must ship anfluffbuzz.plugin.json in the package root.
FluffBuzz uses this to validate config without executing plugin code.
kind and channels:
ClawHub publishing
For plugin packages, use the package-specific ClawHub command:buzzhub package publish.
Setup entry
Thesetup-entry.ts file is a lightweight alternative to index.ts that
FluffBuzz loads when it only needs setup surfaces (onboarding, config repair,
disabled channel inspection).
defineBundledChannelSetupEntry(...) from
fluffbuzz/plugin-sdk/channel-entry-contract instead of
defineSetupPluginEntry(...). That bundled contract also supports an optional
runtime export so setup-time runtime wiring can stay lightweight and explicit.
When FluffBuzz uses setupEntry instead of the full entry:
- The channel is disabled but needs setup/onboarding surfaces
- The channel is enabled but unconfigured
- Deferred loading is enabled (
deferConfiguredChannelFullLoadUntilAfterListen)
setupEntry must register:
- The channel plugin object (via
defineSetupPluginEntry) - Any HTTP routes required before gateway listen
- Any gateway methods needed during startup
config.* or update.*.
What setupEntry should NOT include:
- CLI registrations
- Background services
- Heavy runtime imports (crypto, SDKs)
- Gateway methods only needed after startup
Narrow setup helper imports
For hot setup-only paths, prefer the narrow setup helper seams over the broaderplugin-sdk/setup umbrella when you only need part of the setup surface:
| Import path | Use it for | Key exports |
|---|---|---|
plugin-sdk/setup-runtime | setup-time runtime helpers that stay available in setupEntry / deferred channel startup | createPatchedAccountSetupAdapter, createEnvPatchedAccountSetupAdapter, createSetupInputPresenceValidator, noteChannelLookupFailure, noteChannelLookupSummary, promptResolvedAllowFrom, splitSetupEntries, createAllowlistSetupWizardProxy, createDelegatedSetupWizardProxy |
plugin-sdk/setup-adapter-runtime | environment-aware account setup adapters | createEnvPatchedAccountSetupAdapter |
plugin-sdk/setup-tools | setup/install CLI/archive/docs helpers | formatCliCommand, detectBinary, extractArchive, resolveBrewExecutable, formatDocsLink, CONFIG_DIR |
plugin-sdk/setup seam when you want the full shared setup
toolbox, including config-patch helpers such as
moveSingleAccountChannelSectionToDefaultAccount(...).
The setup patch adapters stay hot-path safe on import. Their bundled
single-account promotion contract-surface lookup is lazy, so importing
plugin-sdk/setup-runtime does not eagerly load bundled contract-surface
discovery before the adapter is actually used.
Channel-owned single-account promotion
When a channel upgrades from a single-account top-level config tochannels.<id>.accounts.*, the default shared behavior is to move promoted
account-scoped values into accounts.default.
Bundled channels can narrow or override that promotion through their setup
contract surface:
singleAccountKeysToMove: extra top-level keys that should move into the promoted accountnamedAccountPromotionKeys: when named accounts already exist, only these keys move into the promoted account; shared policy/delivery keys stay at the channel rootresolveSingleAccountPromotionTarget(...): choose which existing account receives promoted values
defaultAccount points at an existing non-canonical key
such as Ops, promotion preserves that account instead of creating a new
accounts.default entry.
Config schema
Plugin config is validated against the JSON Schema in your manifest. Users configure plugins via:api.pluginConfig during registration.
For channel-specific config, use the channel config section instead:
Building channel config schemas
UsebuildChannelConfigSchema from fluffbuzz/plugin-sdk/core to convert a
Zod schema into the ChannelConfigSchema wrapper that FluffBuzz validates:
Setup wizards
Channel plugins can provide interactive setup wizards forfluffbuzz onboard.
The wizard is a ChannelSetupWizard object on the ChannelPlugin:
ChannelSetupWizard type supports credentials, textInputs,
dmPolicy, allowFrom, groupAccess, prepare, finalize, and more.
See bundled plugin packages (for example the Discord plugin src/channel.setup.ts) for
full examples.
For DM allowlist prompts that only need the standard
note -> prompt -> parse -> merge -> patch flow, prefer the shared setup
helpers from fluffbuzz/plugin-sdk/setup: createPromptParsedAllowFromForAccount(...),
createTopLevelChannelParsedAllowFromPrompt(...), and
createNestedChannelParsedAllowFromPrompt(...).
For channel setup status blocks that only vary by labels, scores, and optional
extra lines, prefer createStandardChannelSetupStatus(...) from
fluffbuzz/plugin-sdk/setup instead of hand-rolling the same status object in
each plugin.
For optional setup surfaces that should only appear in certain contexts, use
createOptionalChannelSetupSurface from fluffbuzz/plugin-sdk/channel-setup:
plugin-sdk/channel-setup also exposes the lower-level
createOptionalChannelSetupAdapter(...) and
createOptionalChannelSetupWizard(...) builders when you only need one half of
that optional-install surface.
The generated optional adapter/wizard fail closed on real config writes. They
reuse one install-required message across validateInput,
applyAccountConfig, and finalize, and append a docs link when docsPath is
set.
For binary-backed setup UIs, prefer the shared delegated helpers instead of
copying the same binary/status glue into every channel:
createDetectedBinaryStatus(...)for status blocks that vary only by labels, hints, scores, and binary detectioncreateCliPathTextInput(...)for path-backed text inputscreateDelegatedSetupWizardStatusResolvers(...),createDelegatedPrepare(...),createDelegatedFinalize(...), andcreateDelegatedResolveConfigured(...)whensetupEntryneeds to forward to a heavier full wizard lazilycreateDelegatedTextInputShouldPrompt(...)whensetupEntryonly needs to delegate atextInputs[*].shouldPromptdecision
Publishing and installing
External plugins: publish to ClawHub or npm, then install:npm: override. Use the normal npm package spec when you
want the npm path after ClawHub fallback:
For npm-sourced installs,
fluffbuzz plugins install runs
npm install --ignore-scripts (no lifecycle scripts). Keep plugin dependency
trees pure JS/TS and avoid packages that require postinstall builds.Related
- SDK Entry Points —
definePluginEntryanddefineChannelPluginEntry - Plugin Manifest — full manifest schema reference
- Building Plugins — step-by-step getting started guide