Plugin development
The @pragma-sh/plugin API — sidebar tabs, cards, commands, web views, agents, watchers, usage limits, and themes.
Pragma's own agent integrations are plugins. Everything they use is public, so anything you build sits at the same level as what ships.
import { definePlugin, defineSidebarTab, useProject } from "@pragma-sh/plugin";
function Queue() {
const project = useProject();
return <div>Queue for {project?.name ?? "none"}</div>;
}
export default definePlugin({
name: "Review Queue",
description: "Everything waiting on me, across every worktree.",
ui: {
sidebarTabs: [defineSidebarTab({ id: "queue", title: "Queue", component: Queue })],
},
});Getting started
Scaffold a plugin, register it, and load it.
UI contributions
Sidebar tabs and cards, settings pages, topper items, commands, and web views.
Agents & watchers
defineAgent, model lists, prefill, and the watcher that drives status.
Usage limits
defineUsageLimitProvider — power the usage-limits popover for your agent.
Runtime & themes
Hooks, storage, events, the SDK handle, and defineTheme.
The model
- A plugin is one self-contained ESM bundle (
mainin itspackage.json). - The host injects React, React DOM, the JSX runtime, zod, UI primitives, and icons —
never bundle them.
@pragma-sh/pluginis a compile-time stub that delegates to the host bridge (globalThis.__PRAGMA__). - Registration is declarative: a
plugins[]entry in.pragma/config.json(global or per project). Presence installs it; project scope wins over global. - The agent catalog, usage-limit providers, and server-side hooks run in the
pragma-pluginshost sidecar; UI contributions run in the desktop webview. OnedefinePlugincall contributes to both.
Browser-safe code
A static node: import or a module-scope process.* read in the plugin entry fails the webview
load (status: "failed"). Server-side work belongs in the sidecar hooks (onInstall,
onPragmaLoad) which run under Bun.