178 Commits

Author SHA1 Message Date
mjallen18
d123c38add hmm 2026-04-21 11:04:36 -05:00
mjallen18
3737bda5e5 cachy 2026-04-21 11:01:36 -05:00
mjallen18
e887f7a0e5 proton cachy 2026-04-21 10:51:33 -05:00
80be0450a9 upd flake 2026-04-21 07:46:52 -05:00
mjallen18
d18f972feb wsl 2026-04-20 19:00:51 -05:00
2fc972ac8a upd rpi kern 2026-04-20 16:01:02 -05:00
b47affa65a upd 2026-04-20 16:01:02 -05:00
mjallen18
9f3ad51a33 change password 2026-04-20 15:42:39 -05:00
mjallen18
6deda3b619 paperlessAi 2026-04-20 15:35:46 -05:00
mjallen18
a1bcccca09 filtering 2026-04-20 10:58:29 -05:00
mjallen18
3e5f6d6862 filtering 2026-04-20 10:56:07 -05:00
f51c362086 upd 2026-04-17 19:23:32 -05:00
mjallen18
a158d401ae filtering 2026-04-16 20:12:18 -05:00
mjallen18
95842b22f0 agh 2026-04-16 19:24:59 -05:00
mjallen18
3977227889 idk 2026-04-16 19:22:57 -05:00
mjallen18
cb8ef87229 nuc 2026-04-16 13:03:55 -05:00
mjallen18
44b3459d49 lol 2026-04-16 13:01:27 -05:00
mjallen18
c59ac2ccb6 kern 2026-04-16 12:40:03 -05:00
mjallen18
1767debfd8 upd 2026-04-16 12:38:07 -05:00
mjallen18
95f08a258e hue 2026-04-16 09:58:32 -05:00
mjallen18
c5ba5d4164 bluetooth 2026-04-15 11:39:41 -05:00
mjallen18
004eb3c29c esphome 2026-04-14 17:45:29 -05:00
mjallen18
616d357a59 cyd 2026-04-14 17:42:19 -05:00
mjallen18
d4481923a8 cyd 2026-04-14 17:38:59 -05:00
mjallen18
246f65190e cyd 2026-04-14 17:37:38 -05:00
mjallen18
b6df62a875 cyd 2026-04-14 17:31:10 -05:00
mjallen18
8d81a1d6e1 cyd 2026-04-14 17:29:22 -05:00
mjallen18
7368968fd5 cyd 2026-04-14 17:25:44 -05:00
mjallen18
9a719479bc cyd 2026-04-14 17:15:13 -05:00
mjallen18
38922cd526 cyd 2026-04-14 17:01:48 -05:00
mjallen18
26e7fffbd1 cyd 2026-04-14 16:56:12 -05:00
mjallen18
9792f86548 cyd 2026-04-14 16:54:32 -05:00
mjallen18
dd9fa58c5c cyd 2026-04-14 16:46:58 -05:00
mjallen18
db620cd22a cyd 2026-04-14 16:36:35 -05:00
mjallen18
dab3a37b0a cyd 2026-04-14 16:18:33 -05:00
mjallen18
74b1825d4d cyd 2026-04-14 16:12:54 -05:00
mjallen18
c3abeb846d ip 2026-04-13 14:22:27 -05:00
mjallen18
d676b6dc1e nuc 2026-04-13 14:11:45 -05:00
mjallen18
86fffbd512 upd 2026-04-13 13:25:52 -05:00
mjallen18
1b5f695f40 todo remove 2026-04-13 09:41:40 -05:00
mjallen18
9491c0356d grafana 2026-04-13 09:41:27 -05:00
152efb84da esp 2026-04-10 09:49:19 -05:00
26d5a8c686 esp 2026-04-10 09:48:58 -05:00
mjallen18
ee55a543fa caddy int 2026-04-09 15:01:01 -05:00
mjallen18
7cc6732a7e caddy int 2026-04-09 14:57:27 -05:00
mjallen18
b73ad049e7 darwin 2026-04-09 11:20:29 -05:00
mjallen18
5d23b3db93 .face 2026-04-09 11:03:35 -05:00
mjallen18
aa609630a1 darwin 2026-04-09 10:35:50 -05:00
mjallen18
1e1eb9886c darwin 2026-04-09 10:32:06 -05:00
9c326f5768 neb 2026-04-08 17:36:21 -05:00
e8cae7fff1 vesktop 2026-04-08 17:32:32 -05:00
88b9d5309f vesktop 2026-04-08 17:23:36 -05:00
d44d03d0b1 vesktop 2026-04-08 17:14:32 -05:00
4ac7463a1f ... 2026-04-08 16:11:17 -05:00
mjallen18
b354dc202a nas 2026-04-08 16:08:00 -05:00
mjallen18
079493b55e nas 2026-04-08 16:08:00 -05:00
mjallen18
d06a43bf06 build2 2026-04-08 15:40:48 -05:00
mjallen18
6b8395ffdb nebula 2026-04-08 15:16:25 -05:00
mjallen18
7adbafb848 attic 2026-04-08 15:13:03 -05:00
mjallen18
3af0d99f98 attic 2026-04-08 15:08:00 -05:00
025ab854f0 vesktop 2026-04-08 14:57:15 -05:00
mjallen18
5ce8433aa8 lol 2026-04-08 14:56:39 -05:00
mjallen18
2e8c2ddd3a lol 2026-04-08 13:24:09 -05:00
mjallen18
4cb746afc5 hmm 2026-04-07 22:02:54 -05:00
mjallen18
3234029ae5 hmm 2026-04-07 22:02:54 -05:00
mjallen18
928de1837b lol 2026-04-07 21:23:51 -05:00
mjallen18
70002a19e2 hmm 2026-04-07 18:39:42 -05:00
a418d03b19 clev 2026-04-06 15:48:34 -05:00
mjallen18
8aff587014 upd llama 2026-04-06 15:47:34 -05:00
909917f385 version_upgrade=incompatible 2026-04-06 13:35:07 -05:00
mjallen18
c8587da722 bcachefs 1.37.4 2026-04-06 12:10:04 -05:00
mjallen18
2ebe78981a upd 2026-04-06 09:43:12 -05:00
mjallen18
c98d48b43b upd 2026-04-06 09:08:32 -05:00
mjallen18
ff469102ea manual_inherit 2026-04-05 19:10:23 -05:00
mjallen18
a363622659 useless_parens 2026-04-05 15:10:13 -05:00
mjallen18
07b1fc3618 empty_pattern 2026-04-05 14:49:16 -05:00
mjallen18
159ad4cb83 useless_has_attr 2026-04-05 14:29:24 -05:00
mjallen18
c439495d7a repeated_keys 2026-04-05 14:15:20 -05:00
mjallen18
14477a8d85 system -> stdenv 2026-04-05 13:53:49 -05:00
mjallen18
37b0c50821 fmt 2026-04-05 13:50:18 -05:00
mjallen18
10b906a27c hmm 2026-04-05 13:48:41 -05:00
mjallen18
f111b1c725 up llama 2026-04-05 13:25:07 -05:00
mjallen18
869b48d26f govee2mqtt 2026-04-03 09:03:37 -05:00
mjallen18
ffbb820be3 maybe lol 2026-04-02 15:56:06 -05:00
mjallen18
eda929b4eb robo 2026-04-02 15:26:33 -05:00
mjallen18
8367c2c068 automation 2026-04-02 15:18:43 -05:00
mjallen18
6d0f109564 pypath 2026-04-02 15:03:05 -05:00
mjallen18
657849140f upd 2026-04-02 13:17:47 -05:00
mjallen18
13cf58de7c orca 2026-04-02 10:53:47 -05:00
mjallen18
acc683bac3 databasus 2026-04-01 18:05:40 -05:00
mjallen18
166123e8fe suggestarr and bookshelf 2026-04-01 18:05:40 -05:00
e4daf12f39 calibre 2026-04-01 14:54:20 -05:00
mjallen18
03f6b730cf kek 2026-04-01 13:21:25 -05:00
mjallen18
57fa32bf9c overrides for hass lol 2026-03-31 17:24:46 -05:00
mjallen18
c1efceef55 roborock 2026-03-31 14:23:32 -05:00
mjallen18
a125017c93 roborock 2026-03-31 14:15:54 -05:00
mjallen18
35154eb694 fix nfc 2026-03-31 14:00:04 -05:00
mjallen18
bd799661b9 fix avahi 2026-03-31 13:33:42 -05:00
mjallen18
6ca55504f0 net 2026-03-30 19:35:09 -05:00
mjallen18
0aa9a0f994 fmt 2026-03-30 19:34:40 -05:00
mjallen18
9728f49e42 fmt 2026-03-30 19:16:09 -05:00
mjallen18
c97e96f2da lol 2026-03-30 19:03:22 -05:00
mjallen18
eec051b256 cider 2026-03-30 16:27:55 -05:00
mjallen18
a88736cf6e net 2026-03-30 16:09:25 -05:00
mjallen18
8d8d49bd38 net 2026-03-30 15:38:25 -05:00
mjallen18
a673f379c7 test 2026-03-30 14:57:09 -05:00
mjallen18
2f8f5092c4 nc 2026-03-30 14:46:08 -05:00
mjallen18
47b9c1ae98 fix cloud 2026-03-30 13:34:47 -05:00
6d6618a683 rpi 2026-03-30 11:56:31 -05:00
mjallen18
62736ed77c kavita 2026-03-29 22:24:04 -05:00
mjallen18
0967e27fca hass 2026-03-28 10:41:03 -05:00
mjallen18
383013f425 stylix 2026-03-28 10:39:16 -05:00
mjallen18
23139fe492 asd 2026-03-27 18:32:24 -05:00
mjallen18
add39956f7 hass 2026-03-27 18:32:24 -05:00
mjallen18
4c1332e67a theme 2026-03-27 18:31:01 -05:00
mjallen18
5fe8c897aa unihj 2026-03-27 18:25:58 -05:00
mjallen18
8217b83798 atlauncher 2026-03-27 16:54:19 -05:00
06c1ae13df config cleanups 2026-03-27 13:29:45 -05:00
9ae5c8ab6d int test 2026-03-27 09:05:03 -05:00
mjallen18
515792132f hm 2026-03-26 20:33:16 -05:00
53489fe173 hmm 2026-03-26 20:26:31 -05:00
979344917e idk 2026-03-26 15:40:50 -05:00
f80144d22b wallpaper 2026-03-26 15:33:53 -05:00
mjallen18
8732e65f1c caffiene 2026-03-26 15:29:42 -05:00
mjallen18
f7a0460646 desktop 2026-03-26 13:52:13 -05:00
9515a5d317 wallpaper 2026-03-26 13:47:15 -05:00
c4bc1b155a what 2026-03-26 12:52:11 -05:00
mjallen18
c15f0b0f0b mbp 2026-03-26 12:51:27 -05:00
mjallen18
a060a84cf1 mbp 2026-03-26 12:16:00 -05:00
mjallen18
5fe8c08653 mbp 2026-03-26 12:09:33 -05:00
832ac9d0df what 2026-03-26 12:07:59 -05:00
mjallen18
92358d0415 mbp 2026-03-26 11:44:59 -05:00
mjallen18
aed841d32e hass 2026-03-26 11:42:19 -05:00
85ea3039f4 upd 2026-03-26 11:41:59 -05:00
5e22760799 plasma specialisation fix 2026-03-26 10:53:46 -05:00
84f600eb04 upd 2026-03-26 10:31:37 -05:00
mjallen18
6dc138bbf6 allyx plasma 2026-03-26 10:30:47 -05:00
mjallen18
23a04934fb plasma specialisation 2026-03-26 10:30:40 -05:00
0e0ec54b5e firy 2026-03-26 10:24:55 -05:00
c252a07877 upd 2026-03-26 10:15:06 -05:00
mjallen18
47d7d5b11e fix plasma: disable stylix qt target and set widgetStyle=Breeze
Stylix's qt target sets QT_STYLE_OVERRIDE=kvantum and writes qt6ct/qt5ct
configs with style=kvantum. plasmashell/KWin crash with a fatal
'module kvantum is not installed' QML error because the kvantum Qt style
plugin is not available in the Plasma session.

- stylix: targets.qt.enable = false (stops QT_STYLE_OVERRIDE=kvantum)
- plasma: remove kvantum package, add widgetStyle=Breeze as belt-and-suspenders
2026-03-26 09:38:38 -05:00
mjallen18
e119ffaabb xtr temp 2026-03-25 22:24:19 -05:00
mjallen18
ab81e78b60 init xrt and fflm 2026-03-25 20:46:42 -05:00
mjallen18
2013804b17 lemonade 2026-03-25 19:59:49 -05:00
mjallen18
7fcbd0bb7c plasma 2026-03-25 18:23:08 -05:00
mjallen18
78280d5150 fix nix flake check warnings 2026-03-25 16:54:36 -05:00
mjallen18
ccd413d273 fix nix flake check 2026-03-25 16:42:34 -05:00
mjallen18
642cee5dc5 home 2026-03-25 16:02:34 -05:00
981b03b955 upd 2026-03-25 16:02:04 -05:00
mjallen18
18e781d388 agents 2026-03-25 13:55:19 -05:00
mjallen18
91ec603b62 spec 2026-03-24 16:24:23 -05:00
mjallen18
a4c2cbdf7b ntfy crowdsec 2026-03-24 16:11:07 -05:00
mjallen18
f8a86f9b29 sdcard 2026-03-24 14:42:42 -05:00
mjallen18
84eb2e3734 ntfy 2026-03-24 14:41:22 -05:00
mjallen18
4cc58ab381 ntfy 2026-03-24 14:41:07 -05:00
mjallen18
661c7c7771 restic browser 2026-03-24 13:27:40 -05:00
mjallen18
35ac45f5ce restic 2026-03-24 13:23:38 -05:00
mjallen18
540dabcb5d grafana dashboard fixes 2026-03-24 13:02:17 -05:00
mjallen18
7798684d29 grafana 2026-03-24 10:20:46 -05:00
mjallen18
d1960837a0 prometheus 2026-03-24 09:36:36 -05:00
99452eb470 sops 2026-03-24 09:25:42 -05:00
d75c05f74f rpi 7-rc5 2026-03-24 09:11:06 -05:00
mjallen18
2ad3e050fc allyx neb 2026-03-24 09:09:23 -05:00
mjallen18
da1cd27482 sops 2026-03-24 09:07:09 -05:00
mjallen18
0f2239af05 nebula 2026-03-24 08:59:13 -05:00
mjallen18
0ffbeaaea1 idk 2026-03-24 08:52:01 -05:00
mjallen18
cd6ea07e88 nebula cert 2026-03-23 18:13:10 -05:00
mjallen18
72014609a0 nebula cert 2026-03-23 18:02:53 -05:00
mjallen18
01d1086580 nebula 2026-03-23 17:49:38 -05:00
mjallen18
5952eddecb upd ext 2026-03-23 17:46:48 -05:00
mjallen18
309e224a72 test 2026-03-23 17:42:47 -05:00
mjallen18
ecce28b498 iface 2026-03-23 17:36:25 -05:00
mjallen18
bd569962ca log 2026-03-23 17:33:28 -05:00
mjallen18
068d6c8f94 ext 2026-03-23 17:26:01 -05:00
mjallen18
0b9a301a92 neb 2026-03-23 16:37:34 -05:00
mjallen18
23f29b6ca1 fixes and docs 2026-03-23 15:17:10 -05:00
mjallen18
2c0b26ced0 fixes and docs 2026-03-23 15:17:09 -05:00
mjallen18
e647794a0f couple fixes 2026-03-23 14:07:48 -05:00
425 changed files with 21389 additions and 8360 deletions

4
.gitignore vendored
View File

@@ -6,9 +6,9 @@ result*
.direnv .direnv
shell.nix shell.nix
.vscode .vscode
**/*/*.py
.envrc .envrc
.DS_Store .DS_Store
*.qcow2 *.qcow2
keys keys
iso-* iso-*
**/*/__pycache__

View File

@@ -14,7 +14,7 @@ keys:
- &nuc age102el4snus37dj807rwvsmlvwu2sg2d8rw3vfmtntgczfkz04l9nshetcq0 - &nuc age102el4snus37dj807rwvsmlvwu2sg2d8rw3vfmtntgczfkz04l9nshetcq0
- &admin_nuc age1yn82e39pxt0d0pgny34ux4lkge4ff7wxvsye8ragvwngehemt4ps27phyw - &admin_nuc age1yn82e39pxt0d0pgny34ux4lkge4ff7wxvsye8ragvwngehemt4ps27phyw
- &matt_allyx age18z4ctyyj7eq0cmt23eelfzjuacq4fa6hsplyg779d3rdg7ac2q5q2njxqh - &matt_allyx age18z4ctyyj7eq0cmt23eelfzjuacq4fa6hsplyg779d3rdg7ac2q5q2njxqh
- &allyx age164xpf9cepfjqvcn7v5ahcaq9zmm5u3yl9t04d098e3e2zkfjcyws02rx42 - &allyx age1er5qucsc2mugrzrr7n3xhzv7kemkrqrw4m84r544fkk7nkg5g5eswxkqj0
creation_rules: creation_rules:
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$ - path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
key_groups: key_groups:

95
AGENTS.md Normal file → Executable file
View File

@@ -206,3 +206,98 @@ Key inputs:
- `sops-nix` - Secrets management - `sops-nix` - Secrets management
- `lanzaboote` - Secure boot - `lanzaboote` - Secure boot
- `jovian` - Steam Deck support (allyx) - `jovian` - Steam Deck support (allyx)
## Lib Module (`lib/`)
Custom utility library exposed via `lib.mjallen.*` through Snowfall Lib. Used for creating modules and managing versions.
### Directory Structure
```
lib/
├── default.nix # Entry point: exports module, file, versioning
├── README.md # Detailed documentation
├── module/ # Module creation helpers
│ └── default.nix
├── file/ # File/path utilities
│ └── default.nix
└── versioning/ # Multi-source version pinning
└── default.nix
```
### Module Utilities (`lib.mjallen.module`)
**`mkModule`** - Create NixOS service modules with standardized options:
```nix
lib.mjallen.module.mkModule {
config, name, description, options, moduleConfig, domain ? "services"
}
```
Standard options: `enable`, `port`, `reverseProxy`, `firewall`, `createUser`, `configureDb`, `redis`, `puid`, `pgid`, `timeZone`, etc.
**`mkContainerService`** - For Podman/OCI containers (auto-generates container definition):
```nix
lib.mjallen.module.mkContainerService {
config, name, image, internalPort, description, options, volumes, environment
}
```
**`mkSopsEnvFile`** - Generate SOPS secrets + template env-file:
```nix
lib.mjallen.module.mkSopsEnvFile {
secrets, name, content, restartUnit, owner, group, mode, sopsFile
}
```
**Option Helpers:**
- `mkOpt type default description` - Standard option
- `mkBoolOpt default description` - Boolean option
- `mkReverseProxyOpt name` - Caddy reverse proxy sub-options
**Convenience Shorthands:**
- `enabled` = `{ enable = true; }`
- `disabled` = `{ enable = false; }`
### Home Manager Utilities
**`mkHomeModule`** - Create Home Manager modules:
```nix
lib.mjallen.module.mkHomeModule {
config, domain, name, description, options, moduleConfig
}
```
### File Utilities (`lib.mjallen.file`)
- `readFile path` - Read file contents
- `pathExists path` - Check if path exists
- `safeImport path default` - Safe Nix import
- `getFile relativePath` - Get path relative to flake root
- `importModulesRecursive path` - Recursively discover Nix modules
- `scanSystems systemsPath` - Discover system configurations
- `filterNixOSSystems systems` - Filter for Linux systems
- `filterDarwinSystems systems` - Filter for macOS systems
- `scanHomes homesPath` - Parse home-manager configurations
### Versioning Utilities (`lib.mjallen.versioning`)
For packages with `version.json` (multi-variant source pinning):
- `selectVariant spec variantName system` - Select variant from spec
- `render value variables` - Template substitution (`${var}`)
- `mkSrc pkgs comp variables` - Build single source
- `mkAllSources pkgs selected` - Build all sources for selected variant
See `lib/versioning/default.nix` for full API and `docs/version.schema.json` for schema.
### Usage in Packages
Create `packages/<name>/version.json` with variant definitions, then use:
```nix
let
versioning = inputs.self.lib.mjallen.versioning;
spec = inputs.self.lib.mjallen.file.readFile ./version.json;
selected = versioning.selectVariant spec variantName system;
sources = versioning.mkAllSources pkgs selected;
in
# Use sources.componentName for each source
```

118
README.md
View File

@@ -71,7 +71,7 @@ A powerful AMD-based desktop with gaming capabilities, featuring:
### NAS ### NAS
A home server with various self-hosted services: A home server with various self-hosted services:
- Media management (Jellyfin, Jellyseerr) - Media management (Jellyfin, seerr)
- Download automation (Sonarr, Radarr, etc.) - Download automation (Sonarr, Radarr, etc.)
- Document management (Paperless) - Document management (Paperless)
- File sharing (Samba, Nextcloud) - File sharing (Samba, Nextcloud)
@@ -113,6 +113,122 @@ sudo nixos-rebuild switch --flake .#hostname
home-manager switch --flake .#username@hostname home-manager switch --flake .#username@hostname
``` ```
## Secrets Management
Secrets are managed with [sops-nix](https://github.com/Mic92/sops-nix). Each secret file is encrypted with [age](https://age-encryption.org/), using the SSH host key (`/etc/ssh/ssh_host_ed25519_key`) of each machine as a recipient, so that machine can decrypt its own secrets at boot without any passphrase.
### How age keys work
sops-nix derives an age key from the machine's ed25519 SSH host key automatically. The corresponding age **public key** must be added to `.sops.yaml` before you can encrypt secrets for that machine.
To get the age public key for a machine:
```bash
# On the target machine (or from its host key file):
nix-shell -p ssh-to-age --run \
'ssh-keyscan localhost 2>/dev/null | ssh-to-age'
# Or directly from the key file:
nix-shell -p ssh-to-age --run \
'ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub'
```
### Adding a new machine
1. **Get the age public key** for the new machine using the command above.
2. **Add it to `.sops.yaml`**:
```yaml
keys:
- &new-machine age1<public-key-here>
creation_rules:
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *new-machine
# ... existing recipients
```
3. **Re-encrypt all secret files** so the new machine becomes a recipient:
```bash
find secrets/ -name '*.yaml' -exec sops updatekeys {} \;
```
### Adding a new secret
To add a secret to an existing file:
```bash
# Edit the file interactively (sops decrypts, opens $EDITOR, re-encrypts on save)
sops secrets/nas-secrets.yaml
```
To create a new secrets file:
```bash
sops secrets/mymachine-secrets.yaml
```
The `.sops.yaml` `creation_rules` determine which keys encrypt the file based on its path.
### Generating Nebula VPN certificates
The Nebula module (`mjallen.services.nebula`) expects three secrets per host under a configurable prefix:
- `<prefix>/ca-cert` — the CA certificate (shared across all nodes)
- `<prefix>/host-cert` — this node's signed certificate
- `<prefix>/host-key` — this node's private key
**Step 1 — Create the CA** (once per network, on a trusted machine):
```bash
nebula-cert ca -name "jallen-nebula"
# Produces: ca.crt, ca.key
```
**Step 2 — Sign a certificate for each node**:
```bash
# Lighthouse (assign an overlay IP, e.g. 10.1.1.1)
nebula-cert sign -name "pi5" -ip "10.1.1.1/24" \
-ca-crt ca.crt -ca-key ca.key \
-out-crt lighthouse.crt -out-key lighthouse.key
# Regular node (assign a unique overlay IP, e.g. 10.1.1.2)
nebula-cert sign -name "nas" -ip "10.1.1.2/24" \
-ca-crt ca.crt -ca-key ca.key \
-out-crt nas.crt -out-key nas.key
```
**Step 3 — Add the secrets to SOPS**:
```bash
# Edit the target host's secrets file
sops secrets/pi5-secrets.yaml
```
Add the certificate contents under the configured prefix (e.g. `pi5/nebula`):
```yaml
pi5:
nebula:
ca-cert: |
<contents of ca.crt>
lighthouse-cert: |
<contents of lighthouse.crt>
lighthouse-key: |
<contents of lighthouse.key>
```
The key name for the cert/key pair matches the `hostSecretName` option (e.g. `hostSecretName = "lighthouse"` → looks for `lighthouse-cert` / `lighthouse-key`).
**Step 4 — Shred the plaintext key files** once they are in SOPS:
```bash
shred -u ca.key lighthouse.key nas.key
```
> Keep `ca.crt` accessible if you need to sign more nodes later, but store `ca.key` only in SOPS.
## Documentation ## Documentation
Comprehensive documentation is available in the [docs](./docs) directory: Comprehensive documentation is available in the [docs](./docs) directory:

2
WORKAROUNDS.md Normal file → Executable file
View File

@@ -348,7 +348,7 @@ These are not workarounds but known incomplete configurations:
| `systems/x86_64-linux/jallen-nas/apps.nix` | 47 | Authentik environment secrets file not wired up | | `systems/x86_64-linux/jallen-nas/apps.nix` | 47 | Authentik environment secrets file not wired up |
| `modules/nixos/services/sparky-fitness/default.nix` | — | ~~DB passwords not yet moved to SOPS~~ — resolved; secrets now via `mkSopsEnvFile`; run `sops secrets/nas-secrets.yaml` to add real values for `jallen-nas/sparky-fitness/{db-password,api-encryption-key,auth-secret}` | | `modules/nixos/services/sparky-fitness/default.nix` | — | ~~DB passwords not yet moved to SOPS~~ — resolved; secrets now via `mkSopsEnvFile`; run `sops secrets/nas-secrets.yaml` to add real values for `jallen-nas/sparky-fitness/{db-password,api-encryption-key,auth-secret}` |
| `modules/nixos/services/your-spotify/default.nix` | 36 | Spotify API keys not yet moved to SOPS | | `modules/nixos/services/your-spotify/default.nix` | 36 | Spotify API keys not yet moved to SOPS |
| `modules/nixos/services/booklore/default.nix` | 25 | Database password not yet a SOPS secret | | `modules/nixos/services/booklore/default.nix` | 28 | Database password not yet a SOPS secret |
| `packages/raspberrypi/udev-rules/default.nix` | 33 | `15-i2c-modprobe.rules` disabled; `i2cprobe` script not ported | | `packages/raspberrypi/udev-rules/default.nix` | 33 | `15-i2c-modprobe.rules` disabled; `i2cprobe` script not ported |
| `modules/nixos/homeassistant/services/homeassistant/default.nix` | 214 | `roborock` integration marked broken | | `modules/nixos/homeassistant/services/homeassistant/default.nix` | 214 | `roborock` integration marked broken |

20
checks/pre-commit-hooks/default.nix Normal file → Executable file
View File

@@ -10,7 +10,13 @@ in
pre-commit-hooks-nix.lib.${pkgs.stdenv.hostPlatform.system}.run { pre-commit-hooks-nix.lib.${pkgs.stdenv.hostPlatform.system}.run {
src = ../..; src = ../..;
hooks = { hooks = {
pre-commit-hook-ensure-sops.enable = true; pre-commit-hook-ensure-sops = {
enable = true;
excludes = [
"secrets/.*\\.jwe$"
"secrets/.*\\.key$"
];
};
treefmt = { treefmt = {
enable = lib.mkForce true; enable = lib.mkForce true;
settings.fail-on-change = lib.mkForce false; settings.fail-on-change = lib.mkForce false;
@@ -18,5 +24,17 @@ pre-commit-hooks-nix.lib.${pkgs.stdenv.hostPlatform.system}.run {
lib.snowfall.fs.get-file "treefmt.nix" lib.snowfall.fs.get-file "treefmt.nix"
); );
}; };
nixfmt-rfc-style = {
enable = true;
package = pkgs.nixfmt;
};
# statix disabled - too many false positives (manual_inherit warnings)
# statix = {
# enable = true;
# args = [
# "--config"
# (lib.snowfall.fs.get-file "statix.toml")
# ];
# };
}; };
} }

0
docs/README.md Normal file → Executable file
View File

220
docs/architecture.md Normal file → Executable file
View File

@@ -4,101 +4,177 @@ This document provides an overview of the repository architecture, explaining ho
## Overview ## Overview
This NixOS configuration repository is built using [Nix Flakes](https://nixos.wiki/wiki/Flakes) and [Snowfall Lib](https://github.com/snowfallorg/lib) to provide a modular, maintainable configuration for multiple systems. This NixOS configuration repository is built using [Nix Flakes](https://nixos.wiki/wiki/Flakes) and [Snowfall Lib](https://github.com/snowfallorg/lib) to provide a modular, maintainable configuration for multiple systems. The Snowfall namespace is `mjallen`, so all custom options are accessed as `mjallen.<domain>.<name>`.
## Directory Structure ## Directory Structure
``` ```
. .
├── checks/ # Pre-commit hooks and other checks ├── flake.nix # Main flake — inputs, outputs, Snowfall config
├── flake.nix # Main flake configuration ├── flake.lock # Locked dependency versions
├── homes/ # Home-manager configurations for users ├── .sops.yaml # SOPS key management rules
│ ├── aarch64-darwin/ # macOS home configurations ├── treefmt.nix # Code formatter configuration
│ ├── aarch64-linux/ # ARM Linux home configurations ├── qemu.nix # QEMU VM testing config
└── x86_64-linux/ # x86 Linux home configurations
├── checks/ # Pre-commit hooks and CI checks
├── docs/ # Documentation (this directory)
├── homes/ # Home Manager configurations
│ ├── aarch64-darwin/ # macOS user configs
│ ├── aarch64-linux/ # ARM Linux user configs
│ └── x86_64-linux/ # x86 Linux user configs
├── lib/ # Custom Nix library utilities
│ ├── module/ # mkModule, mkOpt, mkBoolOpt helpers
│ ├── file/ # File/path utilities
│ └── versioning/ # Package version pinning helpers
├── modules/ # Reusable configuration modules ├── modules/ # Reusable configuration modules
│ ├── home/ # Home-manager modules │ ├── home/ # Home Manager modules
── nixos/ # NixOS system modules ── nixos/ # NixOS system modules
├── boot/ # Boot configuration modules └── darwin/ # nix-darwin modules (macOS)
├── desktop/ # Desktop environment modules
│ ├── hardware/ # Hardware-specific modules
│ ├── homeassistant/ # Home Assistant modules
│ ├── network/ # Network configuration modules
│ ├── services/ # Service configuration modules
│ └── ... # Other module categories
├── overlays/ # Nixpkgs overlays ├── overlays/ # Nixpkgs overlays
├── packages/ # Custom package definitions ├── packages/ # Custom package definitions
├── secrets/ # Encrypted secrets (managed with sops-nix)
── systems/ # System-specific configurations ── secrets/ # SOPS-encrypted secret files
├── aarch64-darwin/ # macOS system configurations
├── aarch64-linux/ # ARM Linux system configurations └── systems/ # Per-host system configurations
── x86_64-linux/ # x86 Linux system configurations ── aarch64-darwin/ # macOS (nix-darwin) hosts
├── jallen-nas/ # NAS server configuration ├── aarch64-linux/ # ARM Linux hosts
├── matt-nixos/ # Desktop configuration ├── x86_64-install-iso/# Install ISO configurations
├── nuc-nixos/ # NUC configuration └── x86_64-linux/ # x86_64 Linux hosts
└── ... # Other system configurations
``` ```
## Flake Structure ## Flake Inputs
The `flake.nix` file defines the inputs (external dependencies) and outputs (configurations) of this repository: | Input | Source | Purpose |
|---|---|---|
| `nixpkgs-unstable` | `github:NixOS/nixpkgs/nixos-unstable` | Primary package set |
| `nixpkgs-stable` | `github:NixOS/nixpkgs/nixos-25.11` | Stable package set |
| `nixpkgs-otbr` | `github:mrene/nixpkgs` (fork) | OpenThread Border Router packages |
| `home-manager-unstable` | `github:nix-community/home-manager` | User environment management |
| `snowfall-lib` | `github:mjallen18/snowfall-lib` | Flake structure library (personal fork) |
| `impermanence` | `github:nix-community/impermanence` | Ephemeral root filesystem support |
| `lanzaboote` | `github:nix-community/lanzaboote/v1.0.0` | Secure Boot |
| `nixos-hardware` | `github:NixOS/nixos-hardware` | Hardware-specific NixOS configs |
| `sops-nix` | `github:Mic92/sops-nix` | Secret management |
| `disko` | `github:nix-community/disko` | Declarative disk partitioning |
| `cosmic` | `github:lilyinstarlight/nixos-cosmic` | COSMIC desktop environment |
| `jovian` | `github:Jovian-Experiments/Jovian-NixOS` | Steam Deck / handheld support |
| `nixos-apple-silicon` | `github:nix-community/nixos-apple-silicon` | Asahi Linux / Apple Silicon |
| `darwin` | `github:nix-darwin/nix-darwin` | macOS system configuration |
| `nix-homebrew` | `github:zhaofengli/nix-homebrew` | Declarative Homebrew (macOS) |
| `stylix` | `github:nix-community/stylix` | System-wide theming |
| `nix-vscode-extensions` | `github:nix-community/nix-vscode-extensions` | VS Code extension packages |
| `authentik-nix` | `github:nix-community/authentik-nix` | Authentik SSO |
| `nix-cachyos-kernel` | `github:xddxdd/nix-cachyos-kernel` | CachyOS optimised kernels |
| `lsfg-vk` | `github:pabloaul/lsfg-vk-flake` | Lossless Scaling frame generation (Linux) |
| `nix-index-database` | `github:nix-community/nix-index-database` | Pre-built nix-index database |
| `steam-rom-manager` | `github:mjallen18/nix-steam-rom-manager` | Steam ROM Manager package |
| `nix-plist-manager` | `github:sushydev/nix-plist-manager` | macOS plist management |
| `nix-rosetta-builder` | `github:cpick/nix-rosetta-builder` | Rosetta build support (macOS) |
| `pre-commit-hooks-nix` | `github:cachix/pre-commit-hooks.nix` | Pre-commit hooks |
| `treefmt-nix` | `github:numtide/treefmt-nix` | Code formatting |
### Inputs `nixpkgs` and `home-manager` are aliases pointing to the unstable variants.
- **nixpkgs-unstable**: The unstable channel of Nixpkgs
- **nixpkgs-stable**: The stable channel of Nixpkgs (25.11)
- **home-manager**: User environment management
- **snowfall-lib**: Library for structuring flake repositories
- **impermanence**: Persistent state management
- **lanzaboote**: Secure boot implementation
- **nixos-hardware**: Hardware-specific configurations
- **sops-nix**: Secret management
- **disko**: Disk partitioning and formatting
- **And more specialized inputs**
### Outputs
The outputs are generated using Snowfall Lib's `mkFlake` function, which automatically discovers and assembles:
- **NixOS system configurations**: For each system in the `systems/` directory
- **Home Manager configurations**: For each configuration in the `homes/` directory
- **Packages**: From the `packages/` directory
- **Modules**: From the `modules/` directory
- **Overlays**: From the `overlays/` directory
## Module System ## Module System
The module system uses a modular approach where: ### Structure
1. **Common modules** are defined in `modules/nixos/` and `modules/home/` All modules follow a standard Snowfall Lib pattern and are automatically discovered. Each module exposes options under the `mjallen` namespace:
2. **System-specific modules** are defined in `systems/<architecture>/<hostname>/`
Each module follows the NixOS module pattern, with: ```nix
- `default.nix`: Main module implementation # Enable a module
- `options.nix`: Option declarations mjallen.services.jellyfin.enable = true;
mjallen.desktop.gnome.enable = true;
mjallen.hardware.amd.enable = true;
```
## Integration with Snowfall Lib ### `mkModule` helper
Snowfall Lib provides: Most service modules are built with `lib.mjallen.mkModule` (`lib/module/default.nix`), which provides a standard set of options:
1. **Automatic discovery** of modules, overlays, and packages
2. **Consistent structure** across the repository | Option | Default | Description |
3. **Common utilities** for working with flakes |---|---|---|
| `enable` | `false` | Enable/disable the module |
| `port` | `80` | Service listen port |
| `listenAddress` | `"0.0.0.0"` | Bind address |
| `openFirewall` | `true` | Open firewall ports |
| `configDir` | `/var/lib/<name>` | Config directory |
| `dataDir` | `/var/lib/<name>/data` | Data directory |
| `createUser` | `false` | Create a dedicated system user |
| `configureDb` | `false` | Create a PostgreSQL database |
| `environmentFile` | `null` | Path to an env-file |
| `reverseProxy.enable` | `false` | Add a Caddy reverse proxy block |
| `reverseProxy.subdomain` | `<name>` | Caddy subdomain |
| `redis.enable` | `false` | Create a dedicated Redis instance |
### NixOS modules (`modules/nixos/`)
| Category | Paths | Description |
|---|---|---|
| Boot | `boot/common/`, `boot/lanzaboote/`, `boot/plymouth/`, `boot/systemd-boot/` | Bootloader configurations |
| Desktop | `desktop/gnome/`, `desktop/hyprland/`, `desktop/cosmic/` | Desktop environments |
| Development | `development/` | Dev tools, language support, containers |
| Hardware | `hardware/amd/`, `hardware/nvidia/`, `hardware/battery/`, `hardware/raspberry-pi/`, `hardware/openrgb/`, ... | Hardware-specific configs |
| Headless | `headless/` | Headless server profile (watchdog, no suspend) |
| Home Assistant | `homeassistant/` | Smart home automation suite |
| Impermanence | `impermanence/` | Ephemeral root + persistent state |
| Monitoring | `monitoring/` | Prometheus/Grafana metrics |
| Network | `network/` | Hostname, firewall, NetworkManager, static IP |
| Power | `power/` | UPS support |
| Programs | `programs/` | System-wide programs (nix-index, gnupg, etc.) |
| Security | `security/common/`, `security/tpm/` | Common hardening, TPM unlock |
| Services | `services/<name>/` | ~50 self-hosted service modules (see below) |
| SOPS | `sops/` | Secret management setup |
| System | `system/` | Miscellaneous system settings |
| User | `user/` | User account management |
| Virtualization | `virtualization/` | libvirt, containers |
### Home Manager modules (`modules/home/`)
| Category | Paths | Description |
|---|---|---|
| Desktop | `desktop/gnome/`, `desktop/theme/` | GNOME and theming |
| GPG | `gpg/` | GPG agent configuration |
| Programs | `programs/btop/`, `programs/git/`, `programs/zsh/`, `programs/kitty/`, `programs/waybar/`, `programs/hyprland/`, `programs/wofi/`, `programs/mako/`, `programs/wlogout/`, `programs/librewolf/`, `programs/opencode/`, `programs/update-checker/`, ... | User applications |
| Services | `services/pass/` | Password store integration |
| Shell | `shell-aliases/` | Common shell aliases |
| SOPS | `sops/` | User-level secret integration |
| Stylix | `stylix/` | System-wide theming |
| User | `user/` | User environment defaults |
## Secrets Management ## Secrets Management
Secrets are managed using [sops-nix](https://github.com/Mic92/sops-nix), with: Secrets are encrypted with [SOPS](https://github.com/getsops/sops) using age keys derived from each machine's SSH host key (`/etc/ssh/ssh_host_ed25519_key`). The `.sops.yaml` file maps secret file path patterns to the set of age recipients that can decrypt them.
- Encrypted secret files in the `secrets/` directory
- `.sops.yaml` configuration file in the root
- Key management integrated into the configuration
## Deployment Process Each host has its own secrets file:
| File | Host |
|---|---|
| `secrets/secrets.yaml` | Shared (all hosts) |
| `secrets/nas-secrets.yaml` | jallen-nas |
| `secrets/pi5-secrets.yaml` | pi5 |
| `secrets/allyx-secrets.yaml` | allyx |
| `secrets/nuc-secrets.yaml` | nuc-nixos |
| `secrets/mac-secrets.yaml` | macbook-pro-nixos |
| `secrets/desktop-secrets.yaml` | matt-nixos |
See the [Secrets Management](../README.md#secrets-management) section of the root README for full details on generating keys and adding secrets.
## Deployment
Systems are built and deployed using:
```bash ```bash
nixos-rebuild switch --flake .#hostname # NixOS system
``` sudo nixos-rebuild switch --flake .#hostname
This command: # macOS (nix-darwin)
1. Evaluates the flake for the specified hostname darwin-rebuild switch --flake .#hostname
2. Builds the resulting configuration
3. Activates it on the current system # Home Manager only
home-manager switch --flake .#username@hostname
```

348
docs/flake-improvements.md Executable file
View File

@@ -0,0 +1,348 @@
# Flake Improvement Suggestions
A methodical review of the flake against what Snowfall Lib provides and what the codebase currently does. Suggestions are grouped by theme and ordered roughly from highest to lowest impact.
---
## 1. Flake-level: HM module registration — single source of truth via snowfall-lib fix
**Root cause discovered**: Snowfall Lib's `mkFlake` previously merged `systems.modules.home` into `homes` only for standalone `homeConfigurations`. The `homes` attrset passed to `create-systems` (which builds `nixosConfigurations`) was the raw unmerged value, so `systems.modules.home` had no effect on NixOS-integrated homes.
**Fix applied**: Patched the personal snowfall-lib fork (`github:mjallen18/snowfall-lib`) to extract the merge into a shared `homes-with-system-modules` binding and pass it to both `create-homes` (standalone) and `create-systems` (NixOS-integrated). `flake.lock` updated to the new commit.
`modules/nixos/home/default.nix` no longer needs `sharedModules``systems.modules.home` in `flake.nix` is now the single authoritative list for all contexts.
---
## 2. Flake-level: Duplicated Darwin HM module registration
**Problem**: Same issue as above for Darwin. `flake.nix:160167` registers Darwin HM modules via `systems.modules.darwin`, but none of those are actually Home Manager modules — `nix-homebrew`, `home-manager.darwinModules.home-manager`, `nix-plist-manager`, `nix-rosetta-builder`, `nix-index-database`, and `stylix.darwinModules.stylix` are all NixOS-style Darwin system modules, not HM `sharedModules`. This is the correct place for them. The `modules/darwin/home/default.nix` module handles the Darwin-side HM bridge.
**No change needed here**, but add a comment to clarify why this list stays in `flake.nix` while the `modules.home` list should move:
```nix
# Common darwin system-level modules (not HM sharedModules — those live in modules/darwin/home/)
modules.darwin = with inputs; [ ... ];
```
---
## 3. System-level: Repeated nebula lighthouse config
**Problem**: Three systems (`matt-nixos`, `allyx`, `macbook-pro-nixos`) each independently spell out the same lighthouse peer config:
```nix
# Repeated verbatim in 3 files:
lighthouses = [ "10.1.1.1" ];
staticHostMap = {
"10.1.1.1" = [ "mjallen.dev:4242" ];
};
port = 4242;
```
**Suggestion**: Add defaults to `modules/nixos/services/nebula/default.nix` options so that non-lighthouse nodes don't need to spell this out. Since this is a personal network with one lighthouse, the defaults can encode that:
```nix
# In nebula/default.nix options:
lighthouses = lib.mjallen.mkOpt (types.listOf types.str) [ "10.1.1.1" ]
"Nebula overlay IPs of lighthouse nodes";
staticHostMap = lib.mjallen.mkOpt (types.attrsOf (types.listOf types.str))
{ "10.1.1.1" = [ "mjallen.dev:4242" ]; }
"Static host map";
port = lib.mjallen.mkOpt types.port 4242 "Nebula listen port";
```
Client systems can then reduce to:
```nix
services.nebula = {
enable = true;
secretsPrefix = "matt-nixos/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/desktop-secrets.yaml";
hostSecretName = "matt-nixos";
};
```
The lighthouse (`pi5`) already overrides `isLighthouse = true` and doesn't set `lighthouses`/`staticHostMap`, so it would be unaffected.
---
## 4. System-level: `systemd-networkd-wait-online` scattered disablement
**Problem**: `systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false` appears in:
- `systems/x86_64-linux/matt-nixos/default.nix:92`
- `systems/x86_64-linux/allyx/default.nix:135`
`modules/nixos/network/default.nix` already disables `NetworkManager-wait-online` and `systemd.network.wait-online`, but not `systemd-networkd-wait-online`. These are the same underlying concern.
**Suggestion**: Add `systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false;` unconditionally to `modules/nixos/network/default.nix` alongside the existing `NetworkManager-wait-online` disablement (line 89). Remove the per-system overrides.
---
## 5. System-level: `coolercontrol` and GNOME desktop environment variables
**Problem**: Two systems (`matt-nixos:91`, `allyx:82`) share identical config blocks:
```nix
programs.coolercontrol.enable = true;
environment.variables = {
GDK_SCALE = "1";
EDITOR = "${lib.getExe' pkgs.vscodium "codium"} --wait";
VISUAL = "${lib.getExe' pkgs.vscodium "codium"} --wait";
};
```
These belong to a desktop AMD gaming profile, not to the system configs themselves.
**Suggestions** (pick one or both):
- **A** — Add a `coolercontrol.enable` option to `modules/nixos/hardware/amd/default.nix` (default `false`) and wire `programs.coolercontrol.enable` inside it. Each system opts in with `hardware.amd.coolercontrol.enable = true`.
- **B** — Add `vscodium` as the default `EDITOR`/`VISUAL` to `modules/nixos/desktop/gnome/default.nix` behind a `vscodium.enable` option (default `false`). The two systems that want it set `desktop.gnome.vscodium.enable = true`.
- **C** — Create a shared `modules/nixos/desktop/common/default.nix` (or `profiles/desktop.nix`) that both GNOME and Hyprland modules consume, and put `GDK_SCALE` there.
---
## 6. System-level: `networking.networkmanager.wifi.backend = "iwd"` bypass
**Problem**: `matt-nixos:100` and `allyx:140` set `networking.networkmanager.wifi.backend = "iwd"` directly, bypassing the `${namespace}.network.iwd.enable` option that the `network` module already provides.
Looking at `modules/nixos/network/default.nix:143154`, enabling `cfg.iwd.enable` does set this value via `mkForce`, but it also forces `networkmanager.enable = mkForce false` — which is unwanted on these systems that use NetworkManager with the iwd backend.
**Root cause**: The module conflates "use iwd" (the WiFi daemon) with "disable NetworkManager" (the connection manager). These are separate concerns. NetworkManager can use iwd as its WiFi backend while still being the connection manager.
**Suggestion**: Restructure the `network` module's iwd handling:
```nix
# Instead of forcing NM off when iwd is enabled:
networking = {
wireless.iwd.enable = cfg.iwd.enable;
networkmanager = mkIf cfg.networkmanager.enable {
enable = true;
wifi.backend = mkIf cfg.iwd.enable "iwd";
# ... rest of NM config
};
};
```
Then the per-system lines become:
```nix
${namespace}.network = {
hostName = "matt-nixos";
iwd.enable = true;
networkmanager.enable = true;
};
```
---
## 7. System-level: `fileSystems."/etc".neededForBoot` not in impermanence module
**Problem**: `fileSystems."/etc".neededForBoot = true` is set manually in four system configs (`nuc-nixos`, `pi5`, `jallen-nas`, `graphical`). This is a prerequisite of impermanence (tmpfs root), not a per-system choice.
**Suggestion**: Add to `modules/nixos/impermanence/default.nix`:
```nix
config = mkIf cfg.enable {
fileSystems."/etc".neededForBoot = true;
# ... existing config
};
```
Then remove the manual setting from each system. (`macbook-pro-nixos` and `matt-nixos` may already have this in their `filesystems.nix` — verify and remove duplicates there too.)
---
## 8. System-level: `system.stateVersion` and `time.timeZone` should be module options
**Problem**: In `modules/nixos/system/default.nix`:
- Line 3: `timezone = "America/Chicago"` is hardcoded
- Line 54: `system.stateVersion = "23.11"` is hardcoded
Both are set unconditionally for every system with no way to override without using `lib.mkForce`.
**Suggestions**:
```nix
# modules/nixos/system/default.nix
{ config, lib, namespace, pkgs, system, ... }:
let
cfg = config.${namespace}.system;
in
{
options.${namespace}.system = {
timezone = lib.mkOption {
type = lib.types.str;
default = "America/Chicago";
description = "System timezone";
};
stateVersion = lib.mkOption {
type = lib.types.str;
default = "23.11";
description = "NixOS state version. Should match the version used when the system was first installed.";
};
};
config = {
time.timeZone = cfg.timezone;
system.stateVersion = cfg.stateVersion;
# ... packages
};
}
```
This maintains the current default for all systems (no change required) while allowing any system to say `${namespace}.system.stateVersion = "24.05"` cleanly.
---
## 9. Module-level: Darwin and NixOS `nix` modules share ~90% of their content
**Problem**: `modules/darwin/nix/default.nix` and `modules/nixos/nix/default.nix` differ only in:
- Darwin lacks `daemonCPUSchedPolicy`/`daemonIOSchedClass`/`daemonIOSchedPriority`
- Darwin lacks the `systemd.services.nix-gc.serviceConfig` block
- Darwin lacks `cudaSupport`/`rocmSupport` in `nixpkgs.config`
- Darwin's substituters list omits `attic.xuyh0120.win/lantian`
Everything else — substituters, trusted keys, `warn-dirty`, `experimental-features`, `trusted-users`, `builders-use-substitutes`, `connect-timeout`, `fallback`, `log-lines`, `max-free`, `min-free`, GC settings, `optimise` — is identical.
**Suggestion**: Extract a shared Nix attrset into `lib/nix-settings/default.nix` (or a plain `.nix` file imported by both):
```nix
# lib/nix-settings/default.nix
{ lib }:
{
commonSubstituters = [
"http://jallen-nas.local:9012/nas-cache"
"https://nixos-apple-silicon.cachix.org"
"https://nixos-raspberrypi.cachix.org"
"https://nix-community.cachix.org"
"https://cache.nixos.org/"
];
commonTrustedPublicKeys = [ ... ];
commonSettings = { warn-dirty = ...; experimental-features = ...; ... };
commonGc = { automatic = true; options = "--delete-older-than 30d"; };
}
```
Both modules import and spread this. The NixOS module adds scheduler policies and systemd GC service tweaks on top.
---
## 10. Module-level: Home SOPS configuration is inconsistent across homes
**Problem**: Three different patterns are used to configure SOPS in home configs:
1. **`${namespace}.sops.enable = true`** — uses the module at `modules/home/sops/default.nix` (macbook-pro-nixos home, jallen-nas home)
2. **Inline SOPS config** — sets `sops.*` directly (allyx home, pi5 home)
3. **Nothing** — some homes don't configure sops at all (matt-nixos home relies on system-level secrets only)
The `modules/home/sops/default.nix` module already handles the `age.keyFile` path, `defaultSopsFile`, and SSH key setup. The inline patterns duplicate this.
**Suggestion**: Migrate all homes that configure sops inline to use `${namespace}.sops.enable = true`. If the home needs a different `defaultSopsFile` (e.g. pi5 uses `secrets/pi5-secrets.yaml`), that should be a module option:
```nix
# modules/home/sops/default.nix — add option:
options.${namespace}.sops = {
enable = lib.mkEnableOption "home sops";
defaultSopsFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null; # falls back to global secrets.yaml
description = "Override the default SOPS file for this home";
};
};
```
---
## 11. Module-level: `modules/nixos/home/default.nix` — `home-manager` input key coupling
**Problem**: `systems.modules.nixos` in `flake.nix:147` explicitly includes `home-manager.nixosModules.home-manager`. However Snowfall Lib **automatically** injects the home-manager NixOS module when the `home-manager` input is present and there are home configurations (Snowfall Lib `system/default.nix` lines 265270).
**Suggestion**: Verify (by temporarily removing the explicit entry) whether `home-manager.nixosModules.home-manager` can be dropped from `systems.modules.nixos`. If Snowfall Lib handles this automatically, removing it eliminates the manual coupling.
---
## 12. System-level: `nuc-nixos` — large monolithic default.nix
**Problem**: `systems/x86_64-linux/nuc-nixos/default.nix` is over 330 lines and contains everything inline: disk config, networking, Home Assistant dashboard definitions (~170 lines of inline Nix), kernel config, user setup, and services. Every other complex system (jallen-nas) already uses a split structure with `apps.nix`, `services.nix`, `nas-defaults.nix`, etc.
**Suggestion**: Extract into separate files following the jallen-nas pattern:
```
systems/x86_64-linux/nuc-nixos/
├── default.nix # thin: imports + top-level options
├── boot.nix # disk/luks/filesystem config
├── dashboard.nix # Home Assistant dashboard card definitions
├── services.nix # postgres, redis, HA, OTBR etc.
└── sops.nix # (or reuse the shared module)
```
The dashboard in particular (currently lines ~88260) should be isolated so HA configuration changes don't require touching system-level config.
---
## 13. System-level: Verify `admin@jallen-nas` steam-rom-manager double-import
**Problem**: `homes/x86_64-linux/admin@jallen-nas/default.nix:16` explicitly imports `steam-rom-manager.homeManagerModules.default`. This same module is injected globally via `modules/nixos/home/default.nix:92` for all x86_64 systems (the ARM guard is `!isArm`, and jallen-nas is x86_64).
**Suggestion**: Remove the explicit import from `admin@jallen-nas/default.nix`. If it was added for standalone `home-manager switch` builds (without NixOS), document that reason in a comment rather than keeping a potentially conflicting double-import.
---
## 14. Flake-level: `pi5` host entry with empty modules list
**Problem**: `flake.nix:218221` defines:
```nix
pi5 = {
modules = [ ];
};
```
An empty modules list is the default behavior — this entry has no effect and can be removed. The comment `# disko is already in systems.modules.nixos above` is incorrect (disko is global for all systems, not specific to pi5). The comment itself is misleading.
**Suggestion**: Remove the `pi5` host entry from `flake.nix` entirely. If the comment is meant to remind future maintainers that disko is global, move that context to `AGENTS.md` or a comment near the global `systems.modules.nixos` list.
---
## 15. Flake-level: `home-manager-stable` input is pulled in but never used
**Problem**: `flake.nix:1013` defines `home-manager-stable` but `home-manager = home-manager-unstable` is the alias (line 21). No system or module references `home-manager-stable` directly. It adds to lock file churn and evaluation time.
**Suggestion**: Remove `home-manager-stable` unless there is a concrete plan to use it for a stable-channel system. If stable Home Manager support is desired in the future, add it back at that point.
---
## 16. Flake-level: Consider using Snowfall Lib `alias` for formatter output
**Problem**: The `outputs-builder` in `flake.nix:277280` is used only to register the `treefmt` formatter. Snowfall Lib supports an `alias` mechanism and also allows `outputs-builder` to be used, but this is the only use of `outputs-builder` in the entire flake.
**Suggestion**: This is fine as-is, but note that `outputs-builder` output can be overridden by auto-discovery. Since the formatter isn't auto-discovered, `outputs-builder` is the correct approach. No change needed — but the comment on line 279 about the mjallen-lib overlay being auto-discovered is accurate and good to keep.
---
## Summary Table
| # | Location | Type | Effort | Impact |
|---|----------|------|--------|--------|
| 1 | `flake.nix` | Deduplication | Low | High — removes confusing double-registration |
| 2 | `flake.nix` | Documentation | Low | Low |
| 3 | `nebula/default.nix` | Better defaults | Low | Medium — 3 systems simplified |
| 4 | `network/default.nix` | Consolidation | Low | Medium — remove per-system workarounds |
| 5 | `hardware/amd` + `desktop/gnome` | New options | Medium | Medium — DRY gaming desktop profile |
| 6 | `network/default.nix` | Bug fix / refactor | Medium | High — current iwd handling is incorrect |
| 7 | `impermanence/default.nix` | Consolidation | Low | Medium — remove 4 manual entries |
| 8 | `system/default.nix` | New options | Low | Medium — allows per-system overrides cleanly |
| 9 | `lib/` + `darwin/nix` + `nixos/nix` | Extraction | Medium | Medium — single source of truth for nix config |
| 10 | `homes/*/` + `modules/home/sops` | Consistency | Low | Low — consistency improvement |
| 11 | `flake.nix` | Simplification | Low | Low — possible dead entry |
| 12 | `systems/nuc-nixos/` | Refactor | Medium | High — maintainability |
| 13 | `homes/admin@jallen-nas` | Bug fix | Trivial | Low — potential double-import |
| 14 | `flake.nix` | Cleanup | Trivial | Low — dead code |
| 15 | `flake.nix` | Cleanup | Trivial | Low — reduces lock churn |
| 16 | `flake.nix` | N/A | None | No change needed |

245
docs/getting-started.md Normal file → Executable file
View File

@@ -6,167 +6,170 @@ This guide will help you get started with this NixOS configuration repository.
- Basic knowledge of NixOS and the Nix language - Basic knowledge of NixOS and the Nix language
- Git installed on your system - Git installed on your system
- Physical access to the machine you want to configure - Physical or SSH access to the target machine
## Initial Setup ## Cloning the Repository
### 1. Cloning the Repository
Clone this repository to your local machine:
```bash ```bash
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git
cd nix-config cd nix-config
``` ```
### 2. Setting Up a New System ## Installing on a New Machine
#### Option 1: Using an Existing Configuration ### Option 1: Using an existing system configuration
If you're setting up a new machine that should be identical to an existing configuration: If the machine matches an existing configuration (e.g. reinstalling `jallen-nas`):
1. Boot from a NixOS installation media 1. Boot from a NixOS installation ISO
2. Mount your target partitions to `/mnt` 2. Partition and mount disks (or use `disko`):
3. Clone this repository:
```bash ```bash
nixos-enter nix run github:nix-community/disko -- --mode disko /path/to/disko-config.nix
cd /mnt
mkdir -p /mnt/etc/nixos
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git /mnt/etc/nixos
``` ```
4. Install NixOS with the desired system profile: 3. Clone this repo into the target:
```bash
mkdir -p /mnt/etc/nixos
git clone <repo-url> /mnt/etc/nixos
```
4. Install:
```bash ```bash
nixos-install --flake /mnt/etc/nixos#hostname nixos-install --flake /mnt/etc/nixos#hostname
``` ```
Replace `hostname` with the target system name (e.g., `matt-nixos`, `jallen-nas`, etc.)
#### Option 2: Creating a New System Configuration ### Option 2: Adding a new system configuration
If you're adding a completely new system: 1. **Create the system directory** under the appropriate architecture:
1. Create a new directory for your system configuration:
```bash ```bash
mkdir -p systems/$(uname -m)-linux/new-hostname mkdir -p systems/x86_64-linux/new-hostname
``` ```
2. Create the basic configuration files: 2. **Write the configuration** — at minimum a `default.nix`:
```bash ```nix
cat > systems/$(uname -m)-linux/new-hostname/default.nix << EOF { namespace, ... }:
{ lib, pkgs, ... }:
{ {
imports = [ mjallen = {
./hardware-configuration.nix sops.enable = true;
# Add other needed module imports here network.hostName = "new-hostname";
]; user.name = "admin";
};
networking.hostName = "new-hostname";
# Add your system-specific configuration here
} }
EOF
``` ```
3. Generate the hardware configuration: 3. **Generate hardware configuration** (on the target machine):
```bash ```bash
nixos-generate-config --no-filesystems --dir systems/$(uname -m)-linux/new-hostname/ nixos-generate-config --no-filesystems --dir systems/x86_64-linux/new-hostname/
``` ```
4. Add your new system to the flake by adding it to the `hosts` section in `flake.nix` 4. **Add SOPS secrets** for the new host — see [Secrets Management](../README.md#secrets-management).
5. Build and install the configuration: 5. **Build and switch**:
```bash ```bash
sudo nixos-rebuild switch --flake .#new-hostname sudo nixos-rebuild switch --flake .#new-hostname
``` ```
## Secret Management ## Day-to-Day Usage
### Setting Up Sops-Nix ### Applying configuration changes
1. Create a GPG key if you don't already have one:
```bash
gpg --full-generate-key
```
2. Add your key to `.sops.yaml`:
```bash
# Get your key fingerprint
gpg --list-secret-keys --keyid-format=long
# Edit the .sops.yaml file to add your key
```
3. Create a new encrypted secret:
```bash
sops secrets/newsecret.yaml
```
## Common Tasks
### Updating the Repository
```bash ```bash
git pull # On the local machine
sudo nixos-rebuild switch --flake .#hostname sudo nixos-rebuild switch --flake .#$(hostname)
# On a remote machine
nixos-rebuild switch --flake .#hostname --target-host user@host --use-remote-sudo
``` ```
### Adding a New Package ### Updating flake inputs
1. For standard packages, add them to your system or home configuration: ```bash
# Update all inputs
nix flake update
# Update a single input
nix flake lock --update-input nixpkgs
# Apply after updating
sudo nixos-rebuild switch --flake .#$(hostname)
```
### Garbage collection
```bash
# Remove old generations and unreferenced store paths
sudo nix-collect-garbage -d
# Keep the last N generations
sudo nix-collect-garbage --delete-older-than 30d
```
## Enabling a Module
Most functionality is exposed through the `mjallen` namespace. To enable a module, set it in the system's `default.nix` (or a relevant sub-file):
```nix
mjallen = {
desktop.gnome.enable = true;
hardware.amd.enable = true;
gaming.enable = true;
services.jellyfin = {
enable = true;
port = 8096;
reverseProxy.enable = true;
};
};
```
See [Custom Modules](./modules/README.md) for the full list of available modules and options.
## Adding a New Service Module
1. **Create the module directory**:
```bash
mkdir -p modules/nixos/services/my-service
```
2. **Write `default.nix`** using the `mkModule` helper:
```nix ```nix
environment.systemPackages = with pkgs; [ { config, lib, namespace, pkgs, ... }:
new-package
];
```
2. For custom packages, add them to the `packages` directory:
```bash
mkdir -p packages/new-package
# Create the necessary Nix files
```
### Adding a New Module
1. Create a new module directory:
```bash
mkdir -p modules/nixos/new-module
```
2. Create the module files:
```bash
# Create options.nix
cat > modules/nixos/new-module/options.nix << EOF
{ lib, namespace, ... }:
with lib;
{
options.${namespace}.new-module = {
enable = mkEnableOption "Enable new module";
# Add other options here
};
}
EOF
# Create default.nix
cat > modules/nixos/new-module/default.nix << EOF
{ config, lib, namespace, ... }:
let let
cfg = config.${namespace}.new-module; name = "my-service";
in nebulaConfig = lib.${namespace}.mkModule {
{ inherit config name;
imports = [ ./options.nix ]; description = "my service description";
options = { };
config = lib.mkIf cfg.enable { moduleConfig = {
# Add your configuration here services.my-service = {
enable = true;
port = config.${namespace}.services.${name}.port;
};
};
}; };
} in
EOF { imports = [ nebulaConfig ]; }
``` ```
3. Import your module in your system configuration: 3. **Enable it** in a system configuration:
```nix ```nix
imports = [ mjallen.services.my-service = {
# ... enable = true;
../../../modules/nixos/new-module port = 1234;
]; };
```
${namespace}.new-module.enable = true;
``` ## Adding a New Package
1. Create a directory under `packages/`:
```bash
mkdir packages/my-package
```
2. Write a `default.nix` that returns a derivation. The package will be available as `pkgs.mjallen.my-package` in all configurations.
## Secrets
See the [Secrets Management](../README.md#secrets-management) section of the root README for:
- How age keys are derived from SSH host keys
- Adding a new machine as a SOPS recipient
- Adding/editing secrets
- Generating Nebula VPN certificates

0
docs/home-assistant/README.md Normal file → Executable file
View File

0
docs/home-assistant/automations.md Normal file → Executable file
View File

0
docs/home-assistant/fountain-automation.md Normal file → Executable file
View File

343
docs/modules/README.md Normal file → Executable file
View File

@@ -2,115 +2,294 @@
This directory contains documentation for the custom modules used in this NixOS configuration. This directory contains documentation for the custom modules used in this NixOS configuration.
## Module Types ## Overview
The repository uses two main types of modules: Modules are split into three categories:
1. **NixOS Modules** - System-level configurations in `modules/nixos/` - **NixOS modules** (`modules/nixos/`) — system-level configuration
2. **Home Manager Modules** - User-level configurations in `modules/home/` - **Home Manager modules** (`modules/home/`) — user-level configuration
- **Darwin modules** (`modules/darwin/`) — macOS-specific configuration
All modules are auto-discovered by Snowfall Lib and expose options under the `mjallen` namespace.
## NixOS Modules ## NixOS Modules
These modules configure the system-level aspects of NixOS: ### Boot (`modules/nixos/boot/`)
- [Boot Modules](./boot.md) - Boot loader and kernel configurations | Module | Description |
- [Desktop Modules](./desktop.md) - Desktop environment configurations |---|---|
- [Development Modules](./development.md) - Development tools and environments | `boot/common/` | Shared boot defaults (quiet boot, Plymouth) |
- [Hardware Modules](./hardware.md) - Hardware-specific configurations | `boot/lanzaboote/` | Secure Boot via Lanzaboote |
- [Home Assistant Modules](./homeassistant.md) - Home automation configuration | `boot/systemd-boot/` | systemd-boot (non-secure-boot systems) |
- [Networking Modules](./network.md) - Network configuration and services | `boot/plymouth/` | Plymouth splash screen |
- [Security Modules](./security.md) - Security-related configurations
- [Services Modules](./services.md) - Various service configurations ### Desktop (`modules/nixos/desktop/`)
- [System Modules](./system.md) - General system configurations
- [Virtualization Modules](./virtualization.md) - Virtualization and containerization | Module | Description |
|---|---|
| `desktop/gnome/` | GNOME desktop environment |
| `desktop/hyprland/` | Hyprland compositor |
| `desktop/cosmic/` | COSMIC desktop environment |
### Development (`modules/nixos/development/`)
Enables development tools and language support. Options:
```nix
mjallen.development = {
enable = true;
includeLanguages = [ "python" "c" ];
includeContainers = true;
};
```
### Hardware (`modules/nixos/hardware/`)
| Module | Description |
|---|---|
| `hardware/amd/` | AMD GPU (AMDGPU driver, LACT) |
| `hardware/nvidia/` | NVIDIA GPU |
| `hardware/battery/` | Battery charge threshold management |
| `hardware/raspberry-pi/` | Raspberry Pi hardware support and DT overlays |
| `hardware/openrgb/` | OpenRGB for LED control |
| `hardware/btrfs/` | btrfs-specific settings |
| `hardware/common/` | Common hardware defaults |
### Headless (`modules/nixos/headless/`)
Server profile — disables suspend/hibernate, enables systemd watchdog, no display manager.
```nix
mjallen.headless.enable = true;
```
### Home Assistant (`modules/nixos/homeassistant/`)
Full smart home stack. See [Home Assistant docs](../home-assistant/README.md) for details.
```nix
mjallen.services.home-assistant.enable = true;
```
### Impermanence (`modules/nixos/impermanence/`)
Ephemeral root filesystem with explicit persistence declarations.
```nix
mjallen.impermanence = {
enable = true;
extraDirectories = [ { directory = "/var/lib/myapp"; user = "myapp"; } ];
};
```
### Monitoring (`modules/nixos/monitoring/`)
Prometheus metrics and Grafana dashboards.
```nix
mjallen.monitoring.enable = true;
```
### Network (`modules/nixos/network/`)
Hostname, firewall, NetworkManager profiles, static IP configuration.
```nix
mjallen.network = {
hostName = "my-host";
ipv4 = {
method = "manual";
address = "10.0.1.5/24";
gateway = "10.0.1.1";
dns = "1.1.1.1";
interface = "eth0";
};
firewall = {
enable = true;
allowedTCPPorts = [ 80 443 ];
};
};
```
### Power (`modules/nixos/power/`)
UPS (NUT) support.
```nix
mjallen.power.ups.enable = true;
```
### Security (`modules/nixos/security/`)
| Module | Description |
|---|---|
| `security/common/` | Common hardening (kernel params, etc.) |
| `security/tpm/` | TPM2 — Clevis disk unlock |
### Services (`modules/nixos/services/`)
~50 self-hosted service modules, all built with `mkModule`. Each exposes at minimum `enable`, `port`, `reverseProxy`, and `openFirewall`. Common usage pattern:
```nix
mjallen.services.jellyfin = {
enable = true;
port = 8096;
reverseProxy.enable = true;
};
```
Available services:
`actual`, `ai`, `appimage`, `arrs`, `attic`, `authentik`, `authentikRac`, `booklore`, `caddy`, `calibre`, `calibre-web`, `cockpit`, `code-server`, `collabora`, `coturn`, `crowdsec`, `dispatcharr`, `free-games-claimer`, `gitea`, `glance`, `glances`, `grafana`, `guacd`, `headscale`, `immich`, `jellyfin`, `seerr`, `lubelogger`, `manyfold`, `matrix`, `minecraft`, `mongodb`, `nebula`, `netbootxyz`, `nextcloud`, `ntfy`, `onlyoffice`, `opencloud`, `orca`, `paperless`, `paperless-ai`, `protonmail-bridge`, `restic`, `samba`, `sparky-fitness`, `sparky-fitness-server`, `sunshine`, `tdarr`, `termix`, `tunarr`, `unmanic`, `uptime-kuma`, `wyoming`, `your-spotify`
#### Nebula VPN (`services/nebula/`)
Unified module for both lighthouse and node roles:
```nix
# Lighthouse
mjallen.services.nebula = {
enable = true;
isLighthouse = true;
port = 4242;
secretsPrefix = "pi5/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml";
hostSecretName = "lighthouse";
};
# Node
mjallen.services.nebula = {
enable = true;
port = 4242;
lighthouses = [ "10.1.1.1" ];
staticHostMap = { "10.1.1.1" = [ "mjallen.dev:4242" ]; };
secretsPrefix = "mymachine/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/mymachine-secrets.yaml";
hostSecretName = "mymachine";
};
```
See [Secrets Management](../../README.md#generating-nebula-vpn-certificates) for how to generate the required certificates.
### SOPS (`modules/nixos/sops/`)
Configures sops-nix to decrypt secrets using the machine's SSH host key as an age key.
```nix
mjallen.sops = {
enable = true;
sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; # default
};
```
### User (`modules/nixos/user/`)
System user account management.
```nix
mjallen.user = {
name = "matt";
mutableUsers = false;
extraGroups = [ "docker" "video" ];
};
```
---
## Home Manager Modules ## Home Manager Modules
These modules configure user environments: ### Desktop
- [Applications](./home/applications.md) - User applications | Module | Description |
- [Desktop](./home/desktop.md) - User desktop environments |---|---|
- [Development](./home/development.md) - User development environments | `desktop/gnome/` | GNOME user settings (extensions, keybindings, etc.) |
- [Media](./home/media.md) - Media applications | `desktop/theme/` | Theme configuration |
- [Shell](./home/shell.md) - Shell configurations
## Module Structure ### Programs
Each module follows a standard structure: | Module | Description |
|---|---|
| `programs/btop/` | btop system monitor |
| `programs/code/` | VS Code / VSCodium settings |
| `programs/git/` | Git user config |
| `programs/hyprland/` | Hyprland compositor config |
| `programs/kitty/` | Kitty terminal config |
| `programs/librewolf/` | LibreWolf browser settings |
| `programs/mako/` | Mako notification daemon |
| `programs/nwg-dock/` | nwg-dock panel |
| `programs/nwg-drawer/` | nwg-drawer app launcher |
| `programs/nwg-panel/` | nwg-panel bar |
| `programs/opencode/` | OpenCode AI coding assistant |
| `programs/update-checker/` | Automatic flake update checker |
| `programs/waybar/` | Waybar status bar |
| `programs/wlogout/` | Logout menu |
| `programs/wofi/` | Wofi launcher |
| `programs/zsh/` | Zsh shell config |
``` ### Other
modules/nixos/example-module/
├── default.nix # Main implementation
├── options.nix # Option declarations
└── submodule/ # Optional submodules
└── default.nix # Submodule implementation
```
### default.nix | Module | Description |
|---|---|
| `gpg/` | GPG agent configuration |
| `services/pass/` | Password store |
| `shell-aliases/` | Common shell aliases |
| `sops/` | User-level SOPS secrets |
| `stylix/` | System-wide theming (colours, fonts, wallpaper) |
| `user/` | User environment defaults |
The `default.nix` file contains the main implementation of the module: ---
## Module Development
### Using `mkModule`
The `lib.mjallen.mkModule` helper (`lib/module/default.nix`) creates a fully-featured NixOS module from a minimal spec:
```nix ```nix
{ { config, lib, namespace, pkgs, ... }:
config,
lib,
pkgs,
namespace,
...
}:
let let
cfg = config.${namespace}.example-module; name = "my-service";
in cfg = config.${namespace}.services.${name};
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable { serviceConfig = lib.${namespace}.mkModule {
# Module implementation when enabled inherit config name;
description = "my service";
options = {
# extra options beyond the standard set
myOption = lib.${namespace}.mkOpt lib.types.str "default" "Description";
};
moduleConfig = {
services.my-service = {
enable = true;
port = cfg.port;
};
};
}; };
} in
{ imports = [ serviceConfig ]; }
``` ```
### options.nix Standard options provided by `mkModule` for free: `enable`, `port`, `listenAddress`, `openFirewall`, `configDir`, `dataDir`, `createUser`, `configureDb`, `environmentFile`, `reverseProxy.*`, `redis.*`, `extraEnvironment`, `hashedPassword`, `puid`, `pgid`, `timeZone`.
The `options.nix` file declares the module's configuration options: ### Using `mkContainerService`
For Podman/OCI container services, use `mkContainerService` instead:
```nix ```nix
{ lib, namespace, ... }: lib.${namespace}.mkContainerService {
with lib; inherit config name;
let image = "ghcr.io/example/my-app:latest";
inherit (lib.${namespace}) mkOpt; internalPort = 8080;
in volumes = [ "${cfg.configDir}:/config" ];
{ };
options.${namespace}.example-module = {
enable = mkEnableOption "enable example module";
# Other option declarations
};
}
``` ```
## Using Modules ### Option helpers
To use a module in your system configuration:
1. Enable the module in your system configuration:
```nix ```nix
{ config, ... }: lib.mjallen.mkOpt types.str "default" "description"
{ lib.mjallen.mkBoolOpt false "description"
mjallen.example-module = { lib.mjallen.mkOpt' types.int 80 # no description
enable = true; lib.mjallen.enabled # { enable = true; }
# Other options lib.mjallen.disabled # { enable = false; }
};
}
``` ```
## Creating New Modules
To create a new module:
1. Create a new directory in `modules/nixos/` or `modules/home/`
2. Create `default.nix` and `options.nix` files
3. Implement your module functionality
4. Import the module in your system configuration
See the [Getting Started](../getting-started.md) guide for more details on creating modules.

0
docs/modules/homeassistant.md Normal file → Executable file
View File

90
docs/services.md Executable file
View File

@@ -0,0 +1,90 @@
# Services
All services are derived from `lib.mjallen.network` (`lib/network/default.nix`).
Domain: `mjallen.dev`
Services are grouped by host. The **URL** column is only present when a reverse proxy
is configured (i.e. `reverseProxy.enable = true`) or a well-known public URL exists.
Services without a public URL are accessible only on the LAN or internally.
---
## NAS (`jallen-nas` — `10.0.1.3`)
| Service | Enabled | Port | URL |
|---------|---------|------|-----|
| actual | No | 3333 | https://actual.mjallen.dev |
| ai (Ollama + llama.cpp + Open-WebUI) | Yes | 8127 / 11434 / various | https://chat.mjallen.dev |
| arrs (Sonarr + Radarr + SABnzbd) | Yes | 8989 / 7878 / 8280 | — |
| attic | Yes | 9012 | https://cache.mjallen.dev |
| authentik | Yes | 9000 | https://authentik.mjallen.dev |
| authentikRac | Yes | 4823 | — |
| caddy | Yes | 80 / 443 | — |
| calibre | No | 8084 | https://calibre.mjallen.dev |
| calibre-web | No | 8083 | https://calibre-web.mjallen.dev |
| cockpit | Yes | 9091 | — |
| code-server | Yes | 4444 | https://code.mjallen.dev |
| collabora | Yes | 9980 | https://office.mjallen.dev |
| coturn | Yes | 3478 | — |
| crowdsec | Yes | 8181 | — |
| dispatcharr | No | 9191 | https://dispatcharr.mjallen.dev |
| free-games-claimer | No | 6080 | — |
| gitea | Yes | 3000 / SSH 2222 | https://gitea.mjallen.dev |
| glance | Yes | 5555 | https://glance.mjallen.dev |
| glances | Yes | 61208 | https://glances.mjallen.dev |
| grafana | Yes | 9999 | https://grafana.mjallen.dev |
| grimmory | No | 6066 | https://grimmory.mjallen.dev |
| guacd | Yes | 4822 | — |
| headscale | No | 2112 | https://headscale.mjallen.dev |
| immich | Yes | 2283 | https://immich.mjallen.dev |
| jellyfin | Yes | 8096 | https://jellyfin.mjallen.dev |
| seerr | Yes | 5055 | https://seerr.mjallen.dev |
| kavita | Yes | 5000 | — |
| lemonade | No | 8001 | — |
| lubelogger | Yes | 6754 | https://lubelogger.mjallen.dev |
| manyfold | Yes | 3214 | — |
| matrix | Yes | 8448 | https://matrix.mjallen.dev |
| minecraft | No | 25565 | — |
| mongodb | No | 27017 | — |
| nebula | Yes | 4242 | — |
| netbootxyz | No | 4000 | https://netbootxyz.mjallen.dev |
| nextcloud | Yes | 9988 | https://cloud.mjallen.dev |
| ntfy | Yes | 2586 | https://ntfy.mjallen.dev |
| ocis | No | 9200 | — |
| onlyoffice | No | 9943 | — |
| opencloud | No | 9200 | — |
| orca-slicer | No | 3100 | https://orca-slicer.mjallen.dev |
| paperless | Yes | 28981 | — |
| paperless-ai | Yes | 28982 | — |
| protonmail-bridge | Yes | SMTP 1025 / IMAP 1143 | — |
| restic-server | Yes | 8008 | — |
| sparky-fitness (frontend) | Yes | 3004 | https://sparky.mjallen.dev |
| sparky-fitness-server (backend) | Yes | 3010 | — |
| sunshine | Yes | 47989 | — |
| tdarr | No | 8265 / 8266 | https://tdarr.mjallen.dev |
| termix | Yes | 7777 | https://termix.mjallen.dev |
| tunarr | Yes | 8000 | https://tunarr.mjallen.dev |
| unmanic | Yes | 8265 | https://unmanic.mjallen.dev |
| uptime-kuma | Yes | 3001 | — |
| wyoming (Whisper + Piper) | Yes | 10300 / 10200 | — |
---
## NUC (`nuc-nixos` — `10.0.1.4`)
| Service | Enabled | Port | URL |
|---------|---------|------|-----|
| home-assistant | Yes | 8123 | https://hass.mjallen.dev |
| esphome | Yes | 6052 | — |
| otbr (OpenThread Border Router) | Yes | 8880 / REST 8881 | — |
| mosquitto (MQTT) | Yes | 1883 | — |
---
## Pi5 (`pi5` — `10.0.1.2`)
| Service | Enabled | Port | URL |
|---------|---------|------|-----|
| adguard | Yes | 3000 | — |
| nebula (lighthouse) | Yes | 4242 | — |
| dns | Yes | 53 | — |

39
docs/systems/README.md Normal file → Executable file
View File

@@ -4,19 +4,34 @@ This directory contains documentation for each system configuration in this repo
## Systems ## Systems
- [Desktop (matt-nixos)](./matt-nixos.md) - Main desktop computer | Host | Architecture | OS | Role |
- [NAS (jallen-nas)](./jallen-nas.md) - Home server and NAS |---|---|---|---|
- [NUC (nuc-nixos)](./nuc-nixos.md) - Intel NUC | [matt-nixos](./matt-nixos.md) | x86_64-linux | NixOS | Primary AMD desktop |
- [Raspberry Pi 5](./pi5.md) - Raspberry Pi 5 | [jallen-nas](./jallen-nas.md) | x86_64-linux | NixOS | Home server / NAS |
- [MacBook Pro (nixOS)](./macbook-pro-nixos.md) - MacBook Pro running NixOS | [nuc-nixos](./nuc-nixos.md) | x86_64-linux | NixOS | Intel NUC — Home Assistant hub |
| [allyx](./allyx.md) | x86_64-linux | NixOS | ASUS ROG Ally X handheld |
| [pi5](./pi5.md) | aarch64-linux | NixOS | Raspberry Pi 5 — network services |
| [macbook-pro-nixos](./macbook-pro-nixos.md) | aarch64-linux | NixOS (Asahi) | Apple Silicon MacBook Pro |
| [macbook-pro](./macbook-pro.md) | aarch64-darwin | nix-darwin | macOS on the same MacBook Pro |
There are also two ISO targets (`x86_64-install-iso/graphical`, `x86_64-linux/iso-minimal`) used for installation media builds.
## Network
All hosts are on the `10.0.1.0/24` LAN with static IPs:
| Host | LAN IP | Overlay (Nebula) |
|---|---|---|
| pi5 | 10.0.1.2 | 10.1.1.1 (lighthouse) |
| jallen-nas | 10.0.1.3 | 10.1.1.x (node) |
| nuc-nixos | 10.0.1.4 | — |
## Common Configuration ## Common Configuration
All systems share certain common configurations through the modules system. These include: All systems share:
- SOPS secret management (age keys from SSH host keys)
- Impermanence (ephemeral root, explicit persistence)
- Nix flake-based configuration via Snowfall Lib
- The `mjallen` module namespace
- Base system configuration Each system then layers its own modules and hardware configuration on top.
- User management
- Network configuration
- Security settings
Each system then adds its specific configurations on top of these common modules.

57
docs/systems/allyx.md Executable file
View File

@@ -0,0 +1,57 @@
# ASUS ROG Ally X (allyx)
`systems/x86_64-linux/allyx/`
## Hardware
- **Device**: ASUS ROG Ally X handheld gaming PC
- **CPU/GPU**: AMD (LACT, CoolerControl)
- **Disk**: NVMe with LUKS encryption
- **Security**: Lanzaboote (Secure Boot)
## Key Features
- Jovian NixOS for Steam Deck-compatible experience
- Steam auto-starts into Game Mode on boot
- Decky Loader for Steam Deck plugins
- Handheld Daemon for power/TDP/fan control
- GNOME available as a desktop session (selectable from Steam)
- SDDM (Wayland) as display manager — GDM disabled
- Gaming enabled (Gamemode, Gamescope, etc.)
- AMD GPU management via LACT
- CoolerControl for fan curves
- iwd as the Wi-Fi backend
- Impermanence (ephemeral root)
## Jovian NixOS
The allyx uses [Jovian NixOS](https://github.com/Jovian-Experiments/Jovian-NixOS) to provide Steam Deck compatibility:
```nix
jovian.steam = {
enable = true;
autoStart = true;
desktopSession = "gnome"; # fall-through desktop session
};
jovian.decky-loader = {
enable = true;
extraPackages = [ pkgs.python3 pkgs.systemd ];
};
```
## Network
- **Hostname**: allyx
- **Wi-Fi backend**: iwd (via NetworkManager)
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config — Jovian, gaming, hardware |
| `boot.nix` | Lanzaboote, kernel |
## Secrets
Secrets are in `secrets/allyx-secrets.yaml`, encrypted for: `matt`, `desktop`, `deck`, `steamdeck`, `admin`, `jallen-nas`, `matt_allyx`, `allyx`.

167
docs/systems/jallen-nas.md Normal file → Executable file
View File

@@ -1,101 +1,104 @@
# NAS Server (jallen-nas) # NAS Server (jallen-nas)
This document describes the configuration for the NAS server system. `systems/x86_64-linux/jallen-nas/`
## Hardware ## Hardware
The NAS server is built on AMD hardware: - **CPU**: AMD (x86_64)
- **GPU**: AMD (LACT for fan/power control)
- **Disk**: NVMe system drive + bcachefs NAS pool
- **Security**: TPM2 (Clevis disk unlock), Lanzaboote (Secure Boot)
- CPU: AMD processor ## Key Features
- Hardware-specific modules:
- `nixos-hardware.nixosModules.common-pc`
- `nixos-hardware.nixosModules.common-cpu-amd`
- `nixos-hardware.nixosModules.common-cpu-amd-pstate`
- `nixos-hardware.nixosModules.common-hidpi`
## Services - bcachefs storage pool mounted at `/media/nas/main`
- Clevis-based TPM disk unlock at boot (no passphrase required)
- Impermanence — root is ephemeral; state persists to `/media/nas/main/persist`
- Samba shares (Windows file sharing, Time Machine)
- Nebula VPN node (overlay peer, lighthouse at pi5)
- ~40 self-hosted services behind a Caddy reverse proxy
- Authentik SSO protecting most web UIs
- CrowdSec for intrusion detection
- Restic backups
The NAS hosts various services: ## Network
### Media Services - **LAN IP**: 10.0.1.3 (static, `enp197s0`)
- **Gateway**: 10.0.1.1
- **Nebula**: overlay peer, lighthouse at `mjallen.dev:4242`
- **Jellyfin** - Media server ## Storage
- **Jellyseerr** - Media request manager
- **Sonarr** - TV show management
- **Radarr** - Movie management
- **Lidarr** - Music management
- **Bazarr** - Subtitle management
- **Music Assistant** - Music streaming integration with Home Assistant
### Download Services | Mount | Filesystem | Description |
|---|---|---|
| `/media/nas/main` | bcachefs | Primary NAS pool (media, appdata, documents) |
| `/media/nas/test` | bcachefs | Secondary test pool |
- **Transmission** - Torrent client ### Samba Shares
- **NZBGet** - Usenet downloader
- **Prowlarr** - Indexer manager
### Document Management | Share | Time Machine |
|---|---|
| `3d_printer` | no |
| `Backup` | no |
| `Documents` | no |
| `isos` | no |
| `app_data` | no |
| `TimeMachine` | yes (max 1 TB) |
- **Paperless-ngx** - Document management system ## Enabled Services
### File Sharing | Service | Port | Notes |
|---|---|---|
| Caddy | 443/80 | Reverse proxy for all services |
| Authentik | 9000 | SSO / identity provider |
| Attic | 9012 | Nix binary cache (`cache.mjallen.dev`) |
| Immich | 2283 | Photo management |
| Jellyfin | 8096 | Media server |
| Seerr | 5055 | Media request manager |
| Nextcloud | 9988 | Cloud storage |
| Paperless | 28981 | Document management |
| Paperless AI | 28982 | AI-assisted document tagging |
| Gitea | 3000 | Self-hosted Git |
| Matrix | 8448 | Matrix homeserver |
| Ntfy | 2586 | Push notifications |
| Glance | 5555 | Dashboard |
| Immich | 2283 | Photo library |
| Uptime Kuma | 3001 | Uptime monitoring |
| Code Server | 4444 | VS Code in the browser |
| Cockpit | 9090 | System management UI |
| Collabora | 9980 | Online office suite |
| CrowdSec | 8181 | Intrusion detection |
| Glances | 61208 | System stats |
| Coturn | 3478 | TURN/STUN server |
| Nebula | 4242 | Overlay VPN node |
| Restic | 8008 | Backup service |
| Sunshine | 47989 | Remote desktop (Moonlight) |
| Unmanic | 8265 | Media transcoding |
| Lubelogger | 6754 | Vehicle maintenance log |
| Manyfold | 3214 | 3D model library |
| Booklore | 6066 | Book library |
| Tunarr | 8000 | Virtual TV channels |
| Termix | 7777 | Web terminal |
| Sparky Fitness | 3004/3010 | Fitness tracking |
| Protonmail Bridge | 1025/1143 | SMTP/IMAP bridge |
| Arrs | various | Sonarr, Radarr, etc. |
| AI | various | Ollama, etc. |
| Wyoming | various | Voice assistant pipeline |
- **Samba** - Windows file sharing ## Configuration Files
- **Nextcloud** - Self-hosted cloud storage
### AI Services | File | Purpose |
|---|---|
| `default.nix` | Main config — network, hardware, filesystems, packages |
| `apps.nix` | All service enable/disable declarations |
| `nas-defaults.nix` | Sets `configDir`/`dataDir` defaults for all services |
| `boot.nix` | Lanzaboote, kernel, initrd |
| `services.nix` | Home Assistant, samba, and other platform services |
| `users.nix` | User accounts (`admin`, `nix-apps`) |
| `sops.nix` | Secret declarations |
| `vpn.nix` | Nebula VPN configuration |
| `disabled.nix` | Services explicitly disabled |
- **Ollama** - Local AI model hosting ## Secrets
### Smart Home Secrets are in `secrets/nas-secrets.yaml`, encrypted for: `matt`, `desktop`, `admin`, `jallen-nas`.
- **Home Assistant** - Smart home controller
- **Zigbee2MQTT** - Zigbee device integration
- **MQTT** - Message broker for IoT devices
- **Thread Border Router** - Thread network for smart home devices
## Storage Configuration
The NAS uses multiple storage devices:
1. **System Drive** - For the operating system
2. **Data Drives** - Configured as a storage array for media and data
## Network Configuration
The NAS is configured with:
- Static IP address
- Firewall rules for the various services
- Tailscale for secure remote access
## Backup Strategy
The NAS implements a comprehensive backup strategy:
1. **System Backup** - Regular backups of the NixOS configuration
2. **Data Backup** - Backups of important data to secondary storage
3. **Off-site Backup** - Critical data is backed up off-site
## Usage and Management
### Accessing Services
Most services are available through a reverse proxy, which provides:
- HTTPS access
- Authentication via Authentik
- Subdomain-based routing
### Adding Storage
To add additional storage to the NAS:
1. Add the physical drive to the system
2. Update the disko configuration
3. Rebuild the system with `nixos-rebuild switch`
### Monitoring
The system can be monitored through:
- Prometheus metrics
- Grafana dashboards
- Home Assistant sensors

View File

@@ -0,0 +1,69 @@
# MacBook Pro — NixOS / Asahi Linux (macbook-pro-nixos)
`systems/aarch64-linux/macbook-pro-nixos/`
## Hardware
- **Device**: Apple Silicon MacBook Pro (M-series)
- **OS**: NixOS via [Asahi Linux](https://asahilinux.org/) (`nixos-apple-silicon`)
- **Boot**: Asahi boot chain (not traditional EFI)
## Key Features
- Asahi Linux kernel with full Apple Silicon support (sound, GPU, etc.)
- GNOME as the primary desktop; Hyprland available but disabled
- x86_64 emulation via binfmt (enables running x86 binaries)
- Waydroid and libvirtd available (Waydroid disabled by default)
- Battery management — charge threshold set via `macsmc-battery`
- Omnissa Horizon client (custom package) for remote desktop
- Distrobox for containerised Linux environments
- iwd as the Wi-Fi backend
## x86_64 Emulation
```nix
nix.settings.extra-platforms = [ "x86_64-linux" ];
boot.binfmt.emulatedSystems = [ "x86_64-linux" ];
```
This allows building and running x86_64 packages on the ARM host.
## Asahi Hardware
The Asahi hardware module provides:
- Firmware loading from `./firmware/`
- Sound setup (`setupAsahiSound = true`)
- Apple-specific kernel patches and device drivers
Useful packages installed:
`asahi-bless`, `asahi-btsync`, `asahi-nvram`, `asahi-wifisync`, `apfs-fuse`, `apfsprogs`, `muvm`, `fex`
## Network
- **Hostname**: macbook-pro-nixos
- **Wi-Fi backend**: iwd (via NetworkManager)
- Firewall: extra rules for multicast (ports 1990, 2021)
## Battery Management
```nix
mjallen.hardware.battery = {
enable = true;
chargeLimitPath = "/sys/class/power_supply/macsmc-battery/charge_control_end_threshold";
};
```
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config — Asahi hardware, users, network |
| `boot.nix` | Asahi boot configuration |
| `filesystems.nix` | Disk layout |
| `hardware-configuration.nix` | Generated hardware config |
| `services.nix` | logind, GDM, GNOME, Flatpak, power settings |
| `firmware/` | Asahi firmware blobs |
## Secrets
Secrets are in `secrets/mac-secrets.yaml`, encrypted for: `matt`, `matt_pi5`, `desktop`, `pi5`, `admin`, `jallen-nas`, `matt_macbook-pro`, `macbook-pro`.

40
docs/systems/macbook-pro.md Executable file
View File

@@ -0,0 +1,40 @@
# MacBook Pro — macOS / nix-darwin (macbook-pro)
`systems/aarch64-darwin/macbook-pro/`
## Overview
This is the [nix-darwin](https://github.com/nix-darwin/nix-darwin) configuration for the same MacBook Pro running macOS. It provides declarative macOS system management alongside Homebrew.
## Key Features
- Touch ID for `sudo`
- Declarative Homebrew (casks and formulae managed via `nix-homebrew`)
- `nh` for easy NixOS/darwin rebuilds
- `attic-client` for accessing the Nix binary cache
- `macpm` for Apple Silicon power monitoring
- Rosetta builder available (disabled, on-demand)
- Linux builder available (disabled)
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config — packages, users, environment |
| `homebrew.nix` | Declarative Homebrew casks and formulae |
| `programs.nix` | macOS program settings |
| `system.nix` | System defaults (dock, finder, etc.) |
## User
- **Username**: `mattjallen`
- **Home**: `/Users/mattjallen`
- **Flake path**: `/Users/mattjallen/nix-config` (set via `NH_OS_FLAKE`)
## Rebuilding
```bash
darwin-rebuild switch --flake .#macbook-pro
# or using nh:
nh darwin switch
```

50
docs/systems/matt-nixos.md Executable file
View File

@@ -0,0 +1,50 @@
# Desktop (matt-nixos)
`systems/x86_64-linux/matt-nixos/`
## Hardware
- **CPU**: AMD
- **GPU**: AMD (LACT for fan/power control, OpenRGB)
- **Disk**: NVMe with LUKS encryption (disko)
- **Security**: TPM2, Lanzaboote (Secure Boot)
## Key Features
- GNOME as the primary desktop (Hyprland available but disabled)
- COSMIC available as a specialisation (`nixos-rebuild switch --specialisation cosmic`)
- Gaming — Steam, Gamemode, Gamescope, Lossless Scaling (`lsfg-vk`)
- AMD GPU management via LACT
- CoolerControl for fan curves
- Impermanence (ephemeral root)
- iwd as the Wi-Fi backend
- VSCodium as `$EDITOR`/`$VISUAL`
## Desktop Specialisations
| Specialisation | Description |
|---|---|
| *(default)* | GNOME |
| `cosmic` | COSMIC DE (enables `mjallen.desktop.cosmic`, disables GNOME/Hyprland) |
## Network
- **Hostname**: matt-nixos
- **Wi-Fi backend**: iwd (via NetworkManager)
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config |
| `boot.nix` | Lanzaboote, kernel |
| `filesystems.nix` | Disk layout |
| `sops.nix` | Secret declarations |
| `wifi-fixer.nix` | NetworkManager Wi-Fi workaround |
| `services/lsfg-vk/` | Lossless Scaling frame generation |
| `services/ratbagd/` | Gaming mouse config (libratbag) |
| `services/restic/` | Restic backup jobs |
## Secrets
Secrets are in `secrets/desktop-secrets.yaml`, encrypted for: `matt`, `desktop`, `admin`, `jallen-nas`.

57
docs/systems/nuc-nixos.md Executable file
View File

@@ -0,0 +1,57 @@
# Intel NUC (nuc-nixos)
`systems/x86_64-linux/nuc-nixos/`
## Hardware
- **Device**: Intel NUC
- **Disk**: btrfs with LUKS encryption
- **Security**: TPM2, Lanzaboote (Secure Boot)
- **Kernel**: CachyOS `linux-cachyos-lto` (x86_64-v4 build)
## Key Features
- Headless server (no display manager, watchdog enabled)
- Home Assistant — the primary smart home controller
- OpenThread Border Router (OTBR) for Matter/Thread devices
- Impermanence (ephemeral root, persistent state for HA and related services)
- btrfs filesystem (unlike the bcachefs-based NAS and Pi5)
## Network
- **LAN IP**: 10.0.1.4 (static, `enp2s0`)
- **Gateway / DNS**: 10.0.1.1
- **Firewall**: 1883 (MQTT), 8880/8881 (OTBR), 8192
## Services
| Service | Port | Description |
|---|---|---|
| Home Assistant | 8097 | Smart home controller |
| Mosquitto (MQTT) | 1883 | IoT message broker |
| Zigbee2MQTT | 8080 | Zigbee device bridge |
| Music Assistant | 8095 | Music streaming |
| OTBR | 8880/8881 | OpenThread Border Router (Matter/Thread) |
| ESPHome | — | ESP microcontroller firmware |
| PostgreSQL | — | HA database backend |
## Persistent Directories
The following directories survive reboots via impermanence:
- `/esphome`
- `/var/lib/homeassistant`
- `/var/lib/mosquitto`
- `/var/lib/music-assistant`
- `/var/lib/postgresql`
- `/var/lib/zigbee2mqtt`
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | All config in one file — HA, OTBR, network, hardware, impermanence |
## Secrets
Secrets are in `secrets/nuc-secrets.yaml`, encrypted for: `nuc`, `admin_nuc`, `matt`, `admin`, `jallen-nas`.

62
docs/systems/pi5.md Executable file
View File

@@ -0,0 +1,62 @@
# Raspberry Pi 5 (pi5)
`systems/aarch64-linux/pi5/`
## Hardware
- **Board**: Raspberry Pi 5
- **Boot**: UEFI (via `rpi5-uefi`)
- **Storage**: bcachefs
- **Connectivity**: Ethernet (`end0`); Wi-Fi and Bluetooth disabled via device tree overlays
## Key Features
- Headless server (no display, no desktop)
- Nebula VPN **lighthouse** — the central relay for the `jallen-nebula` overlay network
- AdGuard Home DNS server (port 53)
- Docker
- Impermanence (ephemeral root)
- Extensive Raspberry Pi device tree overlays configured (I²C, SPI, UART, SDIO, etc.)
## Network
- **LAN IP**: 10.0.1.2 (static, `end0`)
- **Gateway**: 10.0.1.1
- **DNS**: 1.1.1.1
- **Nebula**: lighthouse at `10.1.1.1`, listening on UDP 4242 (public: `mjallen.dev:4242`)
- Firewall: TCP/UDP 53 open (DNS)
## Nebula Lighthouse
The pi5 acts as the Nebula VPN lighthouse for the whole network. All other Nebula nodes connect to it to discover peers.
```nix
mjallen.services.nebula = {
enable = true;
isLighthouse = true;
port = 4242;
secretsPrefix = "pi5/nebula";
secretsFile = lib.snowfall.fs.get-file "secrets/pi5-secrets.yaml";
hostSecretName = "lighthouse";
};
```
## Services
| Service | Port | Description |
|---|---|---|
| AdGuard Home | 53 | DNS ad-blocking |
| Nebula | 4242 (UDP) | VPN lighthouse |
## Configuration Files
| File | Purpose |
|---|---|
| `default.nix` | Main config |
| `boot.nix` | UEFI boot, kernel |
| `adguard.nix` | AdGuard Home configuration |
| `sops.nix` | Secret declarations (SSH keys, system keys) |
## Secrets
Secrets are in `secrets/pi5-secrets.yaml`, encrypted for: `matt`, `matt_pi5`, `desktop`, `pi5`, `admin`, `jallen-nas`.

354
docs/troubleshooting.md Normal file → Executable file
View File

@@ -1,213 +1,217 @@
# Troubleshooting Guide # Troubleshooting Guide
This guide provides solutions for common issues that may arise when using this NixOS configuration. Common issues and solutions for this NixOS configuration.
## System Issues ## Build Failures
### Failed System Build ### `nixos-rebuild switch` fails
**Problem**: `nixos-rebuild switch` fails with an error. 1. **Syntax error** — the error message includes the file and line number. Common causes: missing `;`, unmatched `{`, wrong type passed to an option.
**Solutions**: 2. **Evaluation error** — read the full error trace. Often caused by a module option receiving the wrong type, or a missing `cfg.enable` guard.
1. **Syntax Errors**: 3. **Fetch failure** — a flake input or package source can't be downloaded. Check network connectivity, or try:
- Check the error message for file and line number information ```bash
- Verify the syntax in the mentioned file nix flake update --update-input <input-name>
- Common issues include missing semicolons, curly braces, or mismatched quotes
2. **Missing Dependencies**:
- If the error mentions a missing package or dependency:
```
git pull # Update to the latest version
nix flake update # Update the flake inputs
```
3. **Conflicting Modules**:
- Look for modules that might be configuring the same options incompatibly
- Disable one of the conflicting modules or adjust their configurations
4. **Disk Space Issues**:
- Check available disk space with `df -h`
- Clear old generations: `sudo nix-collect-garbage -d`
### Boot Issues
**Problem**: System fails to boot after a configuration change.
**Solutions**:
1. **Boot into a Previous Generation**:
- At the boot menu, select an older generation
- Once booted, revert the problematic change:
```
cd /etc/nixos
git revert HEAD # Or edit the files directly
sudo nixos-rebuild switch
```
2. **Boot from Installation Media**:
- Boot from a NixOS installation media
- Mount your system:
```
sudo mount /dev/disk/by-label/nixos /mnt
sudo mount /dev/disk/by-label/boot /mnt/boot # If separate boot partition
```
- Chroot into your system:
```
sudo nixos-enter --root /mnt
cd /etc/nixos
git revert HEAD # Or edit the files directly
nixos-rebuild switch --install-bootloader
```
## Home Assistant Issues
### Home Assistant Fails to Start
**Problem**: Home Assistant service fails to start.
**Solutions**:
1. **Check Service Status**:
```
systemctl status home-assistant
journalctl -u home-assistant -n 100
``` ```
2. **Database Issues**: 4. **Disk space** — build sandbox fills up. Free space:
- Check PostgreSQL is running: `systemctl status postgresql` ```bash
- Verify database connection settings in Home Assistant configuration sudo nix-collect-garbage -d
df -h /nix
3. **Permission Issues**:
- Check ownership and permissions on config directory:
```
ls -la /var/lib/homeassistant
sudo chown -R hass:hass /var/lib/homeassistant
sudo chmod -R 750 /var/lib/homeassistant
```
4. **Custom Component Issues**:
- Try disabling custom components to isolate the issue:
- Edit `modules/nixos/homeassistant/services/homeassistant/default.nix`
- Comment out the `customComponents` section
- Rebuild: `sudo nixos-rebuild switch`
### Zigbee Device Connection Issues
**Problem**: Zigbee devices fail to connect or are unstable.
**Solutions**:
1. **Verify Device Path**:
- Check the Zigbee coordinator is properly detected:
```
ls -la /dev/ttyUSB*
```
- Update the device path if needed:
- Edit your system configuration
- Set `mjallen.services.home-assistant.zigbeeDevicePath` to the correct path
- Rebuild: `sudo nixos-rebuild switch`
2. **Interference Issues**:
- Move the Zigbee coordinator away from other wireless devices
- Try a USB extension cable to improve positioning
- Change Zigbee channel in Zigbee2MQTT configuration
3. **Reset Zigbee2MQTT**:
```
systemctl restart zigbee2mqtt
``` ```
### Automation Issues ### Assertion failures
**Problem**: Automations don't run as expected. If you see `assertion failed`, read the `message` field. For example:
```
error: assertion failed at …/nebula/sops.nix
mjallen.services.nebula.secretsPrefix must be set
```
Set the required option in the system configuration.
**Solutions**: ## Boot Issues
1. **Check Automation Status**: ### System won't boot after a config change
- In Home Assistant UI, verify the automation is enabled
- Check Home Assistant logs for automation execution errors
2. **Entity Issues**: 1. At the boot menu, select a previous generation.
- Verify entity IDs are correct 2. Once booted, revert the change:
- Check if entities are available/connected ```bash
- Test direct service calls to verify entity control works cd /etc/nixos
git revert HEAD
sudo nixos-rebuild switch --flake .#$(hostname)
```
3. **Trigger Issues**: ### Booting from installation media to recover
- Test the automation manually via Developer Tools > Services
- Use `automation.trigger` service with the automation's entity_id
## Flake Issues ```bash
# Mount the system (adjust device paths as needed)
sudo mount /dev/disk/by-label/nixos /mnt
sudo mount /dev/disk/by-label/boot /mnt/boot
### Flake Input Update Errors # Chroot in
sudo nixos-enter --root /mnt
cd /etc/nixos
**Problem**: `nix flake update` fails or causes issues. # Revert and rebuild
git revert HEAD
nixos-rebuild switch --flake .#hostname --install-bootloader
```
**Solutions**: ### Lanzaboote / Secure Boot issues
1. **Selective Updates**: If Secure Boot enrolment fails or the system won't verify:
- Update specific inputs instead of all at once:
```
nix flake lock --update-input nixpkgs
```
2. **Rollback Flake Lock**: ```bash
- If an update causes issues, revert to previous flake.lock: # Check enrolled keys
``` sbctl status
git checkout HEAD^ -- flake.lock
```
3. **Pin to Specific Revisions**: # Re-enrol if needed (run as root)
- In `flake.nix`, pin problematic inputs to specific revisions: sbctl enrol-keys --microsoft
```nix
nixpkgs-stable.url = "github:NixOS/nixpkgs/5233fd2ba76a3accb05f88b08917450363be8899";
```
## Secret Management Issues # Sign bootloader files manually
sbctl sign -s /boot/EFI/systemd/systemd-bootx64.efi
```
### Sops Decryption Errors ## SOPS / Secrets Issues
**Problem**: Sops fails to decrypt secrets. ### `secret not found` or permission denied at boot
**Solutions**: 1. Verify the secret key path matches what's declared in the module's `sops.nix`.
2. Check the secret exists in the SOPS file:
```bash
sops --decrypt secrets/nas-secrets.yaml | grep "the-key"
```
3. Check the `owner`/`group` set on the secret matches the service user.
1. **Key Issues**: ### Can't decrypt — wrong age key
- Verify your GPG key is available and unlocked
- Check `.sops.yaml` includes your key fingerprint
2. **Permission Issues**: The machine's age key is derived from `/etc/ssh/ssh_host_ed25519_key`. If the host key was regenerated, the age key changed and existing secrets can no longer be decrypted.
- Check file permissions on secret files
- Make sure the user running `nixos-rebuild` has access to the GPG key To fix: re-encrypt the secrets file with the new public key:
```bash
# Get the new public key
nix-shell -p ssh-to-age --run 'ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub'
# Update .sops.yaml with the new key, then:
sops updatekeys secrets/nas-secrets.yaml
```
### Adding a new secret to an existing file
```bash
sops secrets/nas-secrets.yaml
# Editor opens with decrypted YAML — add your key, save, sops re-encrypts
```
## Nebula VPN Issues
### Peers can't connect
1. Verify the lighthouse is reachable on its public address:
```bash
nc -zvu mjallen.dev 4242
```
2. Check the nebula service on both hosts:
```bash
systemctl status nebula@jallen-nebula
journalctl -u nebula@jallen-nebula -n 50
```
3. Confirm the CA cert, host cert, and host key are all present and owned by the `nebula-jallen-nebula` user:
```bash
ls -la /run/secrets/pi5/nebula/
```
4. Verify the host cert was signed by the same CA as the other nodes:
```bash
nebula-cert verify -ca ca.crt -crt host.crt
```
### Certificate expired
Re-sign the host certificate:
```bash
nebula-cert sign -name "hostname" -ip "10.1.1.x/24" \
-ca-crt ca.crt -ca-key ca.key \
-out-crt host.crt -out-key host.key
# Update SOPS, rebuild
```
## Impermanence Issues
### Service fails because its data directory is missing after reboot
If a service stores state in a path that isn't in the persistence list, it will be wiped on reboot. Add it to `impermanence.extraDirectories`:
```nix
mjallen.impermanence.extraDirectories = [
{ directory = "/var/lib/my-service"; user = "my-service"; group = "my-service"; mode = "0750"; }
];
```
Then move the existing data if needed:
```bash
cp -a /var/lib/my-service /persist/var/lib/my-service
```
## Flake Input Issues
### Input update breaks a build
Roll back the specific input:
```bash
git checkout HEAD^ -- flake.lock
```
Or pin the input to a specific revision in `flake.nix`:
```nix
nixpkgs-unstable.url = "github:NixOS/nixpkgs/abc123def";
```
## Service Issues
### Service won't start
```bash
systemctl status <service>
journalctl -u <service> -n 100 --no-pager
```
### Caddy reverse proxy not routing
1. Check that `reverseProxy.enable = true` is set on the service.
2. Verify the subdomain matches: `reverseProxy.subdomain = "myapp"` → `myapp.mjallen.dev`.
3. Check Caddy logs:
```bash
journalctl -u caddy -n 50
```
### PostgreSQL database missing for a service
If `configureDb = true` is set, the database is created automatically. If it's missing:
```bash
sudo -u postgres createdb my-service
sudo -u postgres psql -c "GRANT ALL ON DATABASE my-service TO my-service;"
```
## Network Issues ## Network Issues
### Firewall Blocks Services ### Firewall blocking a service
**Problem**: Services are not accessible due to firewall rules. Check which ports are open:
```bash
sudo nft list ruleset | grep accept
```
**Solutions**: Add ports in the system config:
```nix
mjallen.network.firewall.allowedTCPPorts = [ 8080 ];
```
1. **Check Firewall Status**: Or if using `mkModule`, set `openFirewall = true` (it's the default).
```
sudo nix-shell -p iptables --run "iptables -L"
```
2. **Verify Firewall Configuration**:
- Check if ports are properly allowed in the configuration
- Add missing ports if necessary
3. **Temporary Disable Firewall** (for testing only):
```
sudo systemctl stop firewall
# After testing
sudo systemctl start firewall
```
## Getting Help ## Getting Help
If you encounter an issue not covered in this guide: - NixOS manual: `nixos-help` or https://nixos.org/manual/nixos/stable/
- NixOS Wiki: https://nixos.wiki/
1. Check the NixOS Wiki: https://nixos.wiki/ - NixOS Discourse: https://discourse.nixos.org/
2. Search the NixOS Discourse forum: https://discourse.nixos.org/ - Nix package search: https://search.nixos.org/packages
3. Join the NixOS Matrix/Discord community for real-time help
4. File an issue in the repository if you believe you've found a bug

2
docs/version.schema.json Normal file → Executable file
View File

@@ -76,6 +76,7 @@
"repo": { "type": "string", "description": "GitHub repository (github fetcher)." }, "repo": { "type": "string", "description": "GitHub repository (github fetcher)." },
"tag": { "type": "string", "description": "Git tag (github fetcher). Mutually exclusive with 'rev'." }, "tag": { "type": "string", "description": "Git tag (github fetcher). Mutually exclusive with 'rev'." },
"rev": { "type": "string", "description": "Commit revision (github/git fetchers)." }, "rev": { "type": "string", "description": "Commit revision (github/git fetchers)." },
"branch": { "type": "string", "description": "Branch to track for HEAD-commit updates (github/git fetchers). Stored alongside 'rev' to record which branch the pinned commit came from. Has no effect on the Nix fetcher itself — only used by the version management tooling." },
"submodules": { "type": "boolean", "description": "Whether to fetch submodules (github/git fetchers)." }, "submodules": { "type": "boolean", "description": "Whether to fetch submodules (github/git fetchers)." },
"url": { "type": "string", "description": "Final URL (url fetcher). May be templated." }, "url": { "type": "string", "description": "Final URL (url fetcher). May be templated." },
@@ -157,6 +158,7 @@
"repo": { "type": "string" }, "repo": { "type": "string" },
"tag": { "type": "string" }, "tag": { "type": "string" },
"rev": { "type": "string" }, "rev": { "type": "string" },
"branch": { "type": "string" },
"submodules": { "type": "boolean" }, "submodules": { "type": "boolean" },
"url": { "type": "string" }, "url": { "type": "string" },

432
flake.lock generated Normal file → Executable file
View File

@@ -25,7 +25,7 @@
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"napalm": "napalm", "napalm": "napalm",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs-stable"
], ],
"pyproject-build-systems": "pyproject-build-systems", "pyproject-build-systems": "pyproject-build-systems",
"pyproject-nix": "pyproject-nix", "pyproject-nix": "pyproject-nix",
@@ -33,11 +33,11 @@
"uv2nix": "uv2nix" "uv2nix": "uv2nix"
}, },
"locked": { "locked": {
"lastModified": 1772909021, "lastModified": 1776085803,
"narHash": "sha256-hcstQ1Z9aQSJM3AVCLb0/OPTicbME9nhP01GiPrOjZM=", "narHash": "sha256-JvvWVbXJYSY8qOReMbAOD4lxcN2cjKV6lg/jLz8CEuY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "authentik-nix", "repo": "authentik-nix",
"rev": "7e4730351fb6df479c46a1bf7e23d46a0b0c5d46", "rev": "4370b561c8bafb59773ce3a518506bcf1161dbdb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -49,16 +49,16 @@
"authentik-src": { "authentik-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1772567399, "lastModified": 1775573258,
"narHash": "sha256-0Vpf1hj9C8r+rhrCgwoNazpQ+mwgjdjDhuoKCxYQFWw=", "narHash": "sha256-Xq7JGI/8ppIydIuWd9KRJKUrh7UpeniwvZ4NAtXbYJ4=",
"owner": "goauthentik", "owner": "goauthentik",
"repo": "authentik", "repo": "authentik",
"rev": "0dccbd4193c45c581e9fb7cd89df0c1487510f1f", "rev": "5249546862986202b901c2afd860992ec48c6ef6",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "goauthentik", "owner": "goauthentik",
"ref": "version/2026.2.1", "ref": "version/2026.2.2",
"repo": "authentik", "repo": "authentik",
"type": "github" "type": "github"
} }
@@ -134,16 +134,16 @@
"brew-src": { "brew-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1769363988, "lastModified": 1774235677,
"narHash": "sha256-BiGPeulrDVetXP+tjxhMcGLUROZAtZIhU5m4MqawCfM=", "narHash": "sha256-0ryNYmzDAeRlrzPTAgmzGH/Cgc8iv/LBN6jWGUANvIk=",
"owner": "Homebrew", "owner": "Homebrew",
"repo": "brew", "repo": "brew",
"rev": "d01011cac6d72032c75fd2cd9489909e95d9faf2", "rev": "894a3d23ac0c8aaf561b9874b528b9cb2e839201",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "Homebrew", "owner": "Homebrew",
"ref": "5.0.12", "ref": "5.1.1",
"repo": "brew", "repo": "brew",
"type": "github" "type": "github"
} }
@@ -151,11 +151,11 @@
"cachyos-kernel": { "cachyos-kernel": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1773637879, "lastModified": 1776608760,
"narHash": "sha256-hFKu2SaRoqt6+zbmcFW6A0AbBENIX8XooJLXQWa3sLc=", "narHash": "sha256-ehDv8bF7k/2Kf4b8CCoSm51U/MOoFuLsRXqe5wZ57sE=",
"owner": "CachyOS", "owner": "CachyOS",
"repo": "linux-cachyos", "repo": "linux-cachyos",
"rev": "fa09a5bc69d3e7feeed9b1402c7df06c8170402a", "rev": "7e06e29005853bbaaa3b1c1067f915d6e0db728a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -167,11 +167,11 @@
"cachyos-kernel-patches": { "cachyos-kernel-patches": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1773635524, "lastModified": 1776355454,
"narHash": "sha256-JErpxWTdoHq4JuDerfsbPA60FmWOxK4oX9UL9CcsP/Q=", "narHash": "sha256-b9Hc0sTxjEzDbphzS9yQqxVha/7bsPIs2cQQQvaG45E=",
"owner": "CachyOS", "owner": "CachyOS",
"repo": "kernel-patches", "repo": "kernel-patches",
"rev": "5544a0679fd6f6fb714e275514449c4ab9db2a53", "rev": "b5e029226df5cc30c103651072d49a7af2878202",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -223,11 +223,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1773000227, "lastModified": 1775037210,
"narHash": "sha256-zm3ftUQw0MPumYi91HovoGhgyZBlM4o3Zy0LhPNwzXE=", "narHash": "sha256-KM2WYj6EA7M/FVZVCl3rqWY+TFV5QzSyyGE2gQxeODU=",
"owner": "nix-darwin", "owner": "nix-darwin",
"repo": "nix-darwin", "repo": "nix-darwin",
"rev": "da529ac9e46f25ed5616fd634079a5f3c579135f", "rev": "06648f4902343228ce2de79f291dd5a58ee12146",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -244,11 +244,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773889306, "lastModified": 1776613567,
"narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=", "narHash": "sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "5ad85c82cc52264f4beddc934ba57f3789f28347", "rev": "32f4236bfc141ae930b5ba2fb604f561fed5219d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -260,11 +260,11 @@
"firefox-gnome-theme": { "firefox-gnome-theme": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1764873433, "lastModified": 1775176642,
"narHash": "sha256-1XPewtGMi+9wN9Ispoluxunw/RwozuTRVuuQOmxzt+A=", "narHash": "sha256-2veEED0Fg7Fsh81tvVDNYR6SzjqQxa7hbi18Jv4LWpM=",
"owner": "rafaelmardojai", "owner": "rafaelmardojai",
"repo": "firefox-gnome-theme", "repo": "firefox-gnome-theme",
"rev": "f7ffd917ac0d253dbd6a3bf3da06888f57c69f92", "rev": "179704030c5286c729b5b0522037d1d51341022c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -353,6 +353,22 @@
} }
}, },
"flake-compat_6": { "flake-compat_6": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_7": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1767039857, "lastModified": 1767039857,
@@ -391,11 +407,11 @@
"nixpkgs-lib": "nixpkgs-lib_2" "nixpkgs-lib": "nixpkgs-lib_2"
}, },
"locked": { "locked": {
"lastModified": 1772408722, "lastModified": 1730504689,
"narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=", "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3", "rev": "506278e768c2a08bec68eb62932193e341f55c90",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -405,6 +421,24 @@
} }
}, },
"flake-parts_3": { "flake-parts_3": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_3"
},
"locked": {
"lastModified": 1775087534,
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_4": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"stylix", "stylix",
@@ -412,11 +446,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1767609335, "lastModified": 1775087534,
"narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=", "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "250481aafeb741edfe23d29195671c19b36b6dca", "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -545,20 +579,18 @@
"gnome-shell": { "gnome-shell": {
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.gnome.org",
"lastModified": 1767737596, "lastModified": 1767737596,
"narHash": "sha256-eFujfIUQDgWnSJBablOuG+32hCai192yRdrNHTv0a+s=", "narHash": "sha256-eFujfIUQDgWnSJBablOuG+32hCai192yRdrNHTv0a+s=",
"owner": "GNOME", "owner": "GNOME",
"repo": "gnome-shell", "repo": "gnome-shell",
"rev": "ef02db02bf0ff342734d525b5767814770d85b49", "rev": "ef02db02bf0ff342734d525b5767814770d85b49",
"type": "gitlab" "type": "github"
}, },
"original": { "original": {
"host": "gitlab.gnome.org",
"owner": "GNOME", "owner": "GNOME",
"ref": "gnome-49",
"repo": "gnome-shell", "repo": "gnome-shell",
"type": "gitlab" "rev": "ef02db02bf0ff342734d525b5767814770d85b49",
"type": "github"
} }
}, },
"home-manager": { "home-manager": {
@@ -568,11 +600,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1774007980, "lastModified": 1776701552,
"narHash": "sha256-FOnZjElEI8pqqCvB6K/1JRHTE8o4rer8driivTpq2uo=", "narHash": "sha256-CCRzOEFg6JwCdZIR5dLD0ypah5/e2JQVuWQ/l3rYrPY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "9670de2921812bc4e0452f6e3efd8c859696c183", "rev": "c81775b640d4507339d127f5adb4105f6015edf2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -581,27 +613,6 @@
"type": "github" "type": "github"
} }
}, },
"home-manager-stable": {
"inputs": {
"nixpkgs": [
"nixpkgs-stable"
]
},
"locked": {
"lastModified": 1773963144,
"narHash": "sha256-WzBOBfSay3GYilUfKaUa1Mbf8/jtuAiJIedx7fWuIX4=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "a91b3ea73a765614d90360580b689c48102d1d33",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-25.11",
"repo": "home-manager",
"type": "github"
}
},
"home-manager-unstable": { "home-manager-unstable": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -609,11 +620,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1774007980, "lastModified": 1776701552,
"narHash": "sha256-FOnZjElEI8pqqCvB6K/1JRHTE8o4rer8driivTpq2uo=", "narHash": "sha256-CCRzOEFg6JwCdZIR5dLD0ypah5/e2JQVuWQ/l3rYrPY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "9670de2921812bc4e0452f6e3efd8c859696c183", "rev": "c81775b640d4507339d127f5adb4105f6015edf2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -663,11 +674,11 @@
"homebrew-cask": { "homebrew-cask": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1774025771, "lastModified": 1776714912,
"narHash": "sha256-3eMajNhR25AX9Dc9DgR3+cW4215kj/KRIuVyP9+X2/I=", "narHash": "sha256-lnjpoBDRl79Vv5QD8bT/uwcsJ1QeybUpJY2l0ss4XSc=",
"owner": "homebrew", "owner": "homebrew",
"repo": "homebrew-cask", "repo": "homebrew-cask",
"rev": "f69327f0a37edd3197c8e9cf1f34822025251627", "rev": "bac9d4b1c57d4598bee2e218a93741e0440ad3c5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -679,11 +690,11 @@
"homebrew-core": { "homebrew-core": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1774028436, "lastModified": 1776719628,
"narHash": "sha256-mCYHZLfcOfLnNAfTOorW89fzXnmUTwOOwFmQxMViLoc=", "narHash": "sha256-nKQfhlIoKUBGdTkQu6aeTaWfl3psLabChbgQxqgBwmE=",
"owner": "homebrew", "owner": "homebrew",
"repo": "homebrew-core", "repo": "homebrew-core",
"rev": "c5fc98d84606cc1ad94eeb0b61bc7b7c352f35ed", "rev": "1ccb99d5816869a19101857be822286166219c5f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -719,11 +730,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773949806, "lastModified": 1776428236,
"narHash": "sha256-W25eg57cTQSwey9nEf1AhHy895Yiwq74PgyJl2EuY3Q=", "narHash": "sha256-+0SyQglnT2xUiyY07155G+O7aUWISELwqtTnfURufRU=",
"owner": "Jovian-Experiments", "owner": "Jovian-Experiments",
"repo": "Jovian-NixOS", "repo": "Jovian-NixOS",
"rev": "425b357e190632600ca2b2daea3bdf28d57e3047", "rev": "eac78fc379ca47f7e21be8539c405e5fb489a857",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -754,6 +765,27 @@
"type": "github" "type": "github"
} }
}, },
"llama-cpp": {
"inputs": {
"flake-parts": "flake-parts_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1776706879,
"narHash": "sha256-oXm8IABJ82VmuNvR1ttzrN7augbvMKWcLvC/5KM9ODE=",
"owner": "ggml-org",
"repo": "llama.cpp",
"rev": "cf8b0dbda9ac0eac30ee33f87bc6702ead1c4664",
"type": "github"
},
"original": {
"owner": "ggml-org",
"repo": "llama.cpp",
"type": "github"
}
},
"lsfg-vk": { "lsfg-vk": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -805,15 +837,15 @@
"cachyos-kernel": "cachyos-kernel", "cachyos-kernel": "cachyos-kernel",
"cachyos-kernel-patches": "cachyos-kernel-patches", "cachyos-kernel-patches": "cachyos-kernel-patches",
"flake-compat": "flake-compat_4", "flake-compat": "flake-compat_4",
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts_3",
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
}, },
"locked": { "locked": {
"lastModified": 1773804995, "lastModified": 1776622065,
"narHash": "sha256-LL6EG35pbxgjsqYIpwUnpHGDmKFYttE+BILBNhsEaJk=", "narHash": "sha256-yv+04KR/xndDJ8lID/LHpMuYhMCrQfR58ABGTl2OyQ0=",
"owner": "xddxdd", "owner": "xddxdd",
"repo": "nix-cachyos-kernel", "repo": "nix-cachyos-kernel",
"rev": "3286b7ecf1d864e2be050af78aa633d4e3ae8fdb", "rev": "61a3cabe264695c487c6266a7536e5806323985e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -850,11 +882,11 @@
"brew-src": "brew-src" "brew-src": "brew-src"
}, },
"locked": { "locked": {
"lastModified": 1769437432, "lastModified": 1774720267,
"narHash": "sha256-8d7KnCpT2LweRvSzZYEGd9IM3eFX+A78opcnDM0+ndk=", "narHash": "sha256-YYftFe8jyfpQI649yfr0E+dqEXE2jznZNcYvy/lKV1U=",
"owner": "zhaofengli", "owner": "zhaofengli",
"repo": "nix-homebrew", "repo": "nix-homebrew",
"rev": "a5409abd0d5013d79775d3419bcac10eacb9d8c5", "rev": "a7760a3a83f7609f742861afb5732210fdc437ed",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -870,11 +902,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773552174, "lastModified": 1776575850,
"narHash": "sha256-mHSRNrT1rjeYBgkAlj07dW3+1nFEgAd8Gu6lgyfT9DU=", "narHash": "sha256-28Gqz0GDpGsBv8GtAn2dywEQRr+CtTDsD5J7VD6icBE=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-index-database", "repo": "nix-index-database",
"rev": "8faeb68130df077450451b6734a221ba0d6cde42", "rev": "3b9653a107c736222b5ae0d4036dd3b885219065",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -927,11 +959,11 @@
"nixpkgs": "nixpkgs_7" "nixpkgs": "nixpkgs_7"
}, },
"locked": { "locked": {
"lastModified": 1773974569, "lastModified": 1776656326,
"narHash": "sha256-Y71Afv2mVpus+EqUj0qAwPgyaABIvEtjnUAlw5EUo3A=", "narHash": "sha256-cUPRTkwfunNVuPef4KCFqHaLvBjCbqma2hGtHT77YJM=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-vscode-extensions", "repo": "nix-vscode-extensions",
"rev": "5b8548f9e2cbe14146df30858bd281404957846f", "rev": "3dfd035bedf934bf8bd42ca1297db34a87e0c31d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -946,11 +978,11 @@
"nixpkgs": "nixpkgs_8" "nixpkgs": "nixpkgs_8"
}, },
"locked": { "locked": {
"lastModified": 1773418853, "lastModified": 1776370524,
"narHash": "sha256-ELGvz8LW3fEzBTO1FpojRAPqp7+9xs5lspZb9NoZrbY=", "narHash": "sha256-0Gt5qnjNkIZJdOBfu2u47zgyhYL3WmgUrguUhGSxUdk=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixos-apple-silicon", "repo": "nixos-apple-silicon",
"rev": "2fbdf62451bcd9fc83ca99c56a6e379df8c47c8d", "rev": "f9f0650b45e31b3f6c3e2a0405fa198a286e2741",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -961,11 +993,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1774018263, "lastModified": 1775490113,
"narHash": "sha256-HHYEwK1A22aSaxv2ibhMMkKvrDGKGlA/qObG4smrSqc=", "narHash": "sha256-2ZBhDNZZwYkRmefK5XLOusCJHnoeKkoN95hoSGgMxWM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "2d4b4717b2534fad5c715968c1cece04a172b365", "rev": "c775c2772ba56e906cbeb4e0b2db19079ef11ff7",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -975,6 +1007,26 @@
"type": "github" "type": "github"
} }
}, },
"nixos-wsl": {
"inputs": {
"flake-compat": "flake-compat_6",
"nixpkgs": "nixpkgs_9"
},
"locked": {
"lastModified": 1776692876,
"narHash": "sha256-7Q05rUgwbkJnjxIJyi8bHUG+XnyZqLxFJz7c8RncpeU=",
"owner": "nix-community",
"repo": "NixOS-WSL",
"rev": "51b302c28dbf904a5c341be005eebe0779cf4f16",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "main",
"repo": "NixOS-WSL",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1765934234, "lastModified": 1765934234,
@@ -1008,32 +1060,28 @@
}, },
"nixpkgs-lib_2": { "nixpkgs-lib_2": {
"locked": { "locked": {
"lastModified": 1772328832, "lastModified": 1730504152,
"narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=", "narHash": "sha256-lXvH/vOfb4aGYyvFmZK/HlsNsr/0CVWlwYvo2rxJk3s=",
"owner": "nix-community", "type": "tarball",
"repo": "nixpkgs.lib", "url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
"rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742",
"type": "github"
}, },
"original": { "original": {
"owner": "nix-community", "type": "tarball",
"repo": "nixpkgs.lib", "url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
"type": "github"
} }
}, },
"nixpkgs-otbr": { "nixpkgs-lib_3": {
"locked": { "locked": {
"lastModified": 1766776257, "lastModified": 1774748309,
"narHash": "sha256-MG9DnzBn6TdAztaMPVhW9sjYj2bi9Jcux0F0fJ6LeO4=", "narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=",
"owner": "mrene", "owner": "nix-community",
"repo": "nixpkgs", "repo": "nixpkgs.lib",
"rev": "0c4c97066d555b7d27a0a56ee400130ec51f02ee", "rev": "333c4e0545a6da976206c74db8773a1645b5870a",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "mrene", "owner": "nix-community",
"ref": "openthread-border-router", "repo": "nixpkgs.lib",
"repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
@@ -1055,11 +1103,11 @@
}, },
"nixpkgs-stable_2": { "nixpkgs-stable_2": {
"locked": { "locked": {
"lastModified": 1773814637, "lastModified": 1776434932,
"narHash": "sha256-GNU+ooRmrHLfjlMsKdn0prEKVa0faVanm0jrgu1J/gY=", "narHash": "sha256-gyqXNMgk3sh+ogY5svd2eNLJ6oEwzbAeaoBrrxD0lKk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "fea3b367d61c1a6592bc47c72f40a9f3e6a53e96", "rev": "c7f47036d3df2add644c46d712d14262b7d86c0c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1071,27 +1119,43 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1773821835, "lastModified": 1776635459,
"narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", "narHash": "sha256-3UVWm751p/8VAY1Mq+DgSTCv9HpMmdB2byhnRrVKflk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", "rev": "8d8538e67e516362d9d09ee5d3ce73dce944612b",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-unstable", "ref": "nixos-unstable-small",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs_10": { "nixpkgs_10": {
"locked": { "locked": {
"lastModified": 1773507054, "lastModified": 1776447299,
"narHash": "sha256-Q8U5VXgrcxmCxPtCCJCIZkcAX3FCZwGh1GNVIXxMND0=", "narHash": "sha256-fhkbQptSg6w3CG4TCxalK6UZkj4+Afsi+6p0PuofJ48=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e80236013dc8b77aa49ca90e7a12d86f5d8d64c9", "rev": "2c1b4e855f7cded41541747173c697b53c63de9b",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable-small",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_11": {
"locked": {
"lastModified": 1775888245,
"narHash": "sha256-nwASzrRDD1JBEu/o8ekKYEXm/oJW6EMCzCRdrwcLe90=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "13043924aaa7375ce482ebe2494338e058282925",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1135,11 +1199,11 @@
}, },
"nixpkgs_4": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1773738184, "lastModified": 1776544041,
"narHash": "sha256-zWRjT5oPabNCiC1A3QkFXpfnsgUjyg6fUZWC+IiiZH0=", "narHash": "sha256-ryzOZLvuS/4ZbYJzR8+wYZpyG/Ssp6BAe6oTQ8ttAqU=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "41a2715cc472025a19bc0eb9dc4ee8b7406bfa6f", "rev": "f731538cdf1410a3c53d3a75a6a1142afc08e3af",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1199,11 +1263,11 @@
}, },
"nixpkgs_8": { "nixpkgs_8": {
"locked": { "locked": {
"lastModified": 1768305791, "lastModified": 1774106199,
"narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=", "narHash": "sha256-US5Tda2sKmjrg2lNHQL3jRQ6p96cgfWh3J1QBliQ8Ws=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e", "rev": "6c9a78c09ff4d6c21d0319114873508a6ec01655",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1215,11 +1279,11 @@
}, },
"nixpkgs_9": { "nixpkgs_9": {
"locked": { "locked": {
"lastModified": 1773821835, "lastModified": 1776635459,
"narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", "narHash": "sha256-3UVWm751p/8VAY1Mq+DgSTCv9HpMmdB2byhnRrVKflk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", "rev": "8d8538e67e516362d9d09ee5d3ce73dce944612b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1241,11 +1305,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1767810917, "lastModified": 1775228139,
"narHash": "sha256-ZKqhk772+v/bujjhla9VABwcvz+hB2IaRyeLT6CFnT0=", "narHash": "sha256-ebbeHmg+V7w8050bwQOuhmQHoLOEOfqKzM1KgCTexK4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "dead29c804adc928d3a69dfe7f9f12d0eec1f1a4", "rev": "601971b9c89e0304561977f2c28fa25e73aa7132",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1254,6 +1318,29 @@
"type": "github" "type": "github"
} }
}, },
"plasma-manager": {
"inputs": {
"home-manager": [
"home-manager"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1775856943,
"narHash": "sha256-b7Mp7P+q2Md5AGt4rjHfMcBykzMumFTen10ST++AuTU=",
"owner": "nix-community",
"repo": "plasma-manager",
"rev": "a524a6160e6df89f7673ba293cf7d78b559eb1a5",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "plasma-manager",
"type": "github"
}
},
"pre-commit": { "pre-commit": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_3",
@@ -1279,18 +1366,18 @@
}, },
"pre-commit-hooks-nix": { "pre-commit-hooks-nix": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_6", "flake-compat": "flake-compat_7",
"gitignore": "gitignore_2", "gitignore": "gitignore_2",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1772893680, "lastModified": 1775585728,
"narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=", "narHash": "sha256-8Psjt+TWvE4thRKktJsXfR6PA/fWWsZ04DVaY6PUhr4=",
"owner": "cachix", "owner": "cachix",
"repo": "pre-commit-hooks.nix", "repo": "pre-commit-hooks.nix",
"rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", "rev": "580633fa3fe5fc0379905986543fd7495481913d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1356,13 +1443,13 @@
"darwin": "darwin", "darwin": "darwin",
"disko": "disko", "disko": "disko",
"home-manager": "home-manager", "home-manager": "home-manager",
"home-manager-stable": "home-manager-stable",
"home-manager-unstable": "home-manager-unstable", "home-manager-unstable": "home-manager-unstable",
"homebrew-cask": "homebrew-cask", "homebrew-cask": "homebrew-cask",
"homebrew-core": "homebrew-core", "homebrew-core": "homebrew-core",
"impermanence": "impermanence", "impermanence": "impermanence",
"jovian": "jovian", "jovian": "jovian",
"lanzaboote": "lanzaboote", "lanzaboote": "lanzaboote",
"llama-cpp": "llama-cpp",
"lsfg-vk": "lsfg-vk", "lsfg-vk": "lsfg-vk",
"nix-cachyos-kernel": "nix-cachyos-kernel", "nix-cachyos-kernel": "nix-cachyos-kernel",
"nix-homebrew": "nix-homebrew", "nix-homebrew": "nix-homebrew",
@@ -1372,10 +1459,11 @@
"nix-vscode-extensions": "nix-vscode-extensions", "nix-vscode-extensions": "nix-vscode-extensions",
"nixos-apple-silicon": "nixos-apple-silicon", "nixos-apple-silicon": "nixos-apple-silicon",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_9", "nixos-wsl": "nixos-wsl",
"nixpkgs-otbr": "nixpkgs-otbr", "nixpkgs": "nixpkgs_10",
"nixpkgs-stable": "nixpkgs-stable_2", "nixpkgs-stable": "nixpkgs-stable_2",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
"plasma-manager": "plasma-manager",
"pre-commit-hooks-nix": "pre-commit-hooks-nix", "pre-commit-hooks-nix": "pre-commit-hooks-nix",
"snowfall-lib": "snowfall-lib", "snowfall-lib": "snowfall-lib",
"sops-nix": "sops-nix", "sops-nix": "sops-nix",
@@ -1435,11 +1523,11 @@
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
"locked": { "locked": {
"lastModified": 1773689564, "lastModified": 1774478645,
"narHash": "sha256-TJmDl89HPGum3srhggVbcfHV5oN6XL5SgN7/dI3kB4M=", "narHash": "sha256-NeEWeisE2QLCCJg688/vaLp9/V7osVenn/EUm3JXsgg=",
"owner": "mjallen18", "owner": "mjallen18",
"repo": "snowfall-lib", "repo": "snowfall-lib",
"rev": "3dd4e430e291d9f7d0e9c69f89fea8c175041e44", "rev": "23e5a04d70389d58b7c1447924d59cfb78218215",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1450,14 +1538,14 @@
}, },
"sops-nix": { "sops-nix": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_10" "nixpkgs": "nixpkgs_11"
}, },
"locked": { "locked": {
"lastModified": 1773889674, "lastModified": 1776119890,
"narHash": "sha256-+ycaiVAk3MEshJTg35cBTUa0MizGiS+bgpYw/f8ohkg=", "narHash": "sha256-Zm6bxLNnEOYuS/SzrAGsYuXSwk3cbkRQZY0fJnk8a5M=",
"owner": "Mic92", "owner": "Mic92",
"repo": "sops-nix", "repo": "sops-nix",
"rev": "29b6519f3e0780452bca0ac0be4584f04ac16cc5", "rev": "d4971dd58c6627bfee52a1ad4237637c0a2fb0cd",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1496,25 +1584,24 @@
"base16-helix": "base16-helix", "base16-helix": "base16-helix",
"base16-vim": "base16-vim", "base16-vim": "base16-vim",
"firefox-gnome-theme": "firefox-gnome-theme", "firefox-gnome-theme": "firefox-gnome-theme",
"flake-parts": "flake-parts_3", "flake-parts": "flake-parts_4",
"gnome-shell": "gnome-shell", "gnome-shell": "gnome-shell",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"nur": "nur", "nur": "nur",
"systems": "systems_3", "systems": "systems_3",
"tinted-foot": "tinted-foot",
"tinted-kitty": "tinted-kitty", "tinted-kitty": "tinted-kitty",
"tinted-schemes": "tinted-schemes", "tinted-schemes": "tinted-schemes",
"tinted-tmux": "tinted-tmux", "tinted-tmux": "tinted-tmux",
"tinted-zed": "tinted-zed" "tinted-zed": "tinted-zed"
}, },
"locked": { "locked": {
"lastModified": 1773792048, "lastModified": 1776170745,
"narHash": "sha256-Oy9PCLG3vtflFBWcJd8c/EB3h5RU7ABAIDWn6JrGf6o=", "narHash": "sha256-Tl1aZVP5EIlT+k0+iAKH018GLHJpLz3hhJ0LNQOWxCc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "stylix", "repo": "stylix",
"rev": "3f2f9d307fe58c6abe2a16eb9b62c42d53ef5ee1", "rev": "e3861617645a43c9bbefde1aa6ac54dd0a44bfa9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1568,23 +1655,6 @@
"type": "github" "type": "github"
} }
}, },
"tinted-foot": {
"flake": false,
"locked": {
"lastModified": 1726913040,
"narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=",
"owner": "tinted-theming",
"repo": "tinted-foot",
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
"type": "github"
},
"original": {
"owner": "tinted-theming",
"repo": "tinted-foot",
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
"type": "github"
}
},
"tinted-kitty": { "tinted-kitty": {
"flake": false, "flake": false,
"locked": { "locked": {
@@ -1604,11 +1674,11 @@
"tinted-schemes": { "tinted-schemes": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1767710407, "lastModified": 1772661346,
"narHash": "sha256-+W1EB79Jl0/gm4JqmO0Nuc5C7hRdp4vfsV/VdzI+des=", "narHash": "sha256-4eu3LqB9tPqe0Vaqxd4wkZiBbthLbpb7llcoE/p5HT0=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "schemes", "repo": "schemes",
"rev": "2800e2b8ac90f678d7e4acebe4fa253f602e05b2", "rev": "13b5b0c299982bb361039601e2d72587d6846294",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1620,11 +1690,11 @@
"tinted-tmux": { "tinted-tmux": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1767489635, "lastModified": 1772934010,
"narHash": "sha256-e6nnFnWXKBCJjCv4QG4bbcouJ6y3yeT70V9MofL32lU=", "narHash": "sha256-x+6+4UvaG+RBRQ6UaX+o6DjEg28u4eqhVRM9kpgJGjQ=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "tinted-tmux", "repo": "tinted-tmux",
"rev": "3c32729ccae99be44fe8a125d20be06f8d7d8184", "rev": "c3529673a5ab6e1b6830f618c45d9ce1bcdd829d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1636,11 +1706,11 @@
"tinted-zed": { "tinted-zed": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1767488740, "lastModified": 1772909925,
"narHash": "sha256-wVOj0qyil8m+ouSsVZcNjl5ZR+1GdOOAooAatQXHbuU=", "narHash": "sha256-jx/5+pgYR0noHa3hk2esin18VMbnPSvWPL5bBjfTIAU=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "base16-zed", "repo": "base16-zed",
"rev": "11abb0b282ad3786a2aae088d3a01c60916f2e40", "rev": "b4d3a1b3bcbd090937ef609a0a3b37237af974df",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -1678,11 +1748,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1773297127, "lastModified": 1775636079,
"narHash": "sha256-6E/yhXP7Oy/NbXtf1ktzmU8SdVqJQ09HC/48ebEGBpk=", "narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
"owner": "numtide", "owner": "numtide",
"repo": "treefmt-nix", "repo": "treefmt-nix",
"rev": "71b125cd05fbfd78cab3e070b73544abe24c5016", "rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
"type": "github" "type": "github"
}, },
"original": { "original": {

114
flake.nix Normal file → Executable file
View File

@@ -1,16 +1,9 @@
{ {
inputs = rec { inputs = rec {
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11"; nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11";
# Fork required: openthread-border-router is not yet in nixpkgs-unstable. nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
# Used by modules/nixos/homeassistant/services/thread/default.nix
nixpkgs-otbr.url = "github:mrene/nixpkgs/openthread-border-router";
home-manager-stable = {
url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
home-manager-unstable = { home-manager-unstable = {
url = "github:nix-community/home-manager"; url = "github:nix-community/home-manager";
@@ -52,7 +45,7 @@
authentik-nix = { authentik-nix = {
url = "github:nix-community/authentik-nix"; url = "github:nix-community/authentik-nix";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs-stable";
}; };
disko = { disko = {
@@ -116,6 +109,17 @@
url = "github:Jovian-Experiments/Jovian-NixOS"; url = "github:Jovian-Experiments/Jovian-NixOS";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
llama-cpp = {
url = "github:ggml-org/llama.cpp";
inputs.nixpkgs.follows = "nixpkgs";
};
plasma-manager = {
url = "github:nix-community/plasma-manager";
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
};
}; };
# We will handle this in the next section. # We will handle this in the next section.
@@ -133,36 +137,59 @@
overlays = with inputs; [ overlays = with inputs; [
nix-vscode-extensions.overlays.default nix-vscode-extensions.overlays.default
nix-cachyos-kernel.overlays.default nix-cachyos-kernel.overlays.default
# writeShellApplication uses lib.toShellVar which generates unquoted
# variable assignments for simple strings (e.g. username=admin).
# shellcheck SC2209 flags this as a warning, breaking the build when
# the value matches a command name. Exclude SC2209 globally.
(_final: prev: {
writeShellApplication =
args:
prev.writeShellApplication (
args
// {
excludeShellChecks = (args.excludeShellChecks or [ ]) ++ [ "SC2209" ];
}
);
})
]; ];
# Add a module to a specific host. # Add a module to a specific host.
systems = { systems = {
# common modules # common modules
modules.nixos = with inputs; [ modules = {
authentik-nix.nixosModules.default nixos = with inputs; [
disko.nixosModules.disko authentik-nix.nixosModules.default
impermanence.nixosModules.impermanence disko.nixosModules.disko
lanzaboote.nixosModules.lanzaboote impermanence.nixosModules.impermanence
sops-nix.nixosModules.sops lanzaboote.nixosModules.lanzaboote
home-manager.nixosModules.home-manager sops-nix.nixosModules.sops
nix-index-database.nixosModules.nix-index home-manager.nixosModules.home-manager
stylix.nixosModules.stylix nix-index-database.nixosModules.nix-index
]; stylix.nixosModules.stylix
];
modules.home = with inputs; [ # External HM modules injected into ALL homes — both standalone
nix-index-database.homeManagerModules.nix-index # homeConfigurations and homes embedded in nixosConfigurations.
steam-rom-manager.homeManagerModules.default # The snowfall-lib fork patches create-systems to pass systems.modules.home
]; # into create-home-system-modules so both paths are covered from here.
# The ARM guard for steam-rom-manager is handled by that module itself.
home = with inputs; [
nix-index-database.homeModules.nix-index
steam-rom-manager.homeManagerModules.default
sops-nix.homeManagerModules.sops
stylix.homeModules.stylix
plasma-manager.homeModules.plasma-manager
];
# common darwin modules darwin = with inputs; [
modules.darwin = with inputs; [ nix-homebrew.darwinModules.nix-homebrew
nix-homebrew.darwinModules.nix-homebrew home-manager.darwinModules.home-manager
home-manager.darwinModules.home-manager nix-plist-manager.darwinModules.default
nix-plist-manager.darwinModules.default nix-rosetta-builder.darwinModules.default
nix-rosetta-builder.darwinModules.default nix-index-database.darwinModules.nix-index
nix-index-database.darwinModules.nix-index stylix.darwinModules.stylix
stylix.darwinModules.stylix ];
]; };
# Host config # Host config
hosts = { hosts = {
@@ -210,14 +237,6 @@
]; ];
}; };
# ######################################################
# Pi5 #
# ######################################################
pi5 = {
# disko is already in systems.modules.nixos above
modules = [ ];
};
# ###################################################### # ######################################################
# Mac # # Mac #
# ###################################################### # ######################################################
@@ -243,6 +262,15 @@
jovian.nixosModules.jovian jovian.nixosModules.jovian
]; ];
}; };
# ######################################################
# WSL #
# ######################################################
wsl-nixos = {
modules = with inputs; [
nixos-wsl.nixosModules.default
];
};
}; };
}; };
@@ -269,6 +297,10 @@
# ... # ...
# "libsoup-2.74.3" # "libsoup-2.74.3"
# "mbedtls-2.28.10" # "mbedtls-2.28.10"
# ecdsa is pulled in by srp → ha-icloud3 custom component.
# CVE-2024-23342 applies to timing-sensitive cryptographic use cases,
# not the SRP authentication usage here.
"python3.14-ecdsa-0.19.1"
]; ];
}; };

View File

@@ -18,7 +18,7 @@ let
iproute2mac iproute2mac
nebula nebula
nixfmt nixfmt
nodePackages.nodejs nodejs_25
uv uv
sops sops
tree tree

View File

@@ -15,12 +15,14 @@ let
in in
{ {
home.username = "matt"; home = {
home.homeDirectory = "/home/matt"; username = "matt";
home.stateVersion = "23.11"; homeDirectory = "/home/matt";
stateVersion = "23.11";
};
${namespace} = { ${namespace} = {
desktop.gnome = enabled; desktop.plasma = lib.mkForce enabled;
programs.hyprland = { programs.hyprland = {
enable = false; enable = false;
primaryDisplay = "eDP-1"; primaryDisplay = "eDP-1";
@@ -78,12 +80,15 @@ in
}; };
programs = { programs = {
btop = enabled; btop = enabled;
calibre = enabled;
kitty = disabled; kitty = disabled;
mako = disabled; mako = disabled;
nwg-dock = disabled; nwg-dock = disabled;
nwg-drawer = disabled; nwg-drawer = disabled;
nwg-panel = disabled; nwg-panel = disabled;
opencode = enabled; opencode = enabled;
thunderbird = enabled;
vesktop = enabled;
waybar = { waybar = {
enable = false; enable = false;
@@ -122,6 +127,18 @@ in
wlogout = disabled; wlogout = disabled;
wofi = disabled; wofi = disabled;
}; };
services = {
protonmail = enabled;
};
};
sops = {
secrets = {
"protonmail-password" = {
sopsFile = lib.snowfall.fs.get-file "secrets/mac-secrets.yaml";
};
};
}; };
home.packages = home.packages =
@@ -132,14 +149,33 @@ in
] ]
++ (with pkgs; [ ++ (with pkgs; [
bolt-launcher bolt-launcher
bottles
iw iw
iwd iwd
orca-slicer orca-slicer
rpi-imager
vscodium vscodium
gnomeExtensions.notch-clock-offset
]); ]);
# Override the shared Plasma panel to add a standalone battery widget
# (laptop-specific — not needed on desktop systems)
programs.plasma.panels = lib.mkForce [
{
location = "bottom";
floating = true;
height = 44;
widgets = [
"org.kde.plasma.kickoff"
"org.kde.plasma.icontasks"
"org.kde.plasma.marginsseparator"
{ battery = { }; }
"org.kde.plasma.systemtray"
"org.kde.plasma.digitalclock"
];
}
];
services = { services = {
kdeconnect = { kdeconnect = {
enable = lib.mkForce true; enable = lib.mkForce true;
@@ -151,32 +187,4 @@ in
password-store = enabled; password-store = enabled;
}; };
dconf = {
enable = true;
settings = {
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0".name =
"Keyboard Backlight +";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0".binding =
"<Super>MonBrightnessUp";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0".command =
"brightnessctl -d kbd_backlight s +10";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1".name =
"Keyboard Backlight -";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1".binding =
"<Super>MonBrightnessDown";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1".command =
"brightnessctl -d kbd_backlight s 10-";
"org/gnome/shell".enabled-extensions = [
"notch-clock-offset@christophbrill.de"
];
"org/gnome/shell/extensions/notch-clock-offset".percent = 40;
"org/gnome/settings-daemon/plugins/media-keys".custom-keybindings = [
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1/"
];
};
};
} }

View File

@@ -11,10 +11,9 @@ in
home.username = "matt"; home.username = "matt";
${namespace}.sops.enable = true;
sops = { sops = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = { secrets = {
"ssh-keys-public/pi5" = { "ssh-keys-public/pi5" = {
path = "/home/matt/.ssh/id_ed25519.pub"; path = "/home/matt/.ssh/id_ed25519.pub";

View File

@@ -1,6 +1,5 @@
{ {
pkgs, pkgs,
config,
lib, lib,
inputs, inputs,
namespace, namespace,
@@ -10,9 +9,11 @@ let
inherit (lib.${namespace}) enabled; inherit (lib.${namespace}) enabled;
in in
{ {
# steam-rom-manager HM module is needed for the steam-rom-manager program # steam-rom-manager is also injected globally via modules/nixos/home/default.nix
# options. On NixOS hosts it's provided via sharedModules; here we add it # sharedModules for x86_64 NixOS builds. This explicit import ensures it is
# explicitly so the standalone homeConfiguration build also includes it. # also available for standalone `home-manager switch` runs (where sharedModules
# are not applied). NixOS's module system deduplicates the import when both
# paths resolve to the same derivation.
imports = [ imports = [
inputs.steam-rom-manager.homeManagerModules.default inputs.steam-rom-manager.homeManagerModules.default
]; ];
@@ -29,6 +30,7 @@ in
jq jq
] ]
++ (with pkgs.${namespace}; [ ++ (with pkgs.${namespace}; [
hueforge
moondeck-buddy moondeck-buddy
]); ]);
}; };
@@ -36,40 +38,36 @@ in
${namespace} = { ${namespace} = {
sops.enable = true; sops.enable = true;
programs.opencode = enabled; programs.opencode = enabled;
desktop.plasma = enabled;
}; };
sops = { sops.secrets = {
age.keyFile = "/home/admin/.config/sops/age/keys.txt"; "ssh-keys-public/jallen-nas" = {
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml"; path = "/home/admin/.ssh/id_ed25519.pub";
validateSopsFiles = false; mode = "0644";
secrets = { };
"ssh-keys-public/jallen-nas" = { "ssh-keys-private/jallen-nas" = {
path = "/home/admin/.ssh/id_ed25519.pub"; path = "/home/admin/.ssh/id_ed25519";
mode = "0644"; mode = "0600";
}; };
"ssh-keys-private/jallen-nas" = { "ssh-keys-public/desktop-nixos" = {
path = "/home/admin/.ssh/id_ed25519"; path = "/home/admin/.ssh/authorized_keys";
mode = "0600"; mode = "0600";
}; };
"ssh-keys-public/desktop-nixos" = {
path = "/home/admin/.ssh/authorized_keys";
mode = "0600";
};
"ssh-keys-public/desktop-nixos-root" = { "ssh-keys-public/desktop-nixos-root" = {
path = "/home/admin/.ssh/authorized_keys2"; path = "/home/admin/.ssh/authorized_keys2";
mode = "0600"; mode = "0600";
}; };
"ssh-keys-public/desktop-windows" = { "ssh-keys-public/desktop-windows" = {
path = "/home/admin/.ssh/authorized_keys3"; path = "/home/admin/.ssh/authorized_keys3";
mode = "0600"; mode = "0600";
}; };
"ssh-keys-public/macbook-macos" = { "ssh-keys-public/macbook-macos" = {
path = "/home/admin/.ssh/authorized_keys4"; path = "/home/admin/.ssh/authorized_keys4";
mode = "0600"; mode = "0600";
};
}; };
}; };
@@ -86,11 +84,14 @@ in
viAlias = true; viAlias = true;
vimAlias = true; vimAlias = true;
defaultEditor = true; defaultEditor = true;
withRuby = false;
withPython3 = true;
plugins = [ plugins = [
pkgs.vimPlugins.nvim-tree-lua pkgs.vimPlugins.nvim-tree-lua
{ {
plugin = pkgs.vimPlugins.vim-startify; plugin = pkgs.vimPlugins.vim-startify;
config = "let g:startify_change_to_vcs_root = 0"; config = "let g:startify_change_to_vcs_root = 0";
type = "lua";
} }
]; ];
}; };

View File

@@ -10,21 +10,22 @@ in
{ {
home.username = "matt"; home.username = "matt";
${namespace}.desktop.gnome = enabled; ${namespace} = {
desktop.gnome = enabled;
sops.enable = true;
programs = {
vesktop = enabled;
};
};
sops = { sops.secrets = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt"; "ssh-keys-public/matt" = {
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml"; path = "/home/matt/.ssh/id_ed25519.pub";
validateSopsFiles = false; mode = "0644";
secrets = { };
"ssh-keys-public/matt" = { "ssh-keys-private/matt" = {
path = "/home/matt/.ssh/id_ed25519.pub"; path = "/home/matt/.ssh/id_ed25519";
mode = "0644"; mode = "0600";
};
"ssh-keys-private/matt" = {
path = "/home/matt/.ssh/id_ed25519";
mode = "0600";
};
}; };
}; };
@@ -53,7 +54,7 @@ in
ryujinx.enable = true; # Switch (ryubing fork) ryujinx.enable = true; # Switch (ryubing fork)
yuzu.enable = true; # Switch (eden fork) yuzu.enable = true; # Switch (eden fork)
dolphin-emu.enable = true; # GameCube / Wii dolphin-emu.enable = true; # GameCube / Wii
cemu.enable = true; # Wii U cemu.enable = false; # Wii U
melonDS.enable = true; # DS melonDS.enable = true; # DS
citra.enable = true; # 3DS (azahar fork) citra.enable = true; # 3DS (azahar fork)
mgba.enable = true; # Game Boy / GBC mgba.enable = true; # Game Boy / GBC

View File

@@ -28,9 +28,12 @@ in
enable = true; enable = true;
}; };
desktop.gnome = enabled; desktop.plasma = enabled;
programs = { programs = {
vesktop = enabled;
opencode = enabled;
thunderbird = enabled;
hyprland = { hyprland = {
enable = false; enable = false;
primaryDisplay = "DP-1"; primaryDisplay = "DP-1";
@@ -163,6 +166,7 @@ in
home.packages = home.packages =
with pkgs; with pkgs;
[ [
atlauncher
bolt-launcher bolt-launcher
clevis clevis
compose2nix compose2nix
@@ -178,7 +182,6 @@ in
piper piper
prismlauncher prismlauncher
protontricks protontricks
protonvpn-gui
runelite runelite
smile smile
via via
@@ -193,8 +196,17 @@ in
]); ]);
specialisation = { specialisation = {
"gnome".configuration = {
${namespace} = {
desktop = {
plasma = lib.mkForce disabled;
gnome = lib.mkForce enabled;
};
};
};
"cosmic".configuration = { "cosmic".configuration = {
${namespace} = { ${namespace} = {
desktop.plasma = lib.mkForce disabled;
programs = { programs = {
hyprland = lib.mkForce disabled; hyprland = lib.mkForce disabled;
kitty = lib.mkForce disabled; kitty = lib.mkForce disabled;

189
lib/README.md Normal file → Executable file
View File

@@ -4,41 +4,186 @@ Utility functions for the NixOS/nix-darwin configuration. Exposed via Snowfall L
## Directory Structure ## Directory Structure
- `default.nix`: Main entry point exports `module`, `file`, and `versioning` - `default.nix` Main entry point; exports `module`, `file`, and `versioning`
- `module/`: Module creation helpers (`mkModule`, `mkOpt`, `mkBoolOpt`, etc.) - `module/` Module creation helpers (`mkModule`, `mkContainerService`, `mkSopsEnvFile`, `mkOpt`, etc.)
- `file/`: File and path utilities - `file/` File and path utilities
- `versioning/`: Multi-source version pinning helpers (used by packages) - `versioning/` Multi-source version pinning helpers (used by packages)
---
## Module Utilities (`lib.mjallen.module`) ## Module Utilities (`lib.mjallen.module`)
### `mkModule`
Creates a NixOS service module with a standard set of options. All config is gated behind `cfg.enable`.
```nix
lib.mjallen.mkModule {
config # NixOS config attrset (pass-through from module args)
name # Service name — used for option path and systemd unit
description # Text for mkEnableOption (defaults to name)
options # Extra options merged into the submodule
moduleConfig # NixOS config body (applied when cfg.enable = true)
domain # Option namespace domain (default: "services")
serviceName # Systemd service name (default: name)
}
```
**Standard options provided for free:**
| Option | Type | Default | Description |
|---|---|---|---|
| `enable` | bool | `false` | Enable/disable the service |
| `port` | int | `80` | Service listen port |
| `listenAddress` | str | `"0.0.0.0"` | Bind address |
| `openFirewall` | bool | `true` | Open TCP+UDP firewall ports |
| `configDir` | str | `/var/lib/<name>` | Config directory |
| `dataDir` | str | `/var/lib/<name>/data` | Data directory |
| `createUser` | bool | `false` | Create a dedicated system user |
| `configureDb` | bool | `false` | Create a PostgreSQL database |
| `environmentFile` | str\|null | `null` | Path to an env-file |
| `extraEnvironment` | attrs | `{}` | Extra environment variables |
| `hashedPassword` | str\|null | `null` | Hashed password for web auth |
| `puid` / `pgid` | str | `"911"` / `"100"` | UID/GID for container services |
| `timeZone` | str | `"UTC"` | Timezone for container services |
| `redis.enable` | bool | `false` | Create a Redis instance for this service |
| `redis.port` | int | `6379` | Redis port |
| `reverseProxy.enable` | bool | `false` | Add a Caddy reverse proxy block |
| `reverseProxy.subdomain` | str | `<name>` | Caddy subdomain |
| `reverseProxy.domain` | str | `"mjallen.dev"` | Caddy base domain |
| `reverseProxy.upstreamUrl` | str\|null | `null` | Override upstream URL |
| `reverseProxy.extraCaddyConfig` | lines | `""` | Extra Caddyfile directives |
**Default behaviour when enabled:**
- Adds Caddy reverse proxy block (if `reverseProxy.enable = true`)
- Opens firewall ports (if `openFirewall = true`)
- Creates system user/group (if `createUser = true`)
- Creates PostgreSQL database (if `configureDb = true`)
- Creates Redis instance (if `redis.enable = true`)
- Adds `RequiresMountsFor` systemd dependency for `configDir` and `dataDir`
---
### `mkContainerService`
Wraps `mkModule` for Podman/OCI container services. Generates the full container definition automatically.
```nix
lib.mjallen.mkContainerService {
config # NixOS config attrset
name # Service/container name
image # OCI image reference (e.g. "ghcr.io/example/app:latest")
internalPort # Port the container listens on internally
description # Human-readable description (defaults to name)
options # Extra mkModule options
volumes # Extra volume mount strings
environment # Extra environment variables (merged with PUID/PGID/TZ)
environmentFiles # List of env-file paths (e.g. SOPS template paths)
extraOptions # Extra --opt strings for the container runtime
devices # Device mappings
extraConfig # Extra NixOS config merged into moduleConfig
}
```
The systemd service is named `podman-<name>`, and the port binding is `<cfg.port>:<internalPort>`.
---
### `mkSopsEnvFile`
Generates a SOPS secrets block and a SOPS template env-file in a single call. Useful for services that need secrets injected as environment variables.
```nix
lib.mjallen.mkSopsEnvFile {
secrets # attrset: sops-key → extra attrs (owner, group, etc.)
name # Template file name, e.g. "myapp.env"
content # Template body (use config.sops.placeholder."key")
restartUnit # Systemd unit to restart when secrets change
owner # File owner (default: "nix-apps")
group # File group (default: "jallen-nas")
mode # File permissions (default: "660")
sopsFile # Default SOPS file for all secrets
}
```
---
### Option helpers
| Function | Signature | Description |
|---|---|---|
| `mkOpt` | `type → default → description → mkOption` | Standard option shorthand |
| `mkOpt'` | `type → default → mkOption` | `mkOpt` without description |
| `mkBoolOpt` | `default → description → mkOption` | Boolean option shorthand |
| `mkBoolOpt'` | `default → mkOption` | Boolean option without description |
| `mkReverseProxyOpt` | `name → attrset` | Standard Caddy reverse proxy sub-options |
---
### Convenience shorthands
| Value | Expands to |
|---|---|
| `enabled` | `{ enable = true; }` |
| `disabled` | `{ enable = false; }` |
---
### Attribute utilities
| Function | Description | | Function | Description |
|---|---| |---|---|
| `mkModule` | Create a NixOS module with standard options (enable, port, reverseProxy, firewall, user, postgresql, redis) |
| `mkOpt` | `type → default → description → mkOption` shorthand |
| `mkOpt'` | `mkOpt` without description |
| `mkBoolOpt` | Boolean `mkOpt` shorthand |
| `mkBoolOpt'` | Boolean `mkOpt` without description |
| `mkReverseProxyOpt` | Standard Caddy reverse proxy sub-options |
| `enabled` | `{ enable = true; }` shorthand |
| `disabled` | `{ enable = false; }` shorthand |
| `capitalize` | Capitalise the first character of a string |
| `boolToNum` | Convert a boolean to 0 or 1 |
| `default-attrs` | Apply `lib.mkDefault` to every value in an attrset | | `default-attrs` | Apply `lib.mkDefault` to every value in an attrset |
| `force-attrs` | Apply `lib.mkForce` to every value in an attrset | | `force-attrs` | Apply `lib.mkForce` to every value in an attrset |
| `nested-default-attrs` | Apply `default-attrs` one level deeper | | `nested-default-attrs` | Apply `default-attrs` one level deeper |
| `nested-force-attrs` | Apply `force-attrs` one level deeper | | `nested-force-attrs` | Apply `force-attrs` one level deeper |
| `enableForSystem` | Filter a module list to only those that match a given system string |
## File Utilities (`lib.mjallen.file`) ---
### String utilities
| Function | Description | | Function | Description |
|---|---| |---|---|
| `getFile` | Resolve a path relative to the flake root | | `capitalize` | Capitalise the first character of a string |
| `safeImport` | Import a Nix file with a fallback on error |
| `scanDir` | Return a list of directory names under a path | ---
| `importModulesRecursive` | Recursively discover and import all `default.nix` files under a directory |
### Boolean utilities
| Function | Description |
|---|---|
| `boolToNum` | `true → 1`, `false → 0` |
---
## Home Manager Utilities (`lib.mjallen.module`)
### `mkHomeModule`
Creates a Home Manager module with a standard `enable` option.
```nix
lib.mjallen.mkHomeModule {
config # HM config attrset
domain # Option namespace domain, e.g. "programs" or "desktop"
name # Module name, e.g. "btop"
description # Text for mkEnableOption (defaults to name)
options # Extra options merged into the submodule
moduleConfig # HM config body (applied when cfg.enable = true)
}
```
---
## File Utilities (`lib.mjallen.file`)
Helpers for resolving paths relative to the flake root. Primarily used internally by modules and packages.
---
## Versioning Utilities (`lib.mjallen.versioning`) ## Versioning Utilities (`lib.mjallen.versioning`)
Used by packages that track multiple upstream variants (e.g. `linux-rpi`, `proton-cachyos`). Used by packages that track multiple upstream variants (e.g. `proton-cachyos`, `linux-rpi`). Reads a `version.json` file and resolves sources with optional variable substitution and per-variant overrides.
See `lib/versioning/default.nix` for the full API.
See `lib/versioning/default.nix` for the full API and `docs/version.schema.json` for the `version.json` schema.

3
lib/default.nix Normal file → Executable file
View File

@@ -3,8 +3,9 @@
mjallen-lib = { mjallen-lib = {
module = import ./module { inherit inputs; }; module = import ./module { inherit inputs; };
file = import ./file { inherit inputs; }; file = import ./file { inherit inputs; };
inherit (inputs.nixpkgs) lib;
versioning = import ./versioning { versioning = import ./versioning {
lib = inputs.nixpkgs.lib; inherit (inputs.nixpkgs) lib;
inherit inputs; inherit inputs;
}; };
}; };

2
lib/file/default.nix Normal file → Executable file
View File

@@ -1,7 +1,7 @@
{ inputs, ... }@args: { inputs, ... }@args:
let let
# Get self from args or default to ../.. (the flake root) # Get self from args or default to ../.. (the flake root)
self = if args ? self then args.self else ../..; self = args.self or ../..;
inherit (inputs.nixpkgs.lib) inherit (inputs.nixpkgs.lib)
genAttrs genAttrs

23
lib/module/default.nix Normal file → Executable file
View File

@@ -91,8 +91,7 @@ rec {
]; ];
}; };
redis.servers.${name} = lib.mkIf cfg.redis.enable { redis.servers.${name} = lib.mkIf cfg.redis.enable {
enable = true; inherit (cfg.redis) enable port;
port = cfg.redis.port;
}; };
}; };
}; };
@@ -147,6 +146,22 @@ rec {
"Extra environment variables passed to the service"; "Extra environment variables passed to the service";
reverseProxy = mkReverseProxyOpt name; reverseProxy = mkReverseProxyOpt name;
hostedService = {
enable =
mkOpt types.bool cfg.reverseProxy.enable
"Expose this service in Glance dashboard (auto-enabled when reverseProxy is on)";
title = mkOpt types.str name "Display title in Glance";
icon = mkOpt types.str "si:glance" "Icon identifier for Glance (e.g. si:actualbudget)";
group = mkOpt types.str "Services" "Glance group/category for this service";
url = mkOpt types.str (
if cfg.reverseProxy.enable then
"https://${cfg.reverseProxy.subdomain}.${cfg.reverseProxy.domain}"
else
"http://127.0.0.1:${toString cfg.port}"
) "Service URL for Glance (auto-derived from reverseProxy if enabled)";
basicAuth = mkOpt types.bool false "Require basic auth for this service in Glance";
};
} }
// options; // options;
}; };
@@ -239,7 +254,7 @@ rec {
owner ? "nix-apps", owner ? "nix-apps",
group ? "jallen-nas", group ? "jallen-nas",
mode ? "660", mode ? "660",
sopsFile ? (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"), sopsFile ? lib.snowfall.fs.get-file "secrets/nas-secrets.yaml",
}: }:
{ {
sops.secrets = mapAttrs (_key: extra: { inherit sopsFile; } // extra) secrets; sops.secrets = mapAttrs (_key: extra: { inherit sopsFile; } // extra) secrets;
@@ -298,6 +313,8 @@ rec {
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Option creation helpers # Option creation helpers
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Option creation helpers
# ---------------------------------------------------------------------------
mkOpt = mkOpt =
type: default: description: type: default: description:

187
lib/network/default.nix Executable file
View File

@@ -0,0 +1,187 @@
# Central network topology registry.
#
# Exposed as lib.<namespace>.network.* (Snowfall Lib merges lib/ sub-directories
# automatically, so this file is reachable as lib.mjallen.network inside any
# NixOS module, home-manager module, or package that receives `lib`).
#
# Usage examples:
#
# let net = lib.mjallen.network; in
# net.hosts.nas.lan # "10.0.1.3"
# net.hosts.nas.lan4 # "10.0.1.3/24" (CIDR notation)
# net.hosts.nuc.lan # "10.0.1.4"
# net.hosts.pi5.nebula # "10.1.1.1"
# net.subnet.lan # "10.0.1.0/24"
# net.subnet.nebula # "10.1.1.0/24"
# net.ports.nas.nextcloud # 9988
# net.domain # "mjallen.dev"
#
# All attributes intentionally use plain strings / ints so they can be
# interpolated with `toString` or used directly in any context.
{
network = {
# -----------------------------------------------------------------------
# Global domain
# -----------------------------------------------------------------------
domain = "mjallen.dev";
# -----------------------------------------------------------------------
# Subnets
# -----------------------------------------------------------------------
subnet = {
lan = "10.0.1.0/24";
nebula = "10.1.1.0/24";
# Docker / container bridge used by Home Assistant
docker = "172.30.33.0/24";
};
# -----------------------------------------------------------------------
# Hosts
# Each host exposes:
# lan — bare IPv4 address (no prefix length)
# lan4 — IPv4 address with /24 CIDR suffix (for static IP config)
# nebula — Nebula overlay IP (where applicable)
# -----------------------------------------------------------------------
hosts = {
# ---- Raspberry Pi 5 (pi5) — DNS / Nebula lighthouse ----------------
pi5 = {
hostname = "pi5";
lan = "10.0.1.2";
lan4 = "10.0.1.2/24";
nebula = "10.1.1.1";
gateway = "10.0.1.1";
};
# ---- NAS (jallen-nas) — primary server -----------------------------
nas = {
hostname = "jallen-nas";
lan = "10.0.1.3";
lan4 = "10.0.1.3/24";
nebula = "10.1.1.3";
gateway = "10.0.1.1";
};
# ---- Intel NUC (nuc-nixos) — Home Assistant host -------------------
nuc = {
hostname = "nuc-nixos";
lan = "10.0.1.4";
lan4 = "10.0.1.4/24";
nebula = "10.1.1.4";
gateway = "10.0.1.1";
};
# ---- MacBook Pro (macbook-pro-nixos) — Apple Silicon laptop --------
macbook = {
hostname = "macbook-pro-nixos";
nebula = "10.1.1.8";
};
# ---- ASUS ROG Ally X (allyx) ----------------------------------------
allyx = {
hostname = "allyx";
nebula = "10.1.1.10";
};
# ---- Router / gateway / AdGuard upstream ---------------------------
router = {
hostname = "router";
lan = "10.0.1.1";
lan4 = "10.0.1.1/24";
};
};
# -----------------------------------------------------------------------
# Service ports
# Grouped by host. Every entry matches the port set in apps.nix / the
# corresponding mkModule option so there is a single source of truth.
# -----------------------------------------------------------------------
ports = {
# ---- pi5 services --------------------------------------------------
pi5 = {
adguard = 3000;
attic = 9012;
nebula = 4242;
dns = 53;
};
# ---- NAS services --------------------------------------------------
nas = {
actual = 3333;
attic = 9012;
authentik = 9000;
authentikRac = 4823;
calibre = 8084;
calibreWeb = 8083;
codeServer = 4444;
cockpit = 9091;
collabora = 9980;
coturn = 3478;
crowdsec = 8181;
dispatcharr = 9191;
elasticsearch = 9200;
gitea = 3000;
giteaSsh = 2222;
glance = 5555;
glances = 61208;
grafana = 9999;
grimmory = 6066;
guacd = 4822;
headscale = 2112;
immich = 2283;
jellyfin = 8096;
seerr = 5055;
kavita = 5000;
llamaCpp = 8127;
lubelogger = 6754;
manyfold = 3214;
mariadb = 3306;
matrix = 8448;
mongodb = 27017;
nebula = 4242;
netbootxyz = 4000;
netbootxyzWeb = 4080;
nextcloud = 9988;
ntfy = 2586;
nutUpsd = 3493;
ocis = 9200;
onlyoffice = 9943;
opencloud = 9200;
orcaSlicer = 3100;
paperless = 28981;
paperlessAi = 28982;
postgresql = 5432;
protonmailSmtp = 1025;
protonmailImap = 1143;
redisCcache = 6363;
redisManyfold = 6380;
redisOnlyoffice = 6381;
resticServer = 8008;
sabnzbd = 8280;
sonarr = 8989;
radarr = 7878;
sparkyFitnessFe = 3004;
sparkyFitnessBe = 3010;
sunshine = 47989;
tdarr = 8265;
tdarrServer = 8266;
termix = 7777;
tunarr = 8000;
unmanic = 8265;
uptimeKuma = 3001;
wyomingPiper = 10200;
wyomingWhisper = 10300;
};
# ---- NUC services --------------------------------------------------
nuc = {
homeAssistant = 8123;
mqtt = 1883;
otbr = 8880;
otbrRest = 8881;
esphome = 6052;
zigbee2mqtt = 8080;
govee2mqtt = 4002;
};
};
};
}

49
lib/nix-settings/default.nix Executable file
View File

@@ -0,0 +1,49 @@
# Shared nix daemon / nixpkgs settings used by both the NixOS and nix-darwin
# modules (modules/nixos/nix/default.nix and modules/darwin/nix/default.nix).
#
# Snowfall Lib discovers this file and merges its return value into
# lib.<namespace>.* — the nested attrset is accessed as:
# lib.${namespace}.nixSettings.commonSubstituters
# lib.${namespace}.nixSettings.commonTrustedPublicKeys
# lib.${namespace}.nixSettings.commonSettings
# lib.${namespace}.nixSettings.commonGc
{ lib, ... }:
{
nixSettings = {
commonSubstituters = [
"https://nixos-apple-silicon.cachix.org"
"https://nixos-raspberrypi.cachix.org"
"https://nix-community.cachix.org"
"https://cache.nixos.org/"
];
commonTrustedPublicKeys = [
"nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20="
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
commonSettings = {
warn-dirty = lib.mkForce false;
experimental-features = lib.mkForce [
"nix-command"
"flakes"
];
trusted-users = [
"@wheel"
"@admin"
];
builders-use-substitutes = true;
connect-timeout = lib.mkDefault 5;
fallback = true;
log-lines = lib.mkDefault 25;
max-free = lib.mkDefault (3000 * 1024 * 1024);
min-free = lib.mkDefault (512 * 1024 * 1024);
};
commonGc = {
automatic = lib.mkDefault true;
options = lib.mkDefault "--delete-older-than 30d";
};
};
}

84
lib/versioning/default.nix Normal file → Executable file
View File

@@ -1,11 +1,6 @@
{ {
lib, lib,
inputs,
system ? "aarch64-linux",
}: }:
let
pkgs = inputs.nixpkgs.legacyPackages.${system};
in
let let
inherit (builtins) inherit (builtins)
isAttrs isAttrs
@@ -14,12 +9,9 @@ let
hasAttr hasAttr
getAttr getAttr
attrNames attrNames
toString
replaceStrings replaceStrings
; ;
inherit (lib) mapAttrs recursiveUpdate;
mapAttrs = lib.mapAttrs;
recursiveUpdate = lib.recursiveUpdate;
# Deep-merge attrsets (right-biased). # Deep-merge attrsets (right-biased).
deepMerge = a: b: recursiveUpdate a b; deepMerge = a: b: recursiveUpdate a b;
@@ -36,8 +28,8 @@ let
applyVariantOnce = applyVariantOnce =
selected: variant: selected: variant:
let let
vVars = if variant ? variables then variant.variables else { }; vVars = variant.variables or { };
vSrcs = if variant ? sources then variant.sources else { }; vSrcs = variant.sources or { };
in in
{ {
variables = selected.variables // vVars; variables = selected.variables // vVars;
@@ -52,8 +44,8 @@ let
else else
let let
p = variant.platforms.${system}; p = variant.platforms.${system};
pVars = if p ? variables then p.variables else { }; pVars = p.variables or { };
pSrcs = if p ? sources then p.sources else { }; pSrcs = p.sources or { };
in in
{ {
variables = selected.variables // pVars; variables = selected.variables // pVars;
@@ -94,53 +86,48 @@ let
# Decide fetcher for URL type based on optional extra.unpack hint. # Decide fetcher for URL type based on optional extra.unpack hint.
useFetchZip = comp: comp ? extra && comp.extra ? unpack && comp.extra.unpack == "zip"; useFetchZip = comp: comp ? extra && comp.extra ? unpack && comp.extra.unpack == "zip";
# Build a single src from a rendered component spec. # Build a single src from a rendered component spec, using the given pkgs for fetchers.
mkSrcFromRendered = mkSrcFromRendered' =
comp: pkgs': comp:
let let
fetcher = if comp ? fetcher then comp.fetcher else "none"; fetcher = comp.fetcher or "none";
in in
if fetcher == "github" then if fetcher == "github" then
pkgs.fetchFromGitHub ( pkgs'.fetchFromGitHub (
{ {
owner = comp.owner; inherit (comp) owner repo hash;
repo = comp.repo;
# Allow tag as rev (ignore null/empty tag) # Allow tag as rev (ignore null/empty tag)
rev = if comp ? tag && comp.tag != null && comp.tag != "" then comp.tag else comp.rev; rev = if comp ? tag && comp.tag != null && comp.tag != "" then comp.tag else comp.rev;
fetchSubmodules = if comp ? submodules then comp.submodules else false; fetchSubmodules = comp.submodules or false;
hash = comp.hash;
} }
// lib.optionalAttrs (comp ? name) { name = comp.name; } // lib.optionalAttrs (comp ? name) { inherit (comp) name; }
) )
else if fetcher == "git" then else if fetcher == "git" then
pkgs.fetchgit { pkgs'.fetchgit {
url = comp.url; inherit (comp) url rev hash;
rev = comp.rev; fetchSubmodules = comp.submodules or false;
fetchSubmodules = if comp ? submodules then comp.submodules else false;
hash = comp.hash;
} }
else if fetcher == "url" then else if fetcher == "url" then
let let
url = if comp ? url then comp.url else comp.urlTemplate; url = comp.url or comp.urlTemplate;
in in
if useFetchZip comp then if useFetchZip comp then
pkgs.fetchzip ( pkgs'.fetchzip (
{ {
inherit (comp) hash;
inherit url; inherit url;
hash = comp.hash;
} }
// lib.optionalAttrs (comp ? extra && comp.extra ? stripRoot) { stripRoot = comp.extra.stripRoot; } // lib.optionalAttrs (comp ? extra && comp.extra ? stripRoot) { inherit (comp.extra) stripRoot; }
) )
else else
pkgs.fetchurl { pkgs'.fetchurl {
inherit (comp) hash;
inherit url; inherit url;
hash = comp.hash;
} }
else if fetcher == "pypi" then else if fetcher == "pypi" then
pkgs.python3Packages.fetchPypi { pkgs'.python3Packages.fetchPypi {
inherit (comp) version hash;
pname = comp.name; pname = comp.name;
version = comp.version;
hash = comp.hash;
} }
else else
# fetcher == "none": pass-through (e.g., linux version/hash consumed by custom logic) # fetcher == "none": pass-through (e.g., linux version/hash consumed by custom logic)
@@ -160,14 +147,10 @@ rec {
selectVariant = selectVariant =
spec: variantName: system: spec: variantName: system:
let let
chosen = chosen = if variantName != null then variantName else (spec.defaultVariant or null);
if variantName != null then
variantName
else
(if spec ? defaultVariant then spec.defaultVariant else null);
baseSelected = { baseSelected = {
variables = if spec ? variables then spec.variables else { }; variables = spec.variables or { };
sources = if spec ? sources then spec.sources else { }; sources = spec.sources or { };
}; };
in in
resolveVariant spec baseSelected chosen system; resolveVariant spec baseSelected chosen system;
@@ -181,30 +164,33 @@ rec {
/* /*
Render a component with variables and then build its src (or pass-through for fetcher "none"). Render a component with variables and then build its src (or pass-through for fetcher "none").
Prefer using mkAllSources, which handles rendering for all components. Prefer using mkAllSources, which handles rendering for all components.
pkgs: the nixpkgs instance to use for fetchers (must match the target system).
*/ */
mkSrc = mkSrc =
comp: variables: pkgs': comp: variables:
let let
rendered = renderValue comp variables; rendered = renderValue comp variables;
in in
mkSrcFromRendered rendered; mkSrcFromRendered' pkgs' rendered;
/* /*
Produce an attrset of all sources for a selected spec: Produce an attrset of all sources for a selected spec:
mkAllSources selected mkAllSources pkgs selected
Where: Where:
pkgs: the nixpkgs instance to use for fetchers (must match the target system).
selected = selectVariant spec variantName system selected = selectVariant spec variantName system
Returns: Returns:
{ componentName = src | renderedComp (for "none"); ... } { componentName = src | renderedComp (for "none"); ... }
*/ */
mkAllSources = mkAllSources =
selected: pkgs': selected:
mapAttrs ( mapAttrs (
_name: comp: _name: comp:
if comp ? fetcher && comp.fetcher == "none" then if comp ? fetcher && comp.fetcher == "none" then
renderValue comp selected.variables renderValue comp selected.variables
else else
mkSrc (renderValue comp selected.variables) selected.variables mkSrc pkgs' (renderValue comp selected.variables) selected.variables
) selected.sources; ) selected.sources;
# Expose deepMerge for convenience (right-biased). # Expose deepMerge for convenience (right-biased).

8
modules/darwin/home/default.nix Normal file → Executable file
View File

@@ -38,12 +38,12 @@
}; };
# Make ALL external HM modules available globally # Make ALL external HM modules available globally
# Note: sops-nix, nix-index-database, and stylix are already injected
# globally via systems.modules.home in flake.nix; only darwin-specific
# modules that aren't in the global list should go here.
sharedModules = with inputs; [ sharedModules = with inputs; [
sops-nix.homeManagerModules.sops
nix-plist-manager.homeManagerModules.default nix-plist-manager.homeManagerModules.default
nix-index-database.homeModules.nix-index # Add any other darwin-specific external HM modules here
stylix.homeModules.stylix
# Add any other external HM modules here
]; ];
users."mattjallen" = lib.mkAliasDefinitions options.${namespace}.home.extraOptions; users."mattjallen" = lib.mkAliasDefinitions options.${namespace}.home.extraOptions;

46
modules/darwin/nix/default.nix Normal file → Executable file
View File

@@ -1,48 +1,20 @@
{ {
lib, lib,
namespace,
... ...
}: }:
let
inherit (lib.${namespace}) nixSettings;
in
{ {
nix = { nix = {
settings = { settings = nixSettings.commonSettings // {
# extra-sandbox-paths = [ config.programs.ccache.cacheDir ]; substituters = nixSettings.commonSubstituters;
substituters = [ trusted-public-keys = nixSettings.commonTrustedPublicKeys;
"http://jallen-nas.local:9012/nas-cache"
"https://nixos-apple-silicon.cachix.org"
"https://nixos-raspberrypi.cachix.org"
"https://nix-community.cachix.org"
"https://cache.nixos.org/"
];
trusted-public-keys = [
"nas-cache:eK0eRVAt9QNwbkLIyOo9N5Z5+zi6ukI4mSlL196C7Yg="
"nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20="
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
warn-dirty = lib.mkForce false;
experimental-features = lib.mkForce [
"nix-command"
"flakes"
];
trusted-users = [
"@wheel"
"@admin"
];
builders-use-substitutes = true;
connect-timeout = lib.mkDefault 5;
fallback = true;
log-lines = lib.mkDefault 25;
max-free = lib.mkDefault (3000 * 1024 * 1024);
min-free = lib.mkDefault (512 * 1024 * 1024);
};
# Garbage collect automatically every week
gc = {
automatic = lib.mkDefault true;
options = lib.mkDefault "--delete-older-than 30d";
}; };
gc = nixSettings.commonGc;
optimise.automatic = lib.mkDefault true; optimise.automatic = lib.mkDefault true;
}; };

3
modules/darwin/programs/ssh/default.nix Normal file → Executable file
View File

@@ -1,5 +1,4 @@
{ ... }: _: {
{
config = { config = {
programs.ssh.knownHosts = { programs.ssh.knownHosts = {
desktop = { desktop = {

View File

@@ -0,0 +1,47 @@
{
config,
lib,
pkgs,
...
}:
{
accounts = {
email.accounts = {
gmail = {
primary = true;
realName = "Matt Jallen";
address = "matt.l.jallen@gmail.com";
userName = "matt.l.jallen@gmail.com";
passwordCommand = "${pkgs.uutils-coreutils-noprefix}/bin/cat ${
config.sops.secrets."gmail-smtp-password".path
}";
flavor = "gmail.com";
thunderbird.enable = true;
smtp = {
tls = {
enable = false;
useStartTls = true;
};
host = "smtp.gmail.com";
port = lib.mkForce 465;
};
};
protonmail = {
realName = "Matt Jallen";
address = "jalle008@protonmail.com";
userName = "jalle008@protonmail.com";
passwordCommand = "${pkgs.uutils-coreutils-noprefix}/bin/cat ${
config.sops.secrets."protonmail-password".path
}";
smtp = {
tls = {
enable = false;
useStartTls = true;
};
host = "127.0.0.1";
port = lib.mkForce 1025;
};
};
};
};
}

2
modules/home/desktop/gnome/default.nix Normal file → Executable file
View File

@@ -33,6 +33,7 @@ in
gnomeExtensions.boatman-winboat-monitor gnomeExtensions.boatman-winboat-monitor
papirus-icon-theme papirus-icon-theme
pop-gtk-theme pop-gtk-theme
pkgs.mjallen.gnome-nebula-vpn
]; ];
dconf = { dconf = {
@@ -68,6 +69,7 @@ in
"dash-to-dock@micxgx.gmail.com" "dash-to-dock@micxgx.gmail.com"
"BingWallpaper@ineffable-gmail.com" "BingWallpaper@ineffable-gmail.com"
"gsconnect@andyholmes.github.io" "gsconnect@andyholmes.github.io"
"nebula-vpn-status@mjallen"
]; ];
"org/gnome/shell/extensions/bingwallpaper" = { "org/gnome/shell/extensions/bingwallpaper" = {
override-lockscreen-blur = true; override-lockscreen-blur = true;

0
modules/home/desktop/gnome/options.nix Normal file → Executable file
View File

View File

@@ -0,0 +1,104 @@
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.desktop.plasma;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
home.packages =
(with pkgs.kdePackages; [
plasma-browser-integration
kdeplasma-addons
])
++ [
# Caffeine-like tray applet: inhibits screensaver and sleep on demand
pkgs.caffeine-ng
];
programs.plasma = {
enable = true;
configFile.kded5rc = {
"Module-gtkconfig"."autoload" = false;
};
# workspace = {
# colorScheme = "BreezeDark";
# cursor = {
# theme = "breeze_cursors";
# size = 24;
# };
# iconTheme = "breeze-dark";
# theme = "breeze-dark";
# lookAndFeel = "org.kde.breezedark.desktop";
# # Explicitly set Breeze to prevent QT_STYLE_OVERRIDE=kvantum (set by
# # Stylix's qt6ct target) from being picked up by KWin/plasmashell, which
# # would cause a fatal "module kvantum is not installed" QML error and
# # leave the desktop blank.
# widgetStyle = "Breeze";
# };
# # input.mice and input.touchpads require device-specific vendorId/productId
# # identifiers — configure those per-host in the home config instead.
kscreenlocker = {
autoLock = true;
timeout = 10;
};
kwin = {
effects = {
shakeCursor.enable = false;
};
nightLight = {
enable = true;
mode = "automatic";
temperature = {
day = 6500;
night = 3500;
};
};
virtualDesktops = {
number = 4;
rows = 1;
};
};
# panels = [
# {
# location = "bottom";
# floating = true;
# height = 44;
# widgets = [
# "org.kde.plasma.kickoff"
# "org.kde.plasma.icontasks"
# "org.kde.plasma.marginsseparator"
# "org.kde.plasma.systemtray"
# "org.kde.plasma.digitalclock"
# ];
# }
# ];
shortcuts = {
kwin = {
"Switch to Desktop 1" = "Meta+1";
"Switch to Desktop 2" = "Meta+2";
"Switch to Desktop 3" = "Meta+3";
"Switch to Desktop 4" = "Meta+4";
"Window to Desktop 1" = "Meta+Shift+1";
"Window to Desktop 2" = "Meta+Shift+2";
"Window to Desktop 3" = "Meta+Shift+3";
"Window to Desktop 4" = "Meta+Shift+4";
"Toggle Overview" = "Meta+Tab";
};
};
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, namespace, ... }:
with lib;
{
options.${namespace}.desktop.plasma = {
enable = mkEnableOption "KDE Plasma 6 home-manager configuration via plasma-manager";
};
}

3
modules/home/gpg/default.nix Normal file → Executable file
View File

@@ -1,5 +1,4 @@
{ ... }: _: {
{
programs = { programs = {
gpg = { gpg = {
enable = true; enable = true;

18
modules/home/home/default.nix Normal file → Executable file
View File

@@ -42,6 +42,9 @@ in
nix-prefetch-scripts nix-prefetch-scripts
nixfmt nixfmt
pciutils pciutils
proton-pass-cli
proton-vpn-cli
proton-vpn
protonup-ng protonup-ng
rsync rsync
smartmontools smartmontools
@@ -54,9 +57,10 @@ in
wget wget
] ]
++ ( ++ (
if (hasDestopEnvironment) then if hasDestopEnvironment then
[ [
boxbuddy boxbuddy
cider-2
stable.chromium stable.chromium
firefox firefox
gamescope gamescope
@@ -66,11 +70,23 @@ in
parted parted
vesktop vesktop
] ]
++ (
if isArm then
[ ]
else
[
proton-pass
]
)
else else
[ ] [ ]
) )
); );
file = {
".face".source = "${pkgs.${namespace}.profile-pic}/profile-pic";
};
stateVersion = lib.mkDefault "23.11"; stateVersion = lib.mkDefault "23.11";
}; };

View File

@@ -0,0 +1,24 @@
{
config,
lib,
pkgs,
namespace,
...
}:
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "calibre";
moduleConfig = {
programs.calibre = {
enable = true;
plugins = with pkgs.${namespace}; [
dedrm
];
};
};
})
];
}

3
modules/home/programs/code/default.nix Normal file → Executable file
View File

@@ -2,7 +2,6 @@
config, config,
pkgs, pkgs,
system, system,
namespace,
hasDestopEnvironment ? true, hasDestopEnvironment ? true,
... ...
}: }:
@@ -15,7 +14,7 @@ let
in in
{ {
home.packages = with pkgs; [ home.packages = with pkgs; [
nodePackages.nodejs nodejs_25
uv uv
]; ];

0
modules/home/programs/common/default-apps.nix Normal file → Executable file
View File

4
modules/home/programs/git/default.nix Normal file → Executable file
View File

@@ -1,4 +1,3 @@
{ ... }:
let let
gitAliases = { gitAliases = {
co = "checkout"; co = "checkout";
@@ -21,5 +20,8 @@ in
}; };
alias = gitAliases; alias = gitAliases;
}; };
# The default value of `programs.git.signing.format` has changed from `"openpgp"` to `null`.
# You are currently using the legacy default (`"openpgp"`) because `home.stateVersion` is less than "25.05".
signing.format = "openpgp";
}; };
} }

0
modules/home/programs/hyprland/avizo.nix Normal file → Executable file
View File

3
modules/home/programs/hyprland/default.nix Normal file → Executable file
View File

@@ -313,6 +313,7 @@ in
secondMonitor = if builtins.length names > 1 then builtins.elemAt names 1 else firstMonitor; secondMonitor = if builtins.length names > 1 then builtins.elemAt names 1 else firstMonitor;
in in
{ {
inherit (cfg) workspace;
"$mod" = cfg.modKey; "$mod" = cfg.modKey;
# Mouse # Mouse
@@ -513,8 +514,6 @@ in
preserve_split = "yes"; preserve_split = "yes";
}; };
workspace = cfg.workspace;
windowrule = [ windowrule = [
"match:title file_progress, float 1" "match:title file_progress, float 1"
"match:title .*[Cc]onfirm.*, float 1" "match:title .*[Cc]onfirm.*, float 1"

0
modules/home/programs/hyprland/options.nix Normal file → Executable file
View File

1
modules/home/programs/librewolf/default.nix Normal file → Executable file
View File

@@ -1,4 +1,3 @@
{ ... }:
{ {
programs.librewolf = { programs.librewolf = {
enable = false; enable = false;

0
modules/home/programs/nwg-dock/default.nix Normal file → Executable file
View File

0
modules/home/programs/nwg-drawer/default.nix Normal file → Executable file
View File

0
modules/home/programs/nwg-panel/default.nix Normal file → Executable file
View File

0
modules/home/programs/nwg-panel/options.nix Normal file → Executable file
View File

0
modules/home/programs/onlyoffice/default.nix Normal file → Executable file
View File

13
modules/home/programs/opencode/default.nix Normal file → Executable file
View File

@@ -7,6 +7,7 @@
}: }:
let let
cfg = config.${namespace}.programs.opencode; cfg = config.${namespace}.programs.opencode;
net = lib.${namespace}.network;
in in
{ {
options.${namespace}.programs.opencode = { options.${namespace}.programs.opencode = {
@@ -19,7 +20,7 @@ in
sops.templates."hass-mcp.env" = { sops.templates."hass-mcp.env" = {
mode = "0600"; mode = "0600";
content = '' content = ''
HA_URL=http://nuc-nixos.local:8123 HA_URL=http://${net.hosts.nuc.lan}:${toString net.ports.nuc.homeAssistant}
HA_TOKEN=${config.sops.placeholder."hass-mcp/token"} HA_TOKEN=${config.sops.placeholder."hass-mcp/token"}
''; '';
}; };
@@ -33,11 +34,11 @@ in
npm = "@ai-sdk/openai-compatible"; npm = "@ai-sdk/openai-compatible";
name = "llama-server (local)"; name = "llama-server (local)";
options = { options = {
baseURL = "http://jallen-nas.local:8127/v1"; baseURL = "http://${net.hosts.nas.lan}:${toString net.ports.nas.llamaCpp}/v1";
}; };
models = { models = {
Qwen3-Coder-Next-Q4_0 = { "gemma-4-26B-A4B-it-UD-Q8_K_XL" = {
name = "Qwen3 Coder (local)"; name = "Gemma 4 26B-A4B (local)";
modalities = { modalities = {
input = [ input = [
"image" "image"
@@ -46,8 +47,8 @@ in
output = [ "text" ]; output = [ "text" ];
}; };
limit = { limit = {
context = 262144; context = 32768;
output = 262144; output = 8192;
}; };
}; };
}; };

View File

@@ -0,0 +1,9 @@
{
# The default value of `programs.password-store.settings` has changed from `{ PASSWORD_STORE_DIR = "$XDG_DATA_HOME/password-store"; }` to `{ }`.
# You are currently using the legacy default (`{ PASSWORD_STORE_DIR = "$XDG_DATA_HOME/password-store"; }`) because `home.stateVersion` is less than "25.11".
# To silence this warning and keep legacy behavior, set:
# programs.password-store.settings = { PASSWORD_STORE_DIR = "$XDG_DATA_HOME/password-store"; };
programs.password-store = {
settings = { };
};
}

View File

@@ -0,0 +1,29 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.programs.thunderbird;
in
{
options.${namespace}.programs.thunderbird = {
enable = lib.mkEnableOption "thunderbird";
};
config = lib.mkIf cfg.enable {
programs.thunderbird = {
enable = true;
profiles = {
mjallen = {
isDefault = true;
accountsOrder = [
"gmail"
"protonmail"
];
};
};
};
};
}

3
modules/home/programs/update-checker/default.nix Normal file → Executable file
View File

@@ -1,6 +1,5 @@
{ {
config, config,
namespace,
pkgs, pkgs,
... ...
}: }:
@@ -273,7 +272,7 @@ in
config = { config = {
sops = { sops = {
age.keyFile = "/home/${config.${namespace}.user.name}/.config/sops/age/keys.txt"; age.keyFile = "/home/${config.home.username}/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml"; defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false; validateSopsFiles = false;
secrets = { secrets = {

View File

@@ -0,0 +1,51 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.programs.vesktop;
in
{
options.${namespace}.programs.vesktop = {
enable = lib.mkEnableOption "vesktop";
};
config = lib.mkIf cfg.enable {
programs.vesktop = {
enable = true;
settings = {
appBadge = false;
arRPC = true;
checkUpdates = false;
customTitleBar = false;
disableMinSize = true;
minimizeToTray = true;
tray = true;
splashBackground = "#000000";
splashColor = "#ffffff";
splashTheming = true;
staticTitle = true;
hardwareAcceleration = true;
discordBranch = "stable";
};
vencord = {
settings = {
autoUpdate = false;
autoUpdateNotification = false;
notifyAboutUpdates = false;
useQuickCss = true;
disableMinSize = true;
plugins = {
MessageLogger = {
enabled = false;
ignoreSelf = true;
};
FakeNitro.enabled = false;
};
};
};
};
};
}

View File

@@ -294,10 +294,10 @@ in
systemd.enable = true; systemd.enable = true;
settings = { settings = {
mainBar = ( mainBar =
(mkMerge [ (mkMerge [
{ {
layer = cfg.layer; inherit (cfg) layer;
position = "top"; position = "top";
mod = "dock"; mod = "dock";
exclusive = true; exclusive = true;
@@ -342,7 +342,7 @@ in
}; };
network = { network = {
interface = cfg.network.interface; inherit (cfg.network) interface;
on-click = "nm-connection-editor"; on-click = "nm-connection-editor";
format = "{icon}"; format = "{icon}";
tooltip-format = "{ifname} via {gwaddr} 󰊗"; tooltip-format = "{ifname} via {gwaddr} 󰊗";
@@ -589,8 +589,7 @@ in
}; };
}) })
]) ])
// cfg.extra.settings // cfg.extra.settings;
);
} }
// cfg.extraModules; # keep legacy top-level extra modules for compatibility // cfg.extraModules; # keep legacy top-level extra modules for compatibility

0
modules/home/programs/waybar/options.nix Normal file → Executable file
View File

0
modules/home/programs/waybar/scripts/audio-control.nix Normal file → Executable file
View File

0
modules/home/programs/waybar/scripts/media.nix Normal file → Executable file
View File

0
modules/home/programs/waybar/scripts/notifications.nix Normal file → Executable file
View File

0
modules/home/programs/waybar/scripts/weather.nix Normal file → Executable file
View File

0
modules/home/programs/wlogout/default.nix Normal file → Executable file
View File

1
modules/home/programs/zsh/default.nix Normal file → Executable file
View File

@@ -1,4 +1,3 @@
{ ... }:
let let
defaultShellAliases = { defaultShellAliases = {
l = "ls -alh"; l = "ls -alh";

3
modules/home/services/pass/default.nix Normal file → Executable file
View File

@@ -1,6 +1,3 @@
{
...
}:
{ {
#services.gnome-keyring.enable = false; #services.gnome-keyring.enable = false;
#home.packages = [ pkgs.gcr ]; #home.packages = [ pkgs.gcr ];

View File

@@ -0,0 +1,24 @@
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.services.protonmail;
in
{
options.${namespace}.services.protonmail = {
enable = lib.mkEnableOption "protonmail bridge";
};
config = lib.mkIf cfg.enable {
services.protonmail-bridge = {
enable = true;
extraPackages = with pkgs; [ pass ];
};
home.packages = with pkgs; [ protonmail-bridge-gui ];
};
}

7
modules/home/shell-aliases/default.nix Normal file → Executable file
View File

@@ -6,6 +6,7 @@
}: }:
let let
cfg = config.${namespace}.shell-aliases; cfg = config.${namespace}.shell-aliases;
net = lib.${namespace}.network;
in in
{ {
options.${namespace}.shell-aliases = { options.${namespace}.shell-aliases = {
@@ -13,7 +14,7 @@ in
buildHost = lib.mkOption { buildHost = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "admin@10.0.1.3"; default = "admin@${net.hosts.nas.lan}";
description = "Build host for nixos-rebuild commands"; description = "Build host for nixos-rebuild commands";
}; };
@@ -50,8 +51,8 @@ in
) "nix flake update ${lib.concatStringsSep " " cfg.flakeInputs} --flake /etc/nixos"; ) "nix flake update ${lib.concatStringsSep " " cfg.flakeInputs} --flake /etc/nixos";
# NAS management # NAS management
update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@10.0.1.3 --build-host admin@10.0.1.3 --flake ~/nix-config#jallen-nas"; update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@${net.hosts.nas.lan} --build-host admin@${net.hosts.nas.lan} --flake ~/nix-config#jallen-nas";
nas-ssh = "kitten ssh admin@10.0.1.3"; nas-ssh = "kitten ssh admin@${net.hosts.nas.lan}";
} }
// cfg.extraAliases; // cfg.extraAliases;
}; };

8
modules/home/sops/default.nix Normal file → Executable file
View File

@@ -12,12 +12,12 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
sops = { sops = {
age.keyFile = "/home/${config.${namespace}.user.name}/.config/sops/age/keys.txt"; age.keyFile = "/home/${config.home.username}/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml"; defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false; validateSopsFiles = false;
# secrets = { secrets = {
# "github-token" = { }; "gmail-smtp-password" = { };
# }; };
# templates = { # templates = {
# ".env".content = '' # ".env".content = ''
# GITHUB_TOKEN = "${config.sops.placeholder.github-token}" # GITHUB_TOKEN = "${config.sops.placeholder.github-token}"

0
modules/home/sops/options.nix Normal file → Executable file
View File

32
modules/home/stylix/default.nix Normal file → Executable file
View File

@@ -5,32 +5,17 @@
... ...
}: }:
let let
# # Pull from global theme options
# themeSize = "standard"; # "standard" | "compact"
# themeAccent = "default"; # "default" | ... | "all"
# themeTweak = "normal"; # "normal" | "rimless" | "float" | "black"
# themeColor = "dark"; # "light" | "dark"
# iconThemeVariant = "default"; # "default" | ... | "all"
# iconScheme = "nord"; # "default" | "nord" | "dracula" | ...
# # GTK
# gtkTheme = "Colloid-dark-standard";
# gtkThemePkg = pkgs.colloid-gtk-theme.override {
# sizeVariants = [ themeSize ];
# colorVariants = [ themeColor ];
# themeVariants = [ themeAccent ];
# tweaks = [ themeTweak ];
# };
# # Icons
# iconTheme = "Colloid-nord-dark";
# iconThemePkg = pkgs.colloid-icon-theme.override {
# schemeVariants = [ iconScheme ];
# colorVariants = [ iconThemeVariant ];
# };
isDarwin = system == "aarch64-darwin"; isDarwin = system == "aarch64-darwin";
in in
{ {
# The default value of `gtk.gtk4.theme` has changed from `config.gtk.theme` to `null`.
# You are currently using the legacy default (`config.gtk.theme`) because `home.stateVersion` is less than "26.05".
# To silence this warning and keep legacy behavior, set:
# gtk.gtk4.theme = config.gtk.theme;
# To adopt the new default behavior, set:
# gtk.gtk4.theme = null;
gtk.gtk4.theme = config.gtk.theme;
stylix = { stylix = {
enable = true; enable = true;
overlays.enable = false; overlays.enable = false;
@@ -93,6 +78,7 @@ in
useWallpaper = false; useWallpaper = false;
}; };
kde.enable = false; kde.enable = false;
qt.enable = false;
firefox = { firefox = {
enable = false; enable = false;
profileNames = [ profileNames = [

8
modules/home/user/default.nix Normal file → Executable file
View File

@@ -35,18 +35,18 @@ in
description = "The full name of the user."; description = "The full name of the user.";
}; };
home = mkOption { home = mkOption {
type = (types.nullOr types.str); type = types.nullOr types.str;
default = home-directory; default = home-directory;
description = "The user's home directory."; description = "The user's home directory.";
}; };
icon = mkOption { icon = mkOption {
type = (types.nullOr types.package); type = types.nullOr types.package;
default = null; default = null;
description = "The profile picture to use for the user. Set to a package whose output is the icon file (e.g. a derivation producing a PNG)."; description = "The profile picture to use for the user. Set to a package whose output is the icon file (e.g. a derivation producing a PNG).";
}; };
name = mkOption { name = mkOption {
type = (types.nullOr types.str); type = types.nullOr types.str;
default = config.snowfallorg.user.name; default = "matt";
description = "The user account."; description = "The user account.";
}; };
}; };

2
modules/nixos/boot/common/default.nix Normal file → Executable file
View File

@@ -62,7 +62,7 @@ in
bcachefs.package = lib.mkOverride 90 pkgs.${namespace}.bcachefs; bcachefs.package = lib.mkOverride 90 pkgs.${namespace}.bcachefs;
consoleLogLevel = lib.mkDefault 0; consoleLogLevel = lib.mkDefault 0;
bootspec.enable = (!isArm); bootspec.enable = !isArm;
initrd = { initrd = {
verbose = lib.mkDefault false; verbose = lib.mkDefault false;

2
modules/nixos/boot/lanzaboote/default.nix Normal file → Executable file
View File

@@ -32,7 +32,7 @@ in
}; };
}; };
lanzaboote = { lanzaboote = {
enable = cfg.enable; enable = true;
pkiBundle = "/etc/secureboot"; pkiBundle = "/etc/secureboot";
settings = { settings = {
console-mode = "max"; console-mode = "max";

0
modules/nixos/boot/plymouth/default.nix Normal file → Executable file
View File

0
modules/nixos/boot/systemd-boot/default.nix Normal file → Executable file
View File

View File

@@ -1,21 +1,20 @@
{ {
config,
lib, lib,
namespace, namespace,
... ...
}: }:
let
cfg = config.${namespace}.desktop.cosmic;
in
{ {
options.${namespace}.desktop.cosmic = { options.${namespace}.desktop.cosmic = {
enable = lib.mkEnableOption "enable cosmic settings"; enable = lib.mkEnableOption "enable cosmic settings";
}; };
config = lib.mkIf cfg.enable { # TODO: COSMIC DE has an active bug that prevents it from being used.
services = { # Re-enable once upstream fixes land:
desktopManager.cosmic.enable = true; # config = lib.mkIf config.${namespace}.desktop.cosmic.enable {
displayManager.cosmic-greeter.enable = true; # services = {
}; # desktopManager.cosmic.enable = true;
}; # displayManager.cosmic-greeter.enable = true;
# };
# };
config = { };
} }

9
modules/nixos/desktop/gnome/default.nix Normal file → Executable file
View File

@@ -6,12 +6,14 @@
... ...
}: }:
let let
inherit (lib.${namespace}) enabled disabled; inherit (lib.${namespace}) enabled disabled mkBoolOpt;
cfg = config.${namespace}.desktop.gnome; cfg = config.${namespace}.desktop.gnome;
in in
{ {
options.${namespace}.desktop.gnome = { options.${namespace}.desktop.gnome = {
enable = lib.mkEnableOption "GNOME desktop environment"; enable = lib.mkEnableOption "GNOME desktop environment";
vscodium.enable = mkBoolOpt false "Set VSCodium as the default EDITOR/VISUAL";
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
@@ -53,5 +55,10 @@ in
enable = false; enable = false;
package = pkgs.gnomeExtensions.gsconnect; package = pkgs.gnomeExtensions.gsconnect;
}; };
environment.variables = lib.mkIf cfg.vscodium.enable {
EDITOR = "${lib.getExe' pkgs.vscodium "codium"} --wait";
VISUAL = "${lib.getExe' pkgs.vscodium "codium"} --wait";
};
}; };
} }

6
modules/nixos/desktop/hyprland/options.nix Normal file → Executable file
View File

@@ -18,14 +18,16 @@ in
options.${namespace}.desktop.hyprland = { options.${namespace}.desktop.hyprland = {
enable = mkEnableOption "enable hyprland desktop environment"; enable = mkEnableOption "enable hyprland desktop environment";
# These options are convenience aliases that feed into mjallen.wallpaper.*
# when the hyprland wallpaper sub-module is active.
wallpaperSource = mkOpt (types.enum [ wallpaperSource = mkOpt (types.enum [
"bing" "bing"
"nasa" "nasa"
]) "bing" "Source for the wallpaper (bing or nasa)"; ]) "bing" "Source for the wallpaper (bing or nasa)";
wallpaper = mkOpt types.path "/var/lib/wallpapers/current.jpg" "Path to the wallpaper folder"; wallpaper = mkOpt types.path "/var/lib/wallpapers/current.jpg" "Path to the active wallpaper file";
wallpaperDir = mkOpt types.path "/var/lib/wallpapers" "Path to the wallpaper folder"; wallpaperDir = mkOpt types.path "/var/lib/wallpapers" "Path to the wallpaper directory";
defaultWallpaper = mkOpt types.path "${defaultWallpaper}/default.jpg" "Default wallpaper"; defaultWallpaper = mkOpt types.path "${defaultWallpaper}/default.jpg" "Default wallpaper";
}; };

174
modules/nixos/desktop/hyprland/wallpapers/default.nix Normal file → Executable file
View File

@@ -7,176 +7,20 @@
}: }:
let let
cfg = config.${namespace}.desktop.hyprland; cfg = config.${namespace}.desktop.hyprland;
# The script to use based on the selected wallpaper source
wallpaper-command = if cfg.wallpaperSource == "nasa" then "nasa-wallpaper" else "bing-wallpaper";
# System activation script to ensure wallpaper is available early in boot
wallpaper-activation-script = ''
# Create wallpaper directory if it doesn't exist
mkdir -p ${cfg.wallpaperDir}
# Copy default wallpaper as fallback if it doesn't exist
if [ ! -f ${cfg.wallpaperDir}/fallback.jpg ]; then
cp ${cfg.defaultWallpaper} ${cfg.wallpaperDir}/fallback.jpg
fi
# If no current wallpaper exists, use the fallback
if [ ! -f ${cfg.wallpaperDir}/current.jpg ]; then
cp ${cfg.wallpaperDir}/fallback.jpg ${cfg.wallpaperDir}/current.jpg
fi
# Create symlink for Plymouth and SDDM
ln -sf ${cfg.wallpaperDir}/current.jpg /run/wallpaper.jpg
'';
bing-wallpaper = pkgs.writeScriptBin "bing-wallpaper" ''
# Directory to store wallpapers
WALLPAPER_DIR="${cfg.wallpaperDir}"
IMG_PATH="$WALLPAPER_DIR/current.jpg"
FALLBACK_PATH="$WALLPAPER_DIR/fallback.jpg"
# Ensure directory exists
mkdir -p "$WALLPAPER_DIR"
# Copy to the standard location for other services
ln -sf "$IMG_PATH" /run/wallpaper.jpg
# Try to download new wallpaper
if ${lib.getExe pkgs.curl} -s --connect-timeout 5 --max-time 10 "https://www.bing.com" > /dev/null; then
URL=$(${lib.getExe pkgs.curl} -s "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1" | \
${lib.getExe pkgs.jq} -r '.images[0].url')
FULL_URL="https://www.bing.com$URL"
if ${lib.getExe pkgs.curl} -s -o "$IMG_PATH.tmp" "$FULL_URL"; then
mv "$IMG_PATH.tmp" "$IMG_PATH"
echo "Downloaded $FULL_URL to $IMG_PATH successfully"
else
echo "Failed to download Bing wallpaper, using previous or fallback"
# If current doesn't exist, use fallback
if [ ! -f "$IMG_PATH" ] && [ -f "$FALLBACK_PATH" ]; then
cp "$FALLBACK_PATH" "$IMG_PATH"
fi
fi
else
echo "Network unavailable, using previous or fallback wallpaper"
# If current doesn't exist, use fallback
if [ ! -f "$IMG_PATH" ] && [ -f "$FALLBACK_PATH" ]; then
cp "$FALLBACK_PATH" "$IMG_PATH"
fi
fi
'';
nasa-wallpaper = pkgs.writeScriptBin "nasa-wallpaper" ''
# Directory to store wallpapers
WALLPAPER_DIR="${cfg.wallpaperDir}"
IMG_PATH="$WALLPAPER_DIR/current.jpg"
FALLBACK_PATH="$WALLPAPER_DIR/fallback.jpg"
# Ensure directory exists
mkdir -p "$WALLPAPER_DIR"
# Copy to the standard location for other services
ln -sf "$IMG_PATH" /run/wallpaper.jpg
# Try to download new wallpaper
if ${lib.getExe pkgs.curl} -s --connect-timeout 5 --max-time 10 "https://api.nasa.gov" > /dev/null; then
APOD_URL="https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY"
IMAGE_URL=$(${lib.getExe pkgs.curl} -s "$APOD_URL" | ${lib.getExe pkgs.jq} -r '.hdurl // .url')
if ${lib.getExe pkgs.curl} -s -o "$IMG_PATH.tmp" "$IMAGE_URL"; then
mv "$IMG_PATH.tmp" "$IMG_PATH"
echo "Downloaded $IMAGE_URL to $IMG_PATH successfully"
else
echo "Failed to download NASA wallpaper, using previous or fallback"
# If current doesn't exist, use fallback
if [ ! -f "$IMG_PATH" ] && [ -f "$FALLBACK_PATH" ]; then
cp "$FALLBACK_PATH" "$IMG_PATH"
fi
fi
else
echo "Network unavailable, using previous or fallback wallpaper"
# If current doesn't exist, use fallback
if [ ! -f "$IMG_PATH" ] && [ -f "$FALLBACK_PATH" ]; then
cp "$FALLBACK_PATH" "$IMG_PATH"
fi
fi
'';
in in
{ {
imports = [ ../options.nix ]; imports = [ ../options.nix ];
# Wire the hyprland wallpaper options through to the shared wallpaper module,
# and provide the hyprctl hot-reload command so hyprpaper picks up the new image.
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
environment.systemPackages = [ ${namespace}.wallpaper = {
bing-wallpaper inherit (cfg) defaultWallpaper;
nasa-wallpaper enable = true;
]; source = cfg.wallpaperSource;
path = cfg.wallpaper;
# Add system activation script to ensure wallpaper is available early dir = cfg.wallpaperDir;
system.activationScripts.wallpaper = wallpaper-activation-script; reloadCommand = "${lib.getExe' pkgs.hyprland "hyprctl"} hyprpaper wallpaper ,${cfg.wallpaper},";
systemd = {
services = {
preload-wallpaper = {
enable = true;
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
# before = [ "display-manager.service" ];
# requiredBy = [
# "plymouth-quit-wait.service"
# "display-manager.service"
# ];
# wantedBy = [ "display-manager.service" ];
path = [
pkgs.bash
pkgs.jq
pkgs.curl
bing-wallpaper
nasa-wallpaper
];
script = ''
${wallpaper-command}
'';
serviceConfig = {
Type = "oneshot";
TimeoutSec = "10s"; # Limit how long we wait for network
};
};
};
user = {
services = {
reload-wallpaper = {
enable = true;
path = [
pkgs.bash
pkgs.jq
pkgs.curl
pkgs.hyprland
bing-wallpaper
nasa-wallpaper
];
script = ''
${wallpaper-command}
${lib.getExe' pkgs.hyprland "hyprctl"} hyprpaper wallpaper ,${cfg.wallpaper},
'';
serviceConfig = {
Type = "oneshot";
};
};
};
# Create a timer to run the service periodically
timers = {
reload-wallpaper = {
description = "Timer for reload-wallpaper";
wantedBy = [ "timers.target" ];
# Timer configuration
timerConfig = {
OnCalendar = "daily"; # Check every day
Persistent = true; # Run immediately if last run was missed
Unit = "reload-wallpaper.service";
};
};
};
};
}; };
}; };
} }

View File

@@ -0,0 +1,62 @@
{
config,
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}) mkBoolOpt mkOpt;
cfg = config.${namespace}.desktop.plasma;
in
{
options.${namespace}.desktop.plasma = {
enable = lib.mkEnableOption "KDE Plasma 6 desktop environment";
wayland.enable = mkBoolOpt true "Use the Wayland session (default) instead of X11";
wallpaper = {
enable = mkBoolOpt false "Enable automatic wallpaper management (Bing/NASA daily download)";
source = mkOpt (lib.types.enum [
"bing"
"nasa"
]) "bing" "Source for the wallpaper (bing or nasa)";
};
};
config = lib.mkIf cfg.enable (
lib.mkMerge [
{
services = {
desktopManager.plasma6.enable = true;
displayManager.sddm = {
enable = true;
wayland.enable = cfg.wayland.enable;
};
# Required for Bluetooth D-Bus policy (allows WirePlumber/PipeWire
# to communicate with bluetoothd on the system bus).
blueman.enable = true;
};
xdg.portal.extraPortals = [ ];
environment.systemPackages = with pkgs; [
kdePackages.kdeplasma-addons
];
}
# Wallpaper management: wire the shared wallpaper module in when requested.
# plasma-apply-wallpaperimage hot-reloads the wallpaper in the running session.
(lib.mkIf cfg.wallpaper.enable {
${namespace}.wallpaper = {
enable = true;
source = cfg.wallpaper.source;
reloadCommand = "${lib.getExe' pkgs.kdePackages.plasma-workspace "plasma-apply-wallpaperimage"} /run/wallpaper.jpg";
};
})
]
);
}

0
modules/nixos/development/default.nix Normal file → Executable file
View File

0
modules/nixos/disko/default.nix Normal file → Executable file
View File

0
modules/nixos/disko/options.nix Normal file → Executable file
View File

0
modules/nixos/fonts/default.nix Normal file → Executable file
View File

View File

@@ -10,7 +10,8 @@ let
hasDesktop = hasDesktop =
config.${namespace}.desktop.gnome.enable config.${namespace}.desktop.gnome.enable
|| config.${namespace}.desktop.hyprland.enable || config.${namespace}.desktop.hyprland.enable
|| config.${namespace}.desktop.cosmic.enable; || config.${namespace}.desktop.cosmic.enable
|| config.${namespace}.desktop.plasma.enable;
in in
{ {
imports = [ ./options.nix ]; imports = [ ./options.nix ];
@@ -19,7 +20,7 @@ in
assertions = [ assertions = [
{ {
assertion = hasDesktop; assertion = hasDesktop;
message = "mjallen.gaming.enable requires a desktop environment (gnome, hyprland, or cosmic) to be enabled."; message = "mjallen.gaming.enable requires a desktop environment (gnome, hyprland, cosmic, or plasma) to be enabled.";
} }
]; ];
# Network option required using sysctl to let Ubisoft Connect work as of 7-12-2023 # Network option required using sysctl to let Ubisoft Connect work as of 7-12-2023
@@ -53,8 +54,6 @@ in
] ]
++ (with pkgs.${namespace}; [ ++ (with pkgs.${namespace}; [
proton-cachyos proton-cachyos
proton-cachyos-v3
proton-cachyos-v2
proton-cachyos-v1 proton-cachyos-v1
]); ]);
gamescopeSession = lib.mkDefault { gamescopeSession = lib.mkDefault {
@@ -91,7 +90,7 @@ in
# Hardware configs # Hardware configs
hardware = { hardware = {
# Xbox controllers # Xbox controllers
xpadneo.enable = false; xone.enable = true;
# Steam udev rules for remote play # Steam udev rules for remote play
steam-hardware.enable = true; steam-hardware.enable = true;

View File

@@ -14,9 +14,13 @@ in
options.${namespace}.hardware.amd = { options.${namespace}.hardware.amd = {
enable = mkEnableOption "AMD hardware configuration"; enable = mkEnableOption "AMD hardware configuration";
corectrl.enable = mkBoolOpt false "Enable CoreCtrl GPU control"; coolercontrol.enable = mkBoolOpt false "Enable CoolerControl fan/cooling control";
corectrl.enablePolkit = mkBoolOpt false "Enable CoreCtrl polkit rules";
corectrl.polkitGroup = mkOpt types.str "wheel" "Group allowed to use CoreCtrl without password"; corectrl = {
enable = mkBoolOpt false "Enable CoreCtrl GPU control";
enablePolkit = mkBoolOpt false "Enable CoreCtrl polkit rules";
polkitGroup = mkOpt types.str "wheel" "Group allowed to use CoreCtrl without password";
};
lact.enable = mkBoolOpt false "Enable LACT daemon (AMD GPU control)"; lact.enable = mkBoolOpt false "Enable LACT daemon (AMD GPU control)";
}; };
@@ -42,10 +46,12 @@ in
}; };
programs.corectrl = { programs.corectrl = {
enable = cfg.corectrl.enable; inherit (cfg.corectrl) enable;
package = pkgs.corectrl; package = pkgs.corectrl;
}; };
programs.coolercontrol.enable = lib.mkIf cfg.coolercontrol.enable true;
environment = { environment = {
variables = { variables = {
AMD_VULKAN_ICD = "RADV"; AMD_VULKAN_ICD = "RADV";

0
modules/nixos/hardware/battery/default.nix Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More