Skip to content

Key bindings ​

Keys register through the mayflyKeymap service as named actions; a binding that collides within its scope is rejected. The /help overlay lists every registered binding live, followed by the shared panel keys below — it is the authoritative source for this page (if anything differs, trust /help).

Global actions ​

In effect unless a capturing panel (a picker, form, or approval in the editor slot) owns input:

KeyActionDescription
Ctrl-OToggle tool output expansionSwitch the most recent 3 turns of tool cards and thinking blocks between one-line summary and full output
F6 / Shift+F6Move surface focusTraverse the Editor, the views of the status bar, and the pane lanes: with a view available F6 enters the views first, then the interactive panes in layout order; crossing an end returns to the Editor
F7Previous conversationSwitch the complete UI back to the previously displayed conversation (main, BTW, or subagent); show a notice when no other conversation is open
F8Close side conversationClose the displayed side conversation (from main, the F7 counterpart): detach a subagent or dispose the temporary BTW Agent

Shared panel keys ​

Every panel, picker, and form follows one key grammar. The hint row at the bottom of a focused panel is generated from that same grammar, so it only shows keys that do something in the current state (up to three hints below 80 columns, four from 80, always including Esc when Esc does something):

KeyAction
↑/↓Move between rows and fields; scroll documents
←/→Cycle a select value, adjust a row setting, open or close a tree branch, or move along a tab strip
Alt+←/→ or F2/F3Switch tabs from anywhere on the surface; wizards validate the step being left
Alt+↑/↓ or F4/F5Move between controls from anywhere outside text editing and open pickers
←Used by the focused control when it changes something; otherwise it moves focus to the surface's rail of labels, where it does nothing
Enter or → on a railEnter the page beside the rail; ↑/↓ on the rail change the page at once
Alt+↓ or F5, F6From an empty prompt, enter the views of the status bar (F6 enters them first, then the interactive panes); ←/→ switch views and Esc returns to the prompt
PgUp/PgDn, Home/EndPage or jump in lists and documents
EnterChoose, run, open a picker, apply it, or start editing a field
SpaceToggle a checkbox or multi-select row, open a multiselect, or fold a tree branch
Tab/Shift+TabCommit a text field or picker and move to the next or previous control (while editing a field)
EscLeave the innermost layer: picker, editing, search, back, return to the first control, then close
Ctrl+CClose the surface, asking first when there are unsaved changes
Type or /Filter a filterable list; Ctrl+U clears the filter
1-9Pick a numbered row
Ctrl+EExpand focused scrollable content to full screen
DeleteReturn a changed field to its inherited or default value
Alt+Enter or Ctrl+JInsert a newline in a multi-line field
Enter, Ctrl+Enter, Alt+Enter, ↑/↓, BackspaceIn a prompt: send, send as a steer, insert a newline, walk the history of an empty prompt, or select and then remove the last token
Ctrl+S, c, x, r, Ctrl+G, Ctrl+FSave, copy, delete, refresh, open in $EDITOR, or search, wherever a panel offers that meaning

Details that follow from the grammar:

  • Esc leaves one layer per press, the same way everywhere: an open picker is cancelled, then text editing ends (the draft stays), then an active search ends (the filter stays), then a page with a Back target goes back, then focus returns to the panel's first control from anywhere else (the hint reads Esc back), and only then does the panel close. Tab strips are not a stop on the way out.
  • Disabled rows and options never take the cursor; movement steps over them. A row or action that is unavailable says why next to its label.
  • Select fields change with ←/→ and never with ↑/↓, which always move to the next field; a focused select shows its value as ‹ value › while it can cycle. Enter opens the option list; Tab applies the highlighted option and moves on.
  • Inherited settings carry (inherited) or (override) after the value. Changing the value overrides it; Delete on an overriding field returns it to the inherited value. There are no separate override buttons.
  • Filtering starts on the first typed character or /. Modifier shortcuts such as Alt+Enter or Ctrl+R keep working while a filter is active; in multi-select lists Space still toggles.
  • Numbered rows keep their numbers while the list scrolls. In gates such as plan review a digit only moves the cursor; Enter confirms.
  • Confirmations are one shared Yes/No decision with No focused first; the question may carry a sentence about consequences.

Editor context ​

Text-editing keys (cursor movement, multi-line, undo, kill-ring) belong to the underlying editor; in addition:

KeyActionDescription
EscapeInterrupt the flow / clear the draftWhile a session flow is in progress (the selected Agent or a live descendant runs), interrupt it: safe retraction of the just-submitted message first when the buffer is empty and eligible, restoring it into the editor, with the draft preserved; idle, it clears the draft, which stays one ↑ away in history; an open completion popup only closes
Ctrl-CClear draft → interrupt → exitWith a draft it only empties the box (the draft stays one ↑ away) and the flow continues; with an empty buffer while a session flow is in progress it interrupts the selected Agent and all running continuable descendants; when the whole tree is idle and the buffer is empty, a second press within 1 second exits Mayfly
Ctrl-EnterSteerInject the non-empty draft as a steering instruction into the current turn, clearing the buffer
Ctrl-VPaste imageStore the clipboard image in the attachment library, inserting an [image #N] marker at the cursor
Ctrl-GExternal editorHand the draft to an external editor for full-screen editing (mayfly.editorCommand setting → $VISUAL → $EDITOR; Mayfly suspends and yields the terminal); quitting with :cq leaves the draft untouched
Alt+MCycle session modelStep through the current provider's models (same channel as /model — the Host persists the default in the background; the press is consumed, the draft stays intact)
BackspaceDelete / exit modeBackspace on an empty ! bash prompt exits back to prompt mode
?Key helpOn an empty prompt, open key help; anywhere else ? is typed as text
Alt+↑Focus the conversationFrom the prompt, focus the newest row of the stream; a queued message there takes e edit, s send now, d cancel, and u undo. In the prompt, ↑/↓ walk the history only
Shift+TabToggle plan statenormal ↔ plan, preserving permissions and YOLO (see Session modes)

These keys reach the editor even while a notice is shown under the prompt. Editor extensions may add actions only on modifier keys (such as Alt+R); the editor keeps Esc, Tab, Shift+Tab, and every unmodified key.

Panel contexts ​

SurfaceKeys
/help overlay↑↓ / PageUp / PageDown / Home / End scroll; Ctrl+E expands; Tab reaches Close; Escape closes
/sessions pickerType to filter workspaces or conversations; ↑↓ moves; Enter opens a workspace, then session details; ← / → folds session branches; Esc ends editing/filtering, then returns one panel level
Approval panelThe focused default is Reject; ← / → or Tab reach Allow once, Allow for this session, and Reject with feedback; Enter runs; Escape rejects. On the feedback page, Enter sends, Alt+Enter adds a line, Esc ends editing and then returns to the decisions. There are no digit shortcuts
Questionnaire1–9 or ↑↓ + Enter choose and advance; multi-choice toggles with Space and confirms with Enter; typing in Other starts an answer, Enter submits it, Alt+Enter adds a line; the question tabs switch with ← / → on the strip or Alt+← / Alt+→ (F2 / F3) anywhere, and moving forward validates the current question
Form panel↑↓ move between fields; typing or Enter starts editing text, Enter confirms and moves on, Alt+Enter inserts a textarea newline; a select changes with ← / → or opens with Enter; a multiselect opens with Enter or Space; Delete returns an overriding field to its inherited value; a number steps with ← / →; Tab takes a matching completion, or commits and moves to the next group; Ctrl+S saves the form from any field; Escape ends editing, then closes (asking first when there are unsaved changes)
Plan review↑↓ or 1–3 move between decisions and Enter confirms the focused one; c copies the plan, o opens feedback; PageUp / PageDown / Shift+↑↓ scroll the plan
/model panelOne list grouped by provider: type to filter, ↑↓ selects a model, ← / → adjusts its thinking level; Enter sets the default and switches
/effort panel1–9 or ↑↓ + Enter set the default thinking level
/permission picker1–9 or ↑↓ + Enter switch presets; full access first asks a Yes/No decision with No focused
/agents browserType to filter; ↑↓ selects, Space or ← / → expands/collapses, Enter views; Tab reaches Stop selected, which asks first and names why it cannot run for a one-shot, cold, or parent-of-live row
/plugin marketplaceInstalled / Not installed tabs (← / → on the strip or Alt+← / Alt+→, also F2 / F3); type to filter; Tab reaches Details, Install or Update/repair, and Remove, each available per row; Ctrl+R refreshes
Side conversationUses the complete main editor and the same panel keys; PageUp / PageDown scroll its transcript; in a resumable one a send wakes the child: Enter queues the message for its next turn and Ctrl+Enter steers it; F7 switches back and F8 closes it

Named actions and custom bindings ​

Every key belongs to a named action, and the key is only that action's current binding. The panel keys above are the ui.* actions (ui.up, ui.accept, ui.cancel, ui.tab-next, ui.focus-prev, …); the common meanings are ui.save, ui.copy, ui.delete, ui.refresh, ui.external, and ui.search; Mayfly's own keys keep their mayfly.* ids, and a plugin names its row keys <owner>.<action>. A binding is live in one scope: the editor, a panel, the conversation stream, or everywhere. That is why Ctrl+S steers in the editor and saves in a panel, and Shift+Tab toggles plan mode in the editor and moves back a group in a panel.

Overrides live in the keybindings field of the mayfly settings namespace, keyed by action id, each with the keys that replace the defaults and the label to list it under:

yaml
mayfly:
  keybindings:
    ui.delete: { keys: [d], label: delete }
    acme-providers.test: { keys: [ctrl+t], label: Test connection }
  preferPlainKeys: true

A change applies at once, and every hint follows it. A key an action gives up stops working: it is not kept as an alias. A binding that collides with another action in the same scope is skipped with a warning naming that action's owner; Esc and Enter cannot be unbound or given to another action; and a plain character cannot be bound in the editor or everywhere, where it would type text. A panel to capture and restore keys (/keys) comes in a later phase.

Every default that uses Alt has a second one without it, because terminals and multiplexers often swallow Alt: F2/F3 switch tabs and Ctrl+J inserts a newline. The first F2-F5 you press tells Mayfly that Alt may not arrive, and from then on the hint rows show the plain key first; preferPlainKeys: true does that for good. Alt keys are read in every common encoding: xterm's ESC [ 1 ; 3 A with or without a kitty event type, a bare ESC prefix, SS3, kitty's CSI u, and modifyOtherKeys.

Panel accelerators declared by plugins must be valid key ids, cannot take shared navigation keys, cannot repeat on one page unless their scopes name different controls, and cannot be plain characters on a panel with a type-to-filter list.

Preview · v0.1.4-rc.1