Clipbus plugins

Plugins let Clipbus act on what you copy — detect the content, render a rich inline preview, and add quick actions. They're built with the open @clipbus/plugin-sdk, and their UI is a web page (the official template and examples are built with Vue 3).

Overview

A Clipbus plugin is a small module that hooks into the clipboard. Each plugin can provide up to three kinds of capability — you implement only the ones you need.

detectorDetect

Inspect copied content and produce structured artifacts (attachments).

rendererRender

Resolve an attachment in Node, then draw its card in a WebView — tables, swatches, highlighted code.

actionAct

Run an operation on a single item on demand — auto-run, or a draft form.

The authoritative, versioned API surface ships inside the SDK package. After npm install read node_modules/@clipbus/plugin-sdk/docs/README.md (map) and API.md (capability truth). This page explains the concepts; the SDK docs are the source of truth.

How it works

When you copy something, Clipbus runs the registered detectors over the content. A detector that recognizes the content returns one or more artifacts — typed payloads that become attachments on the clipboard item. A renderer then draws a card for each attachment, shown in the attachment panel under the item.

Copydetectorartifact[]rendererattachment card

Cards are collapsible: a chip labels the type, a one-line preview sits beside copy and expand controls, and the expanded body shows the full result.

Runtime & UI

A plugin spans two isolated contexts. Your Node code is registered through one definePlugin({ detectors, attachmentRenderers, actions, messageHandlers }) call and runs headless; every visible surface is a separate HTML page declared as a uiEntry in the manifest. The two halves never share memory — they talk over a bridge: the UI calls clipbus.runtime.invoke(), and the runtime answers from its messageHandlers.

Node runtimeWebView UI
Entryruntime.nodeEntryuiEntry HTML
You writedefinePlugin({ … })HTML + clipbus.* calls
Host APIhost.*clipbus.*

Not every capability needs both halves — that is the distinction that matters:

CapabilityRuns inRuntime handlerUI entry
detectorNode onlydetect()
attachmentRendererNode + WebViewresolveAttachment()uiEntry card
action · auto-runNode onlyrunAutoAction()
action · draftNode + WebViewresolveSession()uiEntry form

Detector

A detector turns raw clipboard input into typed artifacts. It receives the input and returns an array — empty when nothing matches, so several detectors can coexist. Detectors typically run a priority chain and stop at the first hit.

features/decode/detector.ts · illustrative
// detect(input) -> artifact[]
export const decodeDetector = {
  async detect(input) {
    if (input.content.kind !== "text") return [];
    const { header, payload } = tryDecodeJwt(input.content.text);
    if (!header) return [];
    return [{
      attachmentType: "plugin.example.decode.preview",
      attachmentKey: input.item.id,
      payloadJson: JSON.stringify({ header, payload }),
    }];
  },
};

  // no match — return empty; other detectors still run
  return [];

Renderer

A renderer owns one attachment type. Its runtime side, resolveAttachment, returns the card's display name and the buttons to seed. Its UI side is the uiEntry HTML that draws the card — the official template uses Vue 3.

features/decode/renderer.ts · illustrative
export const decodeRenderer = {
  async resolveAttachment(input) {
    const payload = JSON.parse(input.attachment.payloadJson);
    return {
      displayName: "JWT",
      buttons: [{ id: "copy", label: "Copy" }],
    };
  },
};

Each renderer sets height in its manifest entry — a fixed number (1–800), "auto" (content-driven, default bounds 80–800), an explicit { min, max }, or omit for the default 80–400. For "auto" and { min, max } the card UI calls clipbus.window.autoFit(), a SDK DOM helper that observes content size and calls window.setHeight.

Because the card is an ordinary WebView page you can render a color swatch, a QR code, a key/value table, or a fully highlighted JSON tree. To read host settings use clipbus.settings.get(key) / getAll().

Action

Actions run on the current Action value. The runtime receives the original sourceItem separately from the current content, so auto-run results can feed the next Action. lifecycle: 'auto-run' runs via runAutoAction with no UI, while lifecycle: 'draft' opens a uiEntry form backed by resolveSession. During development you can preview a draft form with ?view=action, just like ?view=renderer for renderers. In the real host, a completed draft with a text, image, or path-reference result is presented for confirmation and can be explicitly advanced by the user; none cannot advance, and completion never auto-advances. The Preview harness records submission but does not simulate the host's result-confirmation, next-step filtering, rollback, or focus state machine.

The Toolbox plugin

The open-source plugin.clipbus.toolbox (awesome-clipbus-plugins/clipbus-toolbox-plugin) is a complete real example demonstrating all three capability kinds.

Detector + Renderer — decode preview

The decode-detector (with supportedInputKinds: ["text"]) produces a plugin.clipbus.toolbox.decode.preview attachment. Its renderer card uses height: { min: 32, max: 480 }. The detector runs a priority chain and stops at the first hit:

OrderTypeDetects & shows
1JWTheader.payload.signature structure — decoded header / payload JSON.
2Escaped JSONA "…" or \"-escaped string, unescaped and formatted.
3URLPercent-encoded %XX text, decoded.
4Timestamp10-digit (s) or 13-digit (ms) Unix epoch in a sane year window.
5Date stringA Date.parse-able string with date/time separators.
6Base64Standard or URL-safe, printable ratio ≥ 95%, decoded text.

The collapsible card shows a type chip, a one-line preview, a copy button, and an expand chevron. The expanded body shows the full decoded content with JSON highlight, or time details — local / UTC / ISO / epoch — using the toolbox's own default format yyyy-MM-dd HH:mm:ss.

Auto-run actions — case convert

Six auto-run actions rewrite the copied text in place: uppercase, lowercase, camelCase, pascalCase, snakeCase, and kebabCase. All declare supportedInputKinds: ["text"].

Draft action — image edit

A Crop & Compress draft action (with supportedInputKinds: ["image"]) opens a uiEntry form to crop and recompress an image item.

Plugin anatomy & manifest

A plugin is split by feature — each capability in its own self-contained folder. plugin.ts is the definePlugin entry that registers every handler. manifest.json declares the plugin's identity, runtime, and permissions.

manifest.json
{
  "schemaVersion": 3,
  "plugin": {
    "id": "plugin.example.my-plugin",
    "title": "My Plugin",
    "version": "1.0.0"
  },
  "runtime": {
    "nodeEntry": "dist/plugin.js",
    "uiRoot": "dist/ui"
  },
  "install": "npm install --prefix . --ignore-scripts",
  "permissions": ["setTags", "setPinned", "setAttachment", "setSearchExtension"],
  "attachmentRenderers": [/* ... */],
  "detectors": [/* ... */],
  "actions": [/* ... */]
}
project structure
your-plugin/
├── manifest.json            # plugin id, permissions, install hook
├── package.json            # depends on @clipbus/plugin-sdk
├── src/
│   ├── features/<name>/
│   │   ├── payload.ts       # artifact / draft types
│   │   ├── detector.ts      # detect → artifact[]
│   │   ├── renderer.ts      # resolveAttachment
│   │   ├── action.ts        # runAutoAction / resolveSession
│   │   ├── app.vue          # card / form UI
│   │   └── main.ts          # or index.html for standalone UI
│   ├── shared/
│   ├── preview/
│   └── plugin.ts            # definePlugin — registers handlers
└── tests/runtime/

Getting started

Start by forking the official template github.com/scubers/clipbus-template-plugin — public, mirrors the in-repo template, and minimal but covers every extension point (detector, a compact and an expanded renderer, an auto-run action, a draft action). A fork gives you a production-ready skeleton.

Recommended — vibe-code on the template. It ships complete docs — a bilingual README / GUIDE and an AGENTS.md written for AI assistants — and depends on @clipbus/plugin-sdk, whose API.md / SPECIFICATION.md are the capability truth source. Point an AI assistant at these bundled docs and let it build on your fork: full context, no need to dig into SDK internals.

Local development requires Node.js ≥ 18.

terminal
npm install        # pulls & builds @clipbus/plugin-sdk
npm run dev        # Vite preview workbench
#   ?view=renderer  → preview an attachment card
#   ?view=action    → preview a draft action form
npm test           # integration tests
npm run build      # typecheck + lint + build → dist/

To debug inside the app, open Settings → Plugins → Developer Plugins and Add Path to the directory containing your manifest.json. A declared install hook runs automatically (cwd = that directory); logs go to <AppData>/development-plugins/<id>/install-logs/ and stay out of your git status. Use Reload to re-read the manifest, Run Install to re-run the install hook, and View Logs if install fails.

API reference (SDK)

Everything an author can use is generated into the SDK package, always matching your installed version, so it never drifts from this page. You don't need to read the SDK's internal source.

  • Docs mapnode_modules/@clipbus/plugin-sdk/docs/README.md
  • Capability truth sourcenode_modules/@clipbus/plugin-sdk/API.md (generated; wins on any conflict)
  • Extending capabilitiesSPECIFICATION.md, Ch. 3
  • npm@clipbus/plugin-sdk · refresh with npm update @clipbus/plugin-sdk
Code samples on this page are illustrative and may lag the installed SDK. When in doubt, the SDK's API.md is authoritative.

Plugin limits

The free tier includes up to 3 active plugins per type (detector / renderer / action). Clipbus Pro lifts these limits to unlimited plugins (and adds Cloud Sync) as a one-time purchase. See pricing for details.