# qb
**EMACS for Kubernetes.**
A keyboard-driven terminal UI for managing Kubernetes clusters. Single binary, native K8s API, no kubectl dependency.
```
┌ prod-cluster > All Namespaces > Deployments ───────────────── ⟳ just now ┐
├───────────────────────┬──────────────────────────────────────────────────┤
│ Overview │ NAME NAMESPACE READY UP-TO-DATE │
│ Favorites (3) │▶ api-gateway production 3/3 3 │
│ Port Forwards │ auth-service production 2/2 2 │
│ Profiles │ web-frontend production 5/5 5 │
│ WORKLOADS │ coredns kube-system 2/2 2 │
│ Deployments (12) │ metrics-server monitoring 1/1 1 │
│ StatefulSets (2) │ │
│ Pods (24) │ │
│ NETWORK │ │
│ Services (8) │ │
│ CONFIG │ │
│ Secrets │ │
│ CERT-MANAGER.IO │ │
│ Certificate │ │
│ ClusterIssuer │ │
├───────────────────────┴──────────────────────────────────────────────────┤
│ e Edit l Logs D Delete F PortFwd * Star / Filter ? Help q Quit │
└──────────────────────────────────────────────────────────────────────────┘
```
## Why qb
Most Kubernetes dashboards are web apps that need a running backend, a browser, and a pile of YAML to deploy. `kubectl` is powerful but context-switching between commands and mentally tracking state across namespaces is slow.
qb gives you a single binary that connects directly to the K8s API server through your kubeconfig. You see everything at once -- resources, logs, port forwards, events -- and act on any of it without leaving the terminal. It discovers Custom Resources automatically, so third-party operators (cert-manager, Argo, Istio, etc.) show up in the sidebar with zero configuration.
## Features
### Browse
- **26 built-in resource types** across Workloads, Network, Config, Storage, RBAC, and Cluster categories
- **Custom Resources** discovered automatically from CRDs, grouped by API group in the sidebar
- **All namespaces by default** with a namespace column; narrow with `n`
- **Cluster overview** on startup: node grid cards, pod health gauges, cluster stats
- **Regex filter** (`/`) against name, namespace, and all column values
- **Resource count badges** in the sidebar
- **2-second auto-refresh** that preserves scroll position and selection
### Inspect
- **Smart detail views** with structured, per-resource-type rendering (replicas, conditions, ports, rules, volumes, etc.)
- **YAML view** toggle with `v`
- **Related events** shown at the bottom of every detail view (kubectl-describe style)
- **Related resources** -- navigate to owner references, pods, services with `r`
- **Labels and annotations** -- `l`/`a` to select, `Space` to expand long values, `y` to copy
- **Secret decoding** -- `Space` to decode base64 values in-place
### Act
| `e` | Edit in `$EDITOR` with diff preview before apply | Any resource |
| `C` | Create from YAML template in `$EDITOR` | Any type |
| `D` | Delete with confirmation | Any resource |
| `S` | Scale replicas | Deployment, StatefulSet, ReplicaSet |
| `R` | Rolling restart | Deployment, StatefulSet, DaemonSet |
| `d` | Diff two resources side-by-side | Any two of same type |
| `K` | Cordon/uncordon | Node |
| `T` | Drain (cordon + evict pods) | Node |
| `T` | Trigger Job from CronJob | CronJob |
### Logs
- **All pods, all containers** aggregated by default for any workload
- **Color-coded by pod** -- each source pod gets a distinct prefix color
- **Strictly timestamp-ordered** -- lines from different pods merge correctly
- **Auto-discovery of new pods** -- rolling updates are captured without reopening the log view
- **Follow mode** (`f`) for live streaming
- **Regex filter** (`/`) with inline match highlighting
- **Pod/container selectors** (`p`/`c`) to narrow the stream
- **Time range** (`t`) -- e.g. `30m`, `2h`, `1d`
- **Line selection** with `j`/`k`, multi-select with `Shift+j`/`Shift+k`, copy with `Y`
### Port Forwarding
- **Create** (`F`) from Services, Deployments, StatefulSets, DaemonSets, ReplicaSets, Pods, Jobs, CronJobs
- **Survives pod restarts** -- resolves the current pod per-connection via label selectors
- **Persistent** -- saved to your active profile and restored on next launch
- **Manage** -- dedicated sidebar view to pause (`p`), resume, cancel (`d`), edit local port (`e`)
### Favorites and Profiles
- **Star** (`*`) any resource from list or detail view
- **Favorites view** in the sidebar -- fully functional (edit, logs, delete, etc.)
- **Profiles** -- named groups of favorites and port forwards; `Ctrl+s` to save, `P` to switch
- **Missing indicators** -- `⚠` for favorites from unreachable clusters
### Command Palette
- `Ctrl+p` to open
- Type to fuzzy-search resources across all types in the cluster
- Prefix with `>` to search available commands
- Context-aware help with `?` (press `Tab` to see all keybindings)
### Exec (Experimental)
- `X` to exec into a pod (requires `qb -e` flag)
- Choose container, command, and terminal application in a dialog
- Opens a new terminal window with `kubectl exec -it`
- Supports Ghostty, iTerm2, Alacritty, kitty, WezTerm, Terminal.app, and others via `$TERMINAL` or `$TERM_PROGRAM`
## Installation
### From source
Requires [Rust](https://rustup.rs/) (edition 2021).
```sh
git clone https://github.com/cchexcode/qb.git
cd qb
cargo build --release -p qb
# Binary at target/release/qb
```
## Usage
```sh
qb # default kubeconfig and context
qb -e # enable experimental features (exec)
qb version # print version
```
At runtime, press `c` to switch cluster context, `n` to switch namespace, or `O` to open a different kubeconfig file.
## Key Bindings
### Global
| `Ctrl+c` | Force quit |
| `q` | Quit / go back |
| `Esc` | Dismiss popup or selection |
| `?` | Help (context-aware; `Tab` for all) |
| `Ctrl+p` | Command palette |
| `Ctrl+s` | Save profile |
| `P` | Load/switch profile |
| `p` | Pause/resume auto-refresh |
### Main View
| `j`/`k` | Move down/up |
| `Ctrl+d`/`Ctrl+u` | Page down/up |
| `g`/`G` | Top/bottom |
| `Enter` | Open detail / focus table |
| `Tab` | Toggle sidebar/table focus |
| `<`/`>` | Resize sidebar |
| `c` | Switch cluster |
| `n` | Switch namespace |
| `O` | Open kubeconfig |
| `/` | Filter by regex |
| `x` | Clear filter |
| `e` | Edit resource |
| `l` | Logs |
| `D` | Delete |
| `R` | Restart |
| `S` | Scale |
| `F` | Port forward |
| `C` | Create resource |
| `d` | Mark/diff |
| `y` | Copy name |
| `*` | Toggle favorite |
| `X` | Exec (experimental) |
### Detail View
| `v` | Toggle Smart/YAML |
| `w` | Toggle watch (auto-refresh) |
| `l`/`a` | Select labels/annotations |
| `Space` | Expand value / decode secret |
| `y` | Copy value or YAML |
| `r` | Related resources |
| `e` | Edit |
| `L` | Logs |
| `D` | Delete |
### Log View
| `f` | Toggle follow |
| `/` | Filter by regex |
| `p`/`c` | Select pod/container |
| `t` | Time range |
| `w` | Toggle wrapping |
| `Y` | Copy to clipboard |
| `J`/`K` | Extend selection |
### Edit Diff View
| `v` | Toggle inline/side-by-side |
| `Enter` | Apply changes |
| `e` | Re-edit |
| `Esc` | Cancel |
### Port Forwards View
| `p` | Pause/resume |
| `d` | Cancel forward |
| `e` | Edit local port |
## How It Works
qb uses the [kube](https://github.com/kube-rs/kube) crate with [rustls](https://github.com/rustls/rustls) for direct communication with the Kubernetes API server. Authentication and cluster details come from your kubeconfig (`~/.kube/config` or `$KUBECONFIG`). There is no dependency on `kubectl` for any operation except exec (which spawns `kubectl exec` in a new terminal window).
The TUI is built on [ratatui](https://ratatui.rs/) + [crossterm](https://github.com/crossterm-rs/crossterm). All API calls are deferred and executed between render frames so the UI never blocks. Log streaming and port forwarding run as background async tasks with channel-based updates polled each tick.
Custom Resource support works by discovering all CRDs at startup and using the kube dynamic API (`DynamicObject` + `ApiResource`) to list, inspect, edit, and delete CR instances without compile-time type information. CRD `additionalPrinterColumns` are used to render table columns.
Configuration (favorites, port forwards, profiles) is persisted to `~/.config/qb/config.yaml` and auto-saved on changes.
## License
MIT