Plugin Capability Declarations

capabilities are the contract between a plugin and Ting Reader. They describe which entries a plugin exposes, who calls them, which runtime function is invoked, what UI should be shown, and which permissions must accompany the feature.

Where Capabilities Are Declared

Declare capabilities in the capabilities array of plugin.yml or plugin.yaml. Each item needs at least id and kind. If invoke is omitted, the backend uses the capability id as the runtime method name.

capabilities:
  - id: assistant.panel
    kind: ui_extension
    invoke: openAssistant
    slot: global.floating_action
    title:
      zh: 书单助手
      en: Booklist Assistant
    icon: message-circle
    priority: 20
    contexts: [global, book, reader]
    render:
      mode: web_container
      entry: ui/assistant.html

  - id: metadata.search
    kind: metadata_provider
    invoke: search
    auto_scrape: true
    search_fields:
      - key: title
        label: { zh: 书名, en: Title }
        required: true
        default_from: book.title
    result_fields:
      - key: title
        label: { zh: 书名, en: Title }
      - key: author
        label: { zh: 作者, en: Author }
      - key: cover_url
        label: { zh: 封面, en: Cover }

  - id: assistant.tools
    kind: tool_provider
    invoke: invokeTool
    tools:
      - name: books.recommend
        description: Recommend books from the current user's library

permissions:
  - type: books_read
  - type: progress_read
  - type: network_access
    value: api.example.com
FieldDescription
idUnique capability ID inside the plugin, such as metadata.search or assistant.panel.
kindCapability type. This determines how the system discovers and invokes it.
invokeRuntime function name. JavaScript maps this to globalThis[invoke]; WASM and Native runtimes dispatch through their exported entry points.
title / labelUser-facing entry name. Use a string or a localized { zh, en } object.
iconClient entry icon. UI plugins can use lucide names such as message-circle, or an emoji.
prioritySort order within the same slot. Smaller numbers appear first.
contextsApplicable contexts, such as global, book, reader, and chapter.

Common Capability Kinds

kindPurposeCommon fields
metadata_providerSearch and scrape book or audiobook metadata.auto_scrape, search_fields, result_fields, result_field_labels
format_handlerDetect formats, produce playback URLs, decrypt streams, and read/write media metadata.extensions or matches.extensions
content_processorProbe documents, list sections, read chunks, paginate, and render pages.operations, extensions
ui_extension / client_extensionClient buttons, panels, settings forms, or Web UI.slot, title, icon, render, contexts
http_routePlugin HTTP routes such as RSS, callbacks, and public feeds.route.method, route.path, route.auth
tool_providerExpose tools to AI assistants, clients, or other plugins.tools[].name, tools[].description
plugin_storeProvide a configurable plugin source.Usually returns { plugins: [...] }
task_handlerReceive custom background tasks.task_types
event_handlerSubscribe to system events.events; use * to subscribe to all events
capabilities only declare how a plugin can be called. Reading books, progress, media, cache, files, or network resources still requires matching permissions.

UI Entries, Icons, and Menus

For ui_extension, the slot decides where the entry appears. The Web client reads title, icon, priority, and render to build entry menus. global.floating_action appears in the bottom-right plugin entry menu.

capabilities:
  - id: assistant.panel
    kind: ui_extension
    slot: global.floating_action
    title: { zh: 书单助手, en: Booklist Assistant }
    icon: message-circle
    render:
      mode: web_container
      entry: ui/assistant.html

  - id: quick.note
    kind: ui_extension
    slot: global.floating_action
    title: { zh: 快速笔记, en: Quick Note }
    icon: "📝"
    render: action
slotLocation
global.floating_actionGlobal bottom-right plugin entry menu.
global.panelGlobal plugin panel entry; also used as a fallback when no floating action exists.
settings.sectionPlugin settings area.
book.detail_actionBook detail action entry.
reader.toolbar_actionReader toolbar action.
reader.side_panelReader side panel.
reader.document_viewerDocument reader extension.
render.modeDescription
web_containerLoads an HTML entry from ui/ or assets/; the plugin UI talks to the host with postMessage.
schemaThe client renders a simple form from schema.
builtinUses a host-provided built-in component, such as the document reader.
actionInvokes the capability directly when the entry is clicked.

For icon, prefer lucide icon names such as message-circle, messages-square, or book-open, or use an emoji. The Web client resolves lucide names first and falls back to text rendering. Flutter first matches the Lucide icon catalog, then falls back to common Material mappings. Image icons support object syntax; Web supports http/https, data:image/..., and / paths, while Flutter supports http/https and assets/.

web_container render.entry is loaded through the plugin asset endpoint. Put static assets under ui/ or assets/, and reference CSS, JS, and images with relative paths. External links can be ordinary <a target="_blank" rel="noopener noreferrer">; do not depend on the return value of window.open() to decide whether the browser opened successfully.

Match Capabilities with Permissions

Plugin behaviorCommon permissions
Read books and librariesbooks_read
Read chapterschapters_read
Read recent playback progressprogress_read
Get playback URLsmedia_read_url or media_read
Store plugin cachecache_read, cache_write
Create or update playlistsplaylists_read, playlists_write
Call external APIsnetwork_access; prefer a concrete domain
Write metadata or create tasksmetadata_write, task_create; usually requires admin context

When a permission is missing, HostGateway rejects the call with a permission error. During development, start with minimal permissions and add only what the feature actually needs.