Releases: vulcanshen/km8
v1.5.7
Two small kubectl-parity additions to the panel-2 list view: Pods
gain the IP column from kubectl get pods -o wide, and Ingresses
gain the Address column that kubectl get ingress shows by default
but km8 was previously dropping.
Added
- Pod IP column. New
IPcell betweenAgeandNodecarrying
.status.podIP, matching thekubectl get pods -o widelayout.
Shows<none>while the kubelet hasn't reported one, again matching
kubectl. All three Pod row producers (fetchPods,
fetchPodsWithSelector,fetchPodsForPVC) were updated so
drill-downs from Deployments / ReplicaSets / Jobs / PVCs render the
IP column too — not just the top-level Pods view. - Ingress Address column. New
Addresscell betweenHostsand
Portscarrying.status.loadBalancer.ingress[*].ip|hostname,
joined by commas when multiple entries exist (same as kubectl's
default). Empty when no ingress controller has written status —
clusters without a controller will see the same empty cell that
kubectl get ingressshows.
v1.5.6
Bugfix patch — single UI alignment fix, no feature change.
Fixed
- Pod status color disappeared after exiting a Pod → containers
drill-down. Exiting container view rebuilt the pod table from raw
item.Rowinstead of the helm-augmented form.ColumnsForResource(Pods)
reserves index 1 for the helm marker, so raw rows shifted Status one
column left —stylizeCellthen read the wrong cell and the
Running/Pending/Errorcoloring fell silent until the user
switched resources. Both exit branches (container-level pop, resource
drill-stack pop) now go throughaugmentRowsWithHelm. Regression
guarded byTestAppModel_ExitDrillDownFromContainers_RowsStayHelmAligned.
Changed
- README license badge pinned to a static
GPL-3.0shield instead of
shields.io's dynamicgithub/license/*endpoint, which has been
intermittently returning "Unable to select next GitHub token from pool"
for the past week. No user-visible change when shields.io is healthy.
v1.5.5
Debug visibility. Events tab and a new Conditions tab carry the
"why is this resource sad" story for every workload kind — no more
jumping back to kubectl describe. Events aggregation now walks the
full controller chain (CronJob → Jobs → Pods, Deployment → current
ReplicaSet → Pods, StatefulSet/DaemonSet/Job → Pods). Panel 2 menu
gains Enter (drill) and Esc (back) entries for discoverability. Logs
auto-follow indicator switched from a ▼ marker to coloring the active
[Logs] label green.
Added
- Conditions tab. New detail-panel tab showing the resource's
.status.conditionsas aTYPE / STATUS / REASON / MESSAGE / AGE
table — same content as the Conditions section ofkubectl describe.
StatusFalserows highlighted in red. Tab appears for kinds that
populate conditions: Pod / Node / PVC / Deployment / StatefulSet /
DaemonSet / Job / HorizontalPodAutoscaler / Ingress. Hidden for
kinds without conditions (ConfigMap, Secret, Service, ServiceAccount,
etc.). Why it matters: events expire after the cluster's TTL
(default 1h), but conditions reflect the resource's current state
—PodScheduled: False, Insufficient cpustays visible until the
Pod is actually scheduled. - Aggregate child events for all workload kinds. Selecting a
workload's row and switching to the Events tab now merges events
from the workload itself AND its child Pods, sorted newest first.
The Object column distinguishes source kind so you see the chain
inline. Covers Deployment (via current ReplicaSet), StatefulSet,
DaemonSet, Job, ReplicaSet, CronJob. Mirrors the existing aggregate-
logs pattern; samePodsForWorkloadhelper drives both. - CronJob 3-tier aggregate. CronJob's Events tab additionally
pulls in events from every owned Job (so you see Job-level
SuccessfulCreate/BackoffLimitExceeded/Completedalongside
the CronJob'sSuccessfulCreate/MissingJoband the Pods'
Scheduled/Pulled/Started). Three layers in one view —
the killer feature for "why did last night's cron fail" debug. - Conditions tab Space hint. Same cheatsheet pattern as Logs /
Events tabs —j/k/u/d/gg/G/y/zfor scroll/copy/expand. - Panel 2 menu Enter (drill) entry. When the selected kind
supports drill-down, the per-rowSpacemenu now ends with an
Enter ↘row whose hint names the child kind ("drill into pods" /
"drill into containers" / etc.). Cursor + Enter on it triggers
the same drill as pressing Enter on the row directly — visible
in the menu for discoverability. - Panel 2 menu Esc (back) entry. When the table is inside a drill
chain (e.g. you pressed Enter on a Deployment and are now viewing
its Pods), the menu appends anEsc ↖ back to parent listrow.
Cursor + Enter triggersexitDrillDown. - Container menu Esc entry. Same back row appended to the Pod →
containers context menu (Shell + Esc). - Panel 3 bottom-left hint. On the Relatives tab at depth > 1,
panel 3's border showsesc: backin the bottom-left, mirroring
panel 2's.: toggle helmpattern. Surfaces the pop-one-level
shortcut without requiring the help popup.
Changed
- Logs follow indicator. Active
[Logs]tab label rendered in
Status.Running green when auto-follow is engaged. Replaces the
prior▼text marker. Same semantic ("alive stream") expressed
visually instead of textually. - Popup bottom hints trimmed. All popup border bottom legends
(panel 2 menu, helm doc menu, breadcrumb, hint popup, app log,
YAML popup, confirm, namespace picker, context picker) now show
justSpace: close/Space: cancel. The Esc / q / n / ! keys
still work, just no longer advertised. Reflects the v1.5.x
mental model: Space is the primary popup verb. - CronJob added to demo fixtures.
.local/demos/demo-app.yaml
now includes ademo-cronCronJob firing every minute (busybox
heartbeat) for verifying the 3-tier aggregate path locally.
Fixed
- Stale-events workaround framing. Empty Events tab on a healthy
resource is no longer the only signal — the new Conditions tab
fills the diagnostic gap when events have expired past TTL.
v1.5.4
Universal Space coverage. v1.5.3 closed panel 1; v1.5.4 closes the
remaining no-op corners: panel 3 Logs / Events / Relatives-at-depth-1
tabs each get their own cheatsheet, and empty panel 2 surfaces an
explainer instead of swallowing the keypress.
Added
- Panel 3 tab cheatsheets via Space. Logs / Events tabs each get a
read-only popup listing j/k/u/d/G/y/z (scroll, copy, full-screen).
Relatives tab at depth=1 (no drill chain yet) shows a drill-into
cheatsheet (Enter to drill, Y for YAML, Esc to pop). At depth>1 the
existing breadcrumb popup still opens. - Empty panel 2 Space hint. When the table is empty (e.g., a
namespace with no Deployments), Space no longer no-ops — it opens a
popup naming the likely cause (filter on, helm-managed hidden, wrong
ns/context) and the keys that fix each.
Changed
- SidebarHelpPopupModel → HintPopupModel. Refactored the v1.5.3
sidebar-only popup into a generic title + rows model. One instance
serves all six call sites (sidebar, container drill — via separate
panel 2 menu — Logs / Events / Relatives-depth-1 / empty panel 2).
No user-visible change beyond more places Space works.
v1.5.3
Closes the "Space surfaces what's possible here" loop. v1.5.1 wired it
on panel 2 and panel 3; v1.5.2 added it on container drill; v1.5.3
brings it to panel 1 too, so the rule is now universal: anywhere the
user can land focus, Space shows what they can do.
Added
- Panel 1 (sidebar) Space cheatsheet. Sidebar rows are nav targets,
not action targets — so a per-row menu wouldn't make sense. Instead
Space opens a read-only popup listing the keys that drive the sidebar
(j/k move, Enter focus, / search, search-mode Enter to lock, Esc to
clear, N/C global pickers). Search-mode Enter/Esc are visually nested
under/with the same drill-into arrow used in the Relatives tab.
Esc/q/Space/Enter all close. Long hints wrap onto continuation lines
with the key column left empty.
Changed
Spacescope in README now spelled out per panel. Three-key blurb- Key Bindings table both updated to enumerate which popup opens on
which panel (sidebar cheatsheet / panel 2 menu / Relatives breadcrumb).
- Key Bindings table both updated to enumerate which popup opens on
v1.5.2
Dual-slot PTY + status bar styling pass. The headline fix: KM8erm
(persistent embedded shell) can now coexist with kubectl exec /
kubectl edit — previously a hidden KM8erm shell blocked any new PTY,
forcing the user to exit it. Container drill gets a Space menu too, so
the v1.5.1 "Space = right-click menu" model now reaches the bottom of
the drill chain.
Added
- Dual-slot PTY architecture. Split the single
m.ptyViewinto
m.shellPty(KM8erm, persistent) andm.txPty(kubectl edit / exec,
transient). They run independently — hide KM8erm in the background,
then exec into a container without closing the shell session. Render
layers tx on top of shell; input routing prefers tx; tick + exit
messages carryKindso the right slot cleans up. - Container drill Space menu. Pressing
Spacewhile drilled into a
pod's container list now opens a single-item menu (Shell) instead
of doing nothing.Sdirect hotkey on the container row still works
the same way — the menu just surfaces it so the v1.5.1 "Space =
contextual menu" rule applies at every drill depth.
Changed
- Status bar text labels → Nerd Font icons.
ctx:/cluster:/
ns:replaced with\U+F0237/\U+F1856/\U+F51E— more compact,
matches the KM8erm chip style. Hidden KM8erm chip color synced to
the popup border (#F0AE49). - PTY popup borders tri-color. With two PTYs able to coexist, each
kind needs its own border so the active popup's provenance is
unambiguous: KM8erm shell stays Catppuccin peach#F0AE49,kubectl execswitches to green#a6e3a1,kubectl editkeeps sky blue
#74c7ec. Title (bold) shares each popup's border color.
Fixed
- Hidden KM8erm no longer blocks edit/exec. Old single-slot guard
refusedstartShellExecMsgandstartEditMsgwhenever any PTY was
alive — including a backgrounded KM8erm shell. Guards now check only
the txPty slot, so the persistent shell stays out of the way.
v1.5.1
The keybinding UX pass. v1.5.0 shipped Helm; v1.5.1 steps back and
collapses the accumulated key-binding choices into one consistent mental
model. Four navigation keys with disjoint meanings:
Enter= into — the sole drill / focus / commit-popup keySpace= right-click menu — opens contextual menus, mirror-closes popupsh/l= panel 3 tab switch — only when panel 3 is activeEsc= back — pop drill frame / close popup (LIFO)
Trigger letters (Y/E/S/D/N/C) are uppercase so they require
Shift — the modifier exists to prevent accidental key presses, not to
signal danger. The mental-model anchor is a desktop GUI analogue: Enter
= double-click, Space = right-click.
Added
- Per-row context menu on panel 2. Press
Spaceon a regular row
to open a menu listingYAML(Y)/Edit(E)/Shell(S)/Delete(D).
Items are resource-aware: Shell is hidden for resources without
containers (Service / ConfigMap / Secret / ...). Items can be committed
via cursor +Enteror by hitting the letter directly while the menu
is open. Trigger closes the menu either way — three paths (direct
hotkey at row / menu + cursor / menu + hotkey) reach the same final
state. - Rule A read-only — Helm-managed Delete. Pressing
Don a Helm-
managed K8s resource (labelapp.kubernetes.io/managed-by=Helmor
annotationmeta.helm.sh/release-name) now surfaces a "Helm-managed
(read-only)" toast and refuses, matchingEedit. Closes the v1.5.0
leak whereDskipped the guard. ztoggle expand panel. Single key toggles the focused panel
(table or detail) between expanded and normal — replaces the
=/-pair, which were ergonomically awkward (different keys for
open vs close).
Changed
- Trigger letters uppercase across the board.
e→E(edit),
s→S(shell). Aligns withD/Y/N/Cand the Shift = anti-
accidental modifier rule. Also affects the YAML popup's edit hotkey
(nowE). n/clowercase aliases removed. Namespace / context pickers
only respond toN/Cnow — the lowercase aliases were a leak
in the Shift = intentional rule.h/lpurely panel 3 tab switch. Previouslyh/lswitched
the panel 3 tab while panel 2 was focused; now they only fire when
panel 3 is the active panel. Panel 2 = pure list (cursor + Enter +
Space). Panel 3 = tab navigation (h/l).lretired as a drill key. Enter is now the sole drill / focus-
next-panel key throughout km8 (sidebarl/Enter→Enteronly;
Relatives tabEnter/l→Enteronly).hretired as drill-frame pop.Escwas always an alias; now
it's the only key for back-out.bkey retired. The breadcrumb popup is now reachable via
Spaceon the Relatives tab — folds into the universal "Space =
open menu" rule. The[b]readcrumbspanel-border hint is removed.- Breadcrumb popup:
Entercommits,Spacecloses. Inside the
popup,Enternow commits the cursor row as a panel 1+2 switch
(replaces the old jump-to-drill-level behavior).Spacemirrors
open and closes the popup without committing. - Any menu popup:
Space= close (mirror open). Breadcrumb popup,
Helm doc menu, per-row context menu — uniform rule. Confirm dialogs
already accepted Space as cancel; behavior unchanged. - Status line trimmed. Now shows only
?/q/N/C/
space/enter— plus/filter when panel 1/2 is active
(hidden on panel 3 since in-panel search was retired in v1.5.0).
Trigger letters (Y/E/S/D) live in the per-row context menu
instead of being duplicated on the status bar. - Help popup (
?) rewritten as the single source of truth for the
full key map under the new mental model.
Mental model summary
| Key | Meaning |
|---|---|
Enter |
Into — drill / focus next / commit popup |
Space |
Right-click menu — open context menu / mirror-close popup |
h/l |
Tab switch (panel 3 active only) |
Esc |
Back — pop drill / close popup |
Y/E/S/D/N/C |
Triggers, uppercase = needs Shift = anti-accidental |
j/k/u/d/gg/G |
Vim navigation (unchanged baseline) |
Fixed
- Table cell truncation no longer slices UTF-8 mid-codepoint. The
table renderer used byte-length truncation (val[:w-1]), which broke
any multi-byte cell whose byte count exceeded the column width — the
Nerd Font helm glyph (3 bytes / 1 cell) rendered as◇◇in a 2-cell
column. Now uses visual-width truncation viaansi.Truncate+
lipgloss.Width, so any multi-byte content survives narrow columns
intact. - Pod STATUS color column-index lookup is dynamic. The hard-coded
colIdx == 2check broke when the helm-marker column was inserted at
index 1; STATUS color stopped applying. Status column lookup is now
by column title, not position.
Changed (polish)
- Helm-managed visibility defaults to shown. Previously hidden by
default with the rationale that helm objects are "noise" on a scout
workflow. Reverted — the cluster's actual contents should be the
default surface..on any non-Releases panel 2 list toggles hide. - Helm marker column on every resource type. A dedicated unlabeled
column right after Name shows the `` (Nerd Font nf-dev-helm) glyph
on helm-managed rows, blank otherwise. Same glyph used for popup
title icons. Previously only Secrets list filtered helm storage blobs;
this universalizes the visual signal across all 26 resource types. - Panel 2 bottom-left always shows the
.: toggle helmhotkey hint.
Previously the chip only appeared when helm filter was off, as a
state indicator. Now it's a permanent hotkey advert (Releases panel
is the only exception — toggle is a no-op there). - Space closes every popup uniformly. YAML popup, Help popup, App
log popup, Splash screen all now acceptSpaceto close, matching
the universal "Space mirror-closes the popup that opened" rule from
the v1.5.1 mental model. - README rewritten around zero-learning-curve framing. Three keys
(Enter/Space/Esc) cover the primary interaction; layout
navigation (1/2/3,h/l) and accelerators (Y/E/S/D/...)
are framed as optional. Honest about whereSpaceworks vs not
(sidebar has no per-row menu — every row is itself a navigation
target).
Demo
- 5 demo gifs re-recorded against the v1.5.1 mental model:
demo-basics(three-key tour + Space menu → Y → YAML),
demo-relatives(chain drill + Space breadcrumb popup + confirm
switch),demo-yaml-edit(Space menu → Edit → confirm → vim, the
v1.5.1-correct path tokubectl edit),demo-helm(new — Space
doc menu → Manifest YAML popup),demo-km8erm(two scale cycles
showing hide/show persistence).
v1.5.0
The Helm release. A Helm release becomes km8's 27th resource type and
plugs into the same Relatives / drill / breadcrumb / Y popup machinery
every other resource uses — the divergence is that the fetcher shells
out to helm instead of going through client-go. Registered at startup
only when helm is on PATH; otherwise the entire Helm > Releases
sidebar category never renders and an app-log INFO surfaces.
Beyond Helm, this release polishes search semantics across all three
panels (only the source panel's filter clears on focus leave; cursors
restore to last selection) and removes the panel-3 search entirely
(cursor-driven tabs didn't tolerate filter; "find a string in logs"
goes via Y + your editor).
Added
- Helm Releases category —
Helm > Releasesin the sidebar. Lists
every release in the cluster viahelm list -o json, polled every 3s
(no Helm watch API; the poller fakes awatch.Modifiedevent into
the existing watcher loop so externalhelm install/upgrade
surfaces within seconds without busy-spinning the CLI). Columns:
NAME / NAMESPACE / CHART / APP VER / REV / STATUS / UPDATED. Follows
the current namespace selector —helm list -n <ns>when a ns is
picked,-Aotherwise. - Helm doc menu —
Spaceon a Release row. Pops a 5-item picker:
Manifest(rendered chart),Creator Notes(post-install
NOTES.txt),User Values(user-supplied),Merged Values(incl.
chart defaults),Hooks(install/upgrade hook resources).
Enter/Spacefires the correspondinghelm get ...asynchronously
(10s timeout) and routes the stdout into the YAML popup. The menu
stays open behind the YAML so consecutive picks flow without
re-opening — input routing checksyamlPopupfirst while open, the
menu sits idle underneath, then takes input back when YAML closes.
Esc/qdismisses the menu. - Deployed Resources section in Release Relatives.
helm get manifestparsed into per-document{kind, name, namespace}tuples;
each native K8s ref becomes a drillable RelativeRow under a
Deployed Resources (N)section. Drill /Space/Yall work
exactly as on any other Relatives row, so Release → Deployment →
Pod → ConfigMap is a continuous chain. CRD kinds the registry
doesn't recognize are dropped silently — every visible row stays
drillable. The chain[0] entry is the Release itself, so the
breadcrumb popup showsRelease/foo → Deployment/foo → Pod/foo-.... - History tab — Panel 3, Helm releases only. Replaces Events for
releases (a release isn't a K8s object; kubectl events don't apply —
drill into a deployed resource if you want events). Table view:
REV / STATUS / DATE / CHART / DESCRIPTIONfromhelm history. The
current deployed revision is marked with a●glyph.j/k/g/G
move the revision cursor; the cursor auto-lands on the deployed rev
the first time the tab loads. - Rollback —
Spaceon a History row. On any non-current revision,
Spacepops a confirm popup whosedetailrow prints the exact
helm rollback <rel> <rev> -n <ns>that will run.Enterruns it
asynchronously (30s timeout,CombinedOutputso stderr surfaces);
success fires a toastRolled back to rev Nplus an app-log info
line, failure routes to app-log error with helm's stderr. On the
current row,Spaceis a silent no-op (no surprise re-deploy of the
state you're already on). - Rule A — helm-managed read-only guard. Pressing
eon any
resource carryingapp.kubernetes.io/managed-by: Helm(label) or
meta.helm.sh/release-name(annotation) — or on a Release row
itself — surfaces a "Helm-managed (read-only) — use helm upgrade /
rollback" toast instead of openingkubectl edit. Stops users from
editing fields the next helm reconcile would overwrite. - Helm storage secret filter —
.on the Secrets panel. The
per-revisionsh.helm.release.v1.*Secrets that helm uses for
release storage are hidden from the Secrets list by default — they
dominate the list otherwise..on the Secrets table flips
visibility; a.helmchip in the panel-2 bottom-left border
confirms when the filter is OFF (secrets shown). Enricher lookups
bypass the filter so SA → token-Secret links still work regardless.
Changed
- Confirm popup also dismisses on
Space(same asEsc/n/
q). The same key that opens the confirm (Relatives-tab space-jump,
History-tab rollback) re-pressed by reflex now cancels rather than
re-fires. - Search clears only on the source panel when focus moves away —
the panel you're leaving loses its filter, every other panel keeps
whatever filter it had. Sidebar / Table both restore the cursor to
selectedafter dropping the filter so the unfocus highlight lands
on the last picked item, not on whichever row the filtered index
happened to point at. .helmmarker moved to panel-2 bottom-left border. Earlier
iteration during 1.5 development surfaced helm-secret filter state
as.hiddenin the status bar. Final form uses the unused
bottom-left corner of the affected panel + an unambiguous.helm
label, since the marker only matters while looking at the Secrets
list.- Hidden KM8erm chip relabeled
KM8erm(waskm8ermlowercase)
to match the popup border title. - Breadcrumb + helm doc menu popups grew one row of top/bottom
padding so title/hint don't sit flush against the first/last
content row.
Removed
- Panel 3 search. The
/hotkey on the detail panel and all
associated filter rendering are gone. Cursor-driven tabs (Relatives,
History) don't tolerate row filtering — the cursor index becomes
meaningless once rows are hidden. Logs follow-tail breaks under
filter (new lines that don't match silently vanish). Events are
short enough to scroll. For "find this string in logs", pressY
to copy the content and grep / search in your editor.
Fixed
- Helm watcher busy-spin. The first cut returned a permanently-
closedwatch.Interfacefor releases, which made the watcher's
outer loop reconnect-and-re-list as fast as the CPU could go — a
single km8 sitting on the Releases panel would have pegged the
helm CLI. Replaced with a pollingwatch.Interfacethat fires
onewatch.Modifiedevent per interval and properly blocks
between ticks. - History tab cursor lit only on focus. The cursor row picked
the focused/unfocused style atbuildContentLinestime but
SetFocusedonly rebuilt for the Relatives tab. Switching focus
to a panel-3 History view left the cursor in unfocused-dim style
until the next 3s poll forced a rebuild. Fixed by including
History inSetFocused's rebuild list. - History cursor stuck across releases. Cursor-position state
travelled acrosspanel 2row changes; switching from a release
with 5 revs to one with 2 left the cursor on a now-invisible
index.SetDetailnow resetshistoryCursorwhen the underlying
UID changes (panel 2 row swap) but preserves it when the same UID
re-arrives via polling refresh (so user-typedj/ksurvives). - Sidebar search list "1 of 1" but empty.
resetCursorToFirstMatch
setm.cursorto the first matching index but never reset
scrollOffset— a stale offset from the previous wider list
could push the only match off the visible window. Now resets to
0 andensureCursorVisibles after. - Table search filter survived focus leave. Earlier ClearSearch
cleared the flags but didn't recomputem.rowsfromm.allRows,
so the panel could appear filtered after the search box was gone.
Now mirrors the in-panel Esc path: convert filtered cursor to its
unfiltered position, drop the filter, restore the cursor. - Sidebar focus-leave parked the cursor on a stale row. After
ClearSearch the filtered cursor index pointed at an unrelated
row in the now-larger visible list. ClearSearch now calls
SetSelected(m.selected)to put the cursor back on whatever the
user actually picked. - Long Relatives value wrap lost arrow color. A
harbor-registry-htpasswd ↘value that wrapped onto two lines
rendered the arrow as plain text on row 2 —wrapPlaintrimmed
the leading space before↘, so the suffix-match that decided
which chunk owned the arrow style missed. Now the arrow is
stripped before wrapping and re-appended (styled) to the last
chunk, with reserved width in the wrap budget.
v1.4.0
The Relatives release. The graph navigation tab that v1.3.0 named "Links"
gets the right name (Relatives — it's about what's related to this
resource, not what this resource points at) and the right hotkey
vocabulary to round it out: Space jumps the table cursor to whatever
ref you're highlighting, in either the Relatives tab or the breadcrumb
popup. Pod tab order swaps so Relatives is first — when you space-jump
to a Pod you land where you came from instead of being teleported to
Logs. ServiceAccount and Secret grow bidirectional links (RBAC
subjects + token-secret annotations). Selection styling gains a focused
vs unfocused distinction so you can always see which panel "remembers"
the cursor. Two KM8erm/drill bug fixes from v1.3.0 hotfixes promoted in.
Added
Space— jump panels 1+2 to a related resource. On the Relatives
tab, pressingSpacewhile the cursor is on a drillable ref pops a
confirm popup; pressingy/Enterswitches the sidebar selection
and the table row to that resource (drill chain reset, panel 3
rescoped). Works at any depth, on any drillable entry — including
nested rows likeVolumes / config / configMap/harbor-core. No
round-trip throughEnterto drill first. From inside the breadcrumb
popup,Spacedoes the same thing for the cursor-selected level;
the confirm popup stacks visually above the breadcrumb so cancelling
returns to the breadcrumb instead of dismissing it. (Yis still
cursor-aware YAML preview; the two hotkeys complement.)- ServiceAccount ↔ Secret bidirectional links. SA Relatives now
carry three new sections:RoleBindings (N)(namespace-scoped
bindings naming this SA as a subject),ClusterRoleBindings (N)
(cluster-wide same), andToken Secrets (N)(Secrets whose
kubernetes.io/service-account.nameannotation references this SA —
catches legacy auto-created token Secrets that aren't insa.Secrets).
Secret Relatives now show aServiceAccountsection back when that
annotation is set, completing the round trip. RBAC subject queries
are how you'd actually debug "why can / can't this SA do X" — they
needed a first-class surface, not a guess. - Focus-shift hotkeys (
l/Enter). SidebarlandEnterused
to re-fireResourceSelectedMsgfor the cursor row, duplicating what
j/kalready auto-emitted. They now shift focus to panel 2 — the
natural "I've picked the resource, now show me the rows" motion.
TableEnteron rows without drill capability (Deployments without
child config, ConfigMaps, etc.) likewise shifts focus to panel 3
instead of being a silent no-op. Resources that DO drill (Pods →
containers, HPAs → workloads) keep their drill semantics. Status line
drops the "Enter drill" hint — focus-shift is the obvious
adjacent-panel motion and not worth a slot. - Panel-aware selection styling. Focused panel cursor: reverse-
video — Catppuccin subtext1 (#bac2de) bg + base (#1e1e2e) fg +
bold. Unfocused panel selected: softer bg (#353648, between surface0
and surface1) + text fg + bold. So the panel you're driving and the
panel that "remembers" your selection are both visible at a glance.
Pod STATUS column gets a Catppuccin Latte (darker) palette variant
when the row has the focused light bg — Mocha pastel#a6e3a1washes
out on cream, Latte#40a02breads cleanly.
Changed
- Detail tab renamed: Links → Relatives. The new name describes
the relationship, not the implementation. The tab title at depth ≥ 2
showsRelatives N. Internal Go identifiers also renamed
(LinkSection→RelativeSection,EnrichLinks→EnrichRelatives,
internal/ui/links.go→relatives.go, etc.) so the source vocabulary
matches the UI. Pure mechanical rename, no behavior change. - Pod / Deployment tab order: Relatives first. Was
[Logs, Relatives, Events], now[Relatives, Logs, Events]. Space-
jumping to a Pod lands on Relatives — same tab the user came from, no
visual whiplash. Logs is one]away. - Nested Relatives rows wrap to two lines. Section children
(Volumes / config / configMap/foo) used to render as a single row
alias configMap/very-long-name, which truncated badly on narrow
terminals. Now: alias on one line, indentedresourceKind/name
on the next. Top-level entries (Owner / Node / ServiceAccount) keep
the single-line layout — short relationship words don't benefit from
splitting. - Glyph vocabulary unified. The Relatives drill arrow
→becomes
(Nerd Font chain glyph). Breadcrumb middle rows carry the same
glyph; the bottom row keeps its●you-are-here dot. Three surfaces
(drill arrow, breadcrumb middle, breadcrumb current) now read as
consistent vocabulary. - Search filters clear on
Space-switch. Stale sidebar / table /
detail filters from before the switch can't hide the freshly
selected resource anymore.
Fixed
- KM8erm: Alt+letter / Shift+Tab / Ctrl-arrows / F-keys forwarded
to the embedded shell.ptyKeyByteswas dropping these — zsh
hotkeys likeAlt+./Alt+f/Alt+Backspace, Shift+Tab reverse
completion, Ctrl+Left/Right word jump, and F1–F12 all silently
no-op'd inside KM8erm. Now they serialize to the right escape
sequences (meta convention ESC prefix for Alt, xterm CSI for
modified arrows, DEC SS3 / CSI~for F-keys). - Drill chain survives background watcher refresh. While drilled
into a deeper Relatives level, the watcher's periodic
ResourceDataMsgwould re-firefetchResourceDetailfor the
still-selected root row; the result'sSetDetailwiped the drill
stack and snapped the user back to level 1 just as their fetch
finished.SetDetailno longer touches the drill stack; the
row-change path resets it explicitly, namespace/context switches go
throughClearDetail(which still resets). - Selected-row highlight spans full row width. A long-standing
rendering bug where the Pod STATUS column's inner ANSI reset killed
the row style for every column after it, leaving Restarts / Age /
Node uncolored on the selected row. Per-cell style application
(separator + trailing pad row-styled too) fixes it; the row
highlight now reaches the right edge. - Detail panel cursor row honors focus state. Was always
rendering withTableSelectedRowStyleregardless of panel focus,
so the unfocused-panel softer style only ever applied to the table.
Now the Relatives cursor row picks the unfocused style when panel 3
isn't focused;SetFocusedrebuilds content lines on focus change
so the highlight refreshes immediately.
Internal
- New AppModel messages:
RelativePushMsg,RelativeDrillMsg,
RelativeBreadcrumbMsg,RelativeJumpMsg,relativeDrillFetchedMsg,
FocusTableMsg,FocusDetailMsg,SwitchToResourceMsg,
RequestSwitchToResourceMsg. - New helpers:
SidebarModel.ClearSearch,SidebarModel.SetSelected,
TableModel.SetCursor,DetailModel.ClearSearch,
DetailModel.CurrentLevelRef,AppModel.honorPendingTableSelect. - New k8s enrichers:
enrichServiceAccountBindings,
enrichServiceAccountTokenSecrets,enrichSecretServiceAccount. - New theme fields:
Sidebar.UnfocusedSelectedBg/Fg,
Table.UnfocusedSelectedRowBg/Fg.
v1.3.0
The big one. km8 becomes a graph navigator — the Links tab lets you
chase ownership / consumer / ref chains by repeatedly drilling
(Deployment → Pods → ConfigMap → consumer Pods → ...) without ever
leaving panel 3. 25 of 26 resource kinds carry Links data; every drill
respects a cycle pre-check; a breadcrumb popup lets you jump back to
any ancestor level in one step. Alongside that: a persistent embedded
shell (KM8erm), aggregate Deployment logs, a full-screen Y YAML
popup, and a layout refactor that ditched percentage-math heuristics
for absolute stacking.
Added
- Links tab — Lens-style graph navigation. Every detail panel
(except Namespaces, which has no meaningful refs) carries a Links
tab listing the resource's navigable references.Enter/l
drills into a ref — the panel re-renders showing that resource's
Links, building a navigation chain (Deployment → Pod → ConfigMap →
consumer Pods, ...).h/Escpops one level.bopens a
breadcrumb popup listing the full chain so you can jump back to any
ancestor in one step (j/kto pick,Enterto commit).Yon
the cursor-pointed entry opens its YAML popup. The tab label
surfaces depth asLinks ↳Nand the panel border carries a
[b]readcrumbshint at the top-right whenever you're deeper than
the root. Cycle detection (kind+ns+name) blocks revisiting an
ancestor; fetch failures show a peachShowWarntoast and don't
push a frame. Stale-drop guards (source item UID) keep async fetch
results from clobbering the panel when you've moved on to a
different row. - Links coverage for 25 of 26 resource kinds. Pods / Services /
Deployments / StatefulSets / DaemonSets / Jobs / CronJobs / Ingresses
/ HPAs / PVCs each surface their kind-specific refs (owners,
selected pods, scaleTargetRef, claimRef, ...). ConfigMaps / Secrets
/ ServiceAccounts / PVs surface reverse refs (which pods mount me
/ use me as their SA / are bound to me). Nodes /
PodDisruptionBudgets / NetworkPolicies / EndpointSlices / Roles /
RoleBindings / ClusterRoles / ClusterRoleBindings / StorageClasses /
IngressClasses all wired. Namespace hides the Links tab entirely
(no concrete drill target). - Aggregate Logs for Deployments. Selecting a Deployment row
streams logs from every pod in its current ReplicaSet into one Logs
tab (also Deployment's default tab — "which pod is misbehaving
during a rollout" is the question that opens 90% of Deployment
details). Lines are prefixed<pod-hash>│<container>│<text>with
three independent FNV-derived colors from the 8-entry Catppuccin
palette so any pod / container combination stays visually distinct.
Cross-stream timestamp sorting deliberately not attempted (clock
skew + jitter would make any ordering misleading). Falls back to
the Deployment's full selector when the current-ReplicaSet lookup
fails (RBAC denies RS list, etc.). - Persistent KM8erm (
Alt+t). The embedded shell survives
visibility toggling. FirstAlt+tspawns it; subsequent presses
hide / show while cwd, history, env vars, and background jobs all
persist. Status bar carries a chip in thens:row showing state —
greenattachedwhile visible, peachkm8ermwhile hidden. Shell
exits cleanly on km8 quit.Alt+tonly applies to the Shell-kind
PTY;kubectl editandkubectl execpopups treat it as a regular
key (their lifecycle is bound to the subprocess).e/swhile
any PTY is alive refuse with aShowWarntoast instead of
clobbering the in-flight subprocess. YYAML popup. Full-screen popup of the currently-selected
resource's YAML withj/kline scroll,u/dhalf-page,
gg/Gtop / bottom,/search (Entercommits;n/N
step through matches with full-row highlight; search-box border
flips cyan → amber when the filter locks),eto dispatch
kubectl editdirectly from the popup (skips the table-level
confirm), andyto OSC-52-copy the full YAML to your clipboard.
Solves the "YAML wall in narrow Panel 3 is hard to read" friction
without dropping YAML access. On the Links tab,Yfollows the
cursor — opens the YAML of the link entry you're pointing at, so
previewing a drill target's YAML doesn't require drilling into it
first.- App Log
yto copy. Pressyinside the App Log popup (!)
to OSC-52-copy the full log (newest-first, matching display order).
Makes "paste the error into Slack / GitHub issue" one key away. - Toast levels —
Show/ShowWarn. Info-level (Show) stays
1s sky-blue (Copied!, PTY hints); warning-level (ShowWarn) is 2s
peach with a warning glyph () for cycle-blocked / drill-failed
messages. Longer duration means you actually get to read what
blocked.ShowErrorreserved for when the first error caller
appears. - Per-popup distinct icons. Each popup (toast, confirm, help, app
log, context picker, namespace picker, YAML popup, breadcrumb,
PTY view) gets its own Nerd Font glyph in the title. N/Cuppercase aliases for namespace / context pickers.
Lowercase still works but feels too easy to misfire (nis
vim-search-next muscle memory). Lowercase will be deprecated later.- Sidebar category-name search. Typing
/followed by a category
name (cluster) expands matching categories and shows all their
children, not only items whose own label matches. - Detail panel refetch spinner. Panel 3 border shows an animated
braille spinner whilefetchResourceDetailis in flight.
Changed
-
Detail tab order: YAML moved out, Links is the default tab.
YAML lives in theYpopup now. New defaults:- Pod:
Logs/Links/Events - Deployment:
Logs/Links/Events - Events:
Linksalone - everything else:
Links/Events
Existing users who pressed
1/2/3to cycle to a YAML tab — use
Yinstead. - Pod:
-
h/lno longer switches detail tabs from inside Panel 3.
On the Links tab those keys belong to the drill chain (push / pop),
and dual-purposing them was confusing. To switch detail tabs while
reading panel 3, move focus to panel 2 first. From Panel 2h/
lstill cycle tabs as before. -
Tab label format. Drilled-into Links tab shows
Links ↳N(was
Links(N)); the down-arrow reads as "you've gone N levels deep" at
a glance. -
Panel layout uses absolute stacking math. Replaced percentage
heuristics (*N/100) with named constants (panelSidebarWidth = 24,panelDetailHeight = 14, ...) and pure subtraction. Side
benefit: predictable behavior on any terminal width. Panel 1
narrowed 28 → 24. Panel 2 ↔ Panel 3 vertical space dropped to 0
(borders themselves act as the separator). Sidebar ↔ Table
horizontal space also dropped to 0. -
Status line is fixed 1 row. Removed the dynamic two-row mode.
Hints are condensed (?,q, panel-specific keys,Y,M-t) —
no more vim-convention reminders, no overflow. -
YAML popup spans full terminal width. Was sized to a percentage
of the screen; now matches the panel-border alignment. Same for
the help popup. -
Help popup is two-column. Counts wrap rows per group to balance
the columns; padding distributes across inter-section gaps so the
columns terminate at the same height.
Fixed
- Panic on quit when KM8erm was hidden.
Stop()nil'dp.cmd
whilereadLoopwas still doingcmd.Wait(); the loop now
captures local pointer copies before the wait so the nil
reassignment can't race the in-flight wait. - Pod STATUS column lost its color when truncated. A
CrashLoopBackOffclipped toCrashL…no longer matched the color
lookup switch — color logic now reads the pre-truncation value
while the renderer keeps the clipped string. - Pod owner drill resolves past the ReplicaSet layer. A Pod's
OwnerReferences[0]is the auto-created ReplicaSet, but
kindToResourceTypemapped it toDeployments. The Name was the
RS's (<deployment>-<hash>), so drilling into Owner failed with
deployments.apps "..." not found.EnrichLinksnow looks up the
RS to find its owning Deployment and rewritesPodLinks.Ownerin
place. Also fixes cycle detection for the Deployment → Pod → Owner
round trip. - Stale
ResourceDetailMsgdrops by UID. Rapid row switching
used to let a slow fetch overwrite the current row's detail after
the user had moved on.ResourceDetailMsgnow carries the source
item UID; the handler ignores mismatches. - Help popup right border on odd-width terminals. Off-by-one
from integer-truncated column split — fixed by letting the middle
gutter absorb the leftover column. - KM8erm hidden status-bar marker uses peach (
#fab387). The
previous yellow was identical to thens:text; the new color
matches the panel-border palette and is unambiguous. Alt+thint everywhere is lowercase. The keymap is
case-sensitive; help / status line / KM8erm border hints now match
the actual key.- Long Links values wrap consistently for cursor and non-cursor
rows. Cursor row usedlipgloss.Width()(which wraps); non-
cursor rows had no width constraint and gotansi-truncated by
the outer panel — and the drill arrow disappeared from the
truncated rows, hiding the fact that the row was drillable. Both
branches now share an explicitwrapPlainpath; the drill arrow
→is split back off the last wrap chunk so its color stays in
drillStyle. - Breadcrumb cursor row aligns with non-cursor rows. The
cursor's highlight wrapped both the prefix's leading space and
an outer wrap-space, doubling it up;2.was shifted right by one
cell. Now both render with a single leading space inside the same
content frame. - Various popup margin and padding tightening. Top/bottom
padding rows dropped from the YAML popup, breadcrumb popup, and
overview cursor — the borders alone provide enough visual
separat...