Keybindings and contextual help
The focused pane's border shows useful actions with their loaded shortcuts. Help and keyboard dispatch use the same action catalog and context checks.
Ctrl+? (
⌘/on macOS — the bare Cmd+/, not Cmd+Shift+/) shows the current pane's actions for five seconds, followed by a short fade.Press it again while it is visible to open the same context in the Help drawer.
F1 opens or closes Help directly. Both shortcuts are rebindable.
Escape dismisses the temporary overlay. Any ordinary command dismisses it and still performs its normal action.
If the action list cannot fit legibly inside the pane, Help opens in the drawer directly.
Help is a fourth view of the existing drawer, alongside Julia, Terminal and Monitor. Switching to Help leaves Julia running. Escape returns to the previous drawer and focus; choosing Julia, Terminal or Monitor switches to that view. Help remembers which pane you asked about while you browse or search it.
In the Help drawer, type to search action names, descriptions or shortcuts; use arrows to select, Tab to switch between this pane and all panes, and Enter to open the manual page for the action's group in the browser (the published dev manual). A shadowed shortcut is listed as "binding shadowed" instead of being advertised as working. Embedded terminal applications own their own shortcuts; the catalog describes SoT controls around them. Primary+p (Ctrl+p on Windows/Linux, ⌘P on macOS) in the Help drawer writes a printable cheat sheet of the loaded bindings and opens it in the browser; print it or save it as PDF there.
Configuration
Each action maps to one chord or a list of chords in a [keys] table:
[keys]
help.toggle = "F2"
drawer.help = "F1"
files.run_current = "F8"
preview.png.zoom_in = ["Shift+ArrowUp", "+", "="]The first existing configuration file is selected, in this order (see Where the files are for what each step reads on each OS). Its listed actions override the defaults; unlisted actions keep their defaults:
$SOT_KEYBINDINGS..sot/keybindings.toml, found by walking upward from the frontend's working directory.$HOME/.config/sot/keybindings.toml.Built-in defaults.
Bindings load when the window starts. An agent can reload them live with the reload_keybindings frontend command (a command file in the window's command directory); otherwise restart the window. Invalid entries log a warning and retain the previous binding. The active Help drawer and pane borders reflect that resolved result. When two actions share a chord in the same context, catalog order defines dispatch precedence; Help identifies a shadowed binding.
Where a pane takes typed text (agent, terminal, Julia input, the editor, prompts, Help's search), a binding that is a single printable character, with or without Shift, never fires: the character is typed. Bind such actions with Ctrl, Alt or Super, or to a named key such as F8, if they must work there; Help lists them as "binding shadowed" in those panes.
Modifiers and keyboard layouts
On Windows the operating system hands the frontend the unshifted key while Ctrl, Alt or Win is held (Ctrl+Shift+/ arrives as /). A chord written with the shifted symbol, such as the default Ctrl+?, is therefore matched through the US layout's shifted pairs when Shift is held; Ctrl+/ and Ctrl+? stay distinct. Other layouts see the symbol they actually deliver.
Supported modifier names are Ctrl/Control, Alt/Option, Shift, and Super/Cmd/Command/Win. The legacy Meta alias continues to mean Alt. Primary means Command on macOS and Control on Windows/Linux; most defaults that are app-level chords (not terminal control codes) are spelled with it. Help and the printable cheat sheet always show the resolved form for the frontend's own OS (Ctrl+? on Windows/Linux, ⌘? on macOS), never the word Primary itself.
The frontend OS determines shortcut notation, including when a Mac frontend connects to a Linux backend: Control is ⌃, Command is ⌘, Option is ⌥, and Shift is ⇧. Explicit Control bindings remain Control; they do not silently become Command bindings. A Command binding must match the Command modifier.
Letter and named-key bindings match Shift explicitly: r and Shift+r are different actions, and Shift+ArrowUp does not also pan an image. A punctuation binding written without Shift fires with or without it held (+ and = both zoom in). A bare uppercase letter is shorthand for its shifted binding. Modified letter spelling is case insensitive (Ctrl+s and Ctrl+S mean the same chord).
Character shortcuts use the active keyboard layout. Ctrl+? means Control plus the question-mark character, without assuming its physical key position. Ctrl+Shift+/ explicitly binds the shifted slash key in the active layout. Option-modified keys match the layout's unmodified key on macOS (Option+= delivers ≠ on a US layout; the chord still reads as =). All shortcuts can be reassigned for layouts or OS shortcuts that conflict.
macOS reserves some chords at the system level regardless of what SoT binds: Control+Arrow switches Spaces or opens Mission Control, and F11 shows the desktop, which is why pane focus is ⌘Arrow there and fullscreen also accepts Ctrl+Cmd+F (F11 still works if that system shortcut is off). ⌘H also belongs to the default macOS application menu. Whether ⌘Q reaches the window's quit question or quits at once through that menu has not been tested on macOS; What keeps running says what to do meanwhile. ⇧⌘/ is the system Help-menu shortcut, on by default, and never reaches the app at all — that is why help.toggle's macOS default is the bare ⌘/ instead of the cross-platform Primary+? pattern. On Mac laptop keyboards F1/F5/F11 need the fn key unless "Use F1, F2, etc. keys as standard function keys" is on in System Settings.
Default actions
These are built-in defaults. In-app Help displays the bindings actually loaded. Normal text entry and terminal-application controls retain their own input handling.
| Action | Default shortcut(s) | Description |
|---|---|---|
help.toggle | Ctrl+? (⌘/ on macOS) | Show actions here for five seconds; press again to browse them in the Help drawer. |
drawer.help | F1 | Browse and search actions for the pane you were using. Escape restores the previous drawer. |
transport.reconnect | F5 | Retry backend connections immediately. |
view.fullscreen | F11 (+ Ctrl+Super+f on macOS) | Toggle borderless fullscreen. |
font.scale_up | Primary+= / Primary++ | Increase the frontend font size. |
font.scale_down | Primary+- / Primary+_ | Decrease the frontend font size. |
font.scale_reset | Primary+0 | Restore the default frontend font size. |
focus.pane_left | Primary+ArrowLeft | Move keyboard focus to the pane on the left. |
focus.pane_right | Primary+ArrowRight | Move keyboard focus to the pane on the right. |
focus.pane_up | Primary+ArrowUp | Move keyboard focus to the pane above. |
focus.pane_down | Primary+ArrowDown | Move keyboard focus to the drawer or pane below. |
workspace.cycle_next | Shift+ArrowRight | Switch to the next workspace. |
workspace.cycle_prev | Shift+ArrowLeft | Switch to the previous workspace. |
pane.maximize | Alt+= | Fill the window with the focused pane. |
pane.restore | Escape | Undo maximization, then wide preview, one layer at a time. |
layout.wide_preview | Alt++ | Hide or show the agent column to give the preview more room. |
view.selfie | Primary+Shift+S | Save a PNG of the whole frontend window. |
drawer.repl | Primary+j | Show or hide the Julia REPL. Changing drawer views keeps Julia running. |
drawer.terminal | Primary+t | Show or hide the frontend-local terminal. |
drawer.monitor | Primary+m | Show or hide host resource charts. |
view.scroll_line_up | Alt+ArrowUp | Scroll without moving the input cursor. |
view.scroll_line_down | Alt+ArrowDown | Scroll without moving the input cursor. |
preview.table_left | h / ArrowLeft | Move horizontally through a wide text table. |
preview.table_right | l / ArrowRight | Move horizontally through a wide text table. |
preview.table_reset | 0 | Return to the left edge of a wide table. |
session.create_codex | Primary+Enter | Create a workspace in the selected folder with a Codex agent. |
session.create_bare | Shift+Enter | Create a workspace in the selected folder with a shell and no agent. |
session.create | Enter | Create a workspace in the selected folder with a Claude Code agent. |
session.account_next | Tab | Cycle which login account the new session will use. Hidden when only one account is discovered. |
quit | Primary+q | Close the window from any pane but the agent and the Terminal drawer, whose programs keep Ctrl+Q, asking whether to keep the daemon and sessions running. |
files.copy_path | Primary+c / c | Copy the selected file's backend path to the clipboard. |
files.new | Primary+n | Create a file, or a folder when the name ends with /, in the selected directory. |
files.delete | Primary+d | Delete the selected file after confirmation. Directories are refused. |
nav.down | ArrowDown | Select the next row. |
nav.up | ArrowUp | Select the previous row. |
nav.expand | ArrowRight | Expand the selected node or descend into a folder. |
nav.open | Enter | Open the selected node; in Sessions or Hosts, select that target. |
nav.collapse | ArrowLeft | Collapse the node or go to its parent. |
mode.files | f | Browse project files. |
mode.modules | m | Browse Julia modules and methods. |
mode.sessions | s | Browse workspaces and agent sessions. |
files.pin | p | Keep the selected file in preview while browsing. Unpin returns to the pinned file. |
mode.hosts | h | Browse backend hosts. |
files.toggle_hidden | . | Show or hide dotfiles here or in the folder picker (a hidden folder can be a workspace root). |
session.destroy | Shift+d | Press twice to destroy the selected session. Any other command cancels confirmation. |
file.open | o | Open HTML, video or an interactive document in the browser; Julia files open in Pluto. |
file.docs | Shift+w | Open the built documentation site for this file in the browser. |
file.execute | Shift+o | Render a Quarto document and execute its code chunks. |
files.download | d | Download the selected file to the frontend machine. |
files.upload | u | Choose local files to upload into the selected directory. |
files.run_fresh | r | Restart Julia in this project and run the selected Julia file. Existing REPL variables are cleared. |
files.run_current | Shift+r | Run the selected Julia file using the current Julia session and its variables. |
repl.clear | Ctrl+l | Clear the displayed REPL output; Julia's variables remain. |
input.paste | Ctrl+v / Super+v / Shift+Insert | Paste the clipboard into this pane. |
agent.copy | Primary+Shift+c | Copy selected agent output to the clipboard. |
preview.page_next | n / PageDown | Show the next page of the displayed document. |
preview.page_prev | p / PageUp | Show the previous page of the displayed document. |
preview.png.reset | r / 0 | Reset zoom and pan to fit the image in the pane. |
preview.png.zoom_in | Shift+ArrowUp / + / = | Enlarge the displayed image. Fit image restores the overview. |
preview.png.zoom_out | Shift+ArrowDown / - | Reduce image zoom down to fit-to-pane. |
preview.png.pan_left | ArrowLeft | Move across the zoomed image. |
preview.png.pan_right | ArrowRight | Move across the zoomed image. |
preview.png.pan_up | ArrowUp | Move across the zoomed image. |
preview.png.pan_down | ArrowDown | Move across the zoomed image. |
preview.scalebar.toggle | Primary+s | Toggle the physical scalebar, or enter the pixel size when scale is unknown. |
view.return_nav | Escape | Move focus back to the navigation tree. |
preview.capture | c / Primary+c | Crop the visible image region and attach it to the agent input. |
preview.copy_code | y | Copy the displayed markdown code blocks to the clipboard. |
preview.edit | e | Edit the displayed file or its concept annotation. |
view.page_up | PageUp | Scroll back through this pane. |
view.page_down | PageDown | Scroll forward through this pane. |
preview.up | ArrowUp | Move up through the displayed text. |
preview.down | ArrowDown | Move down through the displayed text. |
preview.start | Home | Scroll to the beginning of the displayed text. |
preview.end | End | Scroll to the end of the displayed text. |
preview.half_up | Ctrl+u | Scroll up half a pane. |
preview.half_down | Ctrl+d | Scroll down half a pane. |
help.up | ArrowUp | Previous action in the Help drawer. |
help.down | ArrowDown | Next action in the Help drawer. |
help.page_up | PageUp | Previous actions in the Help drawer. |
help.page_down | PageDown | Next actions in the Help drawer. |
help.scope | Tab | This pane or all panes in the Help drawer. |
help.manual | Enter | Open manual in the Help drawer. |
help.cheatsheet | Primary+p | Write a printable page of every listed action and its loaded shortcuts, and open it in the browser (print or save as PDF there). |
help.close | Escape | Return to work in the Help drawer. |
files.confirm_delete | y / Shift+y | Delete the file named in the confirmation prompt. Any other key cancels. |
edit.confirm_discard | y / Shift+y / Escape | Discard unsaved edits and close the editor. Another key returns to editing. |
edit.reload | r / Shift+r | Discard this edit buffer and reload the externally changed file. |
edit.keep | k / Shift+k | Dismiss the external-change warning and continue editing. |
edit.undo | Ctrl+z / Super+z | Undo in the editor. |
edit.redo | Ctrl+y / Super+Shift+z | Redo in the editor. |
edit.copy | Ctrl+c / Super+c | Copy selection in the editor. |
edit.cut | Ctrl+x / Super+x | Cut selection in the editor. |
edit.paste | Ctrl+v / Super+v / Shift+Insert | Paste in the editor. |
edit.newline | Enter | Insert newline in the editor. |
edit.backspace | Backspace | Delete previous character in the editor. |
edit.delete | Delete | Delete next character in the editor. |
edit.left | ArrowLeft / Shift+ArrowLeft | Move the editor cursor. Hold Shift to extend the selection. |
edit.right | ArrowRight / Shift+ArrowRight | Move the editor cursor. Hold Shift to extend the selection. |
edit.up | ArrowUp / Shift+ArrowUp | Move the editor cursor. Hold Shift to extend the selection. |
edit.down | ArrowDown / Shift+ArrowDown | Move the editor cursor. Hold Shift to extend the selection. |
edit.home | Home / Shift+Home | Move the editor cursor. Hold Shift to extend the selection. |
edit.end | End / Shift+End | Move the editor cursor. Hold Shift to extend the selection. |
edit.page_up | PageUp / Shift+PageUp | Move the editor cursor. Hold Shift to extend the selection. |
edit.page_down | PageDown / Shift+PageDown | Move the editor cursor. Hold Shift to extend the selection. |
edit.start | Ctrl+Home / Shift+Ctrl+Home | Move the editor cursor. Hold Shift to extend the selection. |
edit.finish | Ctrl+End / Shift+Ctrl+End | Move the editor cursor. Hold Shift to extend the selection. |
edit.save | Ctrl+s / Super+s | Save the current file or concept annotation. |
input.cancel | Escape | Cancel the current input. Unsaved edits require confirmation. |
input.confirm | Enter | Submit the entered filename or value. |
repl.interrupt | Ctrl+c | Interrupt the evaluation the drawer shows running (again while the same evaluations still run: force it, which can crash the REPL inside C code; starting another evaluation in between makes it an ordinary interrupt again), or clear the input when Julia is idle. |
repl.history_prev | ArrowUp | Recall the previous Julia input. |
repl.history_next | ArrowDown | Recall the next Julia input. |
picker.parent | Backspace | Go to the parent folder in the new-session picker. |
repl.submit | Enter | Evaluate the current Julia input. |
repl.newline | Shift+Enter | Continue the Julia input on another line. |