feat(first-boot): post-install hardware hints — one self-gated toast, once
All checks were successful
Check / eval (push) Successful in 3m39s
All checks were successful
Check / eval (push) Successful in 3m39s
After the #81 "you're set" card, at most one additional "Hardware tips" toast: a Firmware line when fwupdmgr is on PATH, a Fingerprint line when fprintd-list is (VISION § B). One-shot marker settings.hardwareHintsShown, in-checkout like firstBootShown. When no tooling matches, the marker is deliberately left unset — the re-check costs a command -v per session, and a later-enabled fwupd or newly-added reader still gets its hint once. Never a permanent nag; live-ISO gate covers the new stage too. Lives inside nomarchy-first-boot: the card's semantics are unchanged (retry loop, exit 1 so a failed notify retries next login, marker only after success); hints run only once the card has landed. Docs: README option row, HARDWARE.md hint paragraphs, VISION § B checked off. Verification: V2 — shellcheck clean, nix flake check --no-build green, nix build .#checks.x86_64-linux.first-boot green (bare node silent → fwupdmgr appears → fires once → silent again → live-ISO still skips). Real toast rendering is the same session surface as the proven #81 card. Implementation by a Sonnet subagent; design and review on Fable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -257,7 +257,7 @@ two tables below are split along exactly that line.
|
||||
| `nomarchy.swaync.enable` | `true` | swaync notifications, themed |
|
||||
| `nomarchy.batteryNotify.enable` | `true` | Low-battery toasts at the bar's thresholds — 25% low, 10% critical (stays up until dismissed); silent no-op on machines without a battery |
|
||||
| `nomarchy.dockAudio.enable` | `true` | On a fresh external-monitor plug, PipeWire/WirePlumber are reprobed after hardware settles and the highest-priority available HDMI/DP/USB sink becomes default, with a toast and journal result. A later manual speaker choice sticks until the next physical plug; unplug falls back to built-in. Manual route: System › Audio |
|
||||
| `nomarchy.firstBootWelcome.enable` | `true` | One dismissible “you're set” toast on the first session (SUPER+M / SUPER+T / SUPER+? + network pointer); marker is `settings.firstBootShown` in the flake checkout |
|
||||
| `nomarchy.firstBootWelcome.enable` | `true` | One dismissible “you're set” toast on the first session (SUPER+M / SUPER+T / SUPER+? + network pointer); marker is `settings.firstBootShown` in the flake checkout. Also fires at most one follow-up “Hardware tips” toast pointing at System › Firmware / Fingerprint when `fwupdmgr` / `fprintd-list` are on PATH (`settings.hardwareHintsShown`) |
|
||||
| `nomarchy.idle.enable` | `true` | hyprlock + hypridle (lock 5 min; display off 10 min in every dock/lid state — input wakes it compositor-side, #127; suspend 15 min battery-only via `nomarchy-suspend`) |
|
||||
| `nomarchy.idle.fingerprint` | `false` | Unlock the lock screen with a fingerprint as well as the password, and say so on the input field. Set it alongside `nomarchy.hardware.fingerprint.pam` in system.nix: hyprlock is configured from Home Manager, which cannot read the NixOS option — and hyprlock does **not** take a fingerprint through PAM at all (its PAM stack runs only on submit), so it uses its own fprintd backend that this switch turns on |
|
||||
| `nomarchy.yazi.enable` | `true` | yazi TUI file manager, themed + curated plugins |
|
||||
|
||||
@@ -316,17 +316,6 @@ offline ISO's behaviour untouched (`checks.*` for the offline path stay green).
|
||||
2026-07-10). Keep #59 commented install guidance; no
|
||||
`nomarchy.hardware.nvidia.*` until a hybrid maintainer + queue.
|
||||
|
||||
- **Post-install hardware hints** (`VISION § B`) — After the general
|
||||
“you're set” card (#81), optionally fire **one** additional
|
||||
self-gated notify when the machine actually has the hardware:
|
||||
(a) `fwupdmgr` on PATH → “System › Firmware to check LVFS updates”;
|
||||
(b) `fprintd-list` on PATH → “System › Fingerprint to enroll”.
|
||||
One-shot markers in `settings.*` (same in-checkout discipline as
|
||||
`firstBootShown`); never a permanent MOTD nag. Cost: small — extend
|
||||
`nomarchy-first-boot` or a sibling oneshot + `checks.first-boot`
|
||||
fixture. Control-center / MOTD already mention these; the gap is the
|
||||
silent first *graphical* session for people who never open those.
|
||||
|
||||
_(#80–#83 + #85–#88 shipped 2026-07-11. Theme A day-2 + neon-glass finish
|
||||
shipped — VISION ✓. Dock/hibernate V3 → HARDWARE-QUEUE. Parallel
|
||||
fingerprint-or-password shipped 2026-07-12 (Bernardo promoted it live;
|
||||
@@ -335,9 +324,9 @@ _(#80–#83 + #85–#88 shipped 2026-07-11. Theme A day-2 + neon-glass finish
|
||||
|
||||
### v1.0 pointer
|
||||
|
||||
See **VISION**. Open PROPOSED: post-install hardware hints; NVIDIA
|
||||
deferred past v1; IR portal (b)/(c) need T14s (HARDWARE-QUEUE § T14s).
|
||||
Standing calls: browser = Chromium; power = PPD.
|
||||
See **VISION**. Open PROPOSED: NVIDIA deferred past v1; IR portal (b)/(c)
|
||||
need T14s (HARDWARE-QUEUE § T14s). Standing calls: browser = Chromium;
|
||||
power = PPD. (Post-install hardware hints shipped 2026-07-17.)
|
||||
|
||||
## Decisions `[human]`
|
||||
|
||||
|
||||
@@ -19,6 +19,22 @@ Template:
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-17 — Hardware hints: the second (and last) first-session toast
|
||||
- **Task:** PROPOSED "Post-install hardware hints" (VISION § B), promoted by
|
||||
Bernardo in-session.
|
||||
- **Did:** `nomarchy-first-boot` grew a hints stage after the card:
|
||||
self-gated Firmware/Fingerprint lines (fwupdmgr / fprintd-list on PATH),
|
||||
one toast, marker `settings.hardwareHintsShown`; marker deliberately unset
|
||||
while no tooling matches so late-appearing hardware still gets its hint.
|
||||
README row, HARDWARE.md hint paragraphs, VISION § B checked off.
|
||||
Implementation by a Sonnet agent from my design; review here.
|
||||
- **Verified:** V2 — shellcheck clean, flake check green,
|
||||
`checks.first-boot` green (bare-node silent → fwupdmgr appears → fires
|
||||
once → silent → live-ISO skip).
|
||||
- **Pending:** real toast rendering is session-surface, same class as the
|
||||
proven #81 card; it will fire once for real on the next fresh session.
|
||||
- **Next suggestion:** #127 close-out (upstream filing pending gh auth).
|
||||
|
||||
## 2026-07-17 — #148: dock intent now enforced without the auto-profiles toggle
|
||||
- **Task:** BACKLOG #148 (promoted from PROPOSED by Bernardo in-session).
|
||||
- **Did:** one-line fix — `enforce_dock_intent` dropped its `auto_on || return`
|
||||
|
||||
@@ -138,7 +138,10 @@ confirms each device and prompts for the reboot a capsule needs; pillar 1
|
||||
|
||||
**Hints (#43 / #73):** MOTD cheat-sheet line when `fwupdmgr` is on PATH.
|
||||
Fingerprint / doctor tips follow the same pattern (fingerprint MOTD only
|
||||
when `nomarchy.hardware.fingerprint.enable`).
|
||||
when `nomarchy.hardware.fingerprint.enable`). A one-shot toast in the
|
||||
first graphical session also points at System › Firmware when `fwupdmgr`
|
||||
is on PATH (`settings.hardwareHintsShown`, `nomarchy-first-boot`) — for
|
||||
people who never read the MOTD.
|
||||
|
||||
**Still queued:** a Doctor “updates available” check, and
|
||||
Waybar/updates-panel integration.
|
||||
@@ -191,7 +194,10 @@ happen — sudo, the lock screen, and the greeter only when
|
||||
|
||||
**Hints (#73):** MOTD line when `fingerprint.enable` is on; first-boot
|
||||
tip when `fprintd-list` is on PATH (`SUPER+M → System › Fingerprint` /
|
||||
`fprintd-enroll`). No permanent nag without a reader.
|
||||
`fprintd-enroll`). No permanent nag without a reader. A one-shot toast in
|
||||
the first graphical session also points at System › Fingerprint when
|
||||
`fprintd-list` is on PATH (`settings.hardwareHintsShown`,
|
||||
`nomarchy-first-boot`) — for people who never read the MOTD.
|
||||
|
||||
```sh
|
||||
# CLI still works:
|
||||
|
||||
@@ -493,6 +493,17 @@ Design/decision records and a running log of shipped work (items marked
|
||||
V2 by render, both heads + the password dialog, via the new
|
||||
`tools/plymouth-preview.sh`. V3 (a real docked boot/shutdown) is queued: the
|
||||
fake heads exist from the start, so the rig cannot resize a canvas.
|
||||
- ✓ **Post-install hardware hints (VISION § B, 2026-07-17):** after the #81
|
||||
"you're set" card, at most one additional "Hardware tips" toast — a
|
||||
Firmware line when `fwupdmgr` is on PATH, a Fingerprint line when
|
||||
`fprintd-list` is — with its own one-shot marker
|
||||
(`settings.hardwareHintsShown`, in-checkout like `firstBootShown`). If no
|
||||
tooling matches, the marker is deliberately left unset so the hint still
|
||||
fires once if fwupd/a reader appears later. Lives inside
|
||||
`nomarchy-first-boot` (the card's exit-1-retries-next-login semantics are
|
||||
preserved; hints only run once the card has landed). V2:
|
||||
`checks.first-boot` grew the silent-bare-node → fwupdmgr-appears →
|
||||
fires-once → silent-again → live-ISO-still-skips flow.
|
||||
- ✓ **Reload re-lit the panel inside a shut lid (#148, 2026-07-17):** every
|
||||
`nomarchy-home` (HM activation → `hyprctl reload`) re-applied the catch-all
|
||||
monitor rule and left eDP-1 burning in the closed clamshell. The #142 tick
|
||||
|
||||
@@ -74,7 +74,7 @@ Reference: [HARDWARE.md](HARDWARE.md) §4–§5, §11 (doctor).
|
||||
| **Silent first-week card** ✓ | One dismissible “you’re set” (menu, themes, keys, network) — not a wizard | ✓ shipped #81 — `settings.firstBootShown` + notify; live ISO keeps its own toast |
|
||||
| **Boreal as default** ✓ | Identity on first boot | ✓ seed `state.json` + install path use Boreal (2026-07-09) |
|
||||
| **Generation readability** ✓ | “What changed last rebuild” in plain language | ✓ shipped #82 — nvd toast + System › What changed? |
|
||||
| **Post-install hints** | One-shot MOTD/notify for fwupd / fprintd when relevant | Partial: MOTD tips; first-session toast is #81; still refine self-gated hardware hints if needed |
|
||||
| **Post-install hints** ✓ | One-shot MOTD/notify for fwupd / fprintd when relevant | ✓ shipped 2026-07-17 — self-gated “Hardware tips” toast after the #81 card (`settings.hardwareHintsShown`), fwupd/fprintd lines when the tooling is on PATH |
|
||||
|
||||
---
|
||||
|
||||
@@ -154,13 +154,11 @@ From GOALS non-goals and installer audits — do not “fill the roadmap” with
|
||||
|
||||
**Still open** (as of 2026-07-11). Shipped items above are *not* open work.
|
||||
|
||||
1. `VISION § B` — post-install hardware hints (self-gated first-session
|
||||
toast when `fwupdmgr` / `fprintd-list` exist; one-shot markers; no nag)
|
||||
2. `VISION § D` / LATER — wallpapers artifact split (decided deferred;
|
||||
1. `VISION § D` / LATER — wallpapers artifact split (decided deferred;
|
||||
promote only if theme-switch latency still hurts after measurement)
|
||||
3. `VISION § H` — HARDWARE-QUEUE burn-down (human-only V3; agents only
|
||||
2. `VISION § H` — HARDWARE-QUEUE burn-down (human-only V3; agents only
|
||||
append exact steps)
|
||||
4. `VISION § v1.0` — install P0 re-verify before any `v1` fast-forward
|
||||
3. `VISION § v1.0` — install P0 re-verify before any `v1` fast-forward
|
||||
(swap=0 / unattended LUKS contracts; human ships the pointer)
|
||||
|
||||
Do **not** re-open Theme A firmware/fingerprint/doctor/rebuild rows —
|
||||
|
||||
43
flake.nix
43
flake.nix
@@ -1773,6 +1773,9 @@
|
||||
# theme-sync, silent on re-run; skips hostname nomarchy-live.
|
||||
# notify-send + state-sync shimmed on PATH (same pattern as
|
||||
# battery-notify). Real toast rendering stays session/V3.
|
||||
# Also covers the hardware-hints stage (VISION § B): silent when
|
||||
# no gated tooling is on PATH, fires once when it appears
|
||||
# (fwupdmgr shimmed here), silent again after.
|
||||
first-boot = pkgs.testers.runNixOSTest {
|
||||
name = "nomarchy-first-boot";
|
||||
nodes.machine = { ... }: {
|
||||
@@ -1803,23 +1806,57 @@
|
||||
"HOME=/root"
|
||||
)
|
||||
|
||||
# First run: toast + marker.
|
||||
# First run: toast + marker. Node has neither fwupdmgr nor
|
||||
# fprintd-list, so the hardware-hints stage (VISION § B)
|
||||
# must stay silent and must NOT set its marker (cheap
|
||||
# re-check each session — see the script comment).
|
||||
machine.succeed(f"{env} nomarchy-first-boot")
|
||||
out = machine.succeed("cat /tmp/notifications")
|
||||
assert "You're set" in out, f"welcome toast missing:\n{out}"
|
||||
assert "SUPER+M" in out and "SUPER+T" in out, f"key pointers missing:\n{out}"
|
||||
assert "Network" in out or "Wi" in out, f"network pointer missing:\n{out}"
|
||||
assert "Hardware tips" not in out, f"unwanted hint toast:\n{out}"
|
||||
shown = machine.succeed(
|
||||
f"{env} nomarchy-state-sync get settings.firstBootShown"
|
||||
).strip()
|
||||
assert shown == "true", f"marker not written: {shown!r}"
|
||||
hints_marker = machine.succeed(
|
||||
f"{env} nomarchy-state-sync get settings.hardwareHintsShown 2>/dev/null || true"
|
||||
).strip()
|
||||
assert hints_marker != "true", f"hints marker set too early: {hints_marker!r}"
|
||||
|
||||
# Second run: silent (no second toast).
|
||||
# Second run: silent (no second toast, still no matching
|
||||
# hardware/tooling).
|
||||
machine.succeed("rm -f /tmp/notifications")
|
||||
machine.succeed(f"{env} nomarchy-first-boot")
|
||||
machine.fail("test -s /tmp/notifications")
|
||||
|
||||
# Live ISO hostname: skip even with marker cleared.
|
||||
# fwupdmgr appears on PATH (e.g. fwupd enabled later): the
|
||||
# hints stage fires once, mentioning Firmware, and sets its
|
||||
# own marker without re-touching firstBootShown.
|
||||
machine.succeed(
|
||||
"printf '#!/bin/sh\\nexit 0\\n' > /shim/fwupdmgr && "
|
||||
"chmod +x /shim/fwupdmgr"
|
||||
)
|
||||
machine.succeed(f"{env} nomarchy-first-boot")
|
||||
out = machine.succeed("cat /tmp/notifications")
|
||||
assert "Hardware tips" in out, f"hint toast missing:\n{out}"
|
||||
assert "Firmware" in out, f"firmware hint missing:\n{out}"
|
||||
hints_marker = machine.succeed(
|
||||
f"{env} nomarchy-state-sync get settings.hardwareHintsShown"
|
||||
).strip()
|
||||
assert hints_marker == "true", f"hints marker not written: {hints_marker!r}"
|
||||
|
||||
# Run again: silent (hints marker now set).
|
||||
machine.succeed("rm -f /tmp/notifications")
|
||||
machine.succeed(f"{env} nomarchy-first-boot")
|
||||
machine.fail("test -s /tmp/notifications")
|
||||
|
||||
# Live ISO hostname: skip even with markers cleared —
|
||||
# covers both the welcome card and the hardware-hints stage.
|
||||
machine.succeed(
|
||||
f"{env} nomarchy-state-sync --quiet set settings.hardwareHintsShown false --no-switch"
|
||||
)
|
||||
machine.succeed(
|
||||
f"{env} nomarchy-state-sync --quiet set settings.firstBootShown false --no-switch"
|
||||
)
|
||||
|
||||
@@ -1,53 +1,117 @@
|
||||
# nomarchy-first-boot — one-shot "you're set" toast on the first session.
|
||||
# Marker is settings.firstBootShown in the flake's state.json
|
||||
# (in-checkout state; never ~/.local/state). notify-send and
|
||||
# nomarchy-state-sync come from PATH so the VM check can shim them.
|
||||
# nomarchy-first-boot — one-shot "you're set" toast on the first session,
|
||||
# plus a second self-gated toast (hardware hints, VISION § B) pointing at
|
||||
# hardware-specific menu items when the matching tooling is on PATH.
|
||||
# Markers are settings.firstBootShown / settings.hardwareHintsShown in the
|
||||
# flake's state.json (in-checkout state; never ~/.local/state). notify-send
|
||||
# and nomarchy-state-sync come from PATH so the VM check can shim them.
|
||||
|
||||
# Live ISO already has its own welcome (hosts/live.nix); skip there so
|
||||
# users aren't double-toasted and the live seed doesn't get a sticky
|
||||
# firstBootShown write every boot.
|
||||
# firstBootShown write every boot. This also covers the hints stage below.
|
||||
# uname -n is coreutils; avoid depending on a separate hostname package.
|
||||
hn=$(uname -n 2>/dev/null || true)
|
||||
if [ "$hn" = nomarchy-live ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Already shown → silent. Missing key / no checkout → treat as not shown
|
||||
# (state-sync get exits non-zero when the key is absent).
|
||||
# Already shown → skip straight to the hardware-hints stage below. Missing
|
||||
# key / no checkout → treat as not shown (state-sync get exits non-zero
|
||||
# when the key is absent).
|
||||
shown=$(nomarchy-state-sync get settings.firstBootShown 2>/dev/null || true)
|
||||
just_shown=
|
||||
case "$shown" in
|
||||
true|1|yes) exit 0 ;;
|
||||
esac
|
||||
|
||||
# Wait for the notification daemon (swaync). On first login the unit can
|
||||
# race graphical-session and get "Timeout was reached" from D-Bus — then
|
||||
# either no toast, or a toast that never lands while we still write the
|
||||
# marker. Retry notify-send; only persist the marker after a success.
|
||||
body="SUPER+M menu · SUPER+T themes · SUPER+? keys
|
||||
true|1|yes) : ;;
|
||||
*)
|
||||
# Wait for the notification daemon (swaync). On first login the unit
|
||||
# can race graphical-session and get "Timeout was reached" from
|
||||
# D-Bus — then either no toast, or a toast that never lands while we
|
||||
# still write the marker. Retry notify-send; only persist the marker
|
||||
# after a success.
|
||||
body="SUPER+M menu · SUPER+T themes · SUPER+? keys
|
||||
Wi‑Fi: System › Network (or the bar tray)
|
||||
Anything off? System › Doctor"
|
||||
|
||||
ok=
|
||||
ok=
|
||||
i=0
|
||||
while [ "$i" -lt 8 ]; do
|
||||
if notify-send -a Nomarchy -u normal -t 0 \
|
||||
"You're set" \
|
||||
"$body"; then
|
||||
ok=1
|
||||
break
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ -z "$ok" ]; then
|
||||
# Leave firstBootShown alone so the next login can try again. Don't
|
||||
# attempt hardware hints either — they're gated on the card landing.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Persist in the checkout so re-login is silent. --no-switch: marker
|
||||
# only.
|
||||
if ! nomarchy-state-sync --quiet set settings.firstBootShown true --no-switch; then
|
||||
# No writable flake checkout (or tool missing) — still showed the
|
||||
# toast; without a marker it may reappear next login. Don't fail
|
||||
# the unit, and skip hints too (state-sync isn't writable anyway).
|
||||
exit 0
|
||||
fi
|
||||
just_shown=1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- hardware hints (post-install hints, VISION § B) ----------------------
|
||||
# At most one additional self-gated toast, once per machine, pointing at
|
||||
# hardware-specific menu items when the matching tooling is on PATH.
|
||||
hints_shown=$(nomarchy-state-sync get settings.hardwareHintsShown 2>/dev/null || true)
|
||||
case "$hints_shown" in
|
||||
true|1|yes) exit 0 ;;
|
||||
esac
|
||||
|
||||
hint_lines=()
|
||||
if command -v fwupdmgr >/dev/null 2>&1; then
|
||||
hint_lines+=("SUPER+M → System › Firmware to check LVFS updates")
|
||||
fi
|
||||
if command -v fprintd-list >/dev/null 2>&1; then
|
||||
hint_lines+=("SUPER+M → System › Fingerprint to enroll a finger")
|
||||
fi
|
||||
|
||||
# No matching hardware/tooling: stay quiet and deliberately don't set the
|
||||
# marker — this re-check is cheap each session, and if the tooling shows
|
||||
# up later (fwupd enabled, a reader added) the hint still fires once.
|
||||
if [ "${#hint_lines[@]}" -eq 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
hints=$(printf '%s\n' "${hint_lines[@]}")
|
||||
|
||||
# Just showed the welcome card in this run: give swaync a moment so the
|
||||
# two toasts don't collide.
|
||||
if [ -n "$just_shown" ]; then
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
hok=
|
||||
i=0
|
||||
while [ "$i" -lt 8 ]; do
|
||||
if notify-send -a Nomarchy -u normal -t 0 \
|
||||
"You're set" \
|
||||
"$body"; then
|
||||
ok=1
|
||||
"Hardware tips" \
|
||||
"$hints"; then
|
||||
hok=1
|
||||
break
|
||||
fi
|
||||
i=$((i + 1))
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ -z "$ok" ]; then
|
||||
# Leave firstBootShown alone so the next login can try again.
|
||||
if [ -z "$hok" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Persist in the checkout so re-login is silent. --no-switch: marker only.
|
||||
if ! nomarchy-state-sync --quiet set settings.firstBootShown true --no-switch; then
|
||||
# No writable flake checkout (or tool missing) — still showed the toast;
|
||||
# without a marker it may reappear next login. Don't fail the unit.
|
||||
if ! nomarchy-state-sync --quiet set settings.hardwareHintsShown true --no-switch; then
|
||||
# No writable flake checkout — still showed the toast; without a marker
|
||||
# it may reappear next login. Don't fail the unit.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user