docs/development.md;
that file overrides anything that drifts here.
The dev loop
Edit the repo, deploy, test on the running system. Never edit~/.config
directly and try to copy it back; the flow is repo to system only.
- Shell (QML and the Go daemon).
ryoku/shell/dev-run.shbuildsryoku-shelland runs it from the checkout (qs -p, hot reload).ryoku/shell/dev-binds.sh onbinds the shell keys to the dev shell for the current session;ryoku/shell/dev-stop.shstops it. Your own~/.configis left alone. - Configs and binaries from a maintainer checkout.
ryoku deploybuilds the binaries and lays the repo into~/.configfrom a checkout (it callsryoku/shell/deploy.sh). On an installed system this is replaced byryoku materialize, which copies the base config in from/usr/share/ryoku/config. TheryokuCLI auto-detects which world it is in; you do not pick a mode.
Verify before committing
The gates below are mechanical. Run them on the running system; do not stop at “it parses”.- Lua:
luac -p <file>parses every changed Lua file. - Shell scripts:
bash -n <file>; the pre-commit hook also checks staged scripts. - Installer: run the backend with
RYOKU_DRYRUN=1(and the requiredRYOKU_*contract variables) to print every action without touching a disk. - QML:
qmllintwhen available. - Behavior: exercise the actual change on the running system. Parse-only passes do not prove behavior.
How a change reaches a user
Where a change lives in the repo decides whether, and how, it reaches an installed machine. There are four paths and no others.
There is no ordered migration ledger. Configuration is reconciled
declaratively by
ryoku materialize; stateful drift (disk layout, subvolumes,
swap, ownership, missing units) is reconciled by ryoku doctor. Reach for a
reconciler only when a fix must change an existing machine’s structure and
neither a package nor materialize can do it.
A desktop change lands on users only after a tagged release rebuilds the
[ryoku] repo. See Release pipeline for how a tag
becomes a signed package.
The materialize boundary: anything Ryoku ships under
ryoku/ is re-laid by
ryoku materialize and treated as owned by the package. User files in
~/.config (including ~/.config/hypr/user.lua, ~/.config/hypr/monitors_user.lua,
and the per-app user.* overrides) are never touched. Drop a personal override
into user.lua; do not edit a shipped file.Adding things: the decision map
Put new code where the existing pattern says it goes. If a similar thing is already in the tree, follow it.Adding a doctor reconciler
A reconciler is one entry inreconcilers() in ryoku/cli/doctor.go. It runs
on every ryoku update, so:
- Be idempotent. Report
okwhen the machine already matches the desired state, otherwise converge. Under--check, report what it would do without changing anything. - Keep the check cheap and the fix safe to repeat.
- Auto-fix only the exact known-safe case and warn on anything unexpected.
- Retire it once every supported install has run it, so the set stays small instead of piling up.
Adding a package to [ryoku]
A new pacman package gets its own directory under release/packages/<name>/
with a PKGBUILD that builds from the checked-out monorepo. release/repo/build-repo.sh
runs makepkg, signs every artifact with the release key, and repo-adds the
signed ryoku.db into out/. See Release pipeline
for the full pipeline and the CI workflows.
Binaries and package managers
- The desktop ships as signed pacman packages from the
[ryoku]repo (release/packages/):ryoku-shell,ryoku-hub,ryoku, andryoku-blobsbuild from source via their PKGBUILDs;ryoku-desktopis the umbrella;ryoku-keyringcarries the release key. - The live ISO still prebuilds the installer TUI (
installation/iso/build.sh). The installed desktop’s binaries come from the repo, so never assumegoexists at install time. - AUR packages install in the post-install step (
installation/backend/lib/aur.sh), not via pacstrap. - User-level package managers install without root, into
~/.local/bin:npm,pip --user,go install,cargo install,pipx,mise. Do not reintroduce root-global installs or assumesudofor user tooling.
Commit gates
Every commit passes the hooks in.githooks/. Never use --no-verify.
commit-msg. Subject is[area] scope: imperative summarywhere area is one ofglobal,installation,system,ryoku,docs,test,tooling,release. (Shell changes use[global].) The hook rejects:- Any other or missing area label.
- Any em-dash (U+2014) anywhere in the message.
- Authorship /
Co-authored-by:trailers. - Generated-content attribution phrases (mentions of generators, AI tools, or “generated with” wording).
pre-commit. Scans staged additions and rejects:- Em-dash (U+2014) in text files (Markdown, shell, Lua, YAML, JSON, TOML, config, README, NOTICE, LICENSE).
bash -nsyntax errors in staged shell scripts.- Low-value filler comment lines (via
bin/ryoku-dev-scan-slop --staged).
pre-push. Runsshellcheckon changed shell when installed.
bin/ryoku-dev-install-hooks, which sets
core.hooksPath = .githooks and makes the hooks executable. Re-run after
pulling hook changes; the operation is idempotent.
Subject labels at a glance
One logical change per commit. Update the matching
CHANGELOG.md for the area
you touched.
Writing prose
- No em-dash. Use a comma, a colon, a period, parentheses, or
" - "with spaces. The pre-commit hook enforces this in committed text. - No emoji. No marketing fluff. Plain, direct, technical prose.
- Match existing files next to yours. When in doubt, copy the structure of the closest neighbour.
- Comment the why when it is not obvious. Never narrate the what, never leave commented-out code, never pad with filler.
Research
When something is unfamiliar, look it up against primary sources: the Arch Wiki, the Hyprland wiki, the Quickshell and Qt docs, each tool’s own docs. Cross-check anything load-bearing, and confirm the result on the running system. Match an existing pattern in the repo over introducing a new one. There is one source for each config, value, and fact: if a thing must exist in two places, extract it to one and reference it.See also
- Updates for the runtime side: what
ryoku update, snapshots, rollback,doctor, and recovery do. - Release pipeline for the path from a tag to a
signed
[ryoku]repo. - ISO build recipe for building and verifying a local ISO.
- Omarchy heritage for what Ryoku adapts and what is Ryoku-owned.

