Plugin manifest and modules

Every plugin contains a plugin.yaml manifest. Kumbuka strictly decodes one YAML document: unknown fields, unsupported module types, invalid permissions, and incompatible API versions are rejected.

Manifest

A minimal executable plugin manifest looks like:

api_version: 1
provider: Example
id: com.example.greeting
name: Greeting
icon: message-circle-lucide
version: 1.0.0
default_enabled: true
modules:
  - type: macro
    id: greeting
    name: greeting
permissions: []

Top-level fields are:

Field Purpose
api_version Plugin API version. API v1 currently uses 1.
provider Optional author/provider label. It is metadata, not a trust grant.
id Globally unique plugin identifier.
name Human-readable plugin name.
icon Optional host icon used for plugin identity in administration.
version Plugin version in MAJOR.MINOR.PATCH form.
description Optional plugin description.
default_enabled Whether the plugin starts enabled by default.
requires Plugin IDs that must be enabled first.
modules One or more contributions supplied by the package.
permissions Host capabilities the package may request.

A manifest can declare up to 32 modules. Plugin and module identifiers are lowercase identifiers using letters, digits, ., _, and - within the public format limits.

The optional top-level icon uses the same host icon identifiers exposed by Kumbuka’s icon catalog. Kumbuka uses it for plugin identity in administration, including the Plugin settings navigation. If the declared icon is unavailable, the host falls back to its generic plugin icon. Module-level icons remain separate and describe individual actions such as editor inserts or administrator actions.

Module types

markdown-syntax

Enables a standard host-provided Markdown grammar. Supported syntax identifiers are tables, strikethrough, task-list, definition-list, footnote, and linkify.

renderer-extension

Runs executable WASM during preprocess, content-preprocess, or postprocess. content-preprocess modules can declare a bounded priority.

macro

Declares a named macro parsed and rendered by the WASM guest. The optional capability field can require one host operation in the active render scope.

code-highlighter

Provides the exclusive fenced-code highlighter. The guest receives the source and language with stage highlight. An optional packaged CSS asset is filtered and scoped by Kumbuka.

widget

Runs executable WASM to render a bounded widget on a host-owned surface. Supported surfaces are home, page.details, page.after-content, page.aside, and sidebar. width can be omitted or set to normal or wide; order controls deterministic placement within the surface.

Widget HTML is sanitized by Kumbuka. A widget can also return bounded host-rendered link or dialog actions with local application URLs, or a command action handled through Kumbuka’s host-owned POST endpoint. Command actions do not expose arbitrary plugin routes. They may include optional confirmation text and are executed only after the host revalidates the current page context. Widgets cannot return recursive Markdown fragments.

content-change

Runs executable WASM after a page save commits changed canonical Markdown. The guest receives public metadata for the committed page plus the previous and current source. The hook returns no render output and is not invoked for metadata-only saves.

This module is the generic mutation boundary for plugins that must compare old and new content. Mutation-only capabilities such as notifications.send can be supplied in this context; they remain unavailable during rendering.

page-action

Adds a declarative action to the current page without requiring WASM. name, optional description and icon, order, kind, and a bounded local url describe the host-rendered control. kind can be link or dialog and defaults to link. URL templates may use ${slug} and ${id}; Kumbuka expands both with path-safe current-page values.

Use page-action for navigation or host dialogs. Fundamental page operations such as edit, move, and delete remain core application actions rather than plugin contributions.

exporter

Runs executable WASM to produce one bounded downloadable file for the current authorized page. The exporter receives public page metadata plus the stored Markdown source and returns a base filename, media type, and file bytes. Kumbuka owns the POST route, page authorization, response headers, and filename/media-type validation.

settings

Declares administrator-managed plugin settings. A settings module has two forms:

  • without fields, it is a boolean feature toggle; requires can reference other modules in the same package;
  • with fields, it is a typed singleton settings group rendered on the plugin’s page under Administration → Plugin settings.

Typed settings use bounded scalar configuration fields: text, textarea, url, secret, boolean, select, and color. Typed settings groups can contain up to 16 fields and cannot use key: true, list fields, or requires. Color values use canonical six-digit CSS hexadecimal form such as #64748b.

For example:

modules:
  - type: settings
    id: appearance
    name: Appearance
    description: Default presentation for embeds.
    fields:
      - id: reference_position
        name: Reference position
        type: select
        required: true
        default: right
        options:
          - right
          - left
      - id: highlight_referenced_lines
        name: Highlight referenced lines
        type: boolean
        default: "true"

An executable plugin with settings:read reads a typed setting through Settings().Get("<module>.<field>"). When the administrator has not saved an explicit value, the host returns the manifest default. Manifest-declared settings are administrator managed; guest settings:write calls cannot overwrite them.

content-style

Adds a packaged stylesheet for rendered page typography. Kumbuka filters selectors, properties, and values before applying it.

render-policy

Declares a bounded semantic rendering-policy marker. Active policies become request-scoped feature flags named render-policy.<policy> that other modules can observe; core does not attach feature-specific behavior to individual policy names.

browser-module

Adds isolated browser-side rendering from packaged JavaScript and optional CSS. It requires the browser:render permission. See Browser modules.

admin-resource

Declares a bounded host-rendered record schema owned by the plugin. Kumbuka owns forms, generic type validation, authorization, CSRF protection, namespaced persistence, and encryption of secret fields. Plugins that declare settings, admin-resource, or admin-action modules appear under Administration → Plugin settings rather than placing their configuration in the Plugins lifecycle page.

Each resource has exactly one required text field marked key: true. Scalar fields use the same types as typed settings: text, textarea, url, secret, boolean, select, and color. Admin resources can additionally use bounded list fields for structured rows. required and max_bytes apply generically. boolean fields may use default: "true" or "false"; select fields declare an options list and may choose one option as default; options must fit the field’s byte limit. url defaults must be absolute HTTP(S) URLs. color values are canonical #RRGGBB values. Secret fields cannot have defaults and are masked in the browser after saving.

A list field declares one to eight typed columns and can set max_items up to 64. List columns can use text, url, select, or color; nested lists, secrets, textareas, booleans, and key columns are not supported. A configuration group or resource may contain at most 16 fields, and a select may contain at most 32 unique options.

For example:

modules:
  - type: admin-resource
    id: sources
    name: Sources
    fields:
      - id: name
        name: Name
        type: text
        required: true
        key: true
      - id: endpoint
        name: API endpoint
        type: url
        required: true
      - id: token
        name: Access token
        type: secret
      - id: enabled
        name: Enabled
        type: boolean
        default: "true"
      - id: provider
        name: Provider
        type: select
        options: [github, gitlab]
        default: github

Executable plugins with settings:read can read their own structured records through the SDK Resources() client. Secret fields are decrypted only for the owning plugin.

admin-action

Declares one explicit administrator-triggered executable operation. Kumbuka renders the action under Administration → Plugin settings and owns authentication, authorization, CSRF handling, and the POST route. The action is disabled while the plugin is disabled; plugins do not receive an arbitrary administration HTTP route.

name is required. description and icon are optional; icons use the normal identifier syntax. The module ID identifies the action dispatched to the guest.

modules:
  - type: admin-action
    id: refresh-cache
    name: Refresh cache
    description: Mark all cached files stale.
    icon: refresh-cw-lucide

Executable plugins register the matching module ID with sdk.RegisterAdminAction. The callback returns an error when the operation fails; successful callbacks return no content because Kumbuka owns the administration UI.

content-substitution

Binds an admin-resource to inline {{prefix:name}} substitutions. Values are restored immediately before Markdown parsing so inserted content is not recursively reinterpreted as new substitutions.

editor-completion

Exposes an admin-resource through a bounded editor-completion trigger and replacement template.

editor-insert

Adds a static insertion action to both editor modes without loading plugin code into Kumbuka’s editor DOM. group is the preferred host-owned toolbar slot and defaults to insert. The stable groups are text, blocks, insert, tools, and plugins. allowed_groups is the bounded set an administrator may choose; when omitted, the contribution stays in its preferred group. order is a hint from -1000 to 1000; Kumbuka applies administrator ordering first and uses the stable plugin-id:module-id contribution ID to break ties.

A single action remains a direct toolbar button:

- type: editor-insert
  id: strikethrough
  name: Strikethrough
  markdown: "~~"
  suffix: "~~"
  placeholder: strikethrough text
  mode: wrap
  group: text
  allowed_groups: [text]
  order: 20
  icon: strikethrough-lucide

editor-menu

Groups closely related editor-insert modules behind one host-rendered toolbar icon. The menu owns its stable ID, label, icon, preferred and allowed groups, and default order. children contains two to sixteen unique editor-insert IDs in plugin-owned order. Administrators move, hide, or order the menu as a unit; they cannot reorder its children.

modules:
  - type: editor-insert
    id: note
    name: Note
    markdown: "!!! note\nImportant information."
    icon: message-square-lucide
  - type: editor-insert
    id: info
    name: Info
    markdown: "!!! info\nInformation."
    icon: info-lucide
  - type: editor-insert
    id: tip
    name: Tip
    markdown: "!!! tip\nHelpful tip."
    icon: lightbulb-lucide
  - type: editor-insert
    id: success
    name: Success
    markdown: "!!! success\nCompleted successfully."
    icon: circle-check-lucide
  - type: editor-insert
    id: warning
    name: Warning
    markdown: "!!! warning\nImportant warning."
    icon: triangle-alert-lucide
  - type: editor-insert
    id: danger
    name: Danger
    markdown: "!!! danger\nDangerous operation."
    icon: octagon-alert-lucide
  - type: editor-menu
    id: callouts
    name: Callouts
    description: Insert a callout block.
    icon: message-square-warning-lucide
    group: insert
    allowed_groups: [insert, blocks, plugins]
    order: 30
    children: [note, info, tip, success, warning, danger]

Toolbar metadata is declarative. Plugins cannot provide toolbar HTML, CSS, JavaScript, pixel positions, DOM locations, or relative placement such as “after button X”. Icons are names from Kumbuka’s validated host icon catalog; an omitted icon uses the host fallback.

icon-resource

Adds a declarative icon set from a packaged JSON asset. Kumbuka validates the resource and emits the SVG wrapper itself; plugin-provided SVG markup is not trusted directly. Icon names join the shared icon catalog and disappear when the owning plugin is disabled or removed.

Usage selectors

Executable source-aware modules can declare usage rules so Kumbuka can avoid invoking a plugin for pages that cannot use it:

modules:
  - type: renderer-extension
    id: diagrams
    stage: postprocess
    usage:
      - fence: mermaid

Each rule contains exactly one selector:

  • contains — literal Markdown text;
  • macro — a standalone macro name;
  • substitution — an inline substitution prefix;
  • fence — a fenced-code language, or * for any fenced block.

Selectors are performance hints and must not create false negatives. Modules without selectors remain active for all candidate renders. Macro modules can infer their selector from the declared macro name.

Permissions required by executable modules are described in Capabilities.