chore(flake): treefmt + deadnix/statix + pre-commit; relocate work module
CI / flake (pull_request) Failing after 1m22s

- treefmt-nix drives `nix fmt` and the formatting check (nixfmt/shfmt/
  prettier; generated files and flake.lock excluded). Replaces the
  bespoke find-based check.
- deadnix and statix as flake checks and pre-commit hooks; deadnix
  ignores module-arg patterns, statix.toml disables the two house-style
  lints (repeated_keys, empty_pattern). Fixed the one real deadnix hit
  (unused overlay arg) and statix hit (use inherit for claude-code).
- git-hooks.nix installs the pre-commit gate via the devShell.
- .editorconfig for the base style.
- Move system/modules/work/default.nix -> lyrathorpe/home/work.nix (it is
  a home-manager module). README gains a Development section; docs
  reformatted by the new formatter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Emma Thorpe
2026-06-10 14:57:21 +01:00
parent 6356e07364
commit d38e3ed616
7 changed files with 238 additions and 115 deletions
+19
View File
@@ -0,0 +1,19 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
[*.{nix,yaml,yml,json,md,sh,toml}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
# Markdown uses trailing whitespace for hard line breaks.
[*.md]
trim_trailing_whitespace = false
+1 -5
View File
@@ -1,10 +1,6 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [ "extends": ["config:recommended", ":dependencyDashboard", ":semanticCommits"],
"config:recommended",
":dependencyDashboard",
":semanticCommits"
],
"nix": { "nix": {
"enabled": true "enabled": true
}, },
+22 -7
View File
@@ -8,7 +8,7 @@ single flake.
Defined in the host table in [`flake.nix`](./flake.nix): Defined in the host table in [`flake.nix`](./flake.nix):
| Configuration | System | Machine | | Configuration | System | Machine |
| ------------------- | --------------- | ---------------------------------------- | | --------------------- | ---------------- | --------------------------------------------------------------------------- |
| `lyrathorpe-mbp` | `aarch64-linux` | MacBook Pro (Apple Silicon, Asahi) | | `lyrathorpe-mbp` | `aarch64-linux` | MacBook Pro (Apple Silicon, Asahi) |
| `lyrathorpe-t400` | `x86_64-linux` | ThinkPad T400 — [install notes](./system/machine/T400/README.md) | | `lyrathorpe-t400` | `x86_64-linux` | ThinkPad T400 — [install notes](./system/machine/T400/README.md) |
| `lyrathorpe-macpro31` | `x86_64-linux` | Mac Pro 3,1, desktop — [install notes](./system/machine/MacPro31/README.md) | | `lyrathorpe-macpro31` | `x86_64-linux` | Mac Pro 3,1, desktop — [install notes](./system/machine/MacPro31/README.md) |
@@ -48,14 +48,29 @@ WSL work box) keep plain TTY login. The target account needs a password
## MacBook (Asahi) firmware ## MacBook (Asahi) firmware
The MBP host references `system/modules/firmware/` for Apple peripheral The MBP host references `system/modules/firmware/` for Apple peripheral
firmware (Wi-Fi/Bluetooth). Those blobs are **not** redistributable, so the firmware (Wi-Fi/Bluetooth). These blobs are **committed** (tracked) even though
directory is gitignored and a clean checkout will not build `lyrathorpe-mbp` `.gitignore` lists the directory: the flake is `git+file`, so it only sees
until it is populated out-of-band. tracked files — untracking them breaks `lyrathorpe-mbp` evaluation (and the CI
host-eval) because the config can't find the firmware. They are not
redistributable; the repo is private.
Copy the firmware extracted during the Asahi install (from To refresh them, copy the firmware extracted during the Asahi install (from
`/etc/nixos/firmware` on the freshly-installed machine, or re-extract per the `/etc/nixos/firmware`, or re-extract per the
[Asahi NixOS docs](https://github.com/tpwrules/nixos-apple-silicon)) into [Asahi NixOS docs](https://github.com/tpwrules/nixos-apple-silicon)) into
`system/modules/firmware/` before rebuilding that host. `system/modules/firmware/` and commit with `git add -f`.
## Development
A dev shell and a formatting/lint gate are wired through the flake:
- `nix develop` — shell with `deadnix`, `statix`, `treefmt`, and the git
`pre-commit` hooks (installed automatically on first entry).
- `nix fmt` — formats the tree via `treefmt` (nixfmt + shfmt + prettier;
generated files and `flake.lock` are excluded).
- `nix flake check` — runs formatting, `deadnix`, `statix`, the pre-commit
hooks, and evaluates every host. `.editorconfig` carries the base style;
`statix.toml` disables the two house-style lints (`repeated_keys`,
`empty_pattern`).
## CI ## CI
Generated
+85 -4
View File
@@ -40,6 +40,22 @@
} }
}, },
"flake-compat": { "flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"locked": { "locked": {
"lastModified": 1761640442, "lastModified": 1761640442,
"narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=", "narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=",
@@ -54,7 +70,7 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_2": { "flake-compat_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1767039857, "lastModified": 1767039857,
@@ -90,6 +106,49 @@
"type": "github" "type": "github"
} }
}, },
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1778507602,
"narHash": "sha256-kTwur1wV+01SdqskVMSo6JMEpg71ps3HpbFY2GsflKs=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "61ab0e80d9c7ab14c256b5b453d8b3fb0189ba0a",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"home-manager": { "home-manager": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -172,7 +231,7 @@
}, },
"nixos-apple-silicon": { "nixos-apple-silicon": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat_2",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ]
@@ -193,7 +252,7 @@
}, },
"nixos-wsl": { "nixos-wsl": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_3",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ]
@@ -248,6 +307,7 @@
"inputs": { "inputs": {
"firefox-addons": "firefox-addons", "firefox-addons": "firefox-addons",
"flake-parts": "flake-parts", "flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"home-manager": "home-manager", "home-manager": "home-manager",
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nix-homebrew": "nix-homebrew", "nix-homebrew": "nix-homebrew",
@@ -255,7 +315,28 @@
"nixos-apple-silicon": "nixos-apple-silicon", "nixos-apple-silicon": "nixos-apple-silicon",
"nixos-wsl": "nixos-wsl", "nixos-wsl": "nixos-wsl",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable" "nixpkgs-unstable": "nixpkgs-unstable",
"treefmt-nix": "treefmt-nix"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1780220602,
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
} }
} }
}, },
+18 -8
View File
@@ -66,11 +66,13 @@
# claude-code tracks nixpkgs-unstable regardless of the pinned nixpkgs. # claude-code tracks nixpkgs-unstable regardless of the pinned nixpkgs.
overlays = [ overlays = [
(_final: prev: { (_final: prev: {
claude-code = inherit
(import nixpkgs-unstable { (import nixpkgs-unstable {
inherit (prev.stdenv.hostPlatform) system; inherit (prev.stdenv.hostPlatform) system;
config.allowUnfree = true; config.allowUnfree = true;
}).claude-code; })
claude-code
;
}) })
]; ];
@@ -309,20 +311,28 @@
programs.shfmt.enable = true; programs.shfmt.enable = true;
programs.prettier.enable = true; programs.prettier.enable = true;
# Generated hardware-configuration.nix files are not hand-edited. # Generated hardware-configuration.nix files are not hand-edited.
settings.global.excludes = [ "*/hardware-configuration.nix" ]; 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 # Pre-commit hooks: format + lint gate run on commit. The same hooks
# are exposed as a flake check (pre-commit.check.enable defaults true). # are exposed as a flake check (pre-commit.check.enable defaults true).
pre-commit.settings.hooks = { 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; nixfmt-rfc-style.enable = true;
deadnix = { deadnix = {
enable = true; enable = true;
# Unused module args ({config,lib,pkgs,...}) are normal; only flag # Unused module args ({config,lib,pkgs,...}) are normal; only
# genuinely dead bindings. # flag genuinely dead bindings.
settings.noLambdaPatternNames = true; settings.noLambdaPatternNames = true;
}; };
statix.enable = true; # reads .statix.toml (repeated_keys/empty_pattern disabled) statix.enable = true; # reads statix.toml (repeated_keys/empty_pattern disabled)
};
}; };
# treefmt-nix exposes its own `checks.treefmt`; alias it to # treefmt-nix exposes its own `checks.treefmt`; alias it to
@@ -336,7 +346,7 @@
deadnix --fail --no-lambda-pattern-names ${./.} && touch $out deadnix --fail --no-lambda-pattern-names ${./.} && touch $out
''; '';
checks.statix = pkgs.runCommandLocal "check-statix" { nativeBuildInputs = [ pkgs.statix ]; } '' checks.statix = pkgs.runCommandLocal "check-statix" { nativeBuildInputs = [ pkgs.statix ]; } ''
statix check ${./.} && touch $out statix check -c ${./.} ${./.} && touch $out
''; '';
# `nix develop` shell with the tooling needed to hack on this flake. # `nix develop` shell with the tooling needed to hack on this flake.
+14 -14
View File
@@ -5,7 +5,7 @@ Everything here is managed declaratively through Nix — edit the listed file an
rebuild, never the generated dotfiles. rebuild, never the generated dotfiles.
| Area | Defined in | | Area | Defined in |
| --- | --- | | ----------------- | --------------------------------------------------------------------------------------------------------------------- |
| Sway (compositor) | [`sway.nix`](./sway.nix) `config.keybindings` + `config.modes`, plus the home-manager Sway module's built-in defaults | | Sway (compositor) | [`sway.nix`](./sway.nix) `config.keybindings` + `config.modes`, plus the home-manager Sway module's built-in defaults |
| tmux | [`shell.nix`](./shell.nix) `programs.tmux` | | tmux | [`shell.nix`](./shell.nix) `programs.tmux` |
| zsh line editor | [`shell.nix`](./shell.nix) `programs.zsh.historySubstringSearch` | | zsh line editor | [`shell.nix`](./shell.nix) `programs.zsh.historySubstringSearch` |
@@ -27,7 +27,7 @@ rebuild, never the generated dotfiles.
### Applications & session ### Applications & session
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ------------------- | ------------------------------------------------------- |
| `Super`+`Return` | Open a terminal (foot) | | `Super`+`Return` | Open a terminal (foot) |
| `Super`+`Space` | App launcher (sway-launcher-desktop in a floating foot) | | `Super`+`Space` | App launcher (sway-launcher-desktop in a floating foot) |
| `Super`+`d` | App launcher (same as above; module default) | | `Super`+`d` | App launcher (same as above; module default) |
@@ -41,7 +41,7 @@ rebuild, never the generated dotfiles.
### Focus ### Focus
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ----------------------- | ---------------------------------------- |
| `Super`+`←`/`↓`/`↑`/`→` | Move focus by direction | | `Super`+`←`/`↓`/`↑`/`→` | Move focus by direction |
| `Super`+`h`/`j`/`k` | Move focus left / down / up (vim-style) | | `Super`+`h`/`j`/`k` | Move focus left / down / up (vim-style) |
| `Super`+`a` | Focus the parent container | | `Super`+`a` | Focus the parent container |
@@ -53,7 +53,7 @@ rebuild, never the generated dotfiles.
### Moving windows ### Moving windows
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ------------------------------- | ---------------------------------------- |
| `Super`+`Shift`+`←`/`↓`/`↑`/`→` | Move the window by direction | | `Super`+`Shift`+`←`/`↓`/`↑`/`→` | Move the window by direction |
| `Super`+`Shift`+`h`/`j`/`k`/`l` | Move the window left / down / up / right | | `Super`+`Shift`+`h`/`j`/`k`/`l` | Move the window left / down / up / right |
| `Super`+`Shift`+`Space` | Toggle the window floating | | `Super`+`Shift`+`Space` | Toggle the window floating |
@@ -63,7 +63,7 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
### Layout ### Layout
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ----------- | -------------------------------------------------------------------------------------- |
| `Super`+`b` | Split horizontally | | `Super`+`b` | Split horizontally |
| `Super`+`v` | Split vertically | | `Super`+`v` | Split vertically |
| `Super`+`s` | Stacking layout | | `Super`+`s` | Stacking layout |
@@ -77,7 +77,7 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
### Workspaces ### Workspaces
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ----------------------- | --------------------------------- |
| `Super`+`1``0` | Switch to workspace 1…10 | | `Super`+`1``0` | Switch to workspace 1…10 |
| `Super`+`Shift`+`1``0` | Move the window to workspace 1…10 | | `Super`+`Shift`+`1``0` | Move the window to workspace 1…10 |
| `Super`+`z` | Previous workspace | | `Super`+`z` | Previous workspace |
@@ -86,14 +86,14 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
### Scratchpad ### Scratchpad
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ------------------- | --------------------------------- |
| `Super`+`Shift`+`-` | Move the window to the scratchpad | | `Super`+`Shift`+`-` | Move the window to the scratchpad |
| `Super`+`-` | Show / cycle the scratchpad | | `Super`+`-` | Show / cycle the scratchpad |
### Modes (submenus) ### Modes (submenus)
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ------------------- | ------------------------------------------------------------------------------------------------------------ |
| `Super`+`r` | **Resize mode**: arrow keys resize; `Return`/`Esc` exit | | `Super`+`r` | **Resize mode**: arrow keys resize; `Return`/`Esc` exit |
| `Super`+`y` | **Layout mode** (see Layout above) | | `Super`+`y` | **Layout mode** (see Layout above) |
| `Super`+`Shift`+`x` | **Power menu**: `l` lock · `e` log out · `s` sleep · `r` reboot · `Shift`+`s` shutdown · `Return`/`Esc` exit | | `Super`+`Shift`+`x` | **Power menu**: `l` lock · `e` log out · `s` sleep · `r` reboot · `Shift`+`s` shutdown · `Return`/`Esc` exit |
@@ -101,14 +101,14 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
### Screenshots ### Screenshots
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | --------------- | ---------------------------------------- |
| `Print` | Select a region → swappy (annotate/save) | | `Print` | Select a region → swappy (annotate/save) |
| `Shift`+`Print` | Focused window → swappy | | `Shift`+`Print` | Focused window → swappy |
### Audio & media ### Audio & media
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ----------------------------------------------- | ---------------------- |
| `XF86AudioRaiseVolume` / `XF86AudioLowerVolume` | Volume ±5% (wpctl) | | `XF86AudioRaiseVolume` / `XF86AudioLowerVolume` | Volume ±5% (wpctl) |
| `XF86AudioMute` | Toggle output mute | | `XF86AudioMute` | Toggle output mute |
| `XF86AudioMicMute` | Toggle microphone mute | | `XF86AudioMicMute` | Toggle microphone mute |
@@ -118,7 +118,7 @@ Mouse (with `Super` held): left-drag moves a window, right-drag resizes it.
### Brightness — laptops only ### Brightness — laptops only
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | ----------------------------------------------- | ----------------------------- |
| `XF86MonBrightnessUp` / `XF86MonBrightnessDown` | Backlight ±5% (brightnessctl) | | `XF86MonBrightnessUp` / `XF86MonBrightnessDown` | Backlight ±5% (brightnessctl) |
Present only on portable hosts (T400, MBP); desktops have no internal backlight. Present only on portable hosts (T400, MBP); desktops have no internal backlight.
@@ -130,7 +130,7 @@ Present only on portable hosts (T400, MBP); desktops have no internal backlight.
Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys. Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys.
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | --------------------------------------- | -------------------------------------------------------------------------------------------- |
| `Ctrl`+`b` then `v` | Split into left/right panes | | `Ctrl`+`b` then `v` | Split into left/right panes |
| `Ctrl`+`b` then `s` | Split into top/bottom panes | | `Ctrl`+`b` then `s` | Split into top/bottom panes |
| `Ctrl`+`h`/`j`/`k`/`l` | Move between panes — and into/out of vim splits — seamlessly (vim-tmux-navigator, no prefix) | | `Ctrl`+`h`/`j`/`k`/`l` | Move between panes — and into/out of vim splits — seamlessly (vim-tmux-navigator, no prefix) |
@@ -156,7 +156,7 @@ Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys.
Only colours are themed; these are foot's default key bindings. Only colours are themed; these are foot's default key bindings.
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | --------------------------------------- | ----------------------------- |
| `Ctrl`+`Shift`+`c` / `Ctrl`+`Shift`+`v` | Copy / paste (clipboard) | | `Ctrl`+`Shift`+`c` / `Ctrl`+`Shift`+`v` | Copy / paste (clipboard) |
| `Shift`+`Insert` | Paste primary selection | | `Shift`+`Insert` | Paste primary selection |
| `Ctrl`+`Shift`+`r` | Search scrollback | | `Ctrl`+`Shift`+`r` | Search scrollback |
@@ -170,7 +170,7 @@ Only colours are themed; these are foot's default key bindings.
## zsh ## zsh
| Shortcut | Action | | Shortcut | Action |
| --- | --- | | --------- | -------------------------------------------------------------------------------------------------- |
| `↑` / `↓` | History **substring** search — type a fragment first, then the arrows cycle matching past commands | | `↑` / `↓` | History **substring** search — type a fragment first, then the arrows cycle matching past commands |
Bound for both CSI and SS3 cursor sequences, so it works in foot, iTerm2 and Bound for both CSI and SS3 cursor sequences, so it works in foot, iTerm2 and
+2
View File
@@ -1,3 +1,5 @@
# Home-manager module for the work (EDaaS/WSL) profile: corporate git signing,
# work toolchain packages and tmux tweaks. Imported only by the work host.
{ pkgs, lib, ... }: { pkgs, lib, ... }:
{ {