Skip to content
Docs/Reference/Extensions

Extensions

Add commands, row actions, settings tabs and UI components to kdashboard with a small ES module.

An extension is a folder with a manifest.json and an ES module. kdashboard loads it at start-up and hands it an API to register things with. The app works the same with none installed.

Extensions run inside the app, with the app’s privileges and your cluster credentials. Only install extensions you trust.

Install an extension

  1. Open Settings → Extensions → Open folder. That is the extensions folder inside kdashboard’s data folder.
  2. Drop the extension’s folder in it.
  3. Click Reload app. Extensions load once, at start-up.

The tab lists each extension with its state — active, failed, or invalid — what it registered, and the error if it did not load. An extension that throws is marked failed, and the app carries on without it.

Write one

extensions/
  audit-log/
    manifest.json
    index.js

manifest.json

{
  "id": "audit-log",
  "name": "Audit log",
  "version": "1.0.0",
  "description": "Writes every restart and delete to a file",
  "main": "index.js",
  "api": 1
}
Field
idLowercase letters, digits and dashes, up to 64 characters. Defaults to the folder name.
name, versionRequired
mainThe entry module, inside the folder. Defaults to index.js.
apiThe extension API version. Must be 1; an extension written for another version is not loaded.

index.js

The module’s default export has an activate(ctx) function. It runs before the app mounts; everything must be registered there.

export default {
  activate(ctx) {
    ctx.registerCommand({
      id: "audit-log.open",
      label: "Open audit log",
      category: "Audit",
      action: () => ctx.toast.info("Audit log", `Context ${ctx.cluster.context}`),
    });

    ctx.registerAction({
      id: "audit-log.note",
      label: "Add note…",
      tier: "green",
      group: "operations",
      priority: 90,
      appliesTo: (resourceType) => resourceType === "deployments",
      execute: (resource) => ctx.storage.set(`note:${resource.metadata.name}`, Date.now()),
    });

    ctx.on("context-changed", ({ contextName }) => ctx.log.info("switched to", contextName));

    ctx.onStartup(async () => {
      const pods = await ctx.invoke("list_resources", {
        resourceType: "pods",
        namespace: ctx.cluster.namespace,
      });
      ctx.log.info(`${pods.items.length} pods at start-up`);
    });
  },
};

The API

MemberWhat it does
registerCommand(item)A command-palette entry: { id, label, category, action }
registerAction(def)An action in row menus and detail headers: { id, label, tier, group, priority, appliesTo, execute }
registerSettingsTab(tab)A tab in Settings that renders your component
registerMount(mount)A component in a named UI slot
registerKbdHint(hint)A key hint in the status bar
onStartup(hook)Runs once the app has mounted
on(type, handler)App events: context-changed, namespace-changed, resource-selected
invoke(command, args)The same calls the app makes to the cluster: list_resources, get_resource, get_resource_yaml, apply_yaml, …
clustercontext, namespace and selectedResource — read-only, always current
toastsuccess, error, warning, info
openResource(type, name, namespace?)Opens a resource’s detail
openExternal(url)Opens a URL in the system browser
storageget and set: key/value storage private to your extension, kept in the settings file
loginfo, warn, error, prefixed with your extension’s id

UI slots

app-overlay · app-top-banner · sidebar-header · sidebar-footer · cluster-rail-top · cluster-rail-bottom · status-bar-start · status-bar-end · table-header-trailing · table-row-leading · table-row-trailing · detail-panel-actions · detail-panel-tabs

Components for slots and settings tabs must be compiled Svelte 5 components. A plain ES module can still register commands, actions, hooks and event handlers.

Types

src/lib/extensions/api.ts in the kdashboard repository exports ExtensionContext, ExtensionModule and defineExtension. The reference this page follows is docs/extensions.md.