All checks were successful
Check / eval (push) Successful in 3m7s
Bernardo, post-reboot: "Use for login" was the wrong question. Whether the
finger works is one decision, not two, and whether login prompts at all is
a different decision that was never in the menu.
System › Fingerprint is now a single Fingerprint (on/off) switch, leading
the menu with enroll/list/verify/delete as the plumbing behind it. It
writes the one settings.fingerprint.pam key, and modules/home/idle.nix now
defaults idle.fingerprint from that same key — so the lock screen and
login/sudo move together instead of drifting apart the way they did until
e2de906. nomarchy-fingerprint does the two rebuilds this needs (sudo
system for PAM, home switch for hyprlock) and refuses to turn on with no
finger enrolled.
System › Auto-login is new (nomarchy-autologin), and it is what decides
whether anything is asked at boot: auto-login on means no prompt whatever
the fingerprint switch says; off means the greeter asks, for a password or
a finger. Installer-seeded ON for LUKS machines — the passphrase already
gates the disk — and off without it, where the greeter is the only thing
between power-on and the desktop.
Both had to become state-owned to be toggleable at all, which surfaced two
real bugs:
* nomarchy.system.greeter.autoLogin defaulted from
`config.nomarchy.settings…` — an attribute that exists ONLY on the Home
Manager side. On NixOS it is absent and `or null` swallowed the error,
so the default silently evaluated to null on every machine ever built.
That is why the installer baked a Nix line: the state path never
worked. Now read via theme-state-read.nix (the hardware.nix/timezone.nix
pattern) and mkDefault'd, so the menu owns it and a hand-set line still
pins it. Two more options read the same phantom bridge — BACKLOG #116.
* `theme-sync get` printed Python's "None" for a JSON null, so every
`case … null)` a caller writes would miss. Now prints "null", as the
comment above it already promised for booleans.
The installer seeds the state instead of emitting the system.nix line,
because that line outranks the state and would strand the toggle.
V1 (V3 pending: HARDWARE-QUEUE). nix flake check --no-build, installer-
safety and option-docs all pass. Proved by eval/build, not assumed: a state
carrying autoLogin yields greetd initial_session {"user":"bernardo"}, the
template state (no autoLogin) yields none, and a hand-set null beats a state
that says otherwise; a state with only fingerprint.pam=true — nothing set by
hand — renders the hyprlock auth.fingerprint block; both new tools pass
bash -n and land in systemPackages (nomarchy-fingerprint only with a
reader); the patcher writes settings.greeter.autoLogin and no system.nix
line; and the get round trip prints null, so the menu reads "Auto-login
(off)" where it would have read "(on)".
The reader itself, the two rebuilds, and the reboot are hardware — queued.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
133 lines
6.1 KiB
Nix
133 lines
6.1 KiB
Nix
# System-level `nomarchy.system.*` options.
|
||
#
|
||
# Deliberately small: only things a downstream user plausibly disagrees
|
||
# with get a toggle. Everything else in the system module is set with
|
||
# lib.mkDefault, so plain NixOS options override it natively.
|
||
{ config, lib, ... }:
|
||
|
||
{
|
||
options.nomarchy.system = {
|
||
greeter.enable = lib.mkEnableOption "the greetd/tuigreet login screen" // { default = true; };
|
||
|
||
greeter.autoLogin = lib.mkOption {
|
||
type = lib.types.nullOr lib.types.str;
|
||
default = null;
|
||
defaultText = lib.literalExpression
|
||
"(settings.greeter.autoLogin from theme-state.json) or null";
|
||
example = "ada";
|
||
description = ''
|
||
Log this user straight into Hyprland on boot (greetd
|
||
initial_session); logging out lands on the normal greeter.
|
||
|
||
Normally you leave this alone and use System › Auto-login, which
|
||
writes `settings.greeter.autoLogin` in theme-state.json —
|
||
./greeter.nix mkDefaults this option from it. The installer seeds
|
||
that state on LUKS-encrypted machines: the disk passphrase already
|
||
gates access, so a second prompt is ceremony. Setting this option by
|
||
hand pins the choice and the menu toggle can no longer move it.
|
||
'';
|
||
};
|
||
|
||
plymouth.enable = lib.mkEnableOption ''
|
||
the Nomarchy Plymouth boot splash (logo + progress + LUKS prompt),
|
||
background-tinted from theme-state.json via nomarchy.system.stateFile.
|
||
Recolors on system rebuilds — theme switches don't touch the initrd'' // { default = true; };
|
||
|
||
stateFile = lib.mkOption {
|
||
type = lib.types.nullOr lib.types.path;
|
||
default = null;
|
||
example = lib.literalExpression "./theme-state.json";
|
||
description = ''
|
||
theme-state.json for the system-side consumers (currently the
|
||
Plymouth splash background). lib.mkFlake wires it automatically
|
||
from your flake; null falls back to the Boreal base color.
|
||
'';
|
||
};
|
||
|
||
fileManager.enable = lib.mkEnableOption ''
|
||
the Thunar GUI file manager + backend services (gvfs/tumbler/udisks2)
|
||
for point-and-click file management and the "open folder" handler.
|
||
The keyboard-driven TUI flagship (yazi) is the nomarchy.yazi.* home
|
||
option'' // { default = true; };
|
||
|
||
audio.enable = lib.mkEnableOption "the Pipewire audio stack" // { default = true; };
|
||
bluetooth.enable = lib.mkEnableOption "Bluetooth support with blueman" // { default = config.nomarchy.settings.bluetooth.enable or true; };
|
||
|
||
autoTimezone.enable = lib.mkEnableOption ''
|
||
automatic timezone detection (geoclue + automatic-timezoned): the
|
||
system timezone — and so the Waybar clock — follows your location, so
|
||
travelling to another zone updates the time on its own. Off by default
|
||
(it's a location service and needs the network); toggle it from the
|
||
System menu, which lands the choice in the in-flake state file. Enabling
|
||
it unsets the static time.timeZone for you (a runtime timezone needs
|
||
/etc/localtime writable), so the menu toggle drives a system rebuild''
|
||
// { default = false; };
|
||
|
||
snapper.enable = lib.mkEnableOption ''
|
||
hourly/daily BTRFS timeline snapshots of / via snapper, plus the
|
||
`nixos-rebuild-snap` pre-rebuild-snapshot helper. No-op unless the
|
||
root filesystem is BTRFS with a /.snapshots subvolume (the installer
|
||
creates one)'';
|
||
|
||
power = {
|
||
enable = lib.mkEnableOption ''
|
||
active power management. By default ships power-profiles-daemon —
|
||
the upstream-aligned power-saver/balanced/performance model,
|
||
switchable from the menu (nomarchy-menu power-profile) and shown
|
||
in Waybar on laptops — plus thermald and a battery charge limit
|
||
where applicable. Harmless on desktops (the profile daemon just
|
||
offers balanced/performance)'' // { default = true; };
|
||
|
||
backend = lib.mkOption {
|
||
type = lib.types.enum [ "ppd" "tlp" ];
|
||
default = "ppd";
|
||
description = ''
|
||
Which daemon governs CPU/platform power. "ppd"
|
||
(power-profiles-daemon) is the default: a clean three-profile
|
||
model with the menu switcher and Waybar indicator. "tlp" trades
|
||
that for TLP's deeper, more aggressive battery tuning, at the
|
||
cost of the profile switcher (TLP has no profile concept). The
|
||
two manage the same knobs and are mutually exclusive.
|
||
'';
|
||
};
|
||
|
||
laptop = lib.mkOption {
|
||
type = lib.types.bool;
|
||
default = false;
|
||
description = ''
|
||
Marks this machine as a laptop, gating battery-only features
|
||
(the charge limit below). The installer sets it to true when it
|
||
detects a battery at install time.
|
||
'';
|
||
};
|
||
|
||
thermal.enable = lib.mkEnableOption ''
|
||
thermald, Intel's thermal-management daemon, to avoid aggressive
|
||
throttling under sustained load. Intel-only — the installer
|
||
enables it when it detects a GenuineIntel CPU. Harmless alongside
|
||
either backend'';
|
||
|
||
batteryChargeLimit = lib.mkOption {
|
||
type = lib.types.nullOr (lib.types.ints.between 50 100);
|
||
default = config.nomarchy.settings.power.batteryChargeLimit or null;
|
||
# Dell Adaptive charge mode ignores the end threshold unless we
|
||
# also select Custom (power.nix oneshot); see Latitude 5310 QA.
|
||
example = 80;
|
||
description = ''
|
||
Stop charging at this percentage to extend battery lifespan,
|
||
where the hardware exposes charge_control_end_threshold on a
|
||
system battery (type=Battery under /sys/class/power_supply;
|
||
name-agnostic — BAT0, CMB0, …).
|
||
null leaves charging at the firmware default (menu writes 100).
|
||
Backend-independent: the menu applies live via sysfs (udev
|
||
GROUP=users on the threshold node) and persists settings in
|
||
theme-state; a oneshot re-applies on boot and AC replug. On
|
||
Dell (and similar) the oneshot also selects charge type Custom
|
||
— Adaptive ignores the threshold while still reporting it.
|
||
Needs nomarchy.system.power.laptop.
|
||
'';
|
||
};
|
||
};
|
||
};
|
||
}
|