kctl-tui
A small terminal entry point for everyday Kubernetes work: pick a context
and a namespace once, then drive rollout restarts and an AWS Secrets
Manager <-> Kubernetes Secret diff/force-sync per environment from one
place instead of retyping long kubectl commands.
Why
Working with several clusters, many namespaces per team, and paired
environments (e.g. beta/prod) quickly turns into a lot of repeated typing
with plain kubectl/k9s. kctl-tui adds:
- A guided context -> team -> namespace selection that starts
directly at team selection (using a configured default context), with
the context screen just one
Escaway. - Namespace grouping by an arbitrary, configurable label instead of scrolling through every namespace in the cluster.
- A 3-pane view (via
tmux): one control pane for actions, two status panes runningk9sfor the current namespace across your two configured environments (e.g. beta/prod), shown side by side. - A control-pane menu organized by environment: pick beta or prod, then Secrets sync or Redeploy for that environment specifically.
- AWS Secrets Manager secret IDs and Kubernetes context names/ARNs are
computed from configurable templates (namespace + environment),
instead of listing secrets or discovering contexts live from
kubectl/aws-cli. - A guided AWS Secrets Manager vs. Kubernetes Secret comparison of every field at once, with a force-sync request for the whole secret if anything differs.
- An AWS auth check before the secrets workflow, offering to run your configured SSO login command interactively if the session has expired.
See SPEC.md for the full requirements and design rationale, and PLAN.md for the implementation roadmap and current status.
How it works
+--------------------------------------------------+
| Control pane: kctl-tui panel |
| -> 1) Quit 2) beta 3) prod |
| each with: a) Secrets sync b) Redeploy |
+--------------------------------------------------+
| k9s --context <resolved beta context> -n <ns> |
+--------------------------------------------------+
| k9s --context <resolved prod context> -n <ns> |
+--------------------------------------------------+
- Run
kctl-tui. It loads your config, applies the default context, and jumps straight to team selection; pressEscthere to pick a different context first. - Pick a team (namespace label filter), then a namespace.
- It opens a
tmuxsession with the layout above: the control pane runs this binary in "panel" mode, the two status panes runk9sagainst your first two configured environments (e.g. beta and prod), resolved fromcontext_template. - In the control pane, pick an environment, then Secrets sync or
Redeploy for that environment.
Escgoes back one level (action menu -> environment menu -> closes the whole tmux session, including bothk9spanes, and returns you to namespace selection).
Requirements
kubectl, configured with access to your cluster(s) (the actual context names/ARNs are resolved from yourcontext_template, see Configuration below - they must already exist in your kubeconfig, e.g. added viaaws eks update-kubeconfig).k9s(used for the two status panes).tmux(used for the 3-pane layout). On Linux/macOS, installtmuxvia your package manager. On Windows, install psmux — a native, tmux-compatible terminal multiplexer:psmux provides ascoop install psmux # or cargo install psmuxtmuxcommand, so kctl-tui works without changes.awsCLI, configured with credentials, only needed for the secrets workflow.
Installation
Quick install (Linux/macOS/WSL)
curl -fsSL https://raw.githubusercontent.com/skoelle/kctl-tui/main/install.sh | bash
Quick install (Windows)
irm https://raw.githubusercontent.com/skoelle/kctl-tui/main/install.ps1 | iex
This downloads the latest release binary for your architecture from GitHub Releases and installs it to your PATH.
This downloads the latest release binary for your OS/architecture from
GitHub Releases and installs it to /usr/local/bin/kctl-tui.
From source
git clone https://github.com/skoelle/kctl-tui.git
cd kctl-tui
go build -o kctl-tui ./cmd/kctl-tui
sudo mv kctl-tui /usr/local/bin/
Requires Go 1.22+.
Prebuilt binaries
Every tagged release (vX.Y.Z) is built for linux, darwin, and
windows, each for amd64 and arm64, via the GitHub Actions workflow in
.github/workflows/build.yml. Download the
matching asset from the Releases page.
Configuration
Copy config.example.yaml to ~/.kctl-tui/config.yaml
and adjust it to your own setup:
contexts:
- "internal"
- "external"
default_context: "internal"
envs:
- "beta"
- "prod"
aws_region: "eu-central-1"
aws_account_id: "123456789012"
secret_name_template: "tf-{namespace}-{env}-secrets"
k8s_secret_name_template: "{namespace}-common-secrets"
context_template: "arn:aws:eks:{region}:{account_id}:cluster/tf-{env}-{context}-1"
team_label_key: "example.org/team"
aws_sso_login_command: "aws sso login"
contexts/default_context: the top-level grouping the tool starts from (e.g. a network boundary such as internal/external-facing clusters). This is the outermost navigation level, oneEscabove team selection.envs: the environments switchable from the control panel (e.g. "beta"/"prod"). The first two entries are also used for the two k9s status panes shown side by side.aws_region/aws_account_id: used for AWS Secrets Manager calls and to fill the{account_id}placeholder incontext_template.123456789012is a placeholder, not a real account.secret_name_template: builds the AWS Secrets Manager secret ID from the chosen namespace and environment. Placeholders:{namespace},{env}.k8s_secret_name_template: builds the Kubernetes secret name from the chosen namespace. Kept separate fromsecret_name_templatebecause the two sides commonly follow different naming conventions. Placeholders:{namespace}.context_template: builds the actual kubectl context name/ARN from region, account ID, environment, and context. Placeholders:{region},{account_id},{env},{context}. Adjust the literal parts (tf-,-1, cluster naming, ARN shape) to match how your own clusters/contexts are actually named — the resolved value must match an existing context in your kubeconfig.team_label_key: the Kubernetes namespace label used to group namespaces by team/ownership in the team-selection screen. This is entirely up to your organization's labeling convention; kctl-tui ships with no default team label of its own.aws_sso_login_command: run interactively ifaws sts get-caller-identityfails before the secrets workflow (e.g. an expired SSO session). Defaults toaws sso login.
~/.kctl-tui/config.yaml is not part of this repository and should stay
that way — it typically contains your organization's internal account ID,
context naming, and label names.
Windows notes
On native Windows (without WSL), install psmux for the 3-pane layout. psmux is a native Windows terminal multiplexer that is tmux-compatible — kctl-tui works without code changes:
scoop install psmux
# or
cargo install psmux
If you prefer WSL, symlink your kubeconfig into WSL:
mkdir -p ~/.kube
ln -s /mnt/c/Users/<your-windows-username>/.kube/config ~/.kube/config
Usage
kctl-tui # start the TUI (full navigation mode)
kctl-tui --help # show all commands and flags
kctl-tui --version # print version
kctl-tui --verbose # enable debug logging to stderr
kctl-tui doctor # check if all tools, config and connections are OK
kctl-tui config check # validate ~/.kctl-tui/config.yaml
kctl-tui panel --context=... --ns=... --team=... # internal (called by tmux)
Development
go test ./...
go vet ./...
go build ./cmd/kctl-tui
Pure logic (template resolution, label filtering, config parsing, secret
diffing) lives in internal/kctl and internal/config and is covered by
unit tests. Code that shells out to kubectl/aws/tmux lives in
internal/kubeexec and in cmd/kctl-tui and is intentionally kept thin
and untested, since it has no meaningful behavior without a live cluster.