Build the app
You need Node.js 24 or later (the repository’s.nvmrc asks for 26) and npm. To package the app, you also need:
- On a Mac: Xcode 26 or later. Lumovi’s icon is compiled by Xcode’s
actool, and packaging stops without it. - On Linux:
rpm, to build the.rpm(sudo apt-get install rpmon Debian and Ubuntu).
1
Get the code
2
Build the installers
release/, for x64 and arm64: a .dmg and .zip on macOS, one .exe on Windows, and an AppImage, .deb and .rpm on Linux. npm run package builds an unpacked app there instead, which is quicker.A copy you build yourself isn’t signed or notarized. For everyday use, the official releases are signed on macOS and come with checksums and provenance.The installers
npm run dist makes look for new versions the way the official ones do, on Lumovi’s GitHub releases. To keep running your own build, turn off Help → Check for Updates Automatically. An app from npm run package can’t update itself.Run it while you work on it
dev and dev:mock reload as you change the code. The demo clusters are the ones the tests use: a busy one with every kind of problem, an empty one without metrics, one with 2,500 pods, and contexts that fail in every way a real one can.
Commands
How it’s built
src
main
backend
server
preload
renderer
shared
charts
tests
e2e
web
views
mock-cluster
mock-oidc
integration
docs
build
scripts
A few ideas hold it together:
- One page, two hosts. The interface talks to its host through one typed API: over IPC in the desktop app, over a WebSocket when served. Both answer from the same handlers. What only one can do, like port forwards on the desktop or sessions on the server, is an optional part of that API, which the page shows only when it’s there.
- Credentials never reach the page. It runs sandboxed, with context isolation, no Node.js access and a strict Content Security Policy. Every IPC call is checked for its sender and validated in the main process, the only place that talks to clusters. See Privacy and security.
- Plain REST. Authentication comes from
@kubernetes/client-node, and requests are plain REST calls with gzip, so any API path, metrics and logs included, works the same way. - Status colors are for health. They always come with an icon and a label, and charts use a palette checked for color blindness in both themes.
Tests
Lumovi keeps 100% end-to-end coverage of statements, branches, functions and lines, enforced in CI.-
End-to-end tests drive the real Electron app with Playwright, against a mock API server with the demo clusters. Coverage is collected from all three Electron processes, the server and the page, and merged across Linux, macOS and Windows. The test windows stay invisible and never take focus, so you can keep working; set
LUMOVI_E2E_FOREGROUND=1to watch them. - Web tests start the server against the same mock clusters and a mock OpenID Connect provider, and drive the page in Chromium: every way of signing in, sessions ending, the WebSocket dropping and coming back, shells, logs and Helm.
-
View checks (
npm run views:check) check every kind, path, template, link, related list and action in Lumovi’s views and add-ons against the CRDs of their tools, pinned intests/views/crds/sources.json. A misremembered field fails here, rather than showing nothing in the app. -
Integration tests check the same app against a real three-node kind cluster with metrics-server and kube-prometheus-stack. They change things for real and check the result with
kubectl, and they install the image with the Helm chart and sign in to it, behind a proxy and with a token. They need Docker, kind,kubectland Helm:npm run test:kindcreates the cluster and runs the tests in one go. The cluster gets its own kubeconfig in.kind/. Your~/.kube/configisn’t read or changed.
Contributing
Bug reports, ideas and pull requests are welcome. The contributing guide has the details; in short:1
Agree on the approach
For anything bigger than a small fix, open an issue first. Lumovi is for looking after workloads, clusters and Helm releases; managing kubeconfig files is out of scope.
2
Make a focused change
Branch from
main, and match the style of the code around it: TypeScript in strict mode, Prettier and ESLint, and the design tokens for anything visual.3
Test it like a user
Add or update end-to-end tests in
tests/e2e/ (and tests/web/ for what’s different when served). Tests drive the real app through its interface. A new cluster state goes in the demo fixture, tests/mock-cluster/fixtures/, when it’s realistic.4
Check it
Run
npm run verify. Screenshots help for interface changes: on a Mac, npm run screenshots -- overview pods takes those two, light and dark.5
Open a pull request
Describe what changed and why.
Adding a tool
Lumovi shows what popular operators run through views and add-ons, written as YAML insrc/renderer/src/views/<tool>.yaml, in the view format. An add-on gives a tool its entry in the sidebar and lists its kinds; views say how each kind is shown. Adding a tool needs no code, and is a welcome first contribution.
1
Pin the tool's CRDs
Add its release to
tests/views/crds/sources.json, under the add-on’s name, with the URLs of its CRD manifests, and run npm run crds -- <name>. That keeps what the check needs in tests/views/crds/<name>.json.2
Write the add-on and its views
In
src/renderer/src/views/<name>.yaml, write the AddOn, then a View for each kind worth more than the generic columns. Status rules help most: say what healthy, in progress, failing and paused look like for this tool.3
Check them
Run
npm run views:check. Labels and annotations aren’t in schemas, so check those against the tool’s documentation, or a real cluster.4
Look at it
Put the file in
~/.lumovi/views while running npm run dev against a cluster with the tool installed. Views are read again when you refresh (⌘R; CtrlR on Windows and Linux).