Renders Kubernetes resources (core kinds, built-ins, and CRDs) from Deskription definitions inside Podman Desktop: a category sidebar, definition-driven resource tables with live updates, and definition-driven detail views.
No — not the existing Kubernetes pages. This was the deciding question and the research result is worth recording:
- The extension UI surface is commands, menus, configuration, icons, and webviews. Webviews are the only way to render custom UI, and a webview always appears as its own entry in the left navigation bar (with the extension's icon) — you cannot inject components into, or add tabs/columns to, the built-in Kubernetes resource pages.
- Menu contribution targets are container-centric
(
dashboard/image|container|pod|volume|compose); there is no Kubernetes resource menu target. - The official Kubernetes Dashboard is itself just an extension that replaces
the built-in dashboard with its own webview; its public
@podman-desktop/kubernetes-dashboard-extension-apionly lets other extensions observe context health/permissions/counts, not add pages or resource views.
So this project is a standalone webview extension that contributes its own "Deskription" navbar entry — the supported, idiomatic path.
Second key finding that shapes the backend: Podman Desktop's kubernetes API
namespace only exposes getKubeconfig(), onDidUpdateKubeconfig, setKubeconfig(),
createResources(), and registerKubernetesGenerator(). There is no API to list
or watch arbitrary resources. Like the built-in dashboard, we therefore drive
@kubernetes/client-node
directly from the backend, using the kubeconfig path Podman Desktop points us at.
Three workspaces (packages/*), built separately, mirroring the official "full"
extension template (extension backend + webview frontend + shared contract):
| Package | Role |
|---|---|
packages/shared |
Framework-free core: Deskription types, definition merging, path resolution + value formatting, the RPC MessageProxy, and the DeskriptionApi frontend↔backend contract. Unit-tested. |
packages/backend |
The extension itself (extension.ts). Creates the webview, serves DeskriptionApi over RPC, owns the definition store (bundled defaults + live-watched cluster deskription.io CRs) and generic per-GVK informers. |
packages/frontend |
Svelte 5 webview: category sidebar → live resource table → detail view. Styled with Podman Desktop's injected --pd-* theme variables to look native. |
The loadable extension is packages/backend/ after a build: its package.json is
the manifest, dist/extension.js the entry, media/ the built frontend, icon.png
the navbar icon.
The built-in dashboard hand-writes a typed factory per kind. Deskription instead renders any kind from data, so the backend is generic:
discovery.tsresolves aGvk→ RESTplural+ namespaced-ness via the API server's discovery info (KubernetesObjectApi).resource-watcher.tsbuilds a cluster-wide informer (makeInformer) for that path; the cache stays in sync via list+watch and reconnects on its own.api-impl.tsref-counts these informers per kind and pushesResourceListUpdates to the webview on a per-kind subscription channel — that is the "watch-based live updates".
Definitions come from bundled defaults (the deskription repo's definitions/,
baked in at build time) merged with any deskription.io CRs found on the
cluster (also watched live), per the Deskription merging spec.
npm install
npm run build # bundles definitions, builds frontend (into backend/media) + backend
npm run watch # rebuild on change
npm run typecheck # all three packages
npm test # shared unit testsThen load packages/backend/ as a development extension in Podman Desktop
(Settings → Extensions → install from a local folder/Containerfile).
Bundled definitions are read from ../deskription/definitions by default; override
with DESKRIPTION_DEFINITIONS_DIR. Re-run npm run build:definitions after editing
them.
memory/cpucolumn types need the Kubernetes metrics API and currently render empty.status/conditionsrender as plain text (no badges/pills yet).- The generic informer (
discovery.ts+resource-watcher.ts) is the one piece exercised only against the@kubernetes/client-node1.4.0 type surface here, not yet against a live cluster — verify there first when wiring up real clusters.