CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m4s
commitizen 4.13.9 ships per-Python-minor golden files for its CLI regression tests. The py_3_13 golden was captured against an early 3.13 whose argparse did not quote invalid choices. CPython later backported quoting into the 3.13.x line, and nixos-26.05 now ships 3.13.14, so the golden no longer matches argparse's output: -cz: error: ... invalid choice: 'x' (choose from init, commit, ...) +cz: error: ... invalid choice: 'x' (choose from 'init', 'commit', ...) This fails commitizen's checkPhase and breaks the home-manager closure. The package itself is unaffected. Deselect just that test via an overlay until nixpkgs updates the fixture (or the 3.13.x revert lands upstream).
482 lines
18 KiB
Nix
482 lines
18 KiB
Nix
{
|
|
description = "NixOS configuration";
|
|
|
|
inputs = {
|
|
# Pinned stable channel; the single source of truth for every host.
|
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-26.05";
|
|
# Bleeding-edge channel, used only to pull individual packages via overlay.
|
|
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
|
# Home-manager release matched to the stable nixpkgs; `follows` keeps a single nixpkgs eval.
|
|
home-manager.url = "github:nix-community/home-manager/release-26.05";
|
|
home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
|
# WSL module for the EDaaS host; flake input avoids the impure <nixos-wsl> NIX_PATH lookup.
|
|
nixos-wsl.url = "github:nix-community/NixOS-WSL";
|
|
nixos-wsl.inputs.nixpkgs.follows = "nixpkgs";
|
|
# Apple Silicon (Asahi) support for the MacBook host.
|
|
nixos-apple-silicon.url = "github:nix-community/nixos-apple-silicon";
|
|
nixos-apple-silicon.inputs.nixpkgs.follows = "nixpkgs";
|
|
# nix-darwin: manage macOS hosts from this same flake.
|
|
nix-darwin.url = "github:nix-darwin/nix-darwin/nix-darwin-26.05";
|
|
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
|
|
# nix-homebrew: declaratively own and install the Homebrew prefix on macOS.
|
|
nix-homebrew.url = "github:zhaofengli/nix-homebrew";
|
|
# Provides mkFlake: the systems/perSystem scaffolding used below.
|
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
|
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
|
# Declarative Firefox add-ons (e.g. the Catppuccin theme); see modules/users.nix.
|
|
firefox-addons = {
|
|
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# Prebuilt nix-index database so "command not found -> which package
|
|
# provides it" works immediately (no manual `nix-index` run). See shell.nix.
|
|
nix-index-database = {
|
|
url = "github:nix-community/nix-index-database";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# treefmt-nix: one multi-language formatter driving `nix fmt` and the
|
|
# formatting flake check (nixfmt + shfmt + prettier).
|
|
treefmt-nix = {
|
|
url = "github:numtide/treefmt-nix";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# git-hooks.nix: declarative pre-commit hooks (nixfmt/deadnix/statix),
|
|
# installed into the repo via the devShell.
|
|
git-hooks = {
|
|
url = "github:cachix/git-hooks.nix";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# Declarative Neovim (the editor; see home/editor.nix). Release
|
|
# branch matched to the pinned nixpkgs (26.05); follows our nixpkgs to keep a
|
|
# single nixpkgs in the closure. editor.nix sets programs.nixvim.nixpkgs.source
|
|
# to this same input so the home module doesn't warn about the pin.
|
|
nixvim = {
|
|
url = "github:nix-community/nixvim/nixos-26.05";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# Curated per-hardware profiles (microcode, SSD, platform quirks) for the
|
|
# physical x86 hosts.
|
|
nixos-hardware = {
|
|
url = "github:NixOS/nixos-hardware";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
# kube-tmux: kube context/namespace for the tmux status line on the work
|
|
# host. Not in nixpkgs and not a flake -- pinned here as a plain source so
|
|
# the script is always in the store (no manual checkout). See work.nix.
|
|
kube-tmux = {
|
|
url = "github:jonmosco/kube-tmux";
|
|
flake = false;
|
|
};
|
|
};
|
|
|
|
outputs =
|
|
inputs@{
|
|
flake-parts,
|
|
nixpkgs,
|
|
nixpkgs-unstable,
|
|
home-manager,
|
|
nixos-wsl,
|
|
nixos-apple-silicon,
|
|
nix-darwin,
|
|
nix-homebrew,
|
|
...
|
|
}:
|
|
flake-parts.lib.mkFlake { inherit inputs; } (
|
|
{ lib, ... }:
|
|
let
|
|
# claude-code tracks nixpkgs-unstable regardless of the pinned nixpkgs.
|
|
overlays = [
|
|
(_final: prev: {
|
|
inherit
|
|
(import nixpkgs-unstable {
|
|
inherit (prev.stdenv.hostPlatform) system;
|
|
config.allowUnfree = true;
|
|
})
|
|
claude-code
|
|
;
|
|
})
|
|
# commitizen 4.13.9's regression test for the invalid-command error
|
|
# message asserts argparse's older, unquoted "invalid choice" wording;
|
|
# the argparse in Python 3.13 quotes each choice, so the fixture no
|
|
# longer matches and the checkPhase fails. The package itself is fine
|
|
# -- deselect just that test. Drop once nixpkgs updates the fixture.
|
|
(_final: prev: {
|
|
commitizen = prev.commitizen.overridePythonAttrs (old: {
|
|
disabledTests = (old.disabledTests or [ ]) ++ [ "test_invalid_command" ];
|
|
});
|
|
})
|
|
];
|
|
|
|
# Unfree packages permitted to be built (replaces blanket allowUnfree).
|
|
unfreePackages = [
|
|
"claude-code"
|
|
];
|
|
|
|
# Per-user identity, keyed by username. See README "Users".
|
|
userRegistry = import ./users/registry.nix;
|
|
|
|
# nixpkgs + nix-daemon settings shared by NixOS and Darwin hosts.
|
|
commonModule = {
|
|
nixpkgs.overlays = overlays;
|
|
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) unfreePackages;
|
|
nix.settings.experimental-features = [
|
|
"nix-command"
|
|
"flakes"
|
|
];
|
|
# Make `nix shell nixpkgs#...` and <nixpkgs> use the pinned nixpkgs.
|
|
nix.registry.nixpkgs.flake = nixpkgs;
|
|
nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
|
|
};
|
|
|
|
# Shared scaffolding for every NixOS host: common user, settings, home-manager.
|
|
baseModules = [
|
|
./modules/users.nix
|
|
./modules/common-nixos.nix
|
|
./modules/features.nix
|
|
commonModule
|
|
home-manager.nixosModules.home-manager
|
|
{
|
|
home-manager.useGlobalPkgs = true;
|
|
home-manager.useUserPackages = true;
|
|
# Back up pre-existing dotfiles (e.g. .zshrc) instead of aborting
|
|
# activation when home-manager would overwrite them.
|
|
home-manager.backupFileExtension = "backup";
|
|
}
|
|
];
|
|
|
|
# Build one NixOS host. `users` is an attrset keyed by username (home
|
|
# modules + optional per-user system bits). See README "Users".
|
|
mkHost =
|
|
{
|
|
system,
|
|
modules,
|
|
users,
|
|
# Host form factor. Laptops inherit the default; a desktop host sets
|
|
# `portable = false` to drop mobile components (battery block,
|
|
# brightness keys) from the home-manager Sway config.
|
|
portable ? true,
|
|
}:
|
|
nixpkgs.lib.nixosSystem {
|
|
inherit system;
|
|
specialArgs = {
|
|
inherit
|
|
inputs
|
|
userRegistry
|
|
portable
|
|
;
|
|
};
|
|
modules =
|
|
baseModules
|
|
++ modules
|
|
++ [
|
|
{ _module.args.hostUsers = users; }
|
|
{
|
|
home-manager.extraSpecialArgs = { inherit inputs portable; };
|
|
home-manager.users = lib.mapAttrs (name: spec: {
|
|
imports = spec.homeModules;
|
|
_module.args.identity = userRegistry.${name} // {
|
|
username = name;
|
|
};
|
|
}) users;
|
|
}
|
|
];
|
|
};
|
|
|
|
# Shared scaffolding for every Darwin (macOS) host.
|
|
darwinBaseModules = [
|
|
commonModule
|
|
nix-homebrew.darwinModules.nix-homebrew
|
|
home-manager.darwinModules.home-manager
|
|
{
|
|
home-manager.useGlobalPkgs = true;
|
|
home-manager.useUserPackages = true;
|
|
# Back up pre-existing dotfiles (e.g. .zshrc) instead of aborting
|
|
# activation when home-manager would overwrite them.
|
|
home-manager.backupFileExtension = "backup";
|
|
}
|
|
];
|
|
|
|
# Darwin counterpart of mkHost: single-user (macOS owns the account),
|
|
# identity still from the registry. See README "Users".
|
|
mkDarwinHost =
|
|
{
|
|
system,
|
|
username,
|
|
modules,
|
|
homeModules,
|
|
}:
|
|
nix-darwin.lib.darwinSystem {
|
|
specialArgs = { inherit inputs username; };
|
|
modules =
|
|
darwinBaseModules
|
|
++ modules
|
|
++ [
|
|
{
|
|
nixpkgs.hostPlatform = system;
|
|
# macOS owns the account; point home-manager at its home dir.
|
|
users.users.${username}.home = "/Users/${username}";
|
|
home-manager.extraSpecialArgs = { inherit inputs; };
|
|
home-manager.users.${username} = {
|
|
imports = homeModules;
|
|
_module.args.identity = userRegistry.${username} // {
|
|
inherit username;
|
|
};
|
|
};
|
|
}
|
|
];
|
|
};
|
|
|
|
# Host table — one entry per machine, realised into a nixosConfiguration
|
|
# of the same name below. See README "Hosts" / "Users".
|
|
hosts = {
|
|
lyrathorpe-mbp = {
|
|
system = "aarch64-linux";
|
|
modules = [
|
|
./hosts/MBP-Asahi/configuration.nix
|
|
./modules/laptop.nix
|
|
nixos-apple-silicon.nixosModules.default
|
|
./modules/sway.nix
|
|
];
|
|
users.lyrathorpe.homeModules = [
|
|
./home
|
|
./users/lyrathorpe/home.nix
|
|
./home/desktop.nix
|
|
];
|
|
};
|
|
|
|
lyrathorpe-t400 = {
|
|
system = "x86_64-linux";
|
|
modules = [
|
|
./hosts/T400/configuration.nix
|
|
./modules/laptop.nix
|
|
./modules/ssh.nix
|
|
# No t400-specific profile exists; compose the generic ThinkPad +
|
|
# laptop/SSD/Intel building blocks (tp_smapi/acpi_call for battery
|
|
# thresholds, SSD + microcode defaults).
|
|
inputs.nixos-hardware.nixosModules.lenovo-thinkpad
|
|
inputs.nixos-hardware.nixosModules.common-pc-laptop
|
|
inputs.nixos-hardware.nixosModules.common-pc-laptop-ssd
|
|
inputs.nixos-hardware.nixosModules.common-cpu-intel
|
|
./modules/sway.nix
|
|
];
|
|
users.lyrathorpe.homeModules = [
|
|
./home
|
|
./users/lyrathorpe/home.nix
|
|
./home/desktop.nix
|
|
];
|
|
};
|
|
|
|
lyrathorpe-macpro31 = {
|
|
system = "x86_64-linux";
|
|
portable = false;
|
|
modules = [
|
|
./hosts/MacPro31/configuration.nix
|
|
./modules/desktop.nix
|
|
./modules/ssh.nix
|
|
inputs.nixos-hardware.nixosModules.common-pc-ssd
|
|
inputs.nixos-hardware.nixosModules.common-cpu-intel
|
|
./modules/sway.nix
|
|
];
|
|
users.lyrathorpe.homeModules = [
|
|
./home
|
|
./users/lyrathorpe/home.nix
|
|
./home/desktop.nix
|
|
];
|
|
};
|
|
|
|
emmathorpe-edaas = {
|
|
system = "x86_64-linux";
|
|
modules = [
|
|
./hosts/EDaaS/configuration.nix
|
|
nixos-wsl.nixosModules.default
|
|
./modules/sway.nix
|
|
];
|
|
users.emmathorpe = {
|
|
homeModules = [
|
|
./home
|
|
./users/emmathorpe/work.nix
|
|
];
|
|
# Keep the systemd --user instance alive without a login session so
|
|
# the renovate-review home timer fires on schedule.
|
|
linger = true;
|
|
};
|
|
};
|
|
|
|
lyrathorpe-rpi5 = {
|
|
system = "aarch64-linux";
|
|
portable = false;
|
|
# Headless server: Docker host + nginx reverse proxy. No sway.nix
|
|
# (no desktop); the raspberry-pi-5 profile supplies kernel/firmware,
|
|
# ssh.nix adds key-only sshd.
|
|
modules = [
|
|
./hosts/RPi5/configuration.nix
|
|
inputs.nixos-hardware.nixosModules.raspberry-pi-5
|
|
./modules/ssh.nix
|
|
];
|
|
users.lyrathorpe.homeModules = [
|
|
./home
|
|
./users/lyrathorpe/home.nix
|
|
];
|
|
};
|
|
};
|
|
|
|
# Darwin host table — macOS machines built via mkDarwinHost. The shared
|
|
# ./home bundle (shell, git, editor) is reused directly; the Linux-only
|
|
# desktop/sway modules are intentionally left out.
|
|
darwinHosts = {
|
|
lyrathorpe-mac = {
|
|
system = "aarch64-darwin";
|
|
username = "lyrathorpe";
|
|
modules = [
|
|
./hosts/Darwin/configuration.nix
|
|
];
|
|
homeModules = [
|
|
./home
|
|
./users/lyrathorpe/home.nix
|
|
];
|
|
};
|
|
};
|
|
in
|
|
{
|
|
# flake-parts modules: treefmt-nix wires `nix fmt` + a formatting check;
|
|
# git-hooks.nix wires the pre-commit check + devShell installation script.
|
|
imports = [
|
|
inputs.treefmt-nix.flakeModule
|
|
inputs.git-hooks.flakeModule
|
|
];
|
|
|
|
systems = [
|
|
"x86_64-linux"
|
|
"aarch64-linux"
|
|
"aarch64-darwin"
|
|
"x86_64-darwin"
|
|
];
|
|
|
|
# perSystem is evaluated once per entry in `systems`; `pkgs` is the
|
|
# nixpkgs instance for that system. Outputs here become per-system
|
|
# attrsets automatically (e.g. devShells.<system>.default).
|
|
perSystem =
|
|
{ config, pkgs, ... }:
|
|
{
|
|
# treefmt drives `nix fmt` and the formatting check below. nixfmt
|
|
# stays the .nix formatter (the tree is already nixfmt-formatted);
|
|
# shfmt covers shell and prettier covers markdown/yaml/json.
|
|
treefmt = {
|
|
projectRootFile = "flake.nix";
|
|
programs.nixfmt.enable = true;
|
|
programs.shfmt.enable = true;
|
|
programs.prettier.enable = true;
|
|
# Generated hardware-configuration.nix files are not hand-edited.
|
|
settings.global.excludes = [
|
|
"*/hardware-configuration.nix" # generated by nixos-generate-config
|
|
"flake.lock" # generated by `nix flake lock`
|
|
];
|
|
};
|
|
|
|
# Pre-commit hooks: format + lint gate run on commit. The same hooks
|
|
# are exposed as a flake check (pre-commit.check.enable defaults true).
|
|
pre-commit.settings = {
|
|
# Generated by nixos-generate-config; don't lint/reformat (treefmt
|
|
# excludes them too).
|
|
excludes = [ "hardware-configuration\\.nix$" ];
|
|
hooks = {
|
|
nixfmt-rfc-style.enable = true;
|
|
deadnix = {
|
|
enable = true;
|
|
# Unused module args ({config,lib,pkgs,...}) are normal; only
|
|
# flag genuinely dead bindings.
|
|
settings.noLambdaPatternNames = true;
|
|
};
|
|
statix.enable = true; # reads statix.toml (repeated_keys/empty_pattern disabled)
|
|
};
|
|
};
|
|
|
|
# treefmt-nix exposes its own `checks.treefmt`; alias it to
|
|
# `formatting` so the existing CI gate (.#checks.*.formatting) keeps
|
|
# working without churn.
|
|
checks.formatting = config.treefmt.build.check inputs.self;
|
|
|
|
# deadnix / statix lints as standalone flake checks so `nix flake
|
|
# check` flags dead code and antipatterns independently of pre-commit.
|
|
checks.deadnix = pkgs.runCommandLocal "check-deadnix" { nativeBuildInputs = [ pkgs.deadnix ]; } ''
|
|
deadnix --fail --no-lambda-pattern-names ${./.} && touch $out
|
|
'';
|
|
checks.statix = pkgs.runCommandLocal "check-statix" { nativeBuildInputs = [ pkgs.statix ]; } ''
|
|
statix check -c ${./.} ${./.} && touch $out
|
|
'';
|
|
|
|
# `nix develop` shell with the tooling needed to hack on this flake.
|
|
# shellHook installs the git pre-commit hooks into the working tree.
|
|
devShells.default = pkgs.mkShellNoCC {
|
|
packages = with pkgs; [
|
|
nixfmt
|
|
nil
|
|
git
|
|
deadnix
|
|
statix
|
|
treefmt
|
|
];
|
|
shellHook = config.pre-commit.installationScript;
|
|
};
|
|
};
|
|
|
|
# Realise the host tables: each entry becomes a {nixos,darwin}Configuration.
|
|
flake.nixosConfigurations = lib.mapAttrs (_name: mkHost) hosts;
|
|
flake.darwinConfigurations = lib.mapAttrs (_name: mkDarwinHost) darwinHosts;
|
|
|
|
# Reusable home modules, exported for use off these hosts. See README
|
|
# "Portable home" for the consumer module-arg expectations.
|
|
flake.homeModules = {
|
|
default = ./home;
|
|
shell = ./home/shell.nix;
|
|
git = ./home/git.nix;
|
|
editor = ./home/editor.nix;
|
|
claude = ./home/claude.nix;
|
|
desktop = ./home/desktop.nix;
|
|
sway = ./home/sway.nix;
|
|
};
|
|
|
|
# Standalone home-manager configs (portable bundle) for machines not
|
|
# managed by this flake. See README "Portable home".
|
|
flake.homeConfigurations =
|
|
let
|
|
mkHome =
|
|
{
|
|
system,
|
|
name,
|
|
}:
|
|
home-manager.lib.homeManagerConfiguration {
|
|
pkgs = import nixpkgs {
|
|
inherit system overlays;
|
|
config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) unfreePackages;
|
|
};
|
|
extraSpecialArgs = {
|
|
inherit inputs;
|
|
portable = true;
|
|
identity = userRegistry.${name} // {
|
|
username = name;
|
|
};
|
|
};
|
|
modules = [
|
|
./home
|
|
{
|
|
home.username = name;
|
|
home.homeDirectory = "/home/${name}";
|
|
}
|
|
];
|
|
};
|
|
in
|
|
{
|
|
"lyrathorpe@x86_64-linux" = mkHome {
|
|
system = "x86_64-linux";
|
|
name = "lyrathorpe";
|
|
};
|
|
"lyrathorpe@aarch64-linux" = mkHome {
|
|
system = "aarch64-linux";
|
|
name = "lyrathorpe";
|
|
};
|
|
};
|
|
}
|
|
);
|
|
}
|