Keybindings
The default virtufin-tui keybindings. Press ? in the TUI for the same
table inline.
Global (App level)
| Key |
Action |
? |
Show help overlay |
q |
Quit |
Dashboard navigation
| Key |
Action |
right |
Next top-level tab (wraps) |
left |
Previous top-level tab (wraps) |
1-9 |
Switch to the Nth sub-tab of the active top-level tab |
The tab layout (which top-level tabs exist, and which panes are under
each) comes from pane_order in config.toml, not a fixed list -- see
Custom panes. The tables below assume the shipped
default layout (Home / Trading / Infra).
Beyond navigation, Dashboard forwards a small set of generic keys to
whichever action_* method the currently-mounted pane implements. A key
is hidden from the footer entirely if the current pane doesn't implement
the matching method.
| Key |
Dispatches to (first match wins) |
r |
action_refresh / action_refresh_data / action_run_script |
a |
action_action / action_add_topic / action_schedule |
d |
action_delete_row / action_disconnect_row / action_delete_topics |
enter |
action_detail / action_switch_context |
space |
action_toggle_pause |
/ |
action_filter |
c |
action_clear |
s |
action_save_script |
n |
action_new_script |
w |
action_toggle_wallclock |
t |
action_toggle_msgtime |
Ctrl+L |
action_clear_chat (AI tab only) |
P |
action_switch_provider (AI tab only) |
Home
No pane-specific bindings.

Trading tab
Instruments, Order Book, Portfolio, P&L, and Risk are, as of
this writing, mostly placeholders (see Architecture) --
all five currently share the same single binding:
The Config sub-tab under Trading is the same page documented under
Infra below. The AI sub-tab is documented at AI tab.
AI
A chat assistant that drives the control plane via tool calls. Appears under
both Trading and Infra (just before Config).
| Key |
Action |
Enter |
Send the typed message |
Ctrl+L |
Clear the transcript and start a fresh conversation |
P |
Switch the active LLM provider |
See AI tab for provider setup (llm_providers.toml,
DEEPSEEK_API_KEY / MINIMAX_API_KEY / OPENAI_API_KEY).
World
| Key |
Action |
r |
Refresh |
Enter |
Set the highlighted source as the active world |
a |
Add an untagged connection as an atomic world |
n |
Connect a websocket config (opens WS, sends handshake, starts publish) |
c |
Compose a new world from 2+ existing worlds |
p |
Toggle publish on / off for the selected connection |
d |
Remove a world (sets the world tag to empty) |
A World dropdown and a filter checkbox sit above the source table.
Pick a world in the dropdown and check the box to show only that world's
sources; uncheck to show all. Worlds are derived from the world field
of the TOML configs in ~/.config/virtufin/tui/worlds/.
The Publishing column uses a three-state symbol for feed rows:
green filled ● (connected + publishing), green hollow ○ (connected but
publishing toggled off), grey hollow ○ (not connected).
Instruments

Order Book

Portfolio

P&L

Risk

Infra tab
Workers
| Key |
Action |
r |
Refresh |
n |
New Worker: pick a type from the local registry (~/.config/virtufin/tui/workers.toml), fill in its config, and create it |
Enter |
Open a read-only worker detail popover (Escape to dismiss) |
a |
Open the action modal: set/clear tag, start, stop, delete |
d |
Delete worker (with confirmation) |

Connections
| Key |
Action |
r |
Refresh |
Enter |
Open a read-only connection detail popover (Escape to dismiss) |
a |
Open the action modal: set/clear tag, start/stop publish (by topic), disconnect |
d |
Disconnect (with confirmation; row is removed on success) |

Scripts
| Key |
Action |
↑ / ↓ |
Navigate the script list |
r |
Run the highlighted script (subprocess, isolated) |
s |
Save the edited script (user scripts only) |
n |
New user script (from a template, saved to ~/.config/virtufin/tui/examples/) |
e |
Toggle between the form (if the script has a paired .form.json) and the code editor |
f7 |
Select all in the editor |
Ctrl+C / Cmd+C |
Editor focused: copy selection (Textual native). Output log or script list focused: copy the entire output log to clipboard. |
Ctrl+V / Cmd+V |
Paste in the editor (Textual native, terminal bracketed paste) |
Ctrl+X / Cmd+X |
Cut selection in the editor (Textual native) |
Textual's binding chain checks the focused widget first, so Ctrl+C
on the editor copies a selection (native TextArea) and on the output
log copies the full buffer (ScriptsPage's own binding). q is the
global app-quit key -- Ctrl+C never quits, it copies.
Scripts, and any custom pane built the same way, use
the same script+form convention: a .py file with an optional sibling
.form.json rendered via textual_jsonforms. See Scripts
for the full write-up, including the env-var contract and the
init_scripts startup mechanism.

Triggers
| Key |
Action |
r |
Refresh |
a |
Schedule a new trigger |
d |
Delete the highlighted trigger |

States
Events
| Key |
Action |
space |
Pause / resume the live event stream |
c |
Clear the events buffer |
/ |
Filter events (substring match) |
a |
Add subscription topics |
d |
Remove subscription topics |
w |
Toggle the wallclock timestamp column |
t |
Toggle the message (CloudEvent time) timestamp column |

Config
| Key |
Action |
Enter |
Switch to the highlighted context |
ctrl+up / ctrl+down |
Move the highlighted pane up/down within its tab |
delete |
Remove the highlighted pane from its tab |
i |
Insert the highlighted "available custom pane" after the highlighted row in "Tabs & Panes" |
x |
Add a brand-new top-level tab (prompts for id + label) |
See Custom panes for the pane_order schema, how
the "Tabs & Panes" section works, and how to write a custom pane. See
Contexts for the contexts table above it.

Action modal
Opened via a from Workers or Connections.
| Key |
Action |
Tab / Shift+Tab |
Move between fields |
Enter |
Submit |
Escape |
Cancel |
Ctrl+Z |
Undo (tag changes only, 2-second grace period after submit) |
Detail popovers / service browser
| Key |
Action |
Escape |
Close (worker/connection detail popovers) or go back a level (service browser) |
Enter |
Drill into the highlighted item (service browser) |