dc47d1a6ec
Coordinated fix with moonarch-pkgbuilds: post-install.sh enabled wlsunset by default, while the PKGBUILD shipped a global-scope WantedBy symlink. Together that made the toggle's user-scope disable a no-op — filter persisted across reboots regardless of user intent. Removing wlsunset from USER_SERVICES makes "off" the install default; the toggle now works in user scope only, where disable can take effect.
30 KiB
30 KiB
Decisions
2026-05-04 – Nightlight default OFF, no global enablement
- Who: Dominik, ClaudeCode
- Why: Filter survived reboots even after the user toggled it off. Root cause:
moonarch-pkgbuilds/moonarch-git/PKGBUILDlooped over every user service indefaults/etc/systemd/user/*.serviceand dropped a WantedBy symlink into/etc/systemd/user/graphical-session.target.wants/. That path is global scope.moonarch-nightlightrunssystemctl --user disable wlsunset, which can only remove user-scope symlinks under~/.config/. Systemd's own warning during disable spelled it out: "The following unit files have been enabled in global scope. This means they will still be started automatically after a successful disablement in user scope." Verified empirically —is-enabledstayedenabled, root symlink untouched. Additionally,scripts/post-install.shenabledwlsunsetby default in itsUSER_SERVICESarray, so even without the global symlink the filter would default ON. - Tradeoffs: Three options weighed. (1) Default OFF + user-scope toggle — minimal change, fresh installs start without filter, toggle creates
~/.config/.../wants/symlink that user-disable can actually remove. (2) Default ON + user-scope toggle — same plumbing, post-install enables in user scope; filter on by default but disable persists. (3) Status-file gate inside the unit — service stays enabled, ExecStartPre checks a file and exits when off. Picked (1): no behavioral default imposed on fresh installs, no extra plumbing, the toggle stays the single source of truth. Could have moved enablement to a per-usersystemctl --user --global enablefrom the .install hook, but that fights the "this is a UI toggle" framing. - How:
moonarch-pkgbuilds/moonarch-git/PKGBUILD— symlink loop now skips askip_enablelist (currentlywlsunset.service); skipped services are still installed under/etc/systemd/user/but not wanted bygraphical-session.targetat the global level.moonarch-pkgbuilds/moonarch-git/moonarch.install—pre_upgrade()deletes any pre-existing/etc/systemd/user/graphical-session.target.wants/wlsunset.serviceto clean up systems that received the old packaging.moonarch/scripts/post-install.sh—wlsunsetremoved fromUSER_SERVICES; comment explains why.moonarch/CLAUDE.md— Nightlight section reflects "Default OFF" and the global-scope-symlink hazard.
2026-05-04 – Battery threshold permissions: udev rule → pkexec helper
- Who: Dominik, ClaudeCode
- Why: The wheel-write-via-udev approach for
/sys/class/power_supply/BAT0/charge_control_end_thresholdhad been broken since 2026-04-08 (commitac2b210, "audit remediation Q-W3"). That commit addedACTION=="add"to90-moonarch-battery.rulesto "avoid firing on every battery event" — but that filter is precisely what the rule needs not to have. On Lenovo, the threshold attribute does not exist yet at theaddevent (the driver creates it slightly later); the rule fires,chmodfails silently because2>/dev/nullswallows the error, and permissions are never set. The unfiltered original rule worked by accident:addfailed silently as well, but a subsequentchangeevent on the same device caught the now-existing attribute and set permissions. After the audit commit, change events stopped re-firing the rule and the toggle was permanently broken —moonarch-batsaver-togglereturnedPermission denied. Verified via journalctl + manual chmod: rule fires for hidpp_battery_0 (visible exit-1 errors), no trace for BAT0; manualchmod g+won BAT0's threshold succeeds (sysfs accepts the change), so the permission model itself works — only the rule path failed. - Tradeoffs: Three approaches considered. (A) Restore the original unfiltered rule — fixes the symptom by accident, leaves the failure mode intact (silent fail at add, retry hopefully at change). (B) Switch to
tmpfiles.d— Arch Wiki explicitly warns this can run before driver modules load, undefined for sysfs. (C) pkexec helper with polkit-rule — standard pattern (Battery-Health-Charging GNOME extension uses exactly this). Picked C with default Standard-pkexec prompt rather than no-password polkit rule: minor UX cost (password once per pkauth session, ≈5min cache), eliminates the entire sysfs-permission problem class, no privilege-escalation surface from a misvalidated helper. The wheel-can-write-sysfs design was a moonarch-specific deviation from common Linux practice — bringing it in line with the standard root-orientiert helper pattern. - How:
defaults/bin/moonarch-batsaver-apply(new): privileged helper invoked via pkexec; strictly validates argument (digits only, range 1-100), writes sysfs (idempotent — skips kernel write when value already matches to avoid Lenovo EINVAL on same-value writes), writes state file.defaults/bin/moonarch-batsaver-toggle(rewritten): user-side reads current threshold, picks 80↔100, dispatchespkexec /usr/bin/moonarch-batsaver-apply $NEW, then signals waybar.defaults/etc/udev/rules.d/90-moonarch-battery.rulesdeleted (and the now-emptydefaults/etc/udev/parent removed). PKGBUILD: udev install line removed.moonarch-doctor: removed the udev-effectiveness check (no longer relevant).moonarch-batsaver.serviceandmoonarch-batsaver-restore(also new in this commit, extracted from the old inline ExecStart for readability) keep root-owned boot-time restore — no permission concerns there.CLAUDE.mdBattery-Conservation-Mode section updated to describe the new flow.
2026-05-04 – Cleanup: remove invented zsh override layer, harden moondoc
- Who: Dominik, ClaudeCode
- Why: Audit revealed two classes of cruft introduced by earlier ClaudeCode sessions without explicit decision or DECISIONS.md entry. (1) An invented user-override mechanism (
~/.zshrc.d/*.zshsnippet loop,~/.zshrc.localfallback) was wired intodefaults/shell/zshrcandscripts/post-install.sh. Not a zsh convention, not documented, redundant to the user's own~/.zshrc.post-install.shcreated the~/.zshrc.ddirectory unconditionally on every fresh install — leaving an empty directory in every user's home. (2)moonarch-doctorhad only existence checks (/etc/zsh/zshrc.moonarchexists?,/usr/share/moonarch/exists?) which are redundant with the package check, and hardcoded service/script lists that drift silently when moonarch-git's payload changes. The udev rule forcharge_control_end_threshold(battery conservation) had no effectiveness check at all — a broken rule would not show up. - Tradeoffs: Could have left the invented override layer alone (no active harm) but it muddies
defaults/shell/zshrcand produces empty directories on every fresh install. Could have kept the existence checks (cosmetic noise, no harm) but they create false positives — doctor reports "pass" while the actual mechanism may be broken. Kept the 7 hardcodedcheck_config_matchentries for/etc/xdg/foot/,/etc/greetd/,/etc/moongreet/etc. — the source-to-destination mapping is not 1:1 (foot →/etc/xdg/foot/, greetd →/etc/greetd/, moongreet →/etc/moongreet/), so dynamic discovery would need a manifest. Acceptable hardcoding for now. - How:
defaults/shell/zshrc—~/.zshrc.d/*.zshsource loop and~/.zshrc.localfallback removed; second ABOUTME line that referenced them removed.scripts/post-install.sh— Zsh-block now writes~/.zshrcwith onlysource /etc/zsh/zshrc.moonarch(no mkdir, no~/.zshrc.dreference); stale "rustup default stable" hint and "User overrides in~/.zshrc.d/" hint removed from next-steps.scripts/lib.sh— deadconfirm()(orphaned since transform.sh deletion 2026-04-21) removed.scripts/moonarch-doctor— user-services and helper-scripts lists now derived frompacman -Qql moonarch-gitplus an explicit list of post-install-enabled externals (currentlystasis); useless existence checks for/etc/zsh/zshrc.moonarchand/usr/share/moonarch/removed; new udev-effectiveness check forcharge_control_end_threshold(group=wheel + group-writable).defaults/bin/moonarch-waybar-cpugov,moonarch-waybar-gpustat— German ABOUTME comments translated to English for consistency.
2026-04-24 – Stasis: flip ignore_remote_media to false for browser video
- Who: Dominik, ClaudeCode
- Why: Idle was firing on a second machine even while a video was playing in the browser. Original config carried the comment "browser uses D-Bus inhibit" and set
ignore_remote_media true, deliberately excluding browser MPRIS on the assumption that Firefox/Chromium would keep the session alive viaorg.freedesktop.ScreenSaver.Inhibit. Verified against browser behavior: both browsers only raise that inhibit during fullscreen video playback (Firefox also requiresdom.screenwakelock.enabled, default off on Linux). Windowed playback — the common case, YouTube in a tab — sends no inhibit, so stasis saw zero inhibitors and zero media players and ran the full idle plan to suspend. Upstream example config listsr"firefox.*"ininhibit_appsfor exactly this reason; Moonarch removed it without a working substitute. - Tradeoffs: Three options. (A) Put
firefox/chromiumback intoinhibit_apps— works but inhibits whenever the browser process is running, even with zero tabs playing; wrong shape. (B) Tell users to flipdom.screenwakelock.enabledper browser — pushes per-user config, fragile across browsers. (C) Let browser MPRIS count as a media player by settingignore_remote_media false— stasis already tracks playback state, so it only inhibits during actual playback. Picked C. Cost: any MPRIS source stasis classifies as "remote" (e.g. a Chromecast bridge) now also inhibits; acceptable — that is usually what a user wants anyway, and the inhibit releases the moment playback stops. - How:
defaults/xdg/stasis/stasis.rune—ignore_remote_media true→false, comment rewritten to document the fullscreen-only D-Bus behavior. PKGBUILD deploys to/etc/xdg/stasis/stasis.rune; existing users still need the 2026-04-22 seed mechanism (or a manual merge) to pick it up in~/.config/stasis/stasis.rune.
2026-04-22 – moonarch-doctor housekeeping: drop stale check, add missing services
- Who: Dominik, ClaudeCode
- Why: Noticed while running
moondocon a healthy system that it reportedParu [moonarch-pkgbuilds] repo missing from /etc/paru.conf— a false failure. The paru PKGBUILD-repo mechanism was retired on 2026-04-20 in favor of the registry-only flow, and themoonarch-gitinstall hook strips the legacy paru.conf section on upgrade; the doctor script was not updated in lockstep. Audit of the rest of the script surfaced two related gaps: the user-services loop skippedwalker.serviceandnautilus.service, even though the PKGBUILD ships both in/etc/systemd/user/and enables them viagraphical-session.target.wantssymlinks. A silently missing walker or nautilus would not show up in diagnostics. - How: Removed the
[moonarch-pkgbuilds]check fromscripts/moonarch-doctor. Addedwalkerandnautilusto the user-service loop. UpdatedCLAUDE.mduser-services listing to match (also filled in the missingwlsunset). The[moonarch]pacman-repo check stays — that is the path that matters now.
2026-04-22 – Seed Stasis user config from post-install.sh
- Who: Dominik, ClaudeCode
- Why: Moonarch shipped
defaults/xdg/stasis/stasis.rune(deployed to/etc/xdg/stasis/stasis.runeby the PKGBUILD) on the assumption that stasis honors the XDG system config hierarchy. It does not. Verified against upstream source (v1.1.0,src/config/mod.rs:30+src/config/bootstrap.rs): stasis only reads~/.config/stasis/stasis.rune(primary) or/etc/stasis/stasis.rune(fallback, noxdg/). On every start with no user config,ensure_user_config_exists()writes its own hardcoded default (laptop/desktop template compiled into the binary) to~/.config/stasis/stasis.rune. Net effect: Moonarch's Idle-Manager tuning (AC/battery plans, moonlock integration, inhibit apps, niri DPMS commands) was never active on fresh installs — users got the upstream defaults withswaylockas locker. - Tradeoffs: Three options were considered. (A) Service drop-in with
--config /etc/stasis/stasis.rune— cleanest, upgrades propagate via package, no user-home touching; rejected because it takes stasis out of the standard config path users expect when they want to customize, and requires packaging a drop-in unit. (B) Seed once from post-install.sh into~/.config/stasis/stasis.rune— chosen: user-owned file, immediately editable, no magic. Cost: package updates to the template never reach users who already ran post-install; they have to merge manually. (C) Recurring systemd user service that keeps seeding — ruled out, too clever, user edits would race with it. Stasis has no config hierarchy / merging, so "system default + user override" cannot be modeled at all. - How: Added a block to
scripts/post-install.shbefore the user-services-enable step: if~/.config/stasis/stasis.runedoes not exist and/etc/xdg/stasis/stasis.runedoes,install -Dm644copies the template into the user home. Order is correct — moonarch-git is installed earlier in the script (deploys/etc/xdg/…), and stasis.service is only enabled (not started) later, so the seed is in place before stasis ever runs. The/etc/xdg/stasis/payload stays as the canonical template source inside the package.
2026-04-21 – post-install.sh pulls aur.txt, rust for paru build, rustup out of official
- Who: Dominik, ClaudeCode
- Why: Three related gaps uncovered while fixing the paru bootstrap: (1)
moonarch-gitcannot depend on AUR packages, so every AUR package inaur.txt(walker-bin, elephant-*-bin, awww's theme, waypaper, stasis, …) was silently never installed by post-install.sh — a fresh install would have a working pacman but no launcher, no idle manager, no theming. (2)makepkg -siforparu(AUR source build) needsrustas makedep; neither archinstall nor post-install.sh installed it, so the restored paru bootstrap would have crashed on rust-less systems. (3)rustupsat inofficial.txt"for something we don't remember" — turned out to be a leftover;rustsuffices for the paru build, and rustup is only needed for dev toolchain management which is a per-user concern, not a Moonarch default. - Tradeoffs: Installing
rust(~350MB) just to bootstrap paru feels heavy. Alternativeparu-binavoids the compile step entirely; rejected because Dominik's documented workflow usesparu(source) and consistency with that matters more than ~30s of build time. rustup can be re-added to official.txt if the dev workflow grows that demand. - How: (1) post-install.sh now runs
read_packages "$AUR_PACKAGES" | paru -S --neededafterparu -S moonarch-git. (2)sudo pacman -S base-devel rustbefore the paru git-clone. (3)rustupremoved fromofficial.txt(remains in PKGBUILDoptdependsfor discoverability).
2026-04-21 – Restore AUR bootstrap for paru in post-install.sh
- Who: Dominik, ClaudeCode
- Why: Commit
0726451(2026-03-29) replaced the workinggit clone https://aur.archlinux.org/paru.git && makepkg -sibootstrap withsudo pacman -S paru, on the (wrong) assumption that paru had landed in[extra]. Verified against archlinux.org API: paru and paru-bin are AUR-only, not in any official repo. Fresh installs have been silently broken since — the command fails, the installer aborts before the moonarch registry is configured. - Tradeoffs: Bootstrap builds paru from source, which needs
base-devel(already pulled by archinstall). Alternativeparu-binwould skip the compile step; choseparuto match the upstream recommendation the user follows. Alternative "bundle paru in the Moonarch registry" would be internally consistent but adds a dependency on a running Gitea during install. - How: Replaced the
pacman -S paruline inpost-install.shwith the original bootstrap —mktemp -d,git clone,makepkg -si --noconfirm,rm -rf. Wrapped in an EXIT trap so the tempdir gets cleaned up even on failure.
2026-04-21 – Drop transform.sh and legacy update.sh shim
- Who: Dominik, ClaudeCode
- Why: transform.sh was added 2026-03-29 to onboard users from existing Arch+Wayland systems, but was never actually used — Moonarch is installed fresh via archinstall. Maintaining it meant duplicated paru/repo/key setup, a second entry point with its own backup/pre-flight logic, and a second reason for the
/opt/moonarchclone. scripts/update.sh was a deprecation shim from before moonarch-update moved into the moonarch-git package; obsolete now that the package ships moonup/moondoc. - Tradeoffs: Existing Arch+Wayland users now have to install paru, add the
[moonarch]repo + key manually, thenparu -S moonarch-git. That's three commands instead of one script — acceptable since nobody actually uses that path. If the need returns, transform can be resurrected from git history. - How: Deleted
scripts/transform.shandscripts/update.sh.lib.shstays (still sourced by post-install.sh). README "Transform" section removed, project-structure listing trimmed. Fresh-install flow via archinstall + post-install.sh is unchanged.
2026-04-20 – Registry-only install: drop paru --pkgbuilds from setup scripts
- Who: Dominik, ClaudeCode
- Why: Two parallel paths for finding moonarch packages (Arch registry via
[moonarch]in pacman.conf, and paru's PKGBUILD-repo via[moonarch-pkgbuilds]in paru.conf) caused ambiguity during debugging:paru -S moonarch-gitwas resolving against the registry's stale DB (zombie r99 entry) while the PKGBUILD source would have had r105. Also: the PKGBUILD-repo path triggered a local build on every client, while the registry ships prebuilt binaries. With the registry DB now stable (seemoonarch-pkgbuilds/DECISIONS.md, same date), the second mechanism is redundant. - Tradeoffs: If the registry is down or broken, clients have no local-build fallback. Acceptable — a broken registry is a server-side bug to fix, not something to mask with a parallel mechanism that complicates diagnostics.
- How:
post-install.shandtransform.shno longer writeMode = arpor a[moonarch-pkgbuilds]section to/etc/paru.conf, and no longer callparu -Syu --pkgbuilds. They runpacman -Sy+paru -S moonarch-gitagainst the registry. Themoonarch-gitinstall hook now strips the legacy paru.conf entries on upgrade (see moonarch-pkgbuilds repo).
2026-04-19 – moonup i18n: reuse pacman gettext catalog + inline fallback
- Who: Dominik, ClaudeCode
- Why: moonup prompts looked foreign next to pacman/paru output (
[y/N]vs[J/n], English strings on a German system). User wanted consistency with the rest of the pacman UX. - Tradeoffs: Full
.po/.mobuild-chain for moonarch was overkill for ~15 strings. gettext-only approach misses most moonarch-specific strings (no matching msgids in pacman catalog). Chose hybrid:TEXTDOMAIN=pacmanfor strings that match upstream msgids (prompts likeProceed with installation?,Do you want to remove these packages?,[Y/n],Starting full system upgrade...), inline_t()helper for moonarch-specific strings. - How:
moonarch-updatesetsTEXTDOMAIN=pacman/TEXTDOMAINDIR=/usr/share/locale._t "en" "de"picks by${LANG%%.*}matchingde_*.confirm()now uses::prefix, default Y, acceptsy/Y/j/J. No PKGBUILD change —gettextis inbase. pacman msgids with trailing\n(e.g.Starting full system upgrade...\n) require ANSI-C quoting$'...\n'to match.
2026-04-08 – Battery conservation mode: udev + sysfs + Waybar toggle
- Who: Dominik, ClaudeCode
- Why: Laptops with
charge_control_end_thresholdsupport benefit from limiting charge to 80% to extend battery lifespan. Needed a user-friendly toggle without requiring sudo. - Tradeoffs: udev RUN approach for permissions (group wheel gets write access) vs polkit/pkexec (password prompt on every toggle). Chose udev for seamless UX. State persisted in
/var/lib/moonarch/(system-wide, not per-user) — acceptable since charge threshold is a hardware setting, not a user preference. Fixed 80% threshold instead of configurable — KISS, matches industry standard. - How: udev rule grants wheel group write on
charge_control_end_threshold. Toggle script writes sysfs + state file. systemd oneshot service restores on boot. Waybar shows ♥ icon when active, hidden when inactive. Click on battery module toggles.
2026-04-07 – Walker theme: gtk-inherit → moonarch with fixed colors
- Who: Dominik, ClaudeCode
- Why: gtk-inherit theme relied on GTK4 color inheritance which works but doesn't update live when switching GTK themes (Walker service needs restart). Explicit color definitions make the theme self-contained and predictable.
- Tradeoffs: Colors no longer auto-follow GTK theme changes. Acceptable since moonarch uses a fixed Catppuccin Mocha palette anyway.
- How: Renamed theme to moonarch, added @define-color with Colloid-Grey-Dark-Catppuccin values, reduced border/shadow weight.
2026-04-07 – Migrate archinstall config to v4 format
- Who: Dominik, ClaudeCode
- Why: archinstall v4.1 introduced new canonical key names. Old keys (audio_config, bootloader, custom-commands) are soft-deprecated and auto-mapped, but custom-commands (hyphen) vs custom_commands (underscore) was risky.
- Tradeoffs: Config now requires archinstall v4+. Older ISOs with v2/v3 may not parse the new keys.
- How: Migrated audio_config into app_config, bootloader into bootloader_config, custom-commands to custom_commands, gfx_driver value updated.
2026-04-07 – kanshi config: no ABOUTME, no overwrite on transform
- Who: Dominik, ClaudeCode
- Why: ABOUTME comments in kanshi config broke the profile parser in wdisplays-persistent store.c, preventing config saves. Additionally, transform.sh was overwriting user display profiles on every run.
- Tradeoffs: kanshi default template is now empty (no comments). Users get no guidance in the seed file, but wdisplays-persistent provides the GUI for config management.
- How: Removed ABOUTME from defaults/xdg/kanshi/config. Added skip logic in transform.sh to preserve existing kanshi user configs.
2026-04-07 – Move paru repo config into moonarch.install hook
- Who: Dominik, ClaudeCode
- Why: paru PKGBUILD repo config was only set up by post-install.sh and transform.sh. If paru updated and overwrote /etc/paru.conf, or the config was missing on existing systems, moonarch-git couldn't update itself — bootstrap loop where the fix requires the package that delivers the fix.
- Tradeoffs: Config setup is now in two places: moonarch.install (for updates) and post-install.sh (for first install before moonarch-git exists). Acceptable duplication to break the circular dependency.
- How: Added paru repo config (Mode=arp + [moonarch-pkgbuilds] section) to moonarch.install post_install/post_upgrade hook. Kept post-install.sh setup for bootstrap. Removed redundant setup from transform.sh.
2026-04-02 – Rename paru PKGBUILD repo, move config to /etc/paru.conf
- Who: Dominik, ClaudeCode
- Why: paru PKGBUILD repo and pacman package registry both used
[moonarch]as section name. When pkgver-bot pushed version bumps, paru tried to resolve PKGBUILD targets (moongreet-git, moonlock-git) against the pacman repo — which only contains moonarch-git — causing "nicht alle benötigten Pakete gefunden" errors. - Tradeoffs: Renaming the PKGBUILD repo section means existing installations need a one-time manual fix. Using
/etc/paru.confinstead of~/.config/paru/paru.confis consistent with moonarch's system-wide config philosophy. - How: Renamed PKGBUILD repo section from
[moonarch]to[moonarch-pkgbuilds]. Moved paru config (Mode + repo) from user-level~/.config/paru/paru.confto system-wide/etc/paru.conf. Updated post-install.sh accordingly.
2026-04-01 – Replace dunst with swaync as notification daemon
- Who: Dominik, ClaudeCode
- Why: Dunst lacks wp_fractional_scale_v1 support, causing aliased/jagged font rendering on external monitors in mixed-DPI setups (laptop eDP-1 at 2.5x, externals at 1x). Confirmed by testing: removing fractional scaling fixed the issue. swaync uses GTK4 which handles fractional scaling natively.
- Tradeoffs: swaync is heavier than dunst (GTK4 + libadwaita dependency). Loses dunstctl CLI (replaced by swaync-client). Gains notification center panel with DnD toggle, grouping, MPRIS widget support. Waybar already had swaync-client integration with exec-if guard.
- How: Replaced dunst with swaync in packages/official.txt and archinstall config. Niri spawn-at-startup updated. Waybar dunstctl widget removed (swaync-client widget already present). New swaync config.json and style.css based on catppuccin/swaync upstream theme with Lavender accent instead of Blue.
2026-03-31 – Audit: shell script quoting fixes, PKGBUILD permissions
- Who: ClaudeCode, Dom
- Why: Security audit found command injection risk in moonarch-cpugov (unquoted array expansion with pkexec), word-splitting in moonarch-btnote (upower output from Bluetooth devices), and nmcli argument injection in moonarch-vpn. PKGBUILD for moongreet had world-readable cache dir.
- Tradeoffs:
evalin cpugov is safe because COMMANDS values are hardcoded string literals, not user input. Alternative (function dispatch) would be cleaner but over-engineered for 3 fixed entries. moonarch-btnote switched from for-loop to while+read with process substitution to avoid subshell. - How: (1)
eval "${COMMANDS[$choice]}"in cpugov. (2)while IFS= read -r+ process substitution + quoted$DEVICE_DATAin btnote. (3)--guard before$connectionin vpn nmcli calls. (4)install -dm700for moongreet cache dirs in PKGBUILD. (5)else errlogging in post-install.sh when USER_DEFAULTS missing.
2026-03-29 – /opt/moonarch stays root-owned, no chown to user
- Who: Dominik, ClaudeCode
- Why: Multi-user system — chown to UID 1000 locks out other users from moonarch-update
- Tradeoffs: sudo required for git operations in update.sh vs. simpler user-owned repo
- How: Repo stays at /opt/moonarch owned by root:root. update.sh uses
sudo gitfor fetch/pull. All scripts already use sudo for system-level operations, so this is consistent.
2026-03-29 – Add transform.sh for existing Arch+Wayland systems
- Who: Dominik, ClaudeCode
- Why: Users with existing Arch+Wayland setups should be able to adopt Moonarch without reinstalling
- Tradeoffs: Hard overwrite of all configs (user + system) vs. selective/merge approach — chose hard overwrite for simplicity and consistency
- How: New transform.sh with pre-flight summary, backup, DM conflict resolution, and --dry-run flag. Shared helpers extracted to lib.sh.
2026-03-29 – Package moonarch as moonarch-git PKGBUILD
- Who: Dominik, ClaudeCode
- Why: System artifacts (XDG configs, helper scripts, zsh config, wallpaper) should be managed by pacman for clean deployment, versioning, rollback, and deinstallation
- Tradeoffs: /etc/xdg/ configs NOT in backup= (moonarch philosophy: system defaults flow through, users override in ~/.config/). /etc/greetd/ and /etc/moongreet/ NOT owned by package (owned by greetd/moongreet-git, overwritten via .install hook). Helper scripts move from /usr/local/bin/ to /usr/bin/ (FHS for package-managed files)
- How: moonarch-git PKGBUILD in moonarch-pkgbuilds repo. sweet-cursors-git as separate package. moonarch-update simplified (no git-sync, pacman handles file deployment). Installer scripts (post-install.sh, transform.sh) remain for orchestration, will be refactored in a follow-up to delegate file deployment to
paru -S moonarch-git
2026-03-30 – Replace Rofi with Walker as application launcher
- Who: Dominik, ClaudeCode
- Why: Walker is Wayland-native (GTK4 + gtk4-layer-shell), has built-in providers for clipboard, bluetooth, audio (wireplumber), and Niri integration. Reduces custom shell scripts from 8 to 3. Rofi required a Wayland fork (rofi-lbonn-wayland-git) and every applet was a custom bash script.
- Tradeoffs: Walker is newer/less battle-tested than Rofi. Requires separate Elephant daemon with per-provider packages. Dmenu mode lacks Rofi's
-a/-u(active/urgent) and-mesgflags. Settings menu (moonarch-setmen) dropped entirely — apps are findable via Walker's app search. - How: Walker + Elephant as systemd user services. Native providers replace 5 rofi scripts (launcher, clipboard, bluetooth, volume, sink-switcher). 3 scripts ported to walker dmenu (vpn, cpugov, sink-switcher). Walker theme inherits GTK4 system theme colors (gtk-inherit). Old rofi configs preserved in
legacy/rofi/.
2026-03-30 – Use nm-applet as VPN secret agent, add WireGuard support
- Who: Dominik, ClaudeCode
- Why: VPN auth previously spawned a foot terminal for
nmcli --ask, which was fragile and ugly. WireGuard connections were invisible to the VPN script and Waybar indicator because both only checked for OpenVPN (tun0/vpntype). - Tradeoffs: nm-applet adds a tray indicator (mitigated with
--indicatormode which is minimal). Requires nm-applet running at session start. Alternative was gnome-keyring or a custom secret agent — nm-applet is simpler and handles all NM secret types. - How: nm-applet started via niri spawn-at-startup. moonarch-vpn rewritten to support both vpn and wireguard types, uses nm-applet for auth instead of foot terminal, sends notify-send for connect/disconnect results. Waybar VPN module uses
nmcliactive connection check instead of/proc/sys/net/ipv4/conf/tun0, plus RTMIN+9 signal for instant updates after toggle.
2026-03-30 – Standardize GTK theme to Colloid-Grey-Dark-Catppuccin
- Who: Dominik, ClaudeCode
- Why: gsettings had
Colloid-Dark-Catppuccinwhile config files hadColloid-Catppuccin— inconsistent. Grey accent matches the icon theme (Colloid-Grey-Catppuccin-Dark). Explicit-Darkvariant is more reliable than depending onprefer-darkcolor-scheme setting. - Tradeoffs: Explicit dark locks out light mode toggle — acceptable since Moonarch is dark-only by design.
- How: Updated transform.sh, post-install.sh, gtk-3.0/settings.ini, and gsettings to
Colloid-Grey-Dark-Catppuccin. GTK4 symlinks updated accordingly.