Skip to content

Keyboard & canvas

The canvas is deliberately shallow: a handful of modifier shortcuts, and everything else on the right mouse button. This page lists what is actually bound. Nothing more.


Every shortcut in the editor’s own handler requires a modifier, and Cmd and Ctrl are interchangeable on every platform. The handler tests metaKey || ctrlKey, so Ctrl+Z works on macOS and Cmd+M works on Linux. Tooltips in the UI say “Cmd” because it was written on a Mac.

All of them are suppressed while the event target is an <input>, a <textarea>, or a contenteditable element. Typing in a note or a prompt never triggers them.

KeysAction
Cmd/Ctrl + ZUndo
Cmd/Ctrl + Shift + ZRedo
Cmd/Ctrl + CCopy the selected nodes
Cmd/Ctrl + VPaste
Cmd/Ctrl + DDuplicate the selection
Cmd/Ctrl + MToggle mute on every selected node
Cmd/Ctrl + BToggle bypass on every selected node

There is no Cmd+Y redo, no Cmd+A, no Cmd+X, no Cmd+S (graphs save themselves), and no arrow-key nudge.

Two keys are bound outside that handler:

KeysActionNote
Backspace or DeleteDelete the selected nodes and wiresThe only way to delete a wire. There is no edge context menu
EscapeClose the node menu, the wire/add-node menu, and the tab menuNot a modal dismiss: the params editor, param-run prompt, validation and detached-gate dialogs close via their own buttons or by clicking the backdrop
Cmd/Ctrl + EnterSend the message in the Live handoff dockOnly while that dock’s composer has focus

The toggle is per-node, so a mixed selection inverts rather than normalizing. Mute and bypass are mutually exclusive. Setting one clears the other. Nodes that cannot be muted (notes, frames) ignore the shortcut silently.


ActionResult
Double-click empty canvasQuick-add menu. Every node type, nothing pre-wired
Right-click empty canvasThe same add-node menu
Drop a wire on empty canvasWire-drop menu, filtered to node types that can legally connect. Titled add next node when you dragged from an output, add input node when you dragged from an input
Shift+click a connectorSame compatible-node menu, pinned next to that handle (compatible next nodes / compatible input nodes)
Right-click a nodeNode context menu
Right-click a workflow tabTab menu. Export, duplicate, promote/convert, close, close others, close to the right, close all

Double-click zoom is disabled so the quick-add gesture is free. Panning or zooming the canvas closes any open menu, because the menus are viewport-fixed.

The wire-drop menu lists the built-in blocks first, then custom nodes, agents, library payloads and sessions. If nothing can legally connect to what you dragged, it says no compatible node.

EntryEffect
❯ run from this nodeRun this node and everything downstream. Upstream nodes feed in their last result
⊙ test this nodeRun only this node
⌫ clearWipe captured content on an Output node
❐ copyCopy captured Output text to the clipboard
⊘ mute / unmuteSkip the node. Downstream starves
⤳ bypass / unbypassPass input straight through without executing
⟳ retryCycle extra attempts (with backoff) before the node counts as failed
⤼ on errorToggle between continue and fail run
⇄ exchange agent ›Swap the agent on an agent node (agent nodes only)
▦ group selectionWrap two or more selected nodes in a frame
⌗ save selection as sub-workflowExtract the selection into its own graph
▦ ungroupDissolve a frame (frames only)
↻ sync from sub-workflowRe-pull a linked frame’s contents (linked frames only)

The two run entries are disabled while the graph is running.

ActionResult
Click a skill or rules nodeOpens the inspector. Reading is the primary action for these
Double-click any nodeOpens the inspector
Double-click a linked frameNavigates into the sub-workflow it points at
Double-click a frame titleRename it inline
Double-click a noteEdit its text
Drag a frameMoves every member with it. Nodes tagged to the frame, plus any node whose centre sits inside it
Drag a node into a frameRe-tags it to the innermost frame containing its centre. Members of a linked frame are exempt and stay put
Drag a palette item onto the canvasAdds it where you dropped it
Drag a .json file onto the canvasImports it as a workflow
Drag a workflow tab (chrome / ×)Reorders it
Drag across a tab titleSelects the name text (copyable). Does not start a reorder
Middle-click a workflow tabCloses it
⊡ in the canvas controlsCleanup arrangement. Pack nodes by wire depth, center fan-outs on predecessors
Hover the minimapExpands it. Otherwise it stays compact in the corner
SignalWhere
Thin progress fillBottom edge of a background tab that is running / waiting / errored
Under-tabbar railOnly the focused graph’s run

These come from the canvas library’s defaults rather than threadle’s own handler, and they are the one place where macOS and other platforms genuinely differ.

ActionResult
Shift + drag on empty canvasRubber-band selection box
Cmd (macOS) / Ctrl (elsewhere) + click a nodeAdd it to the selection
WheelZoom
Drag empty canvasPan
Hold Space + dragPan without hitting the pane

Zoom is clamped to 0.08×–2.5×, and the view fits the graph when a workflow first opens. Scrollable areas inside nodes. Prompt bodies, output panes, run logs. Capture the wheel instead of zooming the canvas. The minimap in the bottom-right stays compact until you hover it, then expands for panning and zooming.


  • Graph & wires. What the canvas is modelling
  • Run. Partial runs and graph settings
  • Graph lint. The dock that catches wiring mistakes