YUME desktop GUI
yume-gui is a desktop window for YUME clients on Linux. It imports sealed
kits, starts and stops each kit’s yume, and shows what the running client
reports. Build it with YUME_BUILD_GUI=ON.
The manual is docs/man/yume-gui.1.
How it relates to yume
The window is an ordinary user process with no privilege. It never holds a
session, a key or the tunnel itself. It reaches a running yume only
through that client’s owner-only control socket, as
control protocol 1 defines, and it runs the yume
program to validate, start and import kits, and yume-setup to apply tuning.
- Start. Connect runs
yume --config KIT/yume.json --control-socket $XDG_RUNTIME_DIR/yume/KIT.sock --validate, then starts the same command without--validateas a detached process in its own session. Closing, killing or crashing the window leaves the tunnel running. Whatyumeprints goes to$XDG_RUNTIME_DIR/yume/KIT.log, replaced at each start, so a start that fails before its socket opens still says why. Until the socket opens, the window counts the process as the kit’s client while its command line names the kit’s socket, or while it runs with an empty command line, as a process does inside execve. - Find. A kit’s socket path follows from its name, so a window opened later asks each kit’s socket and shows a client that already runs.
- Stop. Disconnect sends the protocol’s
stoprequest.yumeanswers, closes its listeners and sessions as onSIGTERM, and the window reports the tunnel stopped once the process has ended, not only its socket. - Watch. While a client runs, the window asks for its status every second and for new printed lines every 1.5 seconds.
This process lifecycle works without a service manager. A yume that crashes
is not restarted, and tunnels do not start at login. A packaged user unit may
provide those features later. A kit with a managed TUN adapter needs privileges a
user process does not have, so the window cannot start one. Run such a kit as
a system service instead.
What each part does
- yume-gui
- Owns the display and kit selection. It links no YUME library and sends no traffic through the tunnel itself.
src/gui/tunnel.cppsrc/gui/control_client.cpp - yume
- Owns credentials, adapters, session and the control socket. The same user can ask status, follow messages and request stop.
src/runtime/native_cli.cppsrc/runtime/control_socket.cpp
Text version
+-----------------+ +-----------------+
| yume-gui | | yume |
| window | | tunnel process |
+-----------------+ +-----------------+
| |
| run with --validate |
|---------------------------------->|
| |
| validation result |
|<----------------------------------|
| |
| start detached, socket path |
|---------------------------------->|
| |
| .--|
| listen, connect, serve socket | |
| '->|
| |
| status and messages |
|---------------------------------->|
| |
| state and printed lines |
|<----------------------------------|
| |
|--. |
| | close window, client runs |
|<-' |
| |
|--. |
| | reopen window, find client |
|<-' |
| |
| Disconnect: stop |
|---------------------------------->|
| |
| acknowledge stop |
|<----------------------------------|
| |
| .--|
| drain and exit | |
| '->|
| |
|--. |
| | process ended: stopped |
|<-' |
| |
The tray
Where the desktop shows tray icons, yume-gui adds one: the YUME mark with
the selected kit’s state as a dot, green while connected, amber while it
connects, starts or waits to retry, red when the running client reports a
failure and grey when it is not running. Its menu names the kit and state,
connects or disconnects it, shows or hides the window and quits the GUI.
With the tray, closing the window hides it. Without one, or with
--no-tray, closing the window ends the GUI. Either way the tunnel keeps
running.
Kits
A kit is a directory under $XDG_CONFIG_HOME/yume/kits, one per client, with
the yume.json and credential files that yume-setup wrote for it. The
Connect page imports a sealed kit: choose the file,
name the kit and type its code. The window runs yume --import-kit FILE
--into DIR and hands it the code on its standard input, so the one
implementation in yume opens, checks and writes the kit, and the window
links no cryptography. The code never goes into a command line or a file.
yume-gui --import-kit FILE --name NAME does the same without a window.
A kit’s name is 1 to 48 letters, digits, dots, dashes or underscores, starting
with a letter, digit or underscore, and names its directory, socket and output
file. Rename opens a name dialog for a stopped kit; Cancel or Escape leaves it
unchanged. Before moving its directory, the window asks both names’ control
sockets again and refuses a running client or an uncertain reply. The move
never replaces an existing target and keeps the kit’s configuration and
credentials unchanged. Relative credential paths follow the directory, as
yume resolves them from yume.json’s parent. An absolute file, forward socket
or program path inside the old directory is refused; use relative file
references or move those other paths outside it first. The selected kit and
saved selection follow its new name.
File references with .. components are also refused, as the native parser
already requires.
The checks do not reserve the name against an independent process starting a
client immediately afterwards; stop clients using the kit before renaming it
from another window or command line.
Removing a kit deletes its directory, keys included, after a second confirmation, and only after the GUI gets a fresh stopped reply from that kit’s control socket. An unanswered, malformed or refused reply leaves the kit in place. Stop clients using the kit in other windows or on the command line before removing it.
The pages
Overview shows the connection as the status reply states it: connecting, connected and for how long, or waiting and when the next attempt starts. It shows the server’s verified identity, send and receive rates with a 90-second history, payload and on-the-wire totals, sessions and failed attempts, the last failure, the local SOCKS5 and forward listeners, and the route. A client without circuits says that one server carries its streams and sees their destinations. A client with circuits shows the length in use against the configured one, whether shorter routes need acceptance or were approved in the kit, the plain HTTP rule and each circuit by node name.
Route consent. When no route of the configured length can be built,
yume proposes a shorter one and connections wait. The Overview shows the
proposal, and Review opens a dialog with its hop count, nodes, latency when
measured and what the shorter route gives up. That text follows the
proposal’s cost, in the interface language for each cost this build
knows, and is yume’s own English for one it does not. Accept
sends accept-route with the id of that exact proposal. If yume proposes
something else while the dialog is open, the dialog refuses to accept and
asks for a new review. Closing it, Escape and no answer accept nothing, and
Keep waiting has the focus.
Connect lists the kits with their state, the import form and each kit’s folder, rename action and removal confirmation. The per-kit actions are icon buttons whose names show on hover and keyboard focus and are what a screen reader says.
Logs shows the latest lines the running yume printed, from the control
socket’s messages request, with a filter, following and copying. yume
keeps its latest 256 lines, and the page says how many earlier ones it no
longer keeps. When the client is not running, the page shows the output of
its latest start instead.
Posture states what protects the tunnel, from the status reply’s
posture: YTP/1 and its fixed composition (X25519 with ML-KEM-1024, Ed25519
with ML-DSA-87 identities, AES-256-GCM with one-use message keys, TLS 1.3 and
HTTP/2 after the captured evidence profile), the session’s key epoch, and the
configured limits. Connection settings above the live posture are an editable
configuration draft, not a report of what the session currently uses.
Three colored, keyboard-operable sliders select stealth, speed and security
levels from the unchanged embedded config/tuning_presets.json. Moving one
keeps its requested level and chooses the nearest combination on the other
two axes, breaking ties by higher stealth, higher security, lower speed and
then table order. Custom limits remain custom until a combination is chosen
explicitly. Reload discards the draft and reads the selected kit again.
The panel shows data per key and flow budget in MiB, credit returns, idle
rotation, and the selected combination’s measured speed with its limit. The
measurement’s conditions and what each axis describes are behind the ?
beside it, shown on hover or keyboard focus. The table’s labels, notes and
conditions appear in the interface language through the shared catalog.
Speed has five positions; stealth and security have four. These levels do
not certify stealth or security, and speed comparisons depend on host TCP
ceilings. The mandatory cryptographic composition and rotation remain fixed.
The live posture.limits are the client’s configured limits. While connected,
posture.epoch_bytes is the negotiated epoch. A smaller negotiated value
establishes a server cap for that session; an equal value does not reveal the
server’s higher allowance. A draft is never presented as an effective limit.
Expert settings require an explicit I know what I’m doing confirmation after the costs of each field are explained. They accept one exact byte, count or boolean value per save. The core schema parser validates it; the GUI does not implement another schema. The confirmation lasts until kit selection changes or the window ends. Escape and Cancel unlock nothing.
Saving runs yume-setup tune --config KIT/yume.json --preset NAME or one
--set KEY=JSON, using yume-setup beside the selected yume program. The
core validates the full client configuration and replaces it atomically,
preserving unrelated members. A refused write leaves the client running.
While connected, Apply and restart saves first, requests stop, waits for
the process to end, then validates and starts the client. Open streams close.
A stopped client stays stopped after saving. Kit selection, import, rename,
removal and the main connection action are held during the operation. Other
windows and same-user command-line writers are not locked out; avoid concurrent
edits. An interrupted save or failed restart reports its uncertainty and does
not claim a connection; saved settings remain available for a later start.
Appearance follows the desktop’s light or dark setting by default, as the Android app does, and can be fixed to light or dark.
Desktop headings use the embedded Quicksand Bold, with the embedded Jost as the Cyrillic fallback. Glyphs absent from both faces use a system font, including Ukrainian і, ї, є and ґ, Japanese and Chinese.
Keyboard and languages
The Credits page lists contributors with the same concise attribution used by Android, the CLI and the website. Roles and descriptions use the shared UI catalog. Desktop interface dependencies are separate from native client and daemon dependencies; the GUI does not link the native libraries.
Ctrl+1 to Ctrl+5 open the pages. Tab moves through every control, each with
a name a screen reader can say. A ? holds an explanation the page leaves
out: hover or focus shows it, and a screen reader reads it as the button’s
description. Space, Return and Enter activate the focused
button, and Escape closes a dialog. --layout-direction rtl mirrors the
whole window for right-to-left scripts, and text in any script is shaped.
The interface ships with maintained Russian, Japanese, Ukrainian and
Simplified Chinese translations, and with any community translation in the
shared catalog. It follows the desktop locale when the catalog has that
language and uses English otherwise, including for what a community
translation leaves out. Chinese follows the locale’s script: zh_CN, zh_SG
and zh_Hans read Simplified Chinese, while Traditional locales such as
zh_TW and zh_HK stay English until the catalog has Traditional Chinese.
The Credits page names who translated each language, under Native and
Community headings. The Android app uses
the same message IDs, translations and credits; its language picker lists
Native and Community languages apart, each with its translators, and
supports on-device machine translation for other languages.
UI messages live in the shared translations/catalog.json. Add or edit one
message there, keep its stable ID, context, owner and translator note, then
run python3 scripts/yume_translations.py validate and generate (with
--android-root for an Android checkout). The generated Qt and Kotlin files
are review artifacts and must not be edited by hand.
Building and testing
The GUI builds with -DYUME_BUILD_GUI=ON and Qt 6.4 or later: Core, Gui,
Network, Qml, Quick and QuickControls2, plus Test for its tests. At run time
it needs the QtQuick Controls, Layouts, Dialogs, Shapes and Window QML
modules. It links no YUME library, so it also builds with
-DYUME_BUILD_NATIVE_APPLICATION=OFF, and no other target links Qt.
cmake/YumeLayering.cmake enforces both directions.
yume_gui_testdrives the headless actions, the import, the command line and the page capture againsttests/gui/fake_yume.py, a stand-in that speaks control protocol 1.yume_gui_ui_testandyume_gui_ui_rtl_testdrive the real pages with the keyboard: page shortcuts, a focus order where every control has a name, connect and disconnect, kit renaming and preservation, and route consent. The second checks the mirrored layout and the rename dialog’s keyboard flow.yume_gui_live_testruns a realyumedandyume: a sealed kit imported through the GUI, connect, stop, reconnect and stop with each leg’s report inspected and a payload fetched through the tunnel, and a killed window whose tunnel keeps carrying traffic.
yume-gui --capture DIR saves every page, and the route review dialog when a
proposal is shown, as images for visual review. It fails when a page raises a
QML warning or a visible card’s heading has no width or overlaps its content.
yume-gui --headless ACTION --kit NAME runs the window’s
lifecycle without a display and prints one JSON report per step. It exits 2
when nothing could be exercised, so an empty run never reads as a pass.
Limits
- The GUI is not packaged, and no Debian package installs it.
- Nothing starts it or a tunnel at login, and it does not restart a crashed
yume. - It runs only on Linux desktops and was checked with the offscreen platform, not on each desktop environment, window system, tray or input method.
- It has no benchmark, chat or file pages: no native benchmark exists yet, and no program uses the chat and file module libraries.
- It shows
yumeonly. The server daemon’s status is not in the window yet.