NAME
zeughaus - edit zeughaus graphs and view what their runners report
SYNOPSIS
zeughaus [join host[:port]/database]
zeughaus --headless --control socket [--size WxH] [--scale factor] [join host[:port]/database]
zeughaus ctl socket command [argument ...]
DESCRIPTION
zeughaus is the editor. It edits the graph held in a session's store and draws what the runners of that session report: values, node errors, frames and terminals. It never executes a node; a graph runs in the zeughaus-runner it names (see zeughaus-runner(1)). Any number of editors, on this machine or others, may join one session.
At start the editor connects to the store of the session it is given, or to the default session 127.0.0.1:3000/zeughaus. It finds every runner in the store's runtime table and dials each one's endpoint over weida, presenting client.pem from its state directory. The editor never creates that key: without it, it prints [editor] no client identity in ... and shows no values. See zeughaus-files(5).
Without a store the editor still starts. It edits a local scratch graph under the tab bar section Local; nothing computes it, the status bar says so, and it is gone on close unless saved as a file.
The window is undecorated and draws its own titlebar, tab bar and resize grips. Its title is Zeughaus Editor; on Linux its application id (X11 WM_CLASS, Wayland app_id) is net.doodleshnookie.Zeughaus. Closing the window first flushes settings edits still held back (400 ms after the last keystroke) to the store. Keys, the command palette and the workspace are described in zeughaus-keys(7); the node types in zeughaus-nodes(7).
OPTIONS
The windowed editor reads one argument, join; everything else on its command line is ignored. --headless and its options, and the ctl command, exist only in a binary built with the remote feature (cargo build -p zeughaus --features remote); without it they are ignored too and a window opens.
joinhost[:port]/database- Join the session in database database on the store at host. port defaults to
3000; a bare database means the store on127.0.0.1:3000. Withoutjoin, the editor uses127.0.0.1:3000/zeughausand offers this machine's LAN address in its place as the token others join with ("Session / Copy Session ID" in the palette). The same token shape is whatzeughaus-runner jointakes. --headless- Run the real application without a window, rendered offscreen by a hardware wgpu adapter, and take input from the control socket. There is no software fallback: without an adapter the process prints
[remote] no wgpu adapterand exits 1. Store and runner connections, subscriptions and signals behave as in a window. The clipboard is kept in memory and never touches the desktop's, and the save and load file dialogs are refused with a hint. Any argument other thanjoinand the options below is an error. --controlsocket- The Unix socket the headless editor listens on. Required with
--headless. A stale socket file at that path is replaced; the file is removed when the host exits. --sizeWxH- Logical size of the pretend window, each side at least 1. Default
1280x800, the size a window opens with. --scalefactor- Scale factor, a positive number. Default
1. Screenshots and recordings are the logical size times this factor.
CONTROL COMMANDS
zeughaus ctl socket command [argument ...] connects to a headless editor, sends the words joined by spaces as one line, and prints the one-line reply on standard output: ok, possibly followed by a result, or err reason. Coordinates are logical pixels and may be fractional. Pointer and key commands deliver their events one at a time with the application's loop running between them, as a window would across frames, and reply once the loop has gone quiet (at most 250 ms). Each connection is served on its own thread, so a waiting wait-idle does not hold up another client. A relative screenshot or record path is resolved against the working directory of ctl, not of the host.
size- Reply
okW H factor: the logical window size and the scale factor. moveX Y [MS]- Move the pointer to X Y. With MS the move starts at the current position and is spread over that many milliseconds, one step per 16 ms.
down[button]- Press a mouse button where the pointer is:
left(default),rightormiddle. up[button]- Release a mouse button, as for
down. clickX Y [button]- Move to X Y, press and release button (default
left). dblclickX Y- Two left clicks at X Y.
dragX1 Y1 X2 Y2 [steps] [MS]- Press the left button at X1 Y1, move to X2 Y2 in steps evenly spaced moves (a positive integer, default 10), release. MS paces the moves over that many milliseconds; without it each step waits only for the loop to settle.
scrollX Y DY [DX]- Move to X Y and turn the wheel by DY lines vertically and DX lines horizontally (default 0).
keychord- Press and release one key. chord is [
ctrl+][shift+][alt+][super+]key, the prefixes in any order and case. key is one character or one ofenter,escape,tab,backspace,delete,space,arrowup,arrowdown,arrowleft,arrowright,home,end,pageup,pagedown,f1tof12.shift+upper-cases a letter as a US layout does; withctrl+,alt+orsuper+the key is a shortcut and types no text. typetext- Type the rest of the line, one key press per character, without modifiers.
findtext- Reply
okX Y W H, the visible bounds of the first widget whose text is exactly text;err not foundorerr not visibleotherwise. Inside the node graph the bounds are graph layout coordinates, not screen coordinates. screenshotpath- Render a frame with the pointer's hover state and write it to path as an RGBA PNG. Reply
okpath WxH in physical pixels. recordpath- Start a recording: frames at 30 fps are piped into
ffmpeg, which writes an H.264 MP4 (libx264,yuv420p,+faststart) to path. The pointer is painted in, with a ring around its tip while the left button is down. Replyok recordingpath WxH. NeedsffmpegonPATH; one recording at a time (err already recordingpath). record-stop- End the recording and wait for
ffmpegto finish the file. Replyokpath nframessecondss, orerr not recording. resizeW H- Set the logical window size, each side at least 1. Refused while recording (
err stop the recording first): a video has one frame size. scalefactor- Set the scale factor, a positive number. Refused while recording.
clip- Reply
okfollowed by the text on the in-memory clipboard, or a bareokwhen it is empty. clip-settext- Put the rest of the line on the in-memory clipboard.
wait-idle[MS]- Reply
ok idleonce no redraw is due and nothing has happened for MS milliseconds (default 200);err timeoutafter 10 s. The periodic tick and the store poll do not count as something happening. restart- Restart the editor as
SIGUSR1does (see SIGNALS) and replyok restarting. The new process binds the same socket path again, so a client pollingsizesees it come back. quit- Close the editor as the window's close button does: held settings edits are flushed and the runner connections closed. Reply
ok; the host then exits 0 and removes the socket.
GRAPH FILES
Ctrl+S saves and Ctrl+O loads a graph file (on macOS also Cmd+S and Cmd+O), through the system's file dialog with the filters Zeughaus Graph (*.zgh) and JSON (*.json). They are keyboard shortcuts, not palette entries. Save writes every node and edge this editor holds as one .zgh document. Load replaces the document this editor holds and writes nothing to the store; a file that does not parse is ignored. The format is described in zeughaus-files(5).
THE BROWSER BUILD
The editor also compiles to wasm32-unknown-unknown and runs in a browser tab (trunk serve in the zeughaus/ crate directory, see zeughaus-install(8)). The browser needs WebGPU: iced_nodegraph has no WebGL fallback. The browser editor edits locally. It does not connect to a store, so it neither sees nor changes a session, and no runner computes what it shows. It has no terminals, none of the native-only plugins (capture, db, record, llm), no file dialogs, and no state directory: the bundled themes are the whole choice and no preference outlives the tab. The canvas is rectangular, without the native window's rounded corners.
ENVIRONMENT
ZEUGHAUS_STATE_DIR- The state directory, when set and not empty. The editor has no
--state-diroption: an editor that is to use the credentials of a runner started with--state-dirpath needsZEUGHAUS_STATE_DIRset to that path. XDG_STATE_HOME,HOME- Without
ZEUGHAUS_STATE_DIR, the state directory is$XDG_STATE_HOME/zeughaus, else$HOME/.local/state/zeughaus.HOMEalso locates the SpacetimeDB client token (see FILES). ZEUGHAUS_RESTORE- Set by the editor itself when it restarts: the path of the restore file the new process reads at start and deletes. A second start with the same environment is a fresh one.
WAYLAND_DISPLAY- Not read by zeughaus; it decides, through winit, whether the window is a Wayland window. A Wayland window carries no icon (winit 0.30 cannot set one; the compositor takes it from the desktop entry named after the application id, which
deploy/install.shinstalls), and a restart cannot restore its position. Screen capture is decided by the runner's environment, not the editor's (see zeughaus-runner(1)).
FILES
All described in zeughaus-files(5).
<state-dir>/client.pem- The client identity the editor presents to runners. Read, never created.
<state-dir>/editor.toml- The theme and the tab bar's placement, written when either changes.
<state-dir>/themes/*.toml- WezTerm colour schemes, offered as themes by file name. Read at start.
<state-dir>/restore-<pid>.json- What a restarting editor hands to the process that replaces it.
~/.spacetimedb_client_credentials/zeughaus-<host>-<database>- The token the store issued to this machine for that store and database, saved by the SpacetimeDB SDK on every connect.
SIGNALS
SIGUSR1- Restart in place (unix). The editor flushes settings edits still held back, writes
<state-dir>/restore-<pid>.json, closes its runner connections andexecs the binary at the path it was started from, with the same arguments andZEUGHAUS_RESTOREnaming the file. A binary rebuilt at that path in the meantime is the one that starts. The file holds the window's size and maximized state, the tab in front and the focused pane, collapsed sections and groups, each graph's camera, resized node sizes, the selection, an open palette with its input, a rename in progress, terminal scroll-back, nested views open in a section without a runner, and, without a store, the scratch document. Tabs, panes, the selection and scroll positions are applied as the runners' snapshots arrive, for up to 15 s. The window's position is not restored: a Wayland client can neither read nor set it. The handler is installed in the windowed and the headless editor alike.
EXIT STATUS
zeughaus ctl exits 0 when the reply starts with ok, 1 on an err reply or when the host cannot be reached, and 2 on a malformed command line (no socket or no command). zeughaus --headless exits 0 after quit, 1 when it finds no wgpu adapter or cannot listen on the socket, and 2 on a malformed command line.
EXAMPLES
Start an editor on the default session, or join a session on another machine:
zeughaus
zeughaus join 10.0.0.8:3000/zeughaus
Build the headless editor, run it against its own store database and state directory, and drive it:
spacetime publish --server local zeughaus-agent --module-path zeughaus-module -y
cargo build -p zeughaus --features remote -p zeughaus-runner
ZEUGHAUS_STATE_DIR=/tmp/zh-agent target/debug/zeughaus-runner join 127.0.0.1:3000/zeughaus-agent &
ZEUGHAUS_STATE_DIR=/tmp/zh-agent target/debug/zeughaus --headless --control /tmp/zh-agent.sock join 127.0.0.1:3000/zeughaus-agent &
target/debug/zeughaus ctl /tmp/zh-agent.sock wait-idle 500
target/debug/zeughaus ctl /tmp/zh-agent.sock key ctrl+space
target/debug/zeughaus ctl /tmp/zh-agent.sock screenshot palette.png
target/debug/zeughaus ctl /tmp/zh-agent.sock key escape
Record a slow drag as a video:
zeughaus ctl /tmp/zh-agent.sock record drag.mp4
zeughaus ctl /tmp/zh-agent.sock drag 400 300 700 420 30 1000
zeughaus ctl /tmp/zh-agent.sock record-stop
Restart the newest editor in place after installing a new build:
kill -USR1 "$(pgrep -nx zeughaus)"
FUTURE DIRECTIONS
Not built: a browser editor that syncs with the store. The wasm build edits locally only.
SEE ALSO
zeughaus-runner(1), zeughaus-files(5), zeughaus-keys(7), zeughaus-nodes(7), zeughaus-architecture(7), zeughaus-install(8), zeughaus-glossary(7)
zeughaus/src/main.rs, zeughaus/src/remote/mod.rs, zeughaus/src/remote/host.rs, zeughaus/src/remote/ctl.rs, zeughaus/src/restart.rs, zeughaus/src/app/restore.rs, zeughaus/src/prefs.rs, zeughaus/Trunk.toml