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
- Open Settings → Extensions → Open folder. That is the
extensionsfolder inside kdashboard’s data folder. - Drop the extension’s folder in it.
- 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 | |
|---|---|
id | Lowercase letters, digits and dashes, up to 64 characters. Defaults to the folder name. |
name, version | Required |
main | The entry module, inside the folder. Defaults to index.js. |
api | The 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
| Member | What 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, … |
cluster | context, namespace and selectedResource — read-only, always current |
toast | success, error, warning, info |
openResource(type, name, namespace?) | Opens a resource’s detail |
openExternal(url) | Opens a URL in the system browser |
storage | get and set: key/value storage private to your extension, kept in the settings file |
log | info, 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.