Skip to main content
A plugin tells Lumovi how to show your kinds. Its views say, for each kind, which columns matter, how to tell whether an object is healthy, which facts to show, which objects it relates to, and which changes people make to it. It’s a YAML file, and data only: it reads fields with the same JSONPath CRD printer columns use, and changes objects only with the patches and objects it spells out. This guide builds a plugin for an in-house Database kind, step by step. Swap in your own kind’s group and fields as you go.
The example’s custom resource looks like this:
Its operator labels each database’s pods with platform.example.com/database: orders, and keeps its backups as DatabaseBackup objects labeled the same way.
1

Find the kind and its fields

Open API resources in the sidebar and find your kind. Note its API group (platform.example.com) and kind (Database). Then open an object of it, and look at its YAML tab: that’s where the paths you’ll use come from.
2

Create the file

Plugins live in ~/.lumovi/plugins. Every .yaml or .yml file there is read, and each file is one plugin.
Create ~/.lumovi/plugins/databases.yaml with the smallest plugin there is, one view of one kind:
databases.yaml
A plugin says what it is before what it shows: its own version, the oldest Lumovi it works with under needs, and the API groups its kinds are in. Every kind it names is in one of those groups. Its name is lowercase letters, digits and hyphens.In Lumovi, press ⌘R (Ctrl+R on Windows and Linux). API resources now shows databases.yaml under Shown by for the kind, and Lumovi uses the database icon for it. Everything in the next steps goes into that view, beside its kinds.
3

Add columns

Columns come after the name and status, and replace the ones the API server prints.
type makes a column sort and read better: number right-aligns and sorts numerically, date reads like “2h ago” and sorts by time, boolean shows Yes or No, and count shows how many values a path finds.
4

Say what healthy means

Status rules are checked in order, and the first that applies decides the status. If none applies, Lumovi falls back to the usual conventions.
health is one of healthy, progressing, warning, critical or neutral: it picks the color, the icon, the sort order and the filter chip. label is what the status says, and detail shows on hover. Both are templates: {{ .path }} puts a value in, and ?? gives a fallback when the path finds nothing.
Comparisons ignore case, so even an unquoted equals: True, which YAML reads as a boolean, matches Kubernetes’ "True".
5

Add details

Details are facts shown in the detail panel’s Details section. They take the same fields as columns.
6

Link related objects

Links point to single objects, and appear under Related in the detail panel’s Overview: click one to open it. kind is a built-in kind (Secret, Pod, Node…), or a kind and its group (Certificate.cert-manager.io). The namespace is this object’s unless you set one.
A link whose kind or name comes out empty isn’t shown.
7

List what belongs to it

Related lists are the objects of another kind that belong to this one, found by their labels or a field selector. Each is a tab in the detail panel, with the kind’s usual columns.
  • A list of pods becomes the panel’s Pods tab, under its own name (Instances here), and brings Logs and Metrics tabs for those pods.
  • Every list needs labels or a fieldSelector, like 'spec.nodeName={{ .status.nodeName }}'.
  • Lists look in this object’s namespace unless you set a namespace. A list whose templates come out empty isn’t shown, since it would find the wrong objects.
8

Add actions

Actions patch the object, like kubectl patch. They show up in the object’s ⋯ menu, its right-click menu and the command palette; primary: true also makes one a button in the detail panel.
  • when offers an action only when it makes sense.
  • undo is a patch offered as Undo in the notification.
  • confirm asks first, with this text. Without it (and without inputs, or an object to create), the action runs at once, and has to say so: runs: at-once.
  • A patch can’t change what’s the cluster’s to set, like an object’s owners, finalizers, name or namespace. See what a patch can’t change.
  • {{ now }} is the current time, as Kubernetes writes times: handy for annotations a controller watches.
9

Ask for a value

An action can ask for values before it runs: text, a number, or a choice. Its templates use them as {{ input.name }}.
Resize… opens a dialog with a New size field, starting at the current size. The undo is filled in from the database as it was before, so Undo puts the old size back. A number input (type: number) gives a number, and a choice (type: choice) is one of its options, or of the values a from path finds.
10

Create objects

An action can create another object instead of patching this one, with create in place of patch:
Back up now… shows the backup as YAML before it’s created, with the name it will get, in the database’s namespace. Once it’s created, Open in the notification opens it. A value that’s a whole template copies what it finds, so spec: '{{ .spec }}' would copy the object’s whole spec. Creating can’t be undone from the notification.Every action checks your permissions first: it needs patch on the kind (or on its status, with subresource: status), or create on the kind it creates. It shows the equivalent command, kubectl patch or kubectl create, and can’t run in a read-only cluster.
11

Give it a place in the sidebar

A place in the sidebar gathers your kinds under one entry, with everything of them in one list and a tab for each. Add a label and the kinds to the plugin’s spec, beside views:
See Plugins.
12

Reload and check

Press ⌘R. If something’s wrong, All plugins, under Plugins in the sidebar, says so on the file’s row, Not in use. 1 problem to fix in the file., with the place in it:
A plugin is used whole or not at all: with a problem anywhere in its file, none of it is used, and its kinds fall back to Lumovi’s own views or the API server’s columns until you fix it.

The whole plugin

databases.yaml

Good to know

  • Quote templates and filters in YAML. A value that starts with {{ must be in quotes, or YAML reads it as a map. Quote paths with brackets or double quotes in them too, like '.status.conditions[?(@.type=="Ready")].status'.
  • A kind is one plugin’s. A plugin of yours shows kinds no other plugin has. To change how one of Lumovi’s plugins shows its kinds, copy its file from Lumovi’s plugins, keep its metadata.name, and edit it: yours is used in its place, all of it.
  • Every kind of a group. kind: '*' with a group covers every kind of that group, and the plugin then has that group to itself. A view for a kind itself wins over one for its group. See Whose a kind is.
  • A tool’s kinds, not Kubernetes’. Pods, Secrets and the other kinds Lumovi has pages for can’t be in a plugin. One it has no page for, like a Lease, a plugin can show without actions, named under shows.
  • Another folder. Set LUMOVI_PLUGINS_DIR to read plugins from somewhere else, like a folder your team shares in a Git repository.
  • Links work too. A link in the folder, named with .yaml or .yml at the end, is read like the file it points to, so you can link a plugin from elsewhere. A link to a file that’s gone can’t be read: All plugins lists it as not in use, with why, like It couldn’t be read: ENOENT: no such file or directory, …, and the other files still load.
  • Limits. Lumovi reads up to 200 files from the folder, each up to 256 KB. Its subfolders aren’t read, except a plugin with code, in the desktop app.
In your cluster: plugins everyone sees come from the chart’s plugins value, one entry per file. People can’t add their own from the browser. See Plugins for everyone.

Plugin format

Every field, path, condition and template, in one place.

Included plugins

Examples from cert-manager, Argo CD, Flux and more.