20 KiB
User flows
See config-schema.md for the exact fields referenced
below, and architecture.md (source repository) for how run resolves all of
this internally.
1. First run on a fresh machine
runi versions auto-discovers whatever's already installed (Steam's
official Proton if Steam is present; nothing else yet). To get GE-Proton:
runi versions list-remote --source ge-proton shows installable
releases, runi versions install ge-proton latest downloads, verifies
checksum, extracts into compatibilitytools.d with a progress bar, and now
shows up in runi versions.
2. Add and run a standalone .exe (no storefront)
runi add ~/Games/MyIndieGame/game.exe --name "My Indie Game"
runi run my-indie-game
Exe path validated, game.id = my-indie-game (unique slug),
identity.umu_gameid = umu-default (shared fallback, no game-specific fixes — expected for an
unknown title). run resolves backend=umu (the global default), builds
PROTONPATH/WINEPREFIX/GAMEID=umu-default, execs umu-run. First launch
creates the Wine prefix.
3. Add a second build of a game you already have
Keeping two builds installed at once — a working one and a newer one you want to test — is a normal thing to do. Both derive the same id, so Runi resolves it instead of overwriting:
runi add ~/Games/Mortal.Shell.II.v92120-P2P/.../MortalShell2-Win64-Shipping.exe \
--name "Mortal Shell II"
added mortal-shell-ii-cl92120 (Mortal Shell II)
note: a different copy of 'Mortal Shell II' is already registered as
mortal-shell-ii; this one is registered alongside it (build version cl92120,
from pe-file-version)
shared with the other copy: game identity, notes, artwork
kept separate: Wine prefix, settings, environment, logs, save backups, mod receipts
The suffix is the build version read from the executable, so the id says which copy it is. When the two copies report the same version — common for engines that stamp their own version rather than the game's — there is nothing to tell them apart and Runi asks instead of guessing:
Error: 'Ascend to ZERO' is already registered as ascend-to-zero and no build
version tells the two copies apart; re-run with --id <unique-id> to add it as a
separate installation
In the GUI this is one dialog with the proposed id pre-filled and editable, showing the raw version string it came from.
If you moved or renamed the folder instead, that is not a second copy — Runi recognises the installation by the marker inside it and offers to repoint the existing registration, keeping its prefix, saves, settings and mods:
Error: this installation is already registered as 'Mortal Shell II'
(mortal-shell-ii); it appears to have moved
4. Add a Steam game with a different Proton version than Steam's own choice
runi steam-scan
runi add --steam-appid 292030 --backend native --proton GE-Proton9-27
steam-scan lists installed titles with their AppIDs. add --steam-appid
resolves title/exe path automatically from the scan (no manual path-typing),
sets game.id = steam-292030, identity.steam_appid = 292030, and
identity.umu_gameid = umu-292030 (so
protonfixes still key correctly even though this game runs outside Steam's
own launch path). runi versions would have already flagged
GE-Proton9-27 as safe for native (no ⚠ needs steamrt), so add doesn't
need to warn here.
In the GUI, Runtime separates Launch Engine from Runner family and Version. UMU Automatic selects the newest installed GE-Proton; Direct Proton selects an explicit installed build.
Manual game creation asks for the executable and suggests Display Name from a
local Steam manifest, PE ProductName/FileDescription, a cleaned installation
folder or finally the executable filename. The player may edit the suggestion.
Runi then resolves Steam/UMU identity in the background from a
game-provided steam_appid.txt, corroborated AppID metadata in bounded local
INI files, an exact local Steam manifest match, or an exact Steam Store title
match. Local AppIDs are validated directly through Steam app details, so an
imperfect folder title does not prevent identification. Ambiguous matches
require confirmation; unavailable or failed validation leaves umu-default. Runtime shows the
canonical title, source, confidence and validation timestamp, retains editable
technical fields and offers explicit revalidation.
Settings → Runners manages GE-Proton, UMU-Proton, Proton-CachyOS and experimental
Proton-EM releases. Proton Experimental is detected but remains Steam-managed.
Installed versions show manager and usage badges. Selecting a games badge
expands the titles configured to use that exact version; removal remains
disabled until those games are moved to another Runtime version.
Selecting an already installed release changes the action to Installed.
New builds are installed transactionally, so Runi never extracts over an
existing runner or exposes a partially extracted build to Steam/UMU.
Add from Dolphin
On KDE Plasma, enable Settings → Desktop Integration → Show “Add to
Runi” in Dolphin. Right-click one local Windows .exe and choose
Add to Runi. Dolphin sends the path to the already-running GUI, or
starts it when necessary, and the normal Add Game review opens.
The local candidate check is shared by Dolphin, the GUI and runi add.
Malformed files and DLLs are blocked. A valid PE whose role is unclear, or a
file that resembles a settings/installer utility, is shown with evidence and
ranked alternatives but may still be added deliberately. Selecting a game
already in the library focuses its existing card instead of creating a
duplicate. Requests received while a game or modal task is active remain in a
small in-memory queue.
The same entry point is available for desktop integration testing:
runi gui --add-file /path/to/game.exe
runi desktop-integration dolphin status
runi desktop-integration dolphin install
runi desktop-integration dolphin remove
5. Add a GOG/Epic title
runi add ~/Games/SomeGogGame/game.exe --store gog --name "Some Game"
Manual registration in v1 (no Heroic/Legendary auto-scan yet — see
roadmap.md (source repository)); STORE=gog is still forwarded so protonfixes keyed
by store apply if the umu-database has an entry for it.
6. Add games from Ubisoft Connect
In the GUI choose + → Ubisoft Connect. Install the client automatically or import an existing Ubisoft prefix, open it to log in/install games, then close it. Review the locally detected titles and import the selected ones. Later, Play sends the Ubisoft deeplink directly; Tools → Stores reopens client management. See ubisoft-connect.md for the shared-prefix, runner, process-monitoring and cloud-sync rules.
7. Tweak display settings on a stuttery game
runi config steam-292030 \
--set gamescope.enabled=true \
--set gamescope.output_width=2560 --set gamescope.output_height=1440 \
--set gamescope.render_width=1920 --set gamescope.render_height=1080 \
--set gamescope.filter=fsr \
--set mangohud.enabled=true
runi run steam-292030 --dry-run
--dry-run prints the fully composed command so you can verify before
committing:
gamescope -W 2560 -H 1440 -w 1920 -h 1080 -F fsr --mangoapp -- umu-run witcher3.exe
Note MangoHud folded into gamescope's own --mangoapp flag rather than
becoming a separate wrapper stage (gamescope's nested compositor doesn't
support the plain MangoHud overlay). Drop --dry-run to launch for real.
8. Install OptiScaler for a game with a weak native upscaler
runi optiscaler install steam-292030 --dll dxgi.dll
runi run steam-292030
Downloads the release, backs up any dxgi.dll the game already shipped,
copies OptiScaler's files alongside the game exe, sets
env.WINEDLLOVERRIDES = "dxgi=n,b" and [optiscaler] state in the config.
run launches normally; in-game Insert opens the OptiScaler overlay to pick
an upscaler backend.
runi optiscaler remove steam-292030
Restores the original file from the recorded manifest and clears the env override.
9. Manage Proton versions over time
runi versions install ge-proton latest
runi versions remove GE-Proton9-20
The second command fails with VersionInUseError listing which games still
reference that version; re-point those games first
(runi config <id> --set runtime.proton=GE-Proton9-27), then removal
succeeds.
10. Clean up
runi remove my-indie-game
The CLI deletes the registration and its Wine prefix by default; pass
--keep-prefix to preserve the prefix. In the GUI, removing only the
registration is the safe default. A separate checkbox can permanently delete
the marked game installation and its prefix, and warns that local saves and
settings stored in either location are also deleted. Runi refuses this
disk deletion when the installation ownership marker does not match. The
originally selected folder remains the deletion unit even when the executable
is nested deeply; recognized Unreal packages include the sibling Engine
directory rather than only Binaries/Win64. Existing Runi save backups
are kept.
For Ubisoft games, the shared prefix is always preserved. The GUI can open Ubisoft Connect's own uninstall confirmation before removing the Runi registration; it never deletes the Ubisoft game directory itself.
11. Recipes, and what replaced them
There is no Recipe tab, and adding a game no longer offers one. Recipes asked the player to assemble a setup from required items, recommended items, supplied asset files and a review step - which is a great deal of deciding for someone who wanted to press Play. The OptiScaler tab now narrows the same ground to two explicit choices with automatic selection between them, so the flow that used to live here is flow 8.
What remains is rollback. A game that had a recipe applied before the retirement still carries its receipt, and shows a Recipe (Legacy) entry for as long as that receipt exists, so the transaction can still be reverted. Nothing creates a new one.
For an upscaler build with no official source to automate - a leaked FSR package, a DLSS/XeSS swap - the supported path is a customize profile, which is flow 13.
12. Known launch compatibility
When Runi recognises an exact canonical game with a verified launch workaround, it applies the safe default during registration or before launch and shows a short notification. Explicit user launch options take precedence.
The first verified case is Pathogenic's Windows build on Linux: its Godot 4.7
D3D12 path crashed in RADV while creating a VKD3D compute pipeline, while the
same executable ran correctly with --rendering-driver vulkan. This argument
is scoped to Pathogenic's PGID; it is not inferred for other Godot games.
13. Apply a community upscaler workaround manually (advanced)
Real example, validated end-to-end: enabling a leaked FSR 4.1.1 INT8 build on non-RDNA4 hardware, for a game with OptiScaler already installed.
runi optiscaler install my-game --dll dxgi.dll
Write ~/.config/runi/profiles/fsr411-workaround.toml once (see
customize-profiles.md for the full format):
[profile]
name = "fsr411-workaround"
description = "Community FSR 4.1.1 INT8 workaround for non-RDNA4 GPUs"
[[files]]
src = "/home/user/Downloads/FidelityFX-Samples-v2.3.0-prebuilt/.../amd_fidelityfx_upscaler_dx12.dll"
dest = "amd_fidelityfx_upscaler_dx12.dll"
[[ini_edits]]
file = "OptiScaler.ini"
[ini_edits.set]
Fsr4Update = "true"
runi customize apply my-game fsr411-workaround
runi run my-game
In-game, press Insert for the OptiScaler overlay and select FSR4 → the
INT8 model. If a newer leaked build shows up later, just edit the profile's
[[files]] source paths and re-apply — the previous version is reverted
automatically before the new one is applied.
runi customize remove my-game
Restores the pre-customize state exactly (the stock OptiScaler files,
Fsr4Update back to its original value) — OptiScaler itself stays installed.
14. Enable LinUwUx for a Reflex/DenuvOwO-protected game
runi config my-game --set linuwux.enabled=true
runi run my-game --dry-run
--dry-run confirms the wrapper is in place:
linuwux umu-run MyGame.exe
Drop --dry-run to launch for real. If the Technology Scan (GUI Overview
tab, or runi doctor) already flagged a "Compat Shim: LinUwUx (Reflex)"
or "LinUwUx (DenuvOwO)" finding for this game, that's an informational hint
only — Runi never enables the wrapper automatically.
[linuwux].debug=true adds LINUWUX_DEBUG=1 for troubleshooting; leave it
off for normal play, since it produces heavy sigsys redirect logging.
[linuwux].enabled cannot be combined with [gamescope].enabled —
confirmed crashing on real hardware (the gamescope session dies before the
game process ever starts), not just untested. runi run/--dry-run
refuse with IncompatibleWrapperError up front rather than launching into a
crash; disable gamescope first if you need linuwux.
[mangohud].enabled works fine alongside linuwux — Runi activates it
with MANGOHUD=1 alone instead of mangohud's usual LD_PRELOAD wrapper
(which does collide), confirmed working on real hardware. No extra
configuration needed; just enable both.
If you want a custom MangoHud layout via [mangohud].config_file, MangoHud's
own core_load option (per-core CPU load/frequency) is worth knowing about:
bisected on real hardware (Monster Hunter Wilds) that enabling core_load
forces MangoHud back to a vertical layout even with horizontal set - a
per-core breakdown doesn't fit a horizontal row. Every other stat option
(cpu_stats, gpu_stats, ram, vram, frame_timing, etc.) composes fine
with horizontal; only core_load is the exception. This is MangoHud's own
behavior, unrelated to Runi or linuwux specifically.
That exact layout ships as a bundled preset - see flow 15 below - so you
don't have to rebuild it by hand:
runi mangohud-preset apply horizontal-complete <id>.
LinUwUx upstream documents only GE-Proton and Proton-CachyOS as supported
(official Valve Proton is not). If [runtime].proton resolves to anything
else, runi doctor surfaces a non-blocking advisory finding rather
than refusing to launch:
runi doctor
Requires linuwux to already be on PATH (installed via upstream's own
install.sh/build.sh --install — see
github.com/brcly/linuwux-runtime);
Runi never installs or manages it.
15. Save and apply a named MangoHud preset
runi mangohud-preset list
Shows every available preset — bundled (shipped with Runi) plus any
you've saved locally. Runi ships one bundled preset out of the box,
horizontal-complete, the exact layout validated in flow 14 above:
runi mangohud-preset apply horizontal-complete my-game
runi config my-game --set mangohud.enabled=true
This writes the preset's content to a per-game file
(~/.local/share/runi/mangohud/<id>.conf) and sets
[mangohud].config_file to it — the same effect as building the file by
hand and pointing config_file at it, just one command. runi run my-game --dry-run shows the resolved MANGOHUD_CONFIGFILE to confirm.
To save your own config (built by hand, or already applied to a game you're happy with) as a reusable preset:
runi mangohud-preset save my-layout --from-game my-game --description "my favorite layout"
# or, from an arbitrary file:
runi mangohud-preset save my-layout --from-file ~/some/MangoHud.conf
Saved presets are plain TOML at
~/.config/runi/mangohud-presets/<name>.toml; a local preset with the
same name as a bundled one takes priority, so you can override
horizontal-complete itself by saving your own version under that name.
runi mangohud-preset remove my-game
Clears [mangohud].config_file (falling back to MangoHud's own default
resolution order) and deletes the applied per-game file.
Deliberately per-game only — there is no "apply globally" (writing
~/.config/MangoHud/MangoHud.conf). That file is commonly managed by
third-party tools like GOverlay/MangoJuice; a second tool silently writing
over it (even with a backup taken first) creates an ongoing "who owns this
file" conflict with no clean resolution, confirmed real on a machine already
running MangoJuice. If you want a preset's layout system-wide, apply it to
each game you care about, or use GOverlay/MangoJuice's own global-config
tooling directly.
16. Import a Ludusavi save backup into a game's prefix
CLI-only, low-key utility — reads a Ludusavi
backup folder (mapping.yaml + drive-C/, the "simple" non-zip format)
directly and copies the files into the game's own Wine prefix. No
dependency on the ludusavi binary itself.
runi saves import-ludusavi my-game /path/to/ludusavi/backups/My\ Game --preview
--preview shows exactly what would be copied — source → destination →
size — without writing anything. The prefix must already exist (launch the
game for real at least once first); otherwise this refuses rather than
half-creating one.
runi saves import-ludusavi my-game /path/to/ludusavi/backups/My\ Game
Copies every recorded file, verifying each one's SHA1 against what
mapping.yaml recorded (catches SMB/network corruption, not just logic
bugs), and — unless --no-set-save-path is passed — updates
[saves].path to the backup's own save location, so Runi's own
saves backup/restore also point at the right place afterward. If the
computed destination already has files in it, the current state is
backed up first via the normal saves backup mechanism, so an import is
always reversible.
Two real things this surfaced, worth knowing if a result looks surprising:
- Path casing and shared folders. Ludusavi records the source Windows
machine's own path casing (
Users, capitalized) and username segment (e.g.Users/cvarandas/...). Wine's real prefix directory is lowercase (users) with its own account name (steamuserin every runi-managed prefix) — a blind copy would create a bogus sibling directory the game never sees. The importer resolves both against what's actually on disk. It also knowsUsers/Public/...is a real, shared folder, not a personal account to remap — confirmed by a real game (The Sinking City 2) whose save data legitimately lives partly underPublic. - A RUNE/crack config's declared save path and a Ludusavi backup's
actual files can legitimately disagree. The Sinking City 2's RUNE
crack (
steam_emu.ini) declares saves atusers/Public/Documents/Steam/RUNE/2825860— that's likely where RUNE stores its own Steam-emulation state (fake achievements/cloud markers), not necessarily the engine's native save files, which for this game turned out to beAppData/Local/TSC2/Saved(confirmed by both the real backup content and an actual game launch). The importer prints a note when this happens (reusing Runi's existing RUNE detection as a cross-check) but always imports to where the backup's files really are.
Runi cannot verify a backup matches the installed game's specific
version/release — Ludusavi's mapping.yaml records hashes for the save
data itself, not the source machine's game build. The safety backup above
is the actual mitigation; confirm compatibility the same way it was
confirmed here — launch the game and check.
Only the simple (non-zip) backup format is supported; a zip-format backup folder is refused with a clear error rather than silently mishandled.