YUME Internet freedom by FixCraft
On this page

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 --validate as a detached process in its own session. Closing, killing or crashing the window leaves the tunnel running. What yume prints 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 stop request. yume answers, closes its listeners and sessions as on SIGTERM, 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.

The GUI controls a separate client process The window validates and starts a detached client, then uses its owner-only UNIX socket. Closing the window leaves the tunnel running. Disconnect waits for the client to exit. 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 yume-gui window yume tunnel process
The window validates and starts a detached client, then uses its owner-only UNIX socket. Closing the window leaves the tunnel running. Disconnect waits for the client to exit.
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_test drives the headless actions, the import, the command line and the page capture against tests/gui/fake_yume.py, a stand-in that speaks control protocol 1.
  • yume_gui_ui_test and yume_gui_ui_rtl_test drive 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_test runs a real yumed and yume: 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 yume only. The server daemon’s status is not in the window yet.