Skip to main content
ryoku is the front door to the whole system. It updates the machine, rolls it back, reports its state, reloads the desktop, and repairs stateful drift, all from one Go program (ryoku/cli/). It does not reimplement package management or snapshots; it orchestrates pacman, yay, and snapper and adds the safety rails around them. Run ryoku with no arguments for the built-in usage.

Two worlds: which install is this?

Every command behaves with respect to one of the two ways Ryoku can live on a machine. Most confusion about the CLI comes from mixing them up.
The desktop is installed from the [ryoku] pacman repo. ryoku-desktop ships the base config under /usr/share/ryoku/config; there is no git checkout and no build toolchain. This is what you have after installing from the ISO or converting an existing Arch box.
ryoku update auto-detects which world it is in, so the same command is correct on both. A recorded checkout means the git path; otherwise it takes the pacman path. A few commands belong to only one world; that is called out below.

At a glance

Everyday commands

These are user-facing and work on any install.

ryoku update

The full, safe update. It is wrapped in a snapper pre/post snapshot pair (best-effort: an unconfigured snapper never blocks the update, but a failed step aborts before anything else changes). Throughout the run it publishes progress to $XDG_RUNTIME_DIR/ryoku-update.json, so the shell’s update island shows the wave while the update runs. What it actually runs depends on the world:
1

Snapshot

Take a snapper pre-snapshot so the run is reversible.
2

System packages

sudo pacman -Syu.
3

AUR packages

yay -Sua, if yay is present.
4

Materialize config

ryoku materialize lays the refreshed base config into ~/.config.
5

Reload

Restart the shell and reload Hyprland so the new config is live.
ryoku update also runs ryoku doctor itself, so self-healing happens on every update. See Updates for the snapshot model and channel details.

ryoku status [--json]

A read-only report; it changes nothing. It always prints the active config base. On a checkout it shows the channel, the deployed commit (installed), and how many commits behind the channel you are. On a packaged install it shows the installed ryoku-desktop version, what the [ryoku] repo offers, and the count of pending package updates (via checkupdates from pacman-contrib). It ends with the snapshot count.
--json is the data seam the Hub and the update island read; it is not meant for humans.

ryoku rollback [id]

Restore a snapper snapshot after a bad change.
With no id it lists the snapshots so you can choose. With an id it runs sudo snapper rollback <id>. The same snapshots are selectable from the Limine boot menu, so a machine that will not boot back into Hyprland can still be recovered from the bootloader. See Troubleshoot for the recovery playbook.

ryoku snapshots

List the snapper snapshots (sudo snapper list). Requires snapper.

ryoku reload

Restart the shell and reload Hyprland by handing off to ryoku-shell reload. Use it after changing config that is already in place, for example a hand-edit to ~/.config/hypr/user.lua.

Keep it healthy: ryoku doctor

ryoku doctor runs the convergent reconcilers: idempotent checks (and, where it is safe, fixes) for stateful drift the package and config layers cannot express. Each reconciler reports ok when the machine matches the desired state, otherwise it converges, proposes the exact fix, or flags it for a human. A healthy machine is quiet.
ryoku update runs ryoku doctor for you, so a finding never aborts an update. Run it by hand any time you suspect drift.
The reconcilers are a living set (each retires once every supported install has run it, so the list stays small rather than growing like a migration ledger). The current set in ryoku/cli/doctor.go covers:
  • Disk and snapshots: swap kept out of snapshots, snapper configuration, btrfs device health.
  • Boot: Limine boot-menu layout, stale install crypt mapper.
  • Packages: stale pacman database lock, the ryoku package channel and keyring, pending .pacnew config, orphaned packages.
  • Session and desktop: desktop session components, Hyprland config integrity (it revalidates and repairs the generated monitors.lua/gpu.lua drop-ins so a corrupt one cannot strand the desktop in emergency mode), the ryoku shell daemon, failed services, cursor theme, SDDM greeter theme.
  • Display and hardware: display backlight, display resolution, NVIDIA boot reliability.

When doctor cannot fix it: --report

When doctor cannot fix something (or finds an unknown problem) it writes a single shareable text report and points you to it. Generate one any time:
It bundles the findings with system state (btrfs usage and device errors, /proc/swaps, failed units, recent journal errors, pacman state, the ryoku channel state, session env, and hardware: backlight devices, GPU drivers, kernel cmdline, recent display-driver log) into one .txt the maintainers can read. It contains no passwords or keys.

When you want it to reason: --explain

ryoku doctor --explain sends that same report to a cloud model and prints its root-cause analysis and fix steps, reaching the long tail the reconcilers cannot pre-encode.
--explain is strictly advisory and read-only: it never runs anything, so a wrong answer can only mislead. It is opt-in and uses your own key; nothing is sent unless you set one.
Any OpenAI-compatible endpoint works. Defaults target Groq (free, fast):
For OpenRouter’s free models, override the URL and model (see Environment and state below).

One layout everywhere: ryoku keyboard

A keyboard layout has to land in four places, and only one of them is the desktop: Hyprland’s config, the X11 file the SDDM greeter reads, /etc/vconsole.conf for the TTYs, and a copy of that file baked into the boot image, which is what the disk passphrase prompt uses. The last one is the trap: mkinitcpio copies the keymap in at build time, so editing the file later, even through localectl, never reaches the passphrase prompt. With no layout argument, apply pushes the desktop’s own layout out. The Displays-page “Apply system-wide” button runs the same command, and doctor reports the drift with the exact fix.

Config lay-down: ryoku materialize

ryoku materialize lays Ryoku’s base configs into ~/.config, declaratively and override-safe. It copies every file the package ships under the base config dir (clobbering the previous Ryoku copy), prunes files a past release shipped but this one dropped (tracked by a manifest at ~/.local/state/ryoku/materialized), and never touches files the package never shipped.
Your own overrides survive every materialize: hypr/user.lua, hypr/monitors_user.lua, kitty/user.conf, fish/user.fish, and anything else you added are left alone. The per-machine generated drop-ins (hypr/monitors.lua from ryoku-monitor, hypr/gpu.lua from ryoku-gpu) are seeded only when absent and never clobbered or pruned, so an update refreshes the shipped config without ever resetting your display layout, GPU pin, or any setting. See Customize.
The base dir is /usr/share/ryoku/config, shipped by ryoku-desktop. This is the packaged-install replacement for a checkout’s config copy: it is run for you by ryoku update and by the installer’s deploy step, not usually by hand.
On a dev checkout ryoku materialize fails (base config dir not found: /usr/share/ryoku/config) because that path only exists once the package is installed. Use ryoku deploy there instead, or point RYOKU_CONFIG_BASE at a base tree yourself.

Emergency: ryoku recovery

The last resort when the desktop is too broken to update normally (a corrupt local config, a broken local build). It resets the checkout to main and redeploys, overwriting configs.
It hands off to bin/ryoku-recovery, preferring the copy in a local checkout and otherwise fetching the canonical script from the repo over the network, so it still works when the local build is broken. See Troubleshoot for when to reach for it.

Developer command: ryoku deploy

The dev loop, never used on production installs. It builds the Go binaries and the QML plugin and lays the repo into ~/.config from a checkout by running ryoku/shell/deploy.sh. It requires RYOKU_REPO to point at the checkout and errors otherwise. The deploy also records the checkout root and the deployed commit under ~/.local/state/ryoku/, which is what lets status and update track the git channel afterwards.

Environment and state

Overrides, mostly for deploy and tests: AI reasoning for doctor --explain (opt-in; the report is sent only when a key is set). Any OpenAI-compatible endpoint works: State the CLI keeps under $XDG_STATE_HOME/ryoku (default ~/.local/state/ryoku): At runtime, $XDG_RUNTIME_DIR/ryoku-update.json is the update island’s progress file, written by update.

See also

Updates

The snapshot model, the channel, and what a safe update guarantees.

Troubleshoot

Logs, ryoku doctor, rollback, and recovery when something breaks.

Customize

The override files materialize never touches.
Last modified on July 29, 2026