Skip to main content
How to maintain the Ryoku Arch repository: the dev loop, the gates a commit passes, the path a change takes from the repo to a user’s machine, and where new code belongs. The spine for this page is the in-repo 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.sh builds ryoku-shell and runs it from the checkout (qs -p, hot reload). ryoku/shell/dev-binds.sh on binds the shell keys to the dev shell for the current session; ryoku/shell/dev-stop.sh stops it. Your own ~/.config is left alone.
  • Configs and binaries from a maintainer checkout. ryoku deploy builds the binaries and lays the repo into ~/.config from a checkout (it calls ryoku/shell/deploy.sh). On an installed system this is replaced by ryoku materialize, which copies the base config in from /usr/share/ryoku/config. The ryoku CLI 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 required RYOKU_* contract variables) to print every action without touching a disk.
  • QML: qmllint when 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 in reconcilers() in ryoku/cli/doctor.go. It runs on every ryoku update, so:
  • Be idempotent. Report ok when 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, and ryoku-blobs build from source via their PKGBUILDs; ryoku-desktop is the umbrella; ryoku-keyring carries 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 assume go exists 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 assume sudo for user tooling.

Commit gates

Every commit passes the hooks in .githooks/. Never use --no-verify.
  • commit-msg. Subject is [area] scope: imperative summary where area is one of global, 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 -n syntax errors in staged shell scripts.
    • Low-value filler comment lines (via bin/ryoku-dev-scan-slop --staged).
  • pre-push. Runs shellcheck on changed shell when installed.
Install the hooks per clone with 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.
Last modified on June 24, 2026