Self-hosted service
bjarneo/ku avatar
bjarneo/ku

bjarneo/ku: a read-only-first Kubernetes TUI for the terminal

A fast, keyboard-driven Kubernetes TUI. Browse any resource, edit objects, follow logs, and shell into pods.

563 stars23 forksGoMIT

At a glance

What is it?
ku is a keyboard-driven Kubernetes TUI written in Go, inspired by k9s and lazygit. It starts read-only, hides mutating keys until you confirm edit mode, and keeps CRDs out of the sidebar until you add them by hand.
Who is it for?
Adopt ku if you want a terminal client that cannot touch your cluster until you press Shift+E and confirm, and you are willing to hand-edit ~/.config/ku/config.yaml to get your CRDs into the sidebar. Skip it if you need a mouse-driven UI, a web dashboard, or browser access for people who do not use a shell; the README points those users at Lens or Headlamp.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What ku does that kubectl does not

kubectl is a one-shot command runner. Every question costs a new invocation, and the answer scrolls away. ku keeps a persistent view open: a resource nav on the left, a server-rendered table on the right, and a status bar that only shows keys that currently do something. The README describes the layout as lazygit-style, with Tab moving between panes.

The intended user is someone who already knows Kubernetes and is tired of retyping kubectl get pods -n foo -o wide. The README also names who should not bother: anyone who wants a mouse-driven UI is pointed at Lens or Headlamp. That is an unusually direct piece of positioning, and it is accurate. ku has no browser surface and no point-and-click affordance.

Two smaller conveniences matter more than they look. C shows the equivalent kubectl command for whatever is selected, which makes the TUI a teaching surface rather than a black box. O opens upstream Kubernetes docs for known resources. Both are read-only, so they work before you ever enter edit mode.

Read-only by default: the mode gate and what it actually blocks

This is ku's main design decision and the one worth arguing about. On launch, every mutating or live access action is off. The README lists them explicitly: edit, delete, rollout restart, scale, CronJob trigger, cordon, drain, shell into pods or nodes, and Service port-forward. Read, describe, YAML, logs, and the kubectl command preview still work.

The gate is visible. The header chip reads a green READ-ONLY and flips to a red EDIT after you press Shift+E or pick "Enter edit mode" from the Ctrl+K command palette and confirm the prompt. Disabled keys are removed from the footer hints and the command palette rather than shown greyed out, so the interface does not advertise actions you cannot take. Pressing ? summarizes the active mode.

The README frames the rationale as protecting against fat-fingering, which is honest about the threat model. It is a guard against your own muscle memory, not against a compromised kubeconfig or an over-permissioned service account. If your RBAC lets the process delete namespaces, edit mode will let it delete namespaces. Treat the chip as a speed bump, not a security control.

--dev is a second, orthogonal filter. It hides cluster admin resources (nodes, persistent volumes, storage classes, namespaces, events), disables node operations, and turns off CRD discovery. It composes with edit mode, giving four combinations: plain, --edit, --dev, and --dev --edit.

Installing ku and getting your first resource on screen

The README offers three install paths. The installer script is the shortest. It fetches and runs install.sh from the main branch, so you are trusting whatever is at that URL at the moment you run it rather than a pinned release artifact.

bash
curl -fsSL https://raw.githubusercontent.com/bjarneo/ku/main/install.sh | sh

If you have Go 1.26.3 or newer, the module path works directly and skips the script:

bash
go install github.com/bjarneo/ku@latest

From a clone, make install builds with -trimpath and stripped linker flags, then picks a destination by precedence: ~/.local/bin if it is on PATH, otherwise /usr/local/bin if that directory exists, otherwise the last directory on PATH. You can override the choice with PREFIX=...

bash
make install   # builds and installs to ~/.local/bin, /usr/local/bin, or your last $PATH dir
go build -o ku .

Running ku requires a reachable cluster; the binary does not ship a demo mode. The quick start flags are worth learning before anything else. ku alone opens your current context and remembered namespace. -n scopes the starting namespace, --resource deploy starts on a resource type, and --theme tokyonight switches the color scheme.

bash
ku                       # current context, remembered namespace
ku -n kube-system        # start in a namespace
ku --resource deploy     # start on a resource type
ku --edit                # start in edit mode (default is read-only)

Press ? for help, Ctrl+K for the command palette, and Shift+E to toggle edit mode. ku also ships a self-upgrade subcommand that replaces the current binary with the latest release, which is convenient but means the binary you are running can be swapped underneath you.

Adding CRDs to the sidebar with ku config init

The sidebar lists common built-in resources by default. Custom resources are not shown until you add them. This is the part of ku that will cost you the most setup time, and it is deliberate: the tool does not enumerate every CRD in your cluster and dump it into the nav.

Start by seeding the config file, then check where it landed.

bash
ku config init     # write ~/.config/ku/config.yaml with the defaults
ku config path     # print the config file location

Add entries under any section, or create a new one. The resource field accepts a plural, singular, kind, short name, or group-qualified key. The README recommends the group-qualified form to avoid ambiguity, which matters when two operators both ship a resource called something generic. The example below mixes all three styles.

yaml
sidebar:
  - section: CRDs
    items:
      - { label: ScaledObjects, resource: scaledobjects.keda.sh }
      - { label: Certificates, resource: certificates.cert-manager.io }
      - { label: HPAs, resource: horizontalpodautoscalers }

Restart ku to apply the change. Two behaviors are worth knowing before you spend time debugging a missing entry: resources your cluster does not expose are dropped silently, and empty sections are hidden. So a typo in a group-qualified key and a CRD that genuinely is not installed look identical on screen. The README does not document an error message for either case, and it does not document rollback for a config edit that breaks startup.

The config file handles sidebar customization; session state goes in ~/.config/ku/state.json, which is where the remembered context and namespace live. The full reference is in docs/configuration.md.

Where ku is the wrong tool

The read-only default cuts both ways. If your job is routine read-only inspection across many clusters, you will press Shift+E and confirm on every launch where you need to restart a deployment, and there is no documented way to persist edit mode other than passing --edit each time. The README does not describe a config key for a default mode, so the flag is the mechanism.

CRD handling is the sharper limitation. A cluster running a large operator stack will have dozens of custom resources, and ku shows none of them until you hand-write each entry and restart. Tools that discover CRDs automatically will feel faster on day one in that environment. ku's --dev flag turns CRD discovery off entirely, which is fine for an app developer and wrong for a platform engineer who lives in custom resources.

There is also no documented multi-cluster view. Contexts come from your kubeconfig, and ku remembers the last one, but the README describes no split view or context switcher beyond what your kubeconfig already provides. And the port-forward, shell, and node operations are all gated behind edit mode, so a read-only session cannot tunnel to a Service even though port-forwarding changes nothing on the cluster.

Finally, this is a single-maintainer project under the bjarneo namespace. The last push was on 2026-08-03, which is recent, and the repository is not archived. That is a point in its favor, but it is one person's release cadence you are depending on.

ku against k9s and Lens: three different answers

The README names its inspirations directly: k9s, Lens, and lazygit. Lens is the mouse-driven GUI the README recommends when you want one; it runs as a desktop application with a graphical resource browser. ku is the opposite bet: no pointer, no window chrome, and a footer that only lists keys valid in the current mode.

k9s is the closer comparison and the more useful one. Both are Go TUIs over client-go that render resource tables in the terminal. The visible difference is the mode gate. ku's README describes a read-only default with an explicit confirmation prompt before mutating keys appear; the README does not describe k9s's behavior, so the honest comparison stops there. What ku states about itself is that edit, delete, restart, scale, cordon, drain, shell, and port-forward are all off until you opt in.

The second difference is configuration surface. ku exposes a small YAML file for sidebar customization and a state.json for session memory, and it expects you to add CRDs by hand. A tool that auto-discovers CRDs trades that setup cost for a noisier nav. Neither approach is strictly better; they optimize for different clusters.

The third is the kubectl command preview on C. It is a small feature with an outsized effect on trust, because you can see exactly what a given view maps to before you act on it.

Licence, upgrade cost, and what to check before adopting

ku is MIT licensed, which is permissive and imposes no copyleft obligation on your own code. The repository ships a LICENSE file at the top level. Nothing in the README or the release list suggests a separate commercial tier, a hosted component, or a telemetry endpoint, so there is no vendor relationship to manage. This is a description of the licence, not legal advice; read LICENSE yourself if the distinction matters to your organization.

Upgrade cost is low by design. ku upgrade replaces the current binary with the latest release, and the three releases listed in the repository (v0.9.0, v0.10.0, v0.11.0) all landed within a two-week window in July and August 2026, which suggests a fast minor-version cadence rather than long-lived stable branches. The README does not document a changelog policy or a deprecation window, so a config key you rely on today has no stated guarantee of surviving the next minor release. Pin a version if that matters.

Building from source requires Go 1.26.3 or newer, which is a hard floor from go.mod, not a suggestion. The dependency list is mostly charm.land Bubble Tea v2 packages plus k8s.io/client-go v0.34.1, so the build is not exotic but it is not tiny either.

What to verify first: that your kubeconfig's current context is the one you expect, that your CRD group-qualified keys resolve, and that your RBAC actually restricts the mutating verbs ku exposes in edit mode. The green-to-red chip tells you what the UI will send, not what the cluster will allow.

Editorial conclusion

Adopt ku if you want a terminal client that cannot touch your cluster until you press Shift+E and confirm, and you are willing to hand-edit ~/.config/ku/config.yaml to get your CRDs into the sidebar. Skip it if you need a mouse-driven UI, a web dashboard, or browser access for people who do not use a shell; the README points those users at Lens or Headlamp. Before rolling it out, verify that your cluster's CRD group-qualified keys resolve as you wrote them, and confirm which of the mutating actions (drain, cordon, port-forward, shell) your RBAC actually permits, because ku's read-only default is a UI gate, not an authorization boundary.

Frequently asked questions

How do I install ku?

The README gives three paths: run the installer with curl -fsSL https://raw.githubusercontent.com/bjarneo/ku/main/install.sh | sh, use go install github.com/bjarneo/ku@latest with Go 1.26.3 or newer, or clone the repository and run make install. Running ku requires a reachable cluster.

How do I add CRDs to the ku sidebar?

Run ku config init to write ~/.config/ku/config.yaml, then add items under a section using the group-qualified resource form, such as scaledobjects.keda.sh. Restart ku to apply the change; resources your cluster does not expose are dropped and empty sections are hidden.

Why can I not edit or delete anything in ku?

ku starts in read-only mode, where edit, delete, rollout restart, scale, CronJob trigger, cordon, drain, shell, and Service port-forward are all disabled. Press Shift+E or open the command palette with Ctrl+K and pick "Enter edit mode", then confirm the prompt; pass --edit to start in edit mode instead.

Official sources

  1. bjarneo/ku on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bjarneo-ku.svg)](https://hysenlabs.com/projects/bjarneo-ku)