feat(lifecycle): auto-commit sweep of the machine flake before pull/rebuild/home
Some checks failed
Check / eval (push) Failing after 3m11s

With settings.autoCommit on, only menu/theme mutations were committed
(theme-sync pathspec-limits to theme-state.json by design), so hand
edits to system.nix/home.nix and lock bumps stayed forever-dirty.

New internal nomarchy-autocommit (nomarchy-lifecycle): live-reads the
same flag, commits everything dirty as "nomarchy: auto-commit before
<pull|rebuild|home switch>" with the swept file list in the body,
fallback identity, never fatal (|| true at call sites). Called at the
top of all three lifecycle commands; before the ff-only pull it also
un-dirties the tree. Exposed via passthru.autocommit + package export;
guarded by checks.lifecycle-autocommit (sandbox repos: sweep, no-op on
clean/off/non-repo). Sync sweep: README, RECOVERY, ROADMAP, rofi
toggle, control-center prompt, theme-sync docstring, JOURNAL.

Verified: V1+ — flake check --no-build green; the new check builds;
end-to-end run of the built nomarchy-rebuild (stubbed sudo/rebuild)
against a copy of a real dirty ~/.nomarchy: 4 files → one commit,
clean tree. No VM boot — no session-visible surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-12 12:52:05 +01:00
parent cc9caf802e
commit 9e37e11915
9 changed files with 146 additions and 7 deletions

View File

@@ -194,7 +194,10 @@ nomarchy-what-changed # plain-language last rebuild (system + desktop; --summar
`~/.nomarchy` is **your machine flake** (`system.nix` / `home.nix`). Newer
Nomarchy code arrives when `flake.lock` updates the `nomarchy` input
(`nomarchy-pull`), not by `git pull` of that directory (many installs have
no remote there — only local commits from auto-commit).
no remote there — only local commits from auto-commit). With auto-commit
on (menu: **System Auto-commit**), all three commands above also sweep
any pending hand edits into a commit before they switch, so
`git -C ~/.nomarchy log` mirrors your generations.
| When | Run |
|---|---|

View File

@@ -19,6 +19,28 @@ Template:
---
## 2026-07-12 — auto-commit sweep before pull/rebuild/home (interactive)
- **Task:** Bernardo's request (no BACKLOG item): with autoCommit on,
hand edits to `~/.nomarchy` (his had 4) stayed forever-dirty —
theme-sync's commit is pathspec-limited to theme-state.json by design.
- **Did:** New internal `nomarchy-autocommit` in nomarchy-lifecycle:
live-reads `settings.autoCommit`, commits *everything* dirty with
message `nomarchy: auto-commit before <label>` + file list in the
body; called (`|| true`, never blocks) at the top of nomarchy-pull /
-rebuild / -home. Exposed as `passthru.autocommit`; package exported.
Docs/comments swept: README, RECOVERY, ROADMAP ✓ entry, rofi toggle
text, control-center prompt, theme-sync docstring.
- **Verified:** V1+ — `nix flake check --no-build` green; new permanent
`checks.lifecycle-autocommit` builds (real binary, sandbox repos:
sweep/clean/off/non-repo); end-to-end on a *copy* of the real
~/.nomarchy via built nomarchy-rebuild with stubbed sudo/rebuild —
the 4 real dirty files landed in one commit, tree clean. No VM boot:
no session-visible surface. Real-machine confirmation lands after the
next nomarchy-pull picks up this rev.
- **Pending:** nothing queued; Bernardo's actual ~/.nomarchy still has
its 4 uncommitted files until his next pull/rebuild with the new rev.
- **Next suggestion:** back to BACKLOG (#89 slice 3, Signal pixmap).
## 2026-07-12 — #89 slice 2: EasyEffects tray icon themed monochrome (b98248f)
- **Task:** BACKLOG #89 slice 2 — EasyEffects SNI shows Papirus' full-
colour blue equaliser, clashing with the monochrome tray.

View File

@@ -30,8 +30,10 @@ boreal` (or any preset). If a switch failed halfway, the state file is written
`home-manager switch --flake ~/.nomarchy` (or `nomarchy-home`).
Your flake checkout is a git repo, and with auto-commit enabled every
apply is a commit: `git -C ~/.nomarchy log` to see what changed,
`git revert` the culprit, then `nomarchy-home`.
apply is a commit — and every `nomarchy-pull`/`-rebuild`/`-home` first
sweeps pending hand edits into one, so history mirrors your generations:
`git -C ~/.nomarchy log` to see what changed, `git revert` the culprit,
then `nomarchy-home`.
## 2. The desktop won't start at all

View File

@@ -960,6 +960,18 @@ Design/decision records and a running log of shipped work (items marked
`get` now prints booleans JSON-style (`true`, not Python's `True`) —
which also un-sticks the System menu's "Auto timezone (on/off)" label,
whose `= true` comparison could never match before.
- ✓ **Auto-commit sweep before switch (2026-07-12):** the pathspec limit
above left hand edits (system.nix/home.nix, lock bumps) forever-dirty
even with `settings.autoCommit` on. Now `nomarchy-pull`/`-rebuild`/
`-home` run `nomarchy-autocommit` (internal, in nomarchy-lifecycle)
first: same live-read flag, commits *everything* dirty with an honest
`nomarchy: auto-commit before <pull|rebuild|home switch>` message whose
body lists the swept files — so `git log` mirrors the generation list
and hand edits still never ride a settings-named commit. Same fallback
identity; never fatal (`|| true` at the call sites — a git hiccup can't
block a rebuild); before the ff-only pull, it also un-dirties the tree.
Guarded by `checks.lifecycle-autocommit` (sandbox-repo round trip of
the real binary: sweep, no-op on clean/off/non-repo).
- **"nomarchy" control center:** a single TUI/GUI front-end over the common
toggles — theme, power profile, opt-in services, display, DND — built on
the same `nomarchy-theme-sync` / `nomarchy.*` surface the menu already

View File

@@ -125,6 +125,7 @@
# Overlay tools exported for `nix build .#nomarchy-doctor` etc.
# (maintainer/CI convenience — modules install them via the overlay).
nomarchy-doctor = pkgs.nomarchy-doctor;
nomarchy-lifecycle = pkgs.nomarchy-lifecycle;
nomarchy-control-center = pkgs.nomarchy-control-center;
nomarchy-battery-notify = pkgs.nomarchy-battery-notify;
nomarchy-first-boot = pkgs.nomarchy-first-boot;
@@ -259,6 +260,55 @@
touch $out
'';
# The lifecycle "sweep before switch": with settings.autoCommit
# on, nomarchy-pull/-rebuild/-home first commit every dirty file
# in the machine flake (theme-sync's own auto_commit stays
# pathspec-limited to theme-state.json). Exercises the real
# helper binary against sandbox repos: flag on → one commit,
# clean tree, fallback identity, file list in the body; clean
# tree / flag off / no repo → untouched, never an error.
lifecycle-autocommit = pkgs.runCommand "nomarchy-lifecycle-autocommit"
{ nativeBuildInputs = [ pkgs.git ]; }
''
set -eu
tool=${pkgs.nomarchy-lifecycle.autocommit}/bin/nomarchy-autocommit
export HOME=$PWD # no global git config fallback identity
mkdir flake && git -C flake init -q
printf '{ "settings": { "autoCommit": true } }' > flake/theme-state.json
echo base > flake/system.nix
git -C flake add -A
git -C flake -c user.name=T -c user.email=t@t commit -qm init
echo edit >> flake/system.nix
echo lock > flake/flake.lock
NOMARCHY_PATH=$PWD/flake $tool rebuild
[ -z "$(git -C flake status --porcelain)" ] \
|| { echo "FAIL: tree still dirty after sweep"; exit 1; }
git -C flake log -1 --format=%s \
| grep -qx 'nomarchy: auto-commit before rebuild'
git -C flake log -1 --format=%ae | grep -qx 'nomarchy@localhost'
git -C flake log -1 --format=%b | grep -q 'flake.lock'
# Clean tree no new commit
NOMARCHY_PATH=$PWD/flake $tool rebuild
[ "$(git -C flake rev-list --count HEAD)" = 2 ]
# Flag off dirty stays dirty, no commit
printf '{ "settings": { "autoCommit": false } }' > flake/theme-state.json
echo more >> flake/system.nix
NOMARCHY_PATH=$PWD/flake $tool rebuild
[ "$(git -C flake rev-list --count HEAD)" = 2 ]
[ -n "$(git -C flake status --porcelain)" ]
# Not a git repo silent no-op, exit 0
mkdir plain
printf '{ "settings": { "autoCommit": true } }' > plain/theme-state.json
NOMARCHY_PATH=$PWD/plain $tool rebuild
touch $out
'';
# Installer hardware DB ↔ nixos-hardware (item 49): every module
# name the DB table and the CPU/GPU/chassis autodetect reference
# must exist in the PINNED nixos-hardware.nixosModules — a lock

View File

@@ -806,7 +806,9 @@ ${themeRows}
autocommit)
# Toggle opt-in auto-commit: every menu/theme mutation also commits
# theme-state.json (that file only) in the downstream flake, so
# settings history is `git log`. Nothing in Nix consumes the flag
# settings history is `git log`; nomarchy-pull/-rebuild/-home
# additionally sweep everything else dirty (hand edits, lock bumps)
# into a commit first. Nothing in Nix consumes the flag
# the tool reads the live state on each write so the toggle is
# instant, no rebuild. The off-write commits too (the tool fires
# when the flag was on before OR after), keeping history consistent.
@@ -815,7 +817,7 @@ ${themeRows}
notify-send "Auto-commit" "Off menu changes stay uncommitted in your flake."
else
nomarchy-theme-sync --quiet set settings.autoCommit true --no-switch
notify-send "Auto-commit" "On each change commits theme-state.json in your flake."
notify-send "Auto-commit" "On menu changes commit; rebuilds sweep pending edits in too."
fi
exit 0 ;;

View File

@@ -25,7 +25,7 @@ function first_boot() {
nomarchy-theme-sync apply "$chosen_theme"
fi
if gum confirm "Enable auto-commit for settings?"; then
if gum confirm "Enable auto-commit for your config? (settings changes + a sweep of pending edits before each rebuild)"; then
set_state "settings.autoCommit" "true"
else
set_state "settings.autoCommit" "false"

View File

@@ -15,6 +15,41 @@ let
flake="''${NOMARCHY_PATH:-$HOME/.nomarchy}"
'';
# Opt-in sweep (settings.autoCommit — the same flag theme-sync honours):
# commit EVERYTHING dirty in the machine flake before a pull/rebuild/
# home switch, so hand edits to system.nix/home.nix and lock bumps land
# in history at the moment they become live — `git log` mirrors the
# generation list. Complements nomarchy-theme-sync's auto_commit, which
# is pathspec-limited to theme-state.json on menu writes precisely so
# half-finished hand edits never ride a settings-named commit; here the
# sweep is the point, and the commit body lists what was swept. Never
# fatal — callers `|| true` so a git hiccup can't block a rebuild. Not
# in the symlinkJoin paths (internal; callers use the store path) but
# exposed as passthru.autocommit for checks.lifecycle-autocommit.
nomarchy-autocommit = writeShellScriptBin "nomarchy-autocommit" ''
${preamble "nomarchy-autocommit"}
label="''${1:-rebuild}"
[ -d "$flake/.git" ] || exit 0
command -v git >/dev/null 2>&1 || exit 0
flag=$(${jq}/bin/jq -r '.settings.autoCommit // false' \
"$flake/theme-state.json" 2>/dev/null || true)
[ "$flag" = "true" ] || exit 0
dirty=$(git -C "$flake" status --porcelain || true)
[ -n "$dirty" ] || exit 0
g=(git -C "$flake")
if [ -z "$("''${g[@]}" config user.email 2>/dev/null || true)" ]; then
g+=(-c user.name=Nomarchy -c user.email=nomarchy@localhost)
fi
"''${g[@]}" add -A
if "''${g[@]}" commit --quiet -m "nomarchy: auto-commit before $label" \
-m "$dirty"; then
echo "nomarchy-autocommit: committed pending flake changes before $label:"
echo "$dirty" | sed 's/^/ /'
else
echo "nomarchy-autocommit: commit failed continuing without it" >&2
fi
'';
nomarchy-pull = writeShellScriptBin "nomarchy-pull" ''
${preamble "nomarchy-pull"}
if [ ! -e "$flake/flake.nix" ]; then
@@ -22,6 +57,9 @@ let
echo " Set NOMARCHY_PATH or put your machine flake in ~/.nomarchy." >&2
exit 1
fi
# With settings.autoCommit on, sweep pending hand edits into a commit
# first also keeps the ff-only pull below safe on a dirty tree.
${nomarchy-autocommit}/bin/nomarchy-autocommit pull || true
# Optional: pull *your* machine config only if this checkout tracks a
# remote. Distro updates come from the nomarchy flake *input* below
# many installs have no upstream on ~/.nomarchy (local auto-commits).
@@ -52,6 +90,9 @@ let
echo "nomarchy-rebuild: no flake.nix at $flake" >&2
exit 1
fi
# With settings.autoCommit on, sweep pending hand edits (system.nix,
# lock bumps, ) into a commit so `git log` mirrors the generations.
${nomarchy-autocommit}/bin/nomarchy-autocommit rebuild || true
before=$(readlink -f /run/current-system)
log=$(mktemp)
trap 'rm -f "$log"' EXIT
@@ -94,6 +135,9 @@ let
echo "nomarchy-home: no flake.nix at $flake" >&2
exit 1
fi
# With settings.autoCommit on, sweep pending hand edits (home.nix, )
# into a commit so `git log` mirrors the generations.
${nomarchy-autocommit}/bin/nomarchy-autocommit "home switch" || true
# Snapshot the active HM generation before the switch so we can nvd it.
hm_before=""
for d in \
@@ -164,6 +208,7 @@ symlinkJoin {
home-update
nomarchy-what-changed
];
passthru.autocommit = nomarchy-autocommit;
meta = {
description = "Nomarchy machine-flake lifecycle: pull, rebuild, home";
mainProgram = "nomarchy-pull";

View File

@@ -143,7 +143,10 @@ def auto_commit(message: str) -> None:
fire this when the flag is on before OR after the write, so the
disable-toggle itself lands in history instead of staying dirty.
`bg` is deliberately excluded (runtime wallpaper churn); the wallpaper
path rides along with the next apply/set commit."""
path rides along with the next apply/set commit. The rest of a dirty
tree (hand edits, lock bumps) is swept by nomarchy-lifecycle's
nomarchy-autocommit right before a pull/rebuild/home switch — same
flag, honest message — so it never rides a settings-named commit."""
if not (FLAKE_DIR / ".git").exists() or shutil.which("git") is None:
return
git = ["git", "-C", str(FLAKE_DIR)]