The default keymap. All built-in keyboard actions are configurable.
See Configure key bindings for scopes and action names.
? inside sofka shows the effective bindings, including your own
plugin, bookmark, and workspace chords. : and ? work from every navigation
screen; closing either returns to the screen where it was opened. Text-entry
pickers keep both characters available as input.
At launch, sofka ctx or sofka contexts opens the context picker before
connecting. Press Enter to connect to the selected context and open its default
resource, or pods if none is set.
Use :resource -n namespace --context context /filter to apply a complete query.
Use :resource @context [namespace] for cross-context navigation. Context names
fuzzy-complete after @; Tab/Shift-Tab or Down/Up fill the selected context in
the command. Add a namespace if needed, then press Enter to run the query.
Without a namespace, a context switch uses its remembered or default namespace.
This does not change kubeconfig's current-context.
Scope options precede the slash. Structured filter terms combine with spaces or
&&, with || for OR and !(...) for group negation. / edits the active filter
and Esc clears it. See filtering
for the grammar and selector persistence rules.
A normal context switch through :ctx keeps the current resource type if the
target cluster supports it. Otherwise, sofka opens that context's configured
default resource, or Pods, and shows a fallback message. Filters and object
ownership scope are cleared. Startup still uses the configured default resource.
| Key | Action |
|---|---|
:resource -n ns --context ctx /filter |
query resource, namespace, context, and filter together |
:resource @context [namespace] |
switch context and resource; context names fuzzy-complete |
:resource -o layout |
open the resource in a named layout; default returns to the default columns, wide turns on wide mode |
:layout / :layout <name> |
pick the current kind's layout, default first / switch to it (the name tab-completes) |
:mouse |
switch mouse capture on/off for this session; off allows terminal text selection |
:<resource> |
command palette - fuzzy over kinds and built-in commands |
:<resource> <ns> |
switch kind and namespace at once (:deploy social; all/* = all namespaces; the namespace tab-completes) |
:ns <name-or-pattern> |
change namespace and keep the resource view; from Namespaces, return to the previous view or Pods (all/* = all namespaces) |
[ / ] |
view history - back / forward through visited kind+namespace views |
Tab / shift-Tab |
next / previous common resource in the current namespace; cycle workspace views when one is open |
enter |
drill down (workload/svc/node/ns → pods, machinedeployment → machines, cronjob → jobs, pod → containers, CRD → its resources, Argo app → :argo, ResourceSet → :gitops, or views) |
esc |
go back / pop the view stack / clear filter / clear marks |
j/k, ↓/↑, g/G |
navigate |
ctrl-f / ctrl-b, PgDn / PgUp |
page forward / back - one screenful at a time |
half_page_down / half_page_up |
half a page forward / back; unbound by default, see key bindings |
S / I |
sort-column picker (fuzzy; ⏎ on the active column inverts) / invert sort direction; saved per kind by default (remember_sort = false disables this) |
A |
sort by AGE; press again to invert; uses the sort memory setting |
ctrl-e |
compact mode: collapse the header + footer (for tiled/multiplexed panes) |
space |
mark/unmark row for bulk actions |
shift-up / shift-down |
extend or reduce the marked range from the starting row |
ctrl-space |
mark every row from the last space mark to the cursor |
/ |
filter: text · a|b · ~fuzzy · /regex/ · !inverse · label:text local label search · -l/-f selectors (server-side on ⏎) · status=X cpu>500m age<2h |
Ctrl+Z |
toggle faults filter in pod, workload, Flux, and Argo CD views; configured actions take precedence; combine with /; press again to turn off |
:workloads [ns] / :wk |
deployments, statefulsets, daemonsets, cronjobs, jobs and pods in one table; row keys act on the row's own kind |
:ns-resources [ns] |
namespaced kinds with objects in the namespace (default: current; all/* = all namespaces) and how many; ⏎ opens the kind in that namespace, r counts again |
R (namespaces view) |
open :ns-resources for the selected namespace |
O (workloads view) |
show or hide pods and jobs that a listed workload owns |
n / 0 |
namespace switcher / all namespaces; 0 also selects all namespaces inside the switcher while the filter is empty |
W |
switch to the selected resource's namespace and keep the resource kind |
1 to 9 |
select a configured favourite namespace in fixed configuration order; also inside the switcher while the filter is empty |
shift-j |
jump to owner/controller |
o |
show the node the selected row names (pods built in; other kinds via [views."…"].node) |
ctrl-r |
refresh the watch |
y / d / E |
view YAML / describe (native opt-in) / live events |
x |
secrets: show data base64-decoded (as stringData) · PVCs: browse the volume |
X / T |
explain why the selection is unhealthy / session-local state-change timeline |
u / :adjacent |
adjacent view: owners, children, and the objects the selection names or is named by (⏎ opens one) |
c (adjacent view) |
Discover direct children of a namespaced custom resource. Search starts on request. Results can be incomplete; see the limits in Features. |
:gitops / :flux |
Flux owner, source, revisions & reconciliation chain for the selection (⏎ to jump) |
:argocd / :argo |
Argo CD Application sync/health, source, managed resources & what's blocking, for the selection or the Application that manages it (⏎ to jump, c to expand what a resource owns) |
:users / :groups |
List subjects from RBAC bindings across all namespaces. Enter shows directly bound rules. |
:policy [u:name | g:name | s:ns/name] |
Show directly bound rules. Without an argument, use the selected service account. |
Enter (Role, ClusterRole, RoleBinding, ClusterRoleBinding) |
Show rules. Follow the binding's role reference when needed. |
t (RBAC rules) |
Switch rules between the resource and verb matrix and the rule list. |
h / l (RBAC rules) |
Scroll the matrix left / right. |
r / Esc (RBAC view) |
Read the data again / return to the previous view. |
:can-i / :can-i <verb> <resource> [ns] |
what you can do here / check a single action (SelfSubjectAccessReview) |
:journal / :audit |
session-local log of the mutating actions you've taken |
:rightsize |
historical right-sizing: P50/P95/P99 usage → suggested requests + patch preview (needs a metrics backend) |
:ctx / :ctx <name> |
context switcher popup (type to filter, r renames, space toggles fleet membership) / switch directly (the name tab-completes) |
:helm |
Helm releases (native storage-Secret decode): ⏎ history → values · y manifest · d notes · r rollback |
:rollout-history |
Deployment, StatefulSet, or DaemonSet revisions: ⏎ diff against the live template · r rollback |
:fleet |
cross-context health dashboard (opt-in: [fleet] contexts or space in :ctx; ⏎ switches, r refreshes) |
:skin |
pick a color skin with live preview; esc restores the previous skin (:skin gruvbox-dark applies directly) |
:reload / :config / :info |
reload config from disk · config sources + warnings · runtime diagnostics |
:check-update |
check for a newer sofka release and show the upgrade command |
l / p |
logs (marked pods, or current row; a pod with a kubectl.kubernetes.io/default-container annotation shows that container; workload = all matching pods) / previous-container logs |
L / :vlogs |
VictoriaLogs history for the selection (pod, container, workload, service, namespace), or its Cloud Logging / log UI link |
c |
copy resource name to clipboard |
Y |
copy any cell of the selected row: picker over the displayed columns (type to match a column name or value), ⏎ copies |
e |
edit in $EDITOR (kubectl edit) |
s |
shell into pod / shell into a PVC's volume / scale a resource with a discovered scale subresource (context-dependent) |
a |
attach to the pod's default container (kubectl.kubernetes.io/default-container, else the first one) |
:debug |
pod: ephemeral debug container (d in the picker targets one) · node: privileged debug pod (previewed + confirmed) |
:debug-clean |
delete the node debugger pods launched this session |
:pvc-explore / :pvc-clean |
browse the selected PVC (also :pvc-browse; see below) · delete helper pods a previous session left behind (also :pvc-cleanup) |
:bundle / :bundle-save |
assemble a redacted diagnostic bundle for the selection · write the previewed bundle to a file |
:snapshot [text|json|yaml] / :snapshots |
capture the current view to a file · browse, open, and delete saved snapshots |
:notify [note] |
toggle watch notifications on the selected object; note prefixes its messages |
:find <text> |
global fuzzy find over object names across common kinds, all namespaces |
:dir [path] |
browse local manifests and apply or delete them (see below) |
i |
set container image; on a Flux HelmRelease, set spec.chart.spec.version |
r |
rollout restart (marked workloads, or current) / force-sync (ExternalSecrets/PushSecrets) / rollback (Helm or rollout history) / refresh (elsewhere) |
f / shift-f |
port-forward (pods/services) — picker shows declared ports, marks busy local ports in use, or "Custom…" for remote and local ports; active forwards show ● next to the name |
t |
Flux and flux-operator: suspend/resume/reconcile (+ force where supported) · ArgoCD: suspend/resume (+ refresh, hard refresh, sync, sync with prune for App) · CronJobs: trigger/suspend/resume · pods: file transfer |
V / N |
CertificateSigningRequests: approve / deny (marked rows, or current); confirm shows requester, signer and usages; already decided requests are skipped |
C / U / D |
nodes: cordon / uncordon / open drain options |
ctrl-d / ctrl-k |
delete / force-delete (marked rows, or current); in confirm: f toggles force, c cycles cascade (background → foreground → orphan) |
w |
toggle wide-only columns (kubectl -o wide), including node IP addresses and labels |
← / → |
scroll sideways by 5 text positions; NAMESPACE/NAME stay fixed; arrows show more content |
:q, ctrl-c |
quit |
? |
help |
| (config) | plugin / bookmark / workspace key chords — ctrl-/alt-/shift-/fN; listed in ? help |
Shift+Arrow selects a range in the visible row order. Reversing direction reduces
the range and keeps separate marks made with space. Other keys end the range
operation. Normal movement keeps marked rows. Filtering, sorting, view changes,
and changes to the row order reset the range before the next Shift+Arrow press.
ctrl-space marks every row between the last row marked with space and the
cursor, in the visible row order. Existing marks stay. Without a marked starting
row, it marks the current row. Terminals that send ctrl-@ for ctrl-space work
the same way.
| Key | Action |
|---|---|
Tab / Down |
Select the next option |
Shift-Tab / Up |
Select the previous option |
Space |
Toggle the selected checkbox |
Text / Backspace / Ctrl-U |
Edit / remove a character / clear the selected duration |
Enter |
Review options, then confirm; close a completed operation |
Esc / Ctrl-C |
Cancel the form or active operation; close its result |
PgUp / PgDn |
Scroll the form, confirmation, or progress |
Drain options apply to the current operation only. The final confirmation shows all target nodes and selected options. Configured confirmation rules still apply. During a drain, navigation is disabled. Canceling stops requests and waiting; it cannot reverse a request that the API has accepted. Nodes remain cordoned. See Node drain options for defaults and limits.
| Key | Action |
|---|---|
enter |
start the selected mapping, or ask for remote and local ports for "Custom…" |
e |
edit only the local port of a declared mapping |
j / k, ↓ / ↑ |
select a mapping |
PgDn / PgUp |
move one page down / up |
esc / q |
close the picker |
A mapping whose local port is already bound on both loopback addresses when
the picker opens shows in use. The port can still change before you press
enter, so starting a forward checks it again.
"Custom…" asks for the remote port, a number or a port name, then for the local
port. The local port starts as the remote port when the remote port is a number.
Forwards bind to localhost, as with the declared mappings.
The local-port prompt contains the current value. enter starts the forward;
esc returns to the same picker row. Invalid or unavailable ports keep the
prompt open for correction. If the forward process cannot start, the prompt
keeps the edited value so you can retry.
A two-pane file browser over a PersistentVolumeClaim: your local filesystem on
the left, the volume on the right. s on a PVC row opens a shell at the mount
point instead. See PVC explore.
| Key | Action |
|---|---|
tab, ← / → |
switch pane (the focused pane has the bright border) |
j/k, g/G |
move within the focused pane |
enter |
open the selected directory |
⌫ or - |
go up one directory - stops at the mount point, never above it |
c |
copy the selection into the other pane: download from the volume, or upload |
s |
shell into the volume at the directory the remote pane is showing |
r |
re-read both panes |
esc / q |
close (and delete the helper pod, if one was created) |
Lists the folders and YAML/JSON manifests in path, or in the directory sofka
was started from. See Manifest browser.
| Key | Action |
|---|---|
j/k, g/G |
move |
enter |
open the selected folder, or show the selected manifest |
⌫ or - |
go up one directory |
e |
edit the selected manifest in $KUBE_EDITOR or $EDITOR |
a |
diff the selection against the cluster; a in the diff applies it |
d |
delete the resources the selection describes, after confirmation |
r |
re-read the directory |
esc / q |
close |
/ filter (substring · /regex/ · !invert) · s/f autoscroll · w wrap · ←/→ or h/l scroll sideways (unwrapped) ·
J JSON view (raw/record/pretty) · Ctrl+Z warning/error filter · m visual marker · t timestamps · x stop/resume stream · z clear buffer · c copy buffer ·
a default/all containers (pods with a default-container annotation) ·
ctrl-s save to a file in save_dir · F fullscreen (no chrome, clean text selection) ·
0–5 time anchors (tail · 1m · 5m · 15m · 30m · 1h) · T custom lookback (s/m/h/d/w, compound like 1h30m, decimal like 1.5h, or tail for kubelet logs)
(VictoriaLogs views) · esc back. The newest line anchors to the bottom of the
viewport.
t shows or hides timestamps in the current buffer without restarting the
streams. Log lines keep their timestamp order in both display settings.
m adds a separator after the latest received log line. Repeated presses add
separate markers. Markers stay visible through filters and are excluded from
sofka copy/save. While paused, a marker is added at the buffer tail without
moving the viewport. Markers have no timestamp. They are removed when the
buffer is cleared or replaced, or when their position is trimmed. Marker count
is limited to the active log buffer cap. Manual terminal selection can include
visible markers.
d uses kubectl by default. Enable the experimental deskribe backend with
--experimental-describe or [experimental] native_describe = true in config.
Unsupported native resources use a labeled kubectl fallback; errors from that
fallback never show cached YAML. See
configuration for overrides
and reload behavior. Helm rows continue to show release notes.
ctrl-f / ctrl-b page forward or back, with PgDn / PgUp as aliases.
/ searches like vim: the whole document stays on screen and every match is
highlighted. n / N go to the next or previous match. w wraps. c copies
the document. ctrl-s saves it to a file. esc backs out - the first press
clears an active search.
ctrl-s writes the whole document as rendered, whatever the search or scroll
position. managedFields are included only after m shows them, and a Helm
row saves the rendered manifest or values it shows. The file goes to
save_dir, the temp directory by default, as
sofka-<view title>-<unix time>.yaml for YAML and diff views and .txt for
the others. The file is readable only by your user, since a document can hold
Secret values, and a name that is already taken gets a -2, -3, … suffix
instead of replacing the earlier save. Log saves follow the same rules. The
write happens off the UI thread; the status line shows the path,
or the error if the directory cannot be created or the file cannot be written.
An empty document is not saved.
F toggles fullscreen for document views and plugin popup output. Fullscreen
uses the full terminal area without the application header, status line, key
hints, borders, or scrollbars. The title and active search or command prompt
remain visible. Search, scrolling, wrapping, copying, and refresh still work.
The setting stays on across refreshes and new documents for the current session.
It starts off in a new session and is separate from the Logs fullscreen setting.
F restores the normal layout. esc and q keep their existing behavior.
In the YAML and describe views, e opens the displayed resource in $EDITOR
(kubectl edit), even if the table selection moved while the document was open.
Read-only mode blocks it, and a Flux-managed resource asks for confirmation
first. sofka reads the resource before opening the editor and refuses if it was
replaced under the same name. The document is read again when the editor closes. The diff and
events views do not support e. Use keys.detail.edit to change the key
binding.
In the decoded Secret view, e opens the text values as stringData in
$KUBE_EDITOR or $EDITOR (vi when neither is set). The file is private to
your user and is deleted when the editor closes. If sofka exits without
deleting it, the next start removes it. Values that are not text are not shown
and cannot be overwritten from the editor. Delete a key to remove it, or write
stringData: {} to remove every text key. Save the file unchanged to cancel.
If the file does not parse, or a value is not a string, the editor opens again
with the error on top. sofka then asks for confirmation, naming the keys it
will change, add, or remove, and patches only those keys. The patch fails if
the Secret changed after e read it. An immutable Secret cannot be edited.
Read-only mode and the secret-edit guardrail apply.
In the YAML view, m shows or hides metadata.managedFields. Fields are hidden
when a document opens. Showing them reads the full resource from the API. The
choice stays in effect during automatic refresh. This key does not change
describe, decoded Secret, or diff views. Use keys.detail.managed_fields to
change the key binding.
Automatic refresh is available in these resource views:
| View | Automatic refresh | Other refresh controls |
|---|---|---|
| YAML, decoded Secret, describe | r turns refresh on or off |
None |
| Diff | r turns refresh on or off |
R resets the baseline to the displayed resource |
| Explain | R turns refresh on or off |
r refreshes immediately |
Automatic refresh is off when a view opens. It reads immediately, then waits 5 seconds after each result before the next read. Describe retains its selected backend: kubectl by default, or native-first with a labeled kubectl fallback when opted in. Native describe fetches fresh resource, related-object, and event data through the current Kubernetes client. The other views also read through the API. YAML and describe support custom resources.
Refresh keeps the original resource and context. It preserves document search,
scroll position where possible, and the selected Explain resource when findings
move or its status text changes. Findings without a resource target match by
content. If the selected finding disappears, the selection clears. Select another
finding before opening its resource, events, or logs.
A shorter document can reduce the scroll position. The status indicator shows
refresh while automatic refresh is on and stopped when it is off. Documents
without refresh support, such as saved snapshots and Helm manifests, show static.
Automatic refresh stops when you leave the view, open help or the command palette, or a request fails. Document search keeps refresh active. A failed request keeps the last result and shows the reason. A deleted resource, or a resource recreated with the same name and a different UID, also stops refresh. Opening events or logs from Explain stops its automatic refresh; returning does not restart it. Its existing manual evidence request can still finish.
Diff keeps the baseline chosen when the view opens, even if the last-applied
annotation or session history changes. R makes the currently displayed object
the new baseline. A Diff view can stay open when both sides match, so automatic
refresh can show later changes. This does not add change highlighting to YAML.
Help opens scrolled to the Keys: section of the view it was opened from. The
section order is the same from every view. A view without a section opens at the
top.
j / k and ↑ / ↓ scroll one line. ctrl-f, PgDn, and space move
forward one page. ctrl-b and PgUp move back one page. The page size is the
number of visible content rows. g / Home go to the top; G / End go to
the bottom. ] jumps to the next section heading and [ to the previous one.
/ filters the bindings. A binding that matches is shown under its section
heading. A section heading that matches keeps the whole section, so /table
lists every table binding. Starting a filter and clearing a filter reset the
scroll position to the top. esc clears an active filter first, then closes
help. q or ? closes help and returns to the previous screen.
j / k move, ⏎ goes to the resource behind a finding (a blocking pod), E
its events, l its logs, r gathers again, esc goes back. After opening
logs or events, one esc returns to Explain and another returns to the table. A
finding you can drill into has a trailing →.
Long findings wrap onto more rows. w toggles between wrapped and clipped
findings here and in the GitOps (:gitops) and Argo CD (:argocd) views. When
a finding is taller than the list, j / k scroll through its rows before
moving to the next or previous finding.
Every object directly connected to the selection: what owns it, what it owns,
what its spec names (a pod's node, claims, ConfigMaps, Secrets), and what names
it (the pods mounting a claim, the claims using a class). j / k move, ⏎
opens the object in its own view - name-filtered, so every action there applies
to it - y shows its YAML, d describes it, r gathers again, esc goes back.
Not offered on namespaces (enter re-scopes to one) or Helm rows.
See Views for adding CRD relations.
PgDn and PgUp move one page through every list picker: contexts,
namespaces, sort and copy fields, port forwards, containers, set image, skins,
snapshots, and the action and transfer menus. The page size is the number of
visible list rows. Paging also works while a picker filter is being typed.
half_page_down and half_page_up move half a page in every view and picker
that pages. They have no default keys; bind them in
key bindings,
for example to ctrl-d and ctrl-u. In pickers with a text filter, a shared
half-page key that types text or edits the line keeps doing that.
Backspace or Ctrl-H removes a character. ctrl-u clears the line,
ctrl-w / alt-⌫ delete the previous word.
In the : palette, tab/↓ and shift-tab/↑ move through the suggestion
list, → fills the highlighted one into the command so you can keep typing,
and ⏎ runs the highlighted one. → replaces only the word it completes: the
resource or command name, or the namespace or context argument. Rebind them under [keys.command] in
config.toml, for example:
[keys.command]
down = "ctrl-n"
up = "ctrl-p"
accept = ["ctrl-y", "enter"]Each value is one key combination or a list of combinations.
It replaces the default set for that action: ["tab", "down"],
["backtab", "up"], ["right"] for complete, or ["enter"]. Include a default in the list to keep it.
An empty list disables the action. Invalid values report errors. Explicit
completion bindings take priority over text editing and cancellation.
To assign ctrl-c or ctrl-e, first move or disable quit or compact under
[keys.global].
Legacy palette_next, palette_prev, and palette_accept settings are
automatically migrated to this format, with a config.toml.bak backup.
If the file cannot be updated, sofka warns and uses the converted settings in
memory. See migration for managed
configs, conflicts, and invalid values.
Interactive actions (e, s for shell, a) suspend the TUI and shell out to
kubectl. e in the manifest browser suspends it for your editor. Delete, scale, restart, set-image, suspend, resume, reconcile, and
port-forward go through the kube API (or a backgrounded process) directly.
If the first PVC listing fails because required tools are missing, sofka tries other suitable containers, then offers a helper pod. Accept or cancel the existing confirmation dialog. Volume access restrictions, read-only mode, and guardrails still apply. Canceling keeps the original error visible.
| Command | Action |
|---|---|
:<plugin> [name=value ...] |
Run a plugin with validated inputs. |
:plugin-activity |
Reopen the active plugin panel or retained report. |
:plugin-cancel |
Stop the active plugin run and its temporary forward. |
:sanitize [states=…] [dry_run=…] |
Delete the pods the namespace has finished with (pods view). |
:sanitize ships with sofka; see Sanitize pods.
A plugin command started from its key chord or with no arguments opens an input
form when an input has no default, or when the command sets prompt = "always".
Fields start with their default values. In the form:
Tab/Shift+Tabor↓/↑move between fields.←/→cycle a field withchoicesor abooleanfield.Backspaceremoves a character;Ctrl-Uclears the field.Entervalidates every field and runs the command. Errors appear under the field.Esccancels without running anything.
Rebind these keys under [keys.plugin_form].
Popup/report runs open a floating activity panel immediately. In that panel:
Ctrl+Alt+Ttoggles the popup without cancelling or restarting the job.Eschides without cancelling;:plugin-activityreopens it.- After completion,
Ctrl+Alt+Trestores diagnostics;Enteropens the report. - Rebind the toggle with
[keys.global].plugin_activity. Ctrl+Ccancels the focused run, not sofka. Outside the panel it still quits.↑/↓ork/j,PgUp/PgDnscroll;Home/ggoes to the start;End/Gresumes following.←/→orh/lscroll horizontally.:hides the panel and opens the command palette.
Installed packages add their commands and key chords to ? help.
Use :reload after a package change.
See Create a plugin package.
PgUp and PgDn scroll text that does not fit in the popup. The action keys stay
visible. In an input popup, typing moves the view to the cursor.
A failed interactive command opens an error dialog. esc or enter dismisses
it; PgUp and PgDn scroll the output. If a pod shell failed because sh is
missing, d opens the debug image prompt for the same pod and container.
Accept the image to start the debug container, subject to the configured
guardrails. Canceling the prompt returns to the original error.