A blazing-fast Kubernetes Terminal User Interface (TUI) written in Zig, inspired by k9s and btop.
Every resource view β pods, deployments, services, daemonsets, PDBs, and the rest β is rendered by a single comptime ResourceView engine (src/view/resource_view.zig). Adding a resource is a declarative config in src/view/resource_configs.zig, not a bespoke renderer. Rendering, sorting, marking, filtering, and namespace scoping behave identically everywhere.
- β Full-width layout: tables fill the terminal; the NAME column stretches to absorb slack.
- β Full namespace names and a full-width selection highlight bar.
- β UTF-8-safe truncation: long values are clipped on glyph boundaries β no broken multi-byte characters.
- β
Per-column sorting:
Shift-<letter>toggles the sort key with a β²/βΌ indicator (e.g. pods:Shift-Nname,Shift-Rready,Shift-Sstatus,Shift-Ccpu,Shift-Mmem,Shift-Iip,Shift-Aage). - β
Row marking:
Spacetoggles a k9s-style mark on the current row; marks persist by row identity across cursor moves and refreshes. - β
Live filtering:
/filters the table; the title shows a</term>indicator. Clear withxorEsc. Prefixes:!terminverse,-f termfuzzy,-l k=vlabel selector. Typed comparisons includestatus=CrashLoopBackOff,cpu>500m,memory>1Gi,restarts>=5, andage<2h.Ctrl-Ztoggles faults-only. - β
Namespace scoping:
0toggles all-namespaces. The box title reflects scope and count k9s-style βpods(default)[8]orpods(all)[104]β and the redundant NAMESPACE column is hidden when scoped to a single namespace.
Press : or Ctrl-P to open a live, fuzzy-ranked command dropdown (bordered popup). Type to filter, Tab/β/β to navigate, Enter to run. Commands can read like :deployments social in production; discovery-only suggestions are filtered by list permission.
Ctrl-A (or :aliases) opens a real table of API resources β NAME / SHORTNAMES / APIVERSION / NAMESPACED / KIND β with working filter. Ctrl-A again toggles it off.
Press t on a deployment to open a live traffic topology:
- Inbound/outbound graph plus a per-peer table (req/s, success %, p50/p99 latency).
- Sourced from Istio's Prometheus metrics via the API-server service proxy.
- Fetched on a background thread β the UI never blocks β with ~5s auto-refresh.
q/Escback,rrefresh,j/kscroll.
Powered by the kubectl_traffic sibling package.
- β Workloads: Pods, Deployments, StatefulSets, DaemonSets, ReplicaSets, Jobs, CronJobs
- β Config & Storage: ConfigMaps, Secrets, PersistentVolumes, PersistentVolumeClaims, StorageClasses, VolumeAttributesClasses, CSIDrivers
- β Networking: Services, Endpoints, EndpointSlices, Ingresses, IngressClasses, NetworkPolicies, IPAddresses, ServiceCIDRs
- β Gateway API: GatewayClasses, Gateways, HTTPRoutes, GRPCRoutes, TCP/TLS/UDPRoutes, ReferenceGrants, BackendTLSPolicies, ListenerSets
- β RBAC: ServiceAccounts, Roles, RoleBindings, ClusterRoles, ClusterRoleBindings
- β Admission: Validating/Mutating AdmissionPolicies and Bindings, Validating/Mutating WebhookConfigurations
- β Cluster: Namespaces, Nodes, Events, ResourceQuotas, LimitRanges, PodDisruptionBudgets, PriorityClasses, RuntimeClasses, Leases, CSRs, StorageVersionMigrations
- β Autoscaling / DRA: HorizontalPodAutoscalers, ResourceClaims, DeviceClasses
Describe (d), YAML (y), logs (l), edit (e β any resource), shell (s), attach (a), port-forward (Shift-F on pods and services), delete (Ctrl-D).
- Context management: list kubeconfig contexts, interactive switching, multi-cluster support.
- 35+ built-in themes plus k9s-compatible custom skins.
Resource views subscribe to a shared LIST + WATCH plane instead of polling. Incremental projections keep rows and selection during relists; pod CPU/MEM come from projected metrics. Direct HTTPS is used for readonly reads, with a bounded proxy fallback.
- β‘ Fast: native Zig, no runtime/GC.
- πͺΆ Lightweight: low memory footprint.
- π― Non-blocking: LIST/WATCH, metrics, and traffic fetch run off the UI thread.
Medians over five fresh processes each, read-only, all namespaces, on a cluster
of 277 nodes, 124 namespaces, 4,792 pods and 1,078 deployments where
kubectl get pods -A takes 5.7 s. Measured 2026-09-10 on an Apple M5
(10 cores, 32 GB, macOS 27) in a 120Γ40 PTY, c3s built ReleaseFast at
v0.2.0+2 against Homebrew k9s 0.51.0.
| c3s | k9s | |
|---|---|---|
| Pod rows visible in the terminal | 2.38 s | 41.5 s |
| RSS 2 s after first rows | 33.9 MB (83.7 MB with helpers) | 1,167 MB |
| RSS at 25 s | 85.9 MB (135.3 MB with helpers) | 620 MB |
| Threads at 25 s | 7 | 22 |
| Binary on disk | 8.4 MB | 142.8 MB |
--version |
2.5 ms | 32.6 ms |
The first row uses the same instrument for both programs: the terminal is read until pod rows appear. c3s also emits its own timing markers, which put the LIST-to-first-rows cost at 0.38 s and process-start-to-first-rows at 2.77 s.
c3s shells out to kubectl and to a credential helper, so the parenthesised
figure β the whole process tree β is the one to compare against k9s, which runs
as a single process. RSS is ps RSS in KB / 1000.
Reproduce with:
zig build -Doptimize=ReleaseFast
python3 tools/perf/compare.py --context <ctx> --all-namespaces --runs 5 --sample-s 25- Startup is not symmetric. k9s is launched with
-A -c poand opens on all namespaces. c3s starts in the default namespace and is switched with0, so its terminal-observed figure includes that switch. - "All rows loaded" is unmeasured. k9s exposes no such signal, and on a cluster this size the c3s all-namespaces pod subscription does not currently emit its completion marker. Neither number is reported, and the table above says nothing about when a full sync finishes.
- One machine, one cluster, read-only. k9s timing includes its Homebrew launcher. The two programs render different columns and refresh on different schedules. Bytes written to the terminal are recorded by the harness but are not a c3s win.
brew install guanchzhou/tap/c3sInstalls the current GitHub Release binary (linux/macOS, amd64/arm64).
- Zig 0.17.0
- kubectl configured with a valid kubeconfig
- Kubernetes cluster access
git clone https://github.com/guanchzhou/c3s.git
cd c3s
zig buildc3s depends on two sibling packages via relative paths in
build.zig.zon:../zig-klient(the Kubernetes client) and../kubectl-traffic(the traffic view). Check them out next to the c3s directory before building.
# Connect to current kubectl context
./zig-out/bin/c3s
# Use a specific context
./zig-out/bin/c3s --context my-cluster| Key | Action |
|---|---|
j / k or β / β |
Move cursor |
g / Shift-G |
Top / bottom |
Space |
Mark / unmark current row |
Shift-<letter> |
Sort by that column (β²/βΌ) |
/ |
Filter (! inverse, -f fuzzy, -l labels) |
Ctrl-Z |
Toggle faults-only |
Tab / Shift-Tab |
Next / previous common resource kind |
Shift-Y |
Pick and copy a full, untruncated column value |
Shift-T |
Session timeline for the selected object |
Shift-X |
Explain unhealthy workload (workload tables) |
x |
Clear filter |
0 |
Toggle all namespaces |
r |
Refresh |
: or Ctrl-P |
Fuzzy command palette |
Ctrl-A |
Aliases (API resources) view |
? |
Help |
Esc |
Clear filter / back |
q |
Quit (or :q) |
| Key | Action |
|---|---|
d |
Describe |
y |
View YAML |
l |
Logs |
e |
Edit (kubectl edit; any resource) |
s |
Shell into container |
a |
Attach |
Shift-F |
Port-forward (pods and services) |
Ctrl-D |
Delete |
| Key | Action |
|---|---|
t |
Open live Istio traffic view |
Lists cedar.k8s.aws Policy objects and runs the official
cedar CLI against them. Read-only:
nothing here writes to the cluster. Install the binary with
cargo install cedar-policy-cli; without it the list still works and the
analysis keys say why they cannot run.
| Key | Action |
|---|---|
Enter |
Policy source |
Shift-P |
cedar check-parse on the selected policy |
Shift-C |
cedar format |
Shift-V |
cedar validate against a schema you name |
Shift-A |
Scan every policy and tally the parse failures |
Shift-I |
Can-i: principal action resource [-n ns] [-g group] |
Shift-I evaluates the question against the policies that parsed. If any
policy could not be read or parsed, the answer is INDETERMINATE rather than
ALLOW or DENY β an answer from an incomplete policy set is not an answer.
This is Cedar, not Kubernetes RBAC: it does not call the admission webhook, and
it is not a substitute for kubectl auth can-i.
:pods # View pods
:deployments # View deployments
:services # View services
:gateways # Gateway API
:httproutes # HTTPRoutes (`:htr`)
:aliases # API-resources table
:contexts # Manage contexts
:events # View cluster events
:hpa # View HorizontalPodAutoscalers
:pf # Manage, start, stop, and inspect port-forwards
:cedar # Cedar policy workbench (`:cedarpol`)
Argo CD applications.argoproj.io views add Shift-R refresh, Shift-H hard
refresh, and Shift-S Kubernetes-native sync details. They do not perform sync,
prune, rollback, or claim to show a manifest diff.
Metric colors use conservative defaults and can be tuned under c3s.ui with
cpu_warn_milli, cpu_error_milli, memory_warn_bytes,
memory_error_bytes, restarts_warn, and restarts_error.
Captured from a live v1.37.0 cluster.
Press / and type; the row count and the active filter show in the title.
Press : and type a fragment β ga ranks gatewayclasses, refgrant, and the admission-policy views.
Every API resource discovered from the cluster, with short names and kinds.
Ctrl-E collapses the header to a single line (or set ui.compact in config), giving the table back six rows.
c3s follows MVVM (Model-View-ViewModel). Resource tables subscribe to a supervised data plane; the UI thread alone mutates table and selection state.
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β View Layer β
β Generic ResourceView engine + dedicated views β
β (traffic, aliases, contexts, themes, help, β¦) β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β ViewModel Layer β
β ViewManager, CommandRegistry, fuzzy palette β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Service Layer β
β K8sService β kubectl mutations, readonly fence β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Data plane β
β LIST + WATCH subscriptions, ChangeQueue, β
β lifecycle supervisor, direct HTTPS / proxy β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β Data Layer β
β zig-klient (K8s API) + kubectl_traffic (Istio) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Components:
- ResourceView: one comptime engine drives every resource table (config in
resource_configs.zig). - ViewManager: stack-based view navigation.
- CommandRegistry: k9s-compatible commands, surfaced through the fuzzy palette.
- Data plane: per-context LIST then WATCH; bounded change batches delivered to the UI thread.
- K8sService: kubectl mutations pinned to kubeconfig/context and fenced by
--readonly. - TrafficView: background-threaded Istio metrics topology.
- Theme System: k9s-compatible theming (35+ themes).
# Build
zig build
# Unit tests + integration suites
zig build test-all
# k9s command/key contract (through App.handleKey / :aliases, not isolated views)
zig build test-k9s-parityUnit tests cover the table engine, resource views, data plane, service layer, and
memory-leak detection. Linux CI runs zig build test-all; macOS CI runs on main only.
Contributions welcome:
- Fork the repository
- Create a feature branch
- Follow the existing patterns (MVVM; add resources declaratively in
resource_configs.zig) - Add tests for new features
- Run
zig fmt --check src/ tests/ build.zig build.zig.zon - Submit a pull request
- 50+ Kubernetes resource views
- Unified generic table engine (pods migrated off its bespoke renderer)
- Supervised LIST + WATCH data plane for resource views
- Full-width layout, glyph-safe UTF-8 truncation, full-width selection bar
- Per-column sorting (
Shift-<letter>with β²/βΌ) - Row marking (
Space) - Live filtering (
/, inverse / fuzzy / labels,Ctrl-Zfaults-only) - Namespace scoping (
0) with k9s-style scoped titles - Fuzzy command palette (
:/Ctrl-P) - Aliases / API-resources view (
Ctrl-A) - Embedded Istio traffic view (
ton a deployment, background-threaded) - Pod actions: describe / YAML / logs / edit / shell / attach / port-forward / delete
- Context management
- Theme system (35+)
- GitHub Actions CI (
zig build test-allon Linux; macOS onmain)
- Custom resource (CRD) support
- Plugin system
- Resource creation wizards
- Diff/compare views
- Multi-cluster dashboard
- Metrics integration beyond pod CPU/MEM
Located at: ~/.config/c3s/config.yml
ui:
theme: dracula # Theme name
compact: false # Compact mode
footer: true # Show footerPlace custom k9s skins in: ~/.config/c3s/skins/
View logs at: ~/.local/state/c3s/c3s.log
# Check kubectl context
kubectl config current-context
# Log at debug level, then read ~/.local/state/c3s/c3s.log
./zig-out/bin/c3s --debug# List available contexts
kubectl config get-contexts
# Use a specific context
./zig-out/bin/c3s --context <name>- β Visual: TUI vs command-line
- β Efficient: navigate with the keyboard
- β Intuitive: see all resources at once
- β Performance: native Zig, no GC β see Measured against k9s
- β Memory: 84 MB of process tree against 1,174 MB on a 4,792-pod cluster
- β Compatible: familiar commands and themes
- β Traffic: built-in Istio topology view
- β Lightweight: TUI vs Electron
- β Fast: instant startup
- β Terminal: works over SSH
Apache License 2.0 β see LICENSE.
- k9s β inspiration for UX and commands
- btop β UI design inspiration
- sofka β inspiration for typed filters and read-only guardrails
- zig-klient β Kubernetes client library
- Zig Community β amazing language and ecosystem
Built with β€οΈ in Zig β fast, lightweight, powerful.






