Skip to content

Releases: vulcanshen/km8

v1.5.7

10 Jun 07:17

Choose a tag to compare

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 IP cell between Age and Node carrying
    .status.podIP, matching the kubectl get pods -o wide layout.
    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 Address cell between Hosts and
    Ports carrying .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 ingress shows.

v1.5.6

29 May 14:23

Choose a tag to compare

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.Row instead of the helm-augmented form. ColumnsForResource(Pods)
    reserves index 1 for the helm marker, so raw rows shifted Status one
    column left — stylizeCell then read the wrong cell and the
    Running / Pending / Error coloring fell silent until the user
    switched resources. Both exit branches (container-level pop, resource
    drill-stack pop) now go through augmentRowsWithHelm. Regression
    guarded by TestAppModel_ExitDrillDownFromContainers_RowsStayHelmAligned.

Changed

  • README license badge pinned to a static GPL-3.0 shield instead of
    shields.io's dynamic github/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

29 May 07:14

Choose a tag to compare

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.conditions as a TYPE / STATUS / REASON / MESSAGE / AGE
    table — same content as the Conditions section of kubectl describe.
    Status False rows 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 cpu stays 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; same PodsForWorkload helper 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 / Completed alongside
    the CronJob's SuccessfulCreate / MissingJob and 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/z for scroll/copy/expand.
  • Panel 2 menu Enter (drill) entry. When the selected kind
    supports drill-down, the per-row Space menu 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 an Esc ↖ back to parent list row.
    Cursor + Enter triggers exitDrillDown.
  • 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 shows esc: back in the bottom-left, mirroring
    panel 2's .: toggle helm pattern. 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
    just Space: 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 a demo-cron CronJob 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

28 May 01:42

Choose a tag to compare

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

27 May 15:26

Choose a tag to compare

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

  • Space scope 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).

v1.5.2

27 May 08:09

Choose a tag to compare

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.ptyView into
    m.shellPty (KM8erm, persistent) and m.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 carry Kind so the right slot cleans up.
  • Container drill Space menu. Pressing Space while drilled into a
    pod's container list now opens a single-item menu (Shell) instead
    of doing nothing. S direct 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 exec switches to green #a6e3a1, kubectl edit keeps sky blue
    #74c7ec. Title (bold) shares each popup's border color.

Fixed

  • Hidden KM8erm no longer blocks edit/exec. Old single-slot guard
    refused startShellExecMsg and startEditMsg whenever 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

27 May 04:30

Choose a tag to compare

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 key
  • Space = right-click menu — opens contextual menus, mirror-closes popups
  • h/l = panel 3 tab switch — only when panel 3 is active
  • Esc = 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 Space on a regular row
    to open a menu listing YAML(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 + Enter or 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 D on a Helm-
    managed K8s resource (label app.kubernetes.io/managed-by=Helm or
    annotation meta.helm.sh/release-name) now surfaces a "Helm-managed
    (read-only)" toast and refuses, matching E edit. Closes the v1.5.0
    leak where D skipped the guard.
  • z toggle 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. eE (edit),
    sS (shell). Aligns with D/Y/N/C and the Shift = anti-
    accidental modifier rule. Also affects the YAML popup's edit hotkey
    (now E).
  • n/c lowercase aliases removed. Namespace / context pickers
    only respond to N / C now — the lowercase aliases were a leak
    in the Shift = intentional rule.
  • h/l purely panel 3 tab switch. Previously h/l switched
    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).
  • l retired as a drill key. Enter is now the sole drill / focus-
    next-panel key throughout km8 (sidebar l/EnterEnter only;
    Relatives tab Enter/lEnter only).
  • h retired as drill-frame pop. Esc was always an alias; now
    it's the only key for back-out.
  • b key retired. The breadcrumb popup is now reachable via
    Space on the Relatives tab — folds into the universal "Space =
    open menu" rule. The [b]readcrumbs panel-border hint is removed.
  • Breadcrumb popup: Enter commits, Space closes. Inside the
    popup, Enter now commits the cursor row as a panel 1+2 switch
    (replaces the old jump-to-drill-level behavior). Space mirrors
    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 via ansi.Truncate +
    lipgloss.Width, so any multi-byte content survives narrow columns
    intact.
  • Pod STATUS color column-index lookup is dynamic. The hard-coded
    colIdx == 2 check 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 helm hotkey 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 accept Space to 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 where Space works 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 to kubectl edit), demo-helm (new — Space
    doc menu → Manifest YAML popup), demo-km8erm (two scale cycles
    showing hide/show persistence).

v1.5.0

25 May 16:21

Choose a tag to compare

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 > Releases in the sidebar. Lists
    every release in the cluster via helm list -o json, polled every 3s
    (no Helm watch API; the poller fakes a watch.Modified event into
    the existing watcher loop so external helm 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, -A otherwise.
  • Helm doc menu — Space on 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/Space fires the corresponding helm 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 checks yamlPopup first while open, the
    menu sits idle underneath, then takes input back when YAML closes.
    Esc/q dismisses the menu.
  • Deployed Resources section in Release Relatives. helm get manifest parsed into per-document {kind, name, namespace} tuples;
    each native K8s ref becomes a drillable RelativeRow under a
    Deployed Resources (N) section. Drill / Space / Y all 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 shows Release/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 / DESCRIPTION from helm 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 — Space on a History row. On any non-current revision,
    Space pops a confirm popup whose detail row prints the exact
    helm rollback <rel> <rev> -n <ns> that will run. Enter runs it
    asynchronously (30s timeout, CombinedOutput so stderr surfaces);
    success fires a toast Rolled back to rev N plus an app-log info
    line, failure routes to app-log error with helm's stderr. On the
    current row, Space is a silent no-op (no surprise re-deploy of the
    state you're already on).
  • Rule A — helm-managed read-only guard. Pressing e on any
    resource carrying app.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 opening kubectl edit. Stops users from
    editing fields the next helm reconcile would overwrite.
  • Helm storage secret filter — . on the Secrets panel. The
    per-revision sh.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 .helm chip 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 as Esc / 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
    selected after dropping the filter so the unfocus highlight lands
    on the last picked item, not on whichever row the filtered index
    happened to point at.
  • .helm marker moved to panel-2 bottom-left border. Earlier
    iteration during 1.5 development surfaced helm-secret filter state
    as .hidden in 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 (was km8erm lowercase)
    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", press Y
    to copy the content and grep / search in your editor.

Fixed

  • Helm watcher busy-spin. The first cut returned a permanently-
    closed watch.Interface for 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 polling watch.Interface that fires
    one watch.Modified event per interval and properly blocks
    between ticks.
  • History tab cursor lit only on focus. The cursor row picked
    the focused/unfocused style at buildContentLines time but
    SetFocused only 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 in SetFocused's rebuild list.
  • History cursor stuck across releases. Cursor-position state
    travelled across panel 2 row changes; switching from a release
    with 5 revs to one with 2 left the cursor on a now-invisible
    index. SetDetail now resets historyCursor when the underlying
    UID changes (panel 2 row swap) but preserves it when the same UID
    re-arrives via polling refresh (so user-typed j/k survives).
  • Sidebar search list "1 of 1" but empty. resetCursorToFirstMatch
    set m.cursor to 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 and ensureCursorVisibles after.
  • Table search filter survived focus leave. Earlier ClearSearch
    cleared the flags but didn't recompute m.rows from m.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 — wrapPlain trimmed
    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

24 May 16:23

Choose a tag to compare

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, pressing Space while the cursor is on a drillable ref pops a
    confirm popup; pressing y / Enter switches 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 like Volumes / config / configMap/harbor-core. No
    round-trip through Enter to drill first. From inside the breadcrumb
    popup, Space does 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. (Y is 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), and Token Secrets (N) (Secrets whose
    kubernetes.io/service-account.name annotation references this SA —
    catches legacy auto-created token Secrets that aren't in sa.Secrets).
    Secret Relatives now show a ServiceAccount section 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). Sidebar l and Enter used
    to re-fire ResourceSelectedMsg for the cursor row, duplicating what
    j/k already auto-emitted. They now shift focus to panel 2 — the
    natural "I've picked the resource, now show me the rows" motion.
    Table Enter on 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 #a6e3a1 washes
    out on cream, Latte #40a02b reads cleanly.

Changed

  • Detail tab renamed: Links → Relatives. The new name describes
    the relationship, not the implementation. The tab title at depth ≥ 2
    shows Relatives N. Internal Go identifiers also renamed
    (LinkSectionRelativeSection, EnrichLinksEnrichRelatives,
    internal/ui/links.gorelatives.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, indented resourceKind/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.
    ptyKeyBytes was dropping these — zsh
    hotkeys like Alt+. / 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
    ResourceDataMsg would re-fire fetchResourceDetail for the
    still-selected root row; the result's SetDetail wiped the drill
    stack and snapped the user back to level 1 just as their fetch
    finished. SetDetail no longer touches the drill stack; the
    row-change path resets it explicitly, namespace/context switches go
    through ClearDetail (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 with TableSelectedRowStyle regardless 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; SetFocused rebuilds 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

23 May 16:25

Choose a tag to compare

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 / Esc pops one level. b opens a
    breadcrumb popup listing the full chain so you can jump back to any
    ancestor in one step (j / k to pick, Enter to commit). Y on
    the cursor-pointed entry opens its YAML popup. The tab label
    surfaces depth as Links ↳N and the panel border carries a
    [b]readcrumbs hint at the top-right whenever you're deeper than
    the root. Cycle detection (kind+ns+name) blocks revisiting an
    ancestor; fetch failures show a peach ShowWarn toast 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. First Alt+t spawns it; subsequent presses
    hide / show while cwd, history, env vars, and background jobs all
    persist. Status bar carries a chip in the ns: row showing state —
    green attached while visible, peach km8erm while hidden. Shell
    exits cleanly on km8 quit. Alt+t only applies to the Shell-kind
    PTY; kubectl edit and kubectl exec popups treat it as a regular
    key (their lifecycle is bound to the subprocess). e / s while
    any PTY is alive refuse with a ShowWarn toast instead of
    clobbering the in-flight subprocess.
  • Y YAML popup. Full-screen popup of the currently-selected
    resource's YAML with j / k line scroll, u / d half-page,
    gg / G top / bottom, / search (Enter commits; n / N
    step through matches with full-row highlight; search-box border
    flips cyan → amber when the filter locks), e to dispatch
    kubectl edit directly from the popup (skips the table-level
    confirm), and y to 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, Y follows 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 y to copy. Press y inside 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. ShowError reserved 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 / C uppercase aliases for namespace / context pickers.
    Lowercase still works but feels too easy to misfire (n is
    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 while fetchResourceDetail is in flight.

Changed

  • Detail tab order: YAML moved out, Links is the default tab.
    YAML lives in the Y popup now. New defaults:

    • Pod: Logs / Links / Events
    • Deployment: Logs / Links / Events
    • Events: Links alone
    • everything else: Links / Events

    Existing users who pressed 1/2/3 to cycle to a YAML tab — use
    Y instead.

  • h / l no 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 2 h /
    l still 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'd p.cmd
    while readLoop was still doing cmd.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
    CrashLoopBackOff clipped to CrashL… 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
    kindToResourceType mapped it to Deployments. The Name was the
    RS's (<deployment>-<hash>), so drilling into Owner failed with
    deployments.apps "..." not found. EnrichLinks now looks up the
    RS to find its owning Deployment and rewrites PodLinks.Owner in
    place. Also fixes cycle detection for the Deployment → Pod → Owner
    round trip.
  • Stale ResourceDetailMsg drops by UID. Rapid row switching
    used to let a slow fetch overwrite the current row's detail after
    the user had moved on. ResourceDetailMsg now 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 the ns: text; the new color
    matches the panel-border palette and is unambiguous.
  • Alt+t hint 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 used lipgloss.Width() (which wraps); non-
    cursor rows had no width constraint and got ansi-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 explicit wrapPlain path; 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...
Read more