kubert lets you hop between Kubernetes contexts and namespaces inside dedicated subshells. Each shell gets its own kubeconfig copy so you can keep production, staging, and local sessions open side-by-side without collisions. On top of that, kubert offers optional guard rails (context protection), multi-context execution, and shell hooks to give you a contextual workflow similar to kubectx, kubens, and kubie in one tool.
Jump to: Installation | Quick Start | Configuration
- Context isolation: spawn shells with temporary kubeconfig files so contexts never bleed into other terminals.
- Namespace management: switch namespaces within an active kubert shell without touching other sessions.
- Context protection: block (or confirm) risky
kubectlcommands in sensitive contexts. (optional, not enabled by default) - Multi-context fan-out: run a command across many contexts with glob or regex selection.
- Interactive selection: opt into fuzzy selection with
fzfor list contexts/namespaces in non-interactive environments. - Shell hooks: run pre/post shell commands to e.g. set tab titles, or log usage.
brew install idebeijer/tap/kubert --caskInstalls the latest binary from GitHub Releases.
curl -fsSL https://raw.githubusercontent.com/idebeijer/kubert/main/scripts/install.sh | bashInstall to a custom directory (e.g., ~/.local/bin):
curl -fsSL https://raw.githubusercontent.com/idebeijer/kubert/main/scripts/install.sh | bash -s -- ~/.local/binyay -S kubert-binPre-built packages are available on the GitHub Releases page.
go install github.com/idebeijer/kubert@latestIf you installed via Homebrew, completions are usually installed automatically. See Homebrew's Shell Completion docs.
For manual installation, add the following to your shell config (e.g., ~/.bashrc, ~/.zshrc):
# Bash
source <(kubert completion bash)
# Zsh
source <(kubert completion zsh)
# Fish
kubert completion fish | sourceBy default, kubert searches for kubeconfigs in these paths (~/.kube/config, ~/.kube/*.yml, ~/.kube/*.yaml). If your config files are in other locations or you need additional configuration, please check out the Configuration section.
Tip: install
fzfto pick contexts and namespaces interactively. Without it, kubert prints the available options so you can copy/paste.
# Start an isolated shell; choose a context interactively (fzf) or name it directly
kubert ctx
kubert ctx my-cluster
kubert ctx - # jump back to the previously used context
# Switch namespaces inside the current kubert shell
kubert ns kube-system
# Run a command across several contexts (glob, regex, or interactive multi-select)
kubert exec "prod-*" "staging-?" -- kubectl get nodes
kubert exec --regex "^(dev|qa)-.*" -- kubectl get pods
kubert exec --parallel --dry-run "prod-*" -- kubectl rollout status
# Open the used kubert config file, editor is determined by $EDITOR or $VISUAL, falls back to 'vim'
kubert config edit
# Wrap kubectl to enforce context protection rules
kubert kubectl get pods
# Manage context protection (optional, no protection by default)
kubert protection info # show current protection status
kubert protection protect # explicitly protect current context (overrides default regex)
kubert protection unprotect # explicitly unprotect current context (overrides default regex)
kubert protection lift 5m # temporarily lift protection for 5 minutes
kubert protection remove # remove explicit override, fall back to regex
# Inspect what kubert is using right now
kubert which ctx
kubert which ns
kubert kubeconfig list
kubert kubeconfig lint # check kubeconfig files for errors and issuesFor more information on all commands, see the docs.
kubert reads from ~/.config/kubert/config.yaml. You can override this location using the KUBERT_CONFIG environment variable or the --config <path> flag.
# All settings shown with their defaults.
# Paths to kubeconfig files. Supports glob patterns.
kubeconfigs:
include:
- "~/.kube/config"
- "~/.kube/*.yml"
- "~/.kube/*.yaml"
# Exclude these patterns. (takes precedence over include)
exclude: []
# Use `fzf` for interactive context/namespace selection when available.
# If `fzf` is not found, kubert falls back to a non-interactive list.
interactive: true
# Context switch mode when already inside a kubert shell (i.e., when KUBERT_SHELL_ACTIVE=1):
# - false (default): switch context in-place, stay in the same shell
# - true: spawn a new nested sub-shell with the new context (nested mode)
nested: false
# Protect contexts against accidental destructive commands. See "Context Protection" below for details. (not configured by default)
protection:
regex: null # regex pattern to auto-protect matching contexts (e.g., "(prod|prd)")
commands: # kubectl commands to block in protected contexts
- delete
- edit
- exec
- drain
- scale
- autoscale
- replace
- apply
- patch
- set
prompt: true # ask for confirmation (false = exit immediately)
hooks:
preShell: "" # run before spawning shell or switching context in-place
postShell: "" # run after exiting shell or switching to another context in-place
fzf:
opts: "" # additional fzf optionsTip: run
kubert kubeconfig listto confirm which kubeconfig files kubert will process.
All config settings can be overridden via environment variables prefixed with KUBERT_. Dots (.) become underscores (_).
Examples:
protection.regex→KUBERT_PROTECTION_REGEXprotection.prompt→KUBERT_PROTECTION_PROMPTfzf.opts→KUBERT_FZF_OPTS
Customize fzf appearance via the fzf.opts config setting:
fzf:
opts: "--height=50% --border --layout=reverse"This can also be overridden via environment variable: KUBERT_FZF_OPTS.
FZF_DEFAULT_OPTS is inherited natively by fzf and applies as a fallback.
Hooks let you run shell commands before and after kubert spawns the subshell (and on every in-place context switch). They run in a child shell process attached to the same TTY, so terminal-side effects like updating the tab title, sending notifications, or logging actions work, but environment changes such as export or prompt-variable updates do not persist in the caller's shell.
Name shell tab after selected Kubernetes context:
hooks:
preShell: 'printf "\033]0;k8s: $KUBERT_SHELL_CONTEXT\007"'
postShell: 'printf "\033]0;\007"'Note:
$KUBERT_SHELL_CONTEXTin hooks is only available and reliable when shell-init is configured. See Shell Init below.
kubert shell-init prints a shell function that wraps the kubert binary. When
sourced, it enables kubert to keep KUBERT_SHELL_CONTEXT and
KUBERT_SHELL_ORIGINAL_KUBECONFIG up to date across in-place context switches —
something kubert cannot do on its own because a child process cannot modify its
parent shell's environment.
Add one of the following to your shell config:
# Bash (~/.bashrc)
eval "$(kubert shell-init bash)"
# Zsh (~/.zshrc)
eval "$(kubert shell-init zsh)"
# Fish (~/.config/fish/config.fish)
kubert shell-init fish | sourceWithout shell-init, KUBERT_SHELL_CONTEXT and KUBERT_SHELL_ORIGINAL_KUBECONFIG
are intentionally not set (a stale value is worse than no value). KUBECONFIG
always works correctly regardless because kubert rewrites the file contents
in-place rather than changing the path.
You can show the current context protection status in your prompt using a custom starship.rs module.
Add the following to your starship.toml:
Click to expand configuration
[custom.kubert]
command = '''
BINARY="kubert"
prot=$($BINARY protection info -o short)
red="\033[31m"
yellow="\033[33m"
green="\033[32m"
reset="\033[0m"
case "$prot" in
"lifted") color=$yellow ;;
"unprotected") color=$green ;;
"protected") color=$red ;;
*) color=$reset ;;
esac
printf "${color}${prot}${reset}"
'''
format = '\([ctx-protection](dimmed white):$output(dimmed white)\) '
when = 'test -n "$KUBERT_SHELL_ACTIVE"'Looks like:
(orbstack:default) (ctx-protection:protected) ~
❯ k get podsFor the context and namespace display, the standard [kubernetes] module works out of the box because kubert manages the standard KUBECONFIG environment variable:
[kubernetes]
format = '\([($cluster)](red):[$namespace](cyan)\) '
disabled = falseWarning
Context protection works only when you run kubectl through kubert kubectl. It does not modify your existing kubectl binary or configuration.
You might want to alias it for convenience, e.g., alias k=kubert kubectl.
Context protection ensures destructive commands can’t hit sensitive clusters by accident. Protection is only enforced when you run kubectl through kubert kubectl (consider aliasing k=kubert kubectl).
Add a regular expression to your config to protect any context whose name matches:
protection:
regex: "(prd|prod)" # protect contexts matching this pattern
commands:
- delete
- apply
- scale
prompt: true # ask for confirmation (false = exit immediately)- Omit or set
regex: nullto disable automatic protection. - Use
regex: ""to protect every context by default.
Use the CLI to manage protection for the current context:
kubert protection protect # explicitly protect this context
kubert protection unprotect # explicitly unprotect this context
kubert protection lift 5m # temporarily lift protection for 5 minutes
kubert protection remove # remove explicit override, fall back to default regexWhen a protected context sees a protected command, kubert will prompt for confirmation (prompt: true) or exit immediately (prompt: false).
When you switch contexts inside an active kubert shell (in-place switch), kubert
runs as a child process of your shell. A child process cannot modify environment
variables in its parent — so KUBERT_SHELL_CONTEXT would go stale the moment
you switch context for the first time.
KUBECONFIG avoids this problem because kubert rewrites the file contents
rather than changing the variable value — the path stays the same, kubectl picks
up the new context automatically.
For KUBERT_SHELL_CONTEXT and KUBERT_SHELL_ORIGINAL_KUBECONFIG to stay
accurate, kubert needs cooperation from the shell itself. kubert shell-init
provides this: the generated shell function sources a small env-update file after
every kubert ctx call so these vars are always current.
Without shell-init, both vars are intentionally not set to avoid misleading stale
values. Configure shell-init if you rely on $KUBERT_SHELL_CONTEXT in hooks or
your prompt. See Shell Init for setup.
See CONTRIBUTING.md for information on how to contribute to kubert.