8 Commits

Author SHA1 Message Date
mjallen18
f70a569755 lower refresh rate to fix artifacting 2025-12-04 19:15:34 -06:00
mjallen18
6a99106ca4 icons 2025-12-01 17:13:37 -06:00
mjallen18
2bf51abad5 icons 2025-12-01 17:01:07 -06:00
mjallen18
31e0a03dc2 cursor 2025-12-01 16:48:16 -06:00
mjallen18
3a84cfd7b8 fonts 2025-12-01 16:32:05 -06:00
mjallen18
f132da0433 more theme 2025-12-01 16:24:40 -06:00
mjallen18
a0870e42ca theme stuff 2025-12-01 16:21:12 -06:00
mjallen18
47e2b0caf8 temp 2025-12-01 14:50:23 -06:00
393 changed files with 11010 additions and 22196 deletions

3
.gitignore vendored
View File

@@ -10,5 +10,4 @@ shell.nix
.envrc
.DS_Store
*.qcow2
keys
iso-*
keys

View File

@@ -2,19 +2,19 @@
keys:
- &matt-pgp CBCB9B18A6B8930B0B6ABFD1CCB8CBEB30633684
- &matt age157jemphjzg6zmk373vpccuguyw6e75qnkqmz8pcnn2yue85p939swqqhy0
- &matt_pi4 age13g9a4d4jrvckfddpgn8sm4kjtzajr67le56pfdg78ktr5pd09phq32j89u
- &matt_pi5 age1wpvfpv5n32lruk7c0da4uaeapsmhjxdvg8z4ljehn06l6g2y0e0sum404l
- &desktop age1jv8ap5zwa49ftv0gg7wqf5ps0e68uuwxe2fekjsn0zkyql964unqyc58rf
- &admin age1pm3fehmmk0vmnrscz9vm96rakn46aaldr5ydpscmde3v9x0k3faswwdzxs
- &jallen-nas age1mn2afyp9my7y7hcyzum0wdwt49zufnkt8swnyy8pj30cwzs4zvgsthj0lt
- &pi4 age1ykkjw57t3z3deup3gtp7dujyaslskn74e0d9hsmqaha2pj3rvazqgndw5a
- &pi5 age1t2d5scrukk0guva5sr97a8tge5j8kd865adezrcru7p269pzwvpsamkgje
- &deck age1c8qw59ffcq9l77gfmtyc3djtvt3md0u6dwhrjcgsm98ntyf72ufqugj7cg
- &steamdeck age1er5qucsc2mugrzrr7n3xhzv7kemkrqrw4m84r544fkk7nkg5g5eswxkqj0
- &matt_macbook-pro age12gu9hqhd56yl5x3t5yenkn9yg57du08h77vzjqsmnu5hdppne38qcur5a0
- &macbook-pro age1t7378n8kmd3f32fkye2gw3jj6qswv3exjdx0dq8kl0xra3tmcdnsvddq3u
- &matt_macbook-pro age19daqsncuzeh3j6cwk8uxp6yfj8h0qtz02jxlwwy4v8j0mfgznsvq30440g
- &macbook-pro age19w4zafpwnq9yhzuf8r5te2yhq7xlqj76rcgzcz935hllyrz4yvws4jn6ca
- &nuc age102el4snus37dj807rwvsmlvwu2sg2d8rw3vfmtntgczfkz04l9nshetcq0
- &admin_nuc age1yn82e39pxt0d0pgny34ux4lkge4ff7wxvsye8ragvwngehemt4ps27phyw
- &matt_allyx age18z4ctyyj7eq0cmt23eelfzjuacq4fa6hsplyg779d3rdg7ac2q5q2njxqh
- &allyx age164xpf9cepfjqvcn7v5ahcaq9zmm5u3yl9t04d098e3e2zkfjcyws02rx42
- &admin_nuc age102el4snus37dj807rwvsmlvwu2sg2d8rw3vfmtntgczfkz04l9nshetcq0
creation_rules:
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
@@ -22,10 +22,12 @@ creation_rules:
- *matt-pgp
age:
- *matt
- *matt_pi4
- *matt_pi5
- *desktop
- *admin
- *jallen-nas
- *pi4
- *pi5
- *deck
- *steamdeck
@@ -33,8 +35,6 @@ creation_rules:
- *macbook-pro
- *admin_nuc
- *nuc
- *matt_allyx
- *allyx
- path_regex: nas-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
@@ -53,7 +53,7 @@ creation_rules:
- *desktop
- *admin
- *jallen-nas
- path_regex: allyx-secrets/[^/]+\.(yaml|json|env|ini)$
- path_regex: steamdeck-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
@@ -64,16 +64,29 @@ creation_rules:
- *steamdeck
- *admin
- *jallen-nas
- *matt_allyx
- *allyx
- path_regex: pi4-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- *matt
- *matt_pi4
- *matt_pi5
- *desktop
- *pi4
- *pi5
- *admin
- *jallen-nas
- path_regex: pi5-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- *matt
- *matt_pi4
- *matt_pi5
- *desktop
- *pi4
- *pi5
- *admin
- *jallen-nas

208
AGENTS.md
View File

@@ -1,208 +0,0 @@
# Agent Guide
## Directory Structure
```
/etc/nixos/
├── flake.nix # Main flake configuration
├── flake.lock # Locked versions
├── AGENTS.md # This file
├── treefmt.nix # Code formatting config
├── qemu.nix # QEMU testing config
├── systems/ # System configurations by architecture
│ ├── aarch64-linux/
│ │ ├── macbook-pro-nixos/ # Apple Silicon MacBook
│ │ │ ├── default.nix
│ │ │ ├── boot.nix
│ │ │ ├── services.nix # logind, gdm, gnome, flatpak, etc.
│ │ │ ├── filesystems.nix
│ │ │ ├── hardware-configuration.nix
│ │ │ └── firmware/ # Asahi firmware
│ │ └── pi5/ # Raspberry Pi 5
│ │ ├── default.nix
│ │ ├── boot.nix
│ │ ├── adguard.nix
│ │ └── sops.nix
│ ├── x86_64-linux/
│ │ ├── matt-nixos/ # Desktop AMD system
│ │ │ ├── default.nix
│ │ │ ├── boot.nix
│ │ │ ├── filesystems.nix
│ │ │ ├── sops.nix
│ │ │ └── services/
│ │ │ ├── lsfg-vk/
│ │ │ ├── ratbagd/
│ │ │ └── restic/
│ │ ├── allyx/ # ASUS ROG Ally X
│ │ │ ├── default.nix
│ │ │ └── boot.nix
│ │ ├── nuc-nixos/ # Intel NUC
│ │ ├── jallen-nas/ # NAS server
│ │ └── iso-minimal/
│ └── aarch64-darwin/
│ └── macbook-pro/ # macOS (nix-darwin)
├── homes/ # Home-manager configurations
│ ├── aarch64-linux/
│ │ └── matt@macbook-pro-nixos/
│ │ └── default.nix
│ ├── x86_64-linux/
│ └── aarch64-darwin/
├── modules/ # Shared modules
│ ├── nixos/ # NixOS system modules
│ ├── home/ # Home-manager modules
│ └── darwin/ # nix-darwin modules
├── packages/ # Custom package overlays
│ ├── omnissa/
│ ├── bcachefs/
│ ├── raspberrypi/
│ ├── comfyui/
│ ├── homeassistant/
│ ├── librepods-beta/
│ └── ...
└── secrets/ # SOPS secrets
├── secrets.yaml # Master key config
└── *-secrets.yaml # Per-host secrets
```
## System Configurations
### macbook-pro-nixos (Apple Silicon MacBook)
- **Path**: `systems/aarch64-linux/macbook-pro-nixos/`
- **Key files**:
- `services.nix:72-81` - logind/sleep settings
- `default.nix` - main config, imports all parts
- `boot.nix` - systemd-boot, kernel params
- **Features**: Asahi Linux, GNOME, Hyprland option, battery management
### matt-nixos (AMD Desktop)
- **Path**: `systems/x86_64-linux/matt-nixos/`
- **Features**: AMD GPU (LACT), GNOME, gaming, Lanzaboote
### allyx (ASUS ROG Ally X)
- **Path**: `systems/x86_64-linux/allyx/`
- **Features**: Jovian NixOS, Steam, handheld-daemon, AMD GPU
### pi5 (Raspberry Pi 5)
- **Path**: `systems/aarch64-linux/pi5/`
- **Features**: Headless, AdGuard, Docker, static IP, UEFI boot
### jallen-nas (NAS Server)
- **Path**: `systems/x86_64-linux/jallen-nas/`
- **Features**: Headless, VPN, bcachefs, restic backups
## NixOS Modules (`modules/nixos/`)
### Desktop Environments
- `desktop/gnome/default.nix` - GNOME configuration
- `desktop/hyprland/default.nix` - Hyprland configuration
- `desktop/cosmic/default.nix` - Cosmic DE configuration
### Hardware
- `hardware/amd/default.nix` - AMD GPU (LACT)
- `hardware/nvidia/default.nix` - NVIDIA GPU
- `hardware/battery/default.nix` - Battery management
- `hardware/raspberry-pi/` - Raspberry Pi support
### Boot & System
- `boot/common/` - Common boot settings
- `boot/lanzaboote/` - Lanzaboote (secure boot)
- `boot/systemd-boot/` - Systemd-boot config
- `boot/plymouth/` - Plymouth splash screen
### Networking
- `network/default.nix` - Network configuration (hostname, firewall, NM)
- `network/options.nix` - Network module options
### Other Services
- `headless/default.nix` - Headless server config (watchdog, no suspend)
- `gaming/default.nix` - Steam, Gamescope, Gamemode
- `programs/default.nix` - System programs (nix-index, gnupg, etc.)
## Home-Manager Modules (`modules/home/`)
### Programs
- `programs/waybar/` - Wayland bar
- `programs/hyprland/` - Hyprland config
- `programs/kitty/` - Kitty terminal
- `programs/wofi/` - Wofi launcher
- `programs/wlogout/` - Logout menu
- `programs/btop/` - System monitor
- `programs/git/` - Git configuration
- `programs/zsh/` - Zsh configuration
- `programs/mako/` - Notification daemon
### Desktop
- `desktop/gnome/` - GNOME settings
- `desktop/stylix/` - Stylix theming
### Services
- `services/sops/` - SOPS integration
## Custom Packages (`packages/`)
- `omnissa/` - Omnissa Horizon client
- `bcachefs/` - Bcachefs tools
- `raspberrypi/` - Raspberry Pi firmware/tools
- `comfyui/` - ComfyUI packages
- `homeassistant/` - Home Assistant components
- `librepods-beta/` - LibrePODS beta (AirPods support)
## Common Patterns
### Enable a desktop environment
```nix
${namespace}.desktop.gnome.enable = true;
${namespace}.desktop.hyprland.enable = true;
```
### Enable SOPS
```nix
${namespace}.sops.enable = true;
```
### Enable headless mode
```nix
${namespace}.headless.enable = true;
```
### System imports
```nix
imports = [
./boot.nix
./filesystems.nix
./hardware-configuration.nix
./services.nix
];
```
### Namespace options (flake.nix:253)
```nix
namespace = "mjallen";
```
## SOPS Secrets
Secrets are encrypted with SOPS. Each system has its own secrets file:
- `secrets/mac-secrets.yaml` - macbook-pro-nixos
- `secrets/pi5-secrets.yaml` - pi5
- `secrets/allyx-secrets.yaml` - allyx
- `secrets/nuc-secrets.yaml` - nuc-nixos
- `secrets/nas-secrets.yaml` - jallen-nas
## Flake Inputs (flake.nix)
Key inputs:
- `nixpkgs-unstable` - Unstable channel
- `nixpkgs-stable` - Stable channel (25.11)
- `home-manager-unstable` - Home-manager
- `nixos-apple-silicon` - Apple Silicon support
- `nixos-hardware` - Common hardware configs
- `disko` - Disk partitioning
- `sops-nix` - Secrets management
- `lanzaboote` - Secure boot
- `jovian` - Steam Deck support (allyx)

View File

@@ -113,17 +113,6 @@ sudo nixos-rebuild switch --flake .#hostname
home-manager switch --flake .#username@hostname
```
## Documentation
Comprehensive documentation is available in the [docs](./docs) directory:
- [Getting Started](./docs/getting-started.md) - Instructions for setting up new systems
- [Architecture](./docs/architecture.md) - Overview of the repository structure
- [System Configurations](./docs/systems/README.md) - Details about each system
- [Home Assistant](./docs/home-assistant/README.md) - Home Assistant setup and automations
- [Custom Modules](./docs/modules/README.md) - Details about reusable configuration modules
- [Troubleshooting](./docs/troubleshooting.md) - Common issues and solutions
## License
This project is licensed under the MIT License - see the LICENSE file for details.

View File

@@ -1,383 +0,0 @@
# Workarounds, Overrides & Temporary Fixes
This document tracks all known workarounds, patches, and temporary overrides in this flake.
Each entry includes the file location, reason, and whether it is still required.
**Status legend:**
- `ACTIVE` — still required, upstream fix not available
- `REDUNDANT` — upstream has fixed the issue; this override can be removed
- `UPSTREAM PENDING` — waiting on an upstream PR/issue
- `INTENTIONAL` — permanent design decision, not a workaround
---
## Overlays (upstream package overrides)
### `overlays/cosmic-settings-daemon/default.nix`
**Status:** `ACTIVE — UPSTREAM PENDING`
`cosmic-settings-daemon 1.0.8` has a buggy `Cargo.lock` that references
`https://github.com/pop-os/dbus-settings-bindings` at two different commits
(`3b86984` for `cosmic-dbus-a11y`/`locale1`/`upower_dbus`, and `0fa672f8`
for the `cosmic-settings-daemon` subcrate). `cargoSetupHook` (used by
`fetchCargoVendor`/`cargoHash`) rejects this: *"Sources are not allowed to be
defined multiple times."*
The fix overrides `cargoDeps` with `rustPlatform.importCargoLock`, which uses
a different vendoring strategy that handles multiple commits from the same repo.
**Removal condition:** When nixpkgs updates `cosmic-settings-daemon` past 1.0.8
with a fixed `Cargo.lock`, or applies `cargoLock` in its own package definition.
---
### `overlays/cosmic-applets/default.nix`
**Status:** `ACTIVE — UPSTREAM PENDING`
`cosmic-applets 1.0.8` has the same class of bug: its `Cargo.lock` references
`https://github.com/pop-os/cosmic-settings` at two different commits (`b46a55d`
for `cosmic-pipewire` and `cosmic-settings-sound-subscription`, and `55b502d`
for `cosmic-settings-a11y-manager-subscription` and several other crates).
`cargoSetupHook` rejects this with the same "Sources are not allowed to be
defined multiple times" error.
Same fix as `cosmic-settings-daemon`: overrides `cargoDeps` with
`rustPlatform.importCargoLock`.
**Removal condition:** When nixpkgs updates `cosmic-applets` past 1.0.8 with a
fixed `Cargo.lock`, or applies `cargoLock` in its own package definition.
---
### ~~`overlays/waybar/default.nix`~~ — REMOVED
**Status:** `REMOVED`
Previously added `-Dexperimental=true` to waybar's meson flags. nixpkgs now
includes `-Dexperimental=true` in its waybar definition, making the overlay
redundant. Removed.
---
### `overlays/radios/default.nix`
**Status:** `ACTIVE` (protective — needed after next `flake update`)
`radios` requires `pycountry>=24.0.0,<25.0.0` (PEP 440: `^24.0.0`). The
current locked nixpkgs has `pycountry 24.6.1` (in range), but nixpkgs HEAD
has already bumped `pycountry` to `26.2.16`, which will break `radios` after
the next `flake update`. The overlay applies `pythonRelaxDepsHook` to loosen
the upper bound.
**Removal condition:** When the upstream `radios` package (`frenck/python-radios`)
or nixpkgs relaxes the pycountry version constraint.
---
### `overlays/redis/default.nix`
**Status:** `INTENTIONAL`
Replaces `redis` with `valkey` (the Redis community fork) globally. This is a
deliberate preference for the open-source fork over the Redis 7.x+ license change.
---
### `overlays/stable/default.nix`
**Status:** `INTENTIONAL`
Injects `pkgs.stable` as an attribute pointing to the stable nixpkgs channel,
so modules can selectively pull in stable packages. Not a workaround.
---
## Flake Inputs (forks and custom branches)
### `nixpkgs-otbr` — `github:mrene/nixpkgs/openthread-border-router`
**File:** `flake.nix:8`
**Status:** `ACTIVE — UPSTREAM PENDING`
`openthread-border-router` is not yet packaged in nixpkgs-unstable. A community
member's nixpkgs fork provides the package, used by
`modules/nixos/homeassistant/services/thread/default.nix`.
The fork is ~52,000 commits behind `nixos-unstable`, so it is pulled
only via `pkgs.callPackage` from the fork's path, not as a full channel overlay.
**Removal condition:** When `openthread-border-router` is merged into nixpkgs.
Check: https://github.com/NixOS/nixpkgs/pulls?q=openthread-border-router
---
### `snowfall-lib` — `github:mjallen18/snowfall-lib`
**File:** `flake.nix:26`
**Status:** `INTENTIONAL`
Personal fork of `snowfallorg/lib` with 46 commits ahead of upstream, including:
- `fix: pass namespace argument to overlays`
- `fix: pass namespace argument to home-manager modules`
- `feat: support same username across multiple targets`
- `feat: enable per-channel configuration and fix pkgs selection`
- Performance improvements and additional features
These are custom changes required by this flake's structure that have not been
upstreamed.
---
### `steam-rom-manager` — `github:mjallen18/nix-steam-rom-manager`
**File:** `flake.nix:41`
**Status:** `INTENTIONAL`
Personal fork/packaging of nix-steam-rom-manager. The upstream
(`nix-community/nix-steam-rom-manager`) may or may not exist; this is a
maintained fork.
---
### Commented-out: `nvmd/disko` fork
**File:** `flake.nix:59-61`
**Status:** `REDUNDANT` (already disabled)
```nix
# the fork is needed for partition attributes support
# url = "github:nvmd/disko/gpt-attrs";
```
A community fork of disko with GPT partition attribute support was previously
used but has since been switched back to upstream `nix-community/disko`. The
comment can be cleaned up if the feature is no longer needed.
---
## Build Fixes & postPatch
### `packages/edk2-basetools/default.nix` — OpenSSL vendoring FIXME
**File:** `packages/edk2-basetools/default.nix:50-52`
**Status:** `UPSTREAM PENDING` (verify PR reference)
```nix
# FIXME: unvendor OpenSSL again once upstream updates
# to a compatible version.
# Upstream PR: https://github.com/tianocore/edk2/pull/10946
```
The comment references tianocore/edk2 PR #10946, but that PR's title is
*"update to openssl 3.5.1"* (now merged), not an unvendoring PR. The FIXME
comment may be referencing the wrong PR number or the issue may have evolved.
The edk2 build still vendor-patches OpenSSL compatibility; this should be
re-evaluated against the current edk2 upstream.
**Action:** Verify whether the OpenSSL vendoring is still needed with current
edk2, and update or remove the FIXME comment.
---
### `packages/bcachefs/default.nix` — Tests disabled
**File:** `packages/bcachefs/default.nix:100`
**Status:** `ACTIVE`
```nix
# FIXME: Try enabling this once the default linux kernel is at least 6.7
doCheck = false; # needs bcachefs module loaded on builder
```
Tests require a live bcachefs kernel module in the build sandbox, which is
not available. The comment mentions kernel ≥ 6.7, which is now the case
(nixpkgs is on 6.12+), but the underlying sandbox limitation still applies —
the build sandbox cannot load kernel modules regardless of kernel version.
**Action:** The `6.7` condition is now met but irrelevant; update the comment
to reflect that the real blocker is sandbox access to kernel modules.
---
### `packages/raspberrypi/linux-rpi/default.nix` — Failed kernel attempts
**File:** `packages/raspberrypi/linux-rpi/default.nix:25-43`
**Status:** `ACTIVE` (informational)
Four newer RPi kernel versions (6.15.11 through 6.19.0-rc5) are commented out
because they "fail for various reasons." The active version is pinned to an
older working commit.
**Action:** Periodically attempt to enable a newer kernel tag. The comments
serve as a history of failed attempts.
---
### `packages/raspberrypi/linux-rpi/default.nix` — DTB aliasing hack
**File:** `packages/raspberrypi/linux-rpi/default.nix:110-148`
**Status:** `ACTIVE`
```nix
# Make copies of the DTBs named after the upstream names so that U-Boot finds them.
# This is ugly as heck, but I don't know a better solution so far.
```
RPi's kernel ships DTBs with non-standard names (e.g. `bcm2708-rpi-zero-w.dtb`);
U-Boot expects canonical upstream names (e.g. `bcm2835-rpi-zero.dtb`). DTBs
are duplicated in `postFixup`.
---
### `packages/homeassistant/ha-mail-and-packages/default.nix` — Hardcoded paths
**File:** `packages/homeassistant/ha-mail-and-packages/default.nix:25-37`
**Status:** `ACTIVE`
The upstream HA integration hard-codes paths relative to its source directory,
which breaks in the Nix store. `postPatch` rewrites them to
`/var/lib/homeassistant/images/`.
---
### `packages/homeassistant/ha-wyzeapi/default.nix` — Version pin relaxation
**File:** `packages/homeassistant/ha-wyzeapi/default.nix:24-27`
**Status:** `ACTIVE`
Relaxes the minimum `wyzeapy` version pin from `0.5.28` to `0.5.27` to match
the version packaged in this flake.
---
## Raspberry Pi — Structural Overrides
### `modules/nixos/hardware/raspberry-pi/default.nix` — jemalloc 16K pages
**File:** `modules/nixos/hardware/raspberry-pi/default.nix:458-470`
**Status:** `ACTIVE` (structural)
```nix
# https://github.com/nvmd/nixos-raspberrypi/issues/64
jemalloc = prev.jemalloc.overrideAttrs (old: {
configureFlags = ... ++ [ "${pageSizeFlag}=14" ];
});
```
RPi5 uses 16K memory pages (2^14). jemalloc must be compiled with
`--with-lg-page=14`, otherwise it will use incorrect page size assumptions
and likely crash or corrupt memory.
**References:** https://github.com/nvmd/nixos-raspberrypi/issues/64
---
### `systems/aarch64-linux/pi5/boot.nix` — 16K page kernel
**File:** `systems/aarch64-linux/pi5/boot.nix:22-35`
**Status:** `ACTIVE` (structural)
Forces `CONFIG_ARM64_16K_PAGES=y` in the kernel config via `linux_6_19.override`.
`ignoreConfigErrors = true` is required because some kernel config options are
unavailable and would otherwise fail validation.
---
### `packages/raspberrypi/ffmpeg-rpi/default.nix` — RPi hardware codec ffmpeg
**File:** `packages/raspberrypi/ffmpeg-rpi/default.nix`
**Status:** `ACTIVE` (structural)
Custom ffmpeg build from `jc-kynesim/rpi-ffmpeg` fork with RPi hardware codec
support (`--enable-v4l2-request`, `--enable-sand`, etc.). Tests disabled
(`doCheck = false`) because the `imgutils` test fails on this build.
---
## systemd Service Overrides
### `systems/x86_64-linux/matt-nixos/default.nix` — networkd-wait-online
**File:** `systems/x86_64-linux/matt-nixos/default.nix:78`
**Status:** `INTENTIONAL`
```nix
systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false;
```
The `systemd-networkd-wait-online` service times out on this desktop,
blocking boot. Standard workaround for desktop systems that don't require
all interfaces to be up before proceeding.
---
### `systems/x86_64-linux/allyx/default.nix` — Jovian NixOS conflicts
**File:** `systems/x86_64-linux/allyx/default.nix:121-123`
**Status:** `ACTIVE`
```nix
systemd-networkd-wait-online.enable = lib.mkForce false;
power-profiles-daemon.enable = lib.mkForce false;
inputplumber.enable = lib.mkForce false;
```
On the ASUS ROG Ally X with Jovian NixOS and `handheld-daemon`:
- `power-profiles-daemon` conflicts with `handheld-daemon`'s power management
- `inputplumber` conflicts with `handheld-daemon`'s input handling
- `systemd-networkd-wait-online` times out as on matt-nixos
---
### `modules/nixos/services/crowdsec/default.nix` — DynamicUser conflict
**File:** `modules/nixos/services/crowdsec/default.nix:133-143`
**Status:** `ACTIVE — UPSTREAM PENDING`
```nix
systemd.services.crowdsec.serviceConfig.DynamicUser = lib.mkForce false;
systemd.services.crowdsec-firewall-bouncer.serviceConfig.DynamicUser = lib.mkForce false;
systemd.services.crowdsec-firewall-bouncer-register.serviceConfig.DynamicUser = lib.mkForce false;
```
The upstream NixOS crowdsec module uses `ReadWritePaths` (not `StateDirectory`)
on the main `crowdsec.service`, expecting `/var/lib/crowdsec` to be a real
directory. However, `crowdsec-firewall-bouncer-register` declares
`StateDirectory=crowdsec` with `DynamicUser=true`, which conflicts — it tries
to create `/var/lib/private/crowdsec` and symlink `/var/lib/crowdsec` to it,
but the directory already exists as a real path. Disabling `DynamicUser` on
all three services resolves the conflict by using the real `crowdsec` user.
Additionally, `crowdsec-firewall-bouncer-register` calls `cscli` without `-c`,
expecting `/etc/crowdsec/config.yaml` to exist, but the upstream NixOS module
uses a Nix store path via `-c` and never creates that file. The module works
around this by extracting the store path at eval time.
**Removal condition:** When the NixOS crowdsec module is fixed upstream to
handle state directory ownership consistently.
---
## Incomplete / TODO Items
These are not workarounds but known incomplete configurations:
| File | Line | Description |
|------|------|-------------|
| `systems/x86_64-linux/jallen-nas/sops.nix` | 89, 113 | Collabora and MariaDB secrets not configured |
| `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/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 |
| `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 |
---
## Kernel Boot Parameters
### `systems/x86_64-linux/matt-nixos/boot.nix` — NVMe power saving
**File:** `systems/x86_64-linux/matt-nixos/boot.nix:46-48`
**Status:** `ACTIVE`
```nix
"nvme_core.default_ps_max_latency_us=0"
"pcie_aspm=off"
```
NVMe SSD power-saving states cause latency/stability issues on this machine.
Disabling ASPM and NVMe power states is a standard workaround for affected
hardware.
---
### `systems/aarch64-linux/macbook-pro-nixos/boot.nix` — Fan control
**File:** `systems/aarch64-linux/macbook-pro-nixos/boot.nix:28`
**Status:** `ACTIVE`
```nix
"melt_my_mac=1"
```
Undocumented Asahi Linux kernel parameter that enables fan control on Apple
Silicon Macs. The name is intentional (set by the Asahi kernel developers).

73
checks/disksnstuff.sh Executable file → Normal file
View File

@@ -1,62 +1,15 @@
#!/usr/bin/env bash
mount -t tmpfs -o mode=755 none /mnt
mkdir -p /mnt/{boot,home,root,etc,nix,var/log}
mount /dev/sdb1 /mnt/boot
mount /dev/sdb3 -o compress=zstd,subvol=home /mnt/home
mount /dev/sdb3 -o compress=zstd,noatime,subvol=root /mnt/root
mount /dev/sdb3 -o compress=zstd,noatime,subvol=etc /mnt/etc
mount /dev/sdb3 -o compress=zstd,noatime,subvol=nix /mnt/nix
mount /dev/sdb3 -o compress=zstd,noatime,subvol=log /mnt/var/log
disk=/dev/mapper/nuc-nixos-cryptroot
wpa_passphrase "Joey's Jungle 5G" "kR8v&3Qd" > 5g.conf
wpa_supplicant -i wlp6s0 -c 5g.conf -B
dhcpcd
# sudo mkfs.vfat "$disk"1
# sudo bcachefs format --label ssd.ssd1 --compression=zstd --discard "$disk"
sudo mount -t tmpfs -o mode=755 none /mnt
sudo mkdir -p /mnt/{boot,home,root,etc,nix,var/log,tmp,persist}
sudo mount /dev/disk/by-partlabel/disk-main-nuc-nixos-EFI /mnt/boot
# sudo mkdir -p /mnt/boot/firmware
# sudo mount "$disk"2 /mnt/boot/firmware
# sudo mount "$disk"2 -o compress=zstd,subvol=home /mnt/home
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=root /mnt/root
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=etc /mnt/etc
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=nix /mnt/nix
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=log /mnt/var/log
# bcachefs unlock -k session /dev/disk/by-partlabel/disk-main-nuc-nixos-bcachefs-root
sudo cryptsetup open /dev/disk/by-partlabel/disk-main-nuc-nixos-cryptroot nuc-nixos-cryptroot
# sudo bcachefs unlock -k session "$disk"2
# sudo mount "$disk" /mnt/tmp
# cd /mnt/tmp
# ls -alh
# sudo bcachefs subvolume create nix
# sudo bcachefs subvolume create etc
# sudo bcachefs subvolume create log
# sudo bcachefs subvolume create root
# sudo bcachefs subvolume create persist
# sudo bcachefs subvolume create home
# ls -alh
# cd /etc/nixos
# sudo umount /mnt/tmp
sudo mount -o noatime,X-mount.subdir=nix "$disk" /mnt/nix
sudo mount -o noatime,X-mount.subdir=etc "$disk" /mnt/etc
sudo mount -o noatime,X-mount.subdir=log "$disk" /mnt/var/log
sudo mount -o noatime,X-mount.subdir=root "$disk" /mnt/root
sudo mount -o noatime,X-mount.subdir=persist "$disk" /mnt/persist
sudo mount -o X-mount.subdir=home "$disk" /mnt/home
# tree /mnt
# sudo nixos-install --flake /etc/nixos#nuc-nixos
# sudo umount /mnt/boot
# sudo umount /mnt/var/log
# sudo umount /mnt/persist
# sudo umount /mnt/home
# sudo umount /mnt/root
# sudo umount /mnt/etc
# sudo umount /mnt/nix
# sudo umount /mnt
# wpa_passphrase "Joey's Jungle 5G" "kR8v&3Qd" > 5g.conf
# wpa_supplicant -i wlp6s0 -c 5g.conf -B
# dhcpcd
# keyctl link @u @s
# clevis decrypt < "/etc/clevis/nas_pool.jwe" | bcachefs unlock /dev/disk/by-label/nas_pool
keyctl link @u @s
clevis decrypt < "/etc/clevis/nas_pool.jwe" | bcachefs unlock /dev/disk/by-label/nas_pool

View File

@@ -1,12 +0,0 @@
# Documentation
This directory contains comprehensive documentation for the NixOS configuration.
## Contents
- [Getting Started](./getting-started.md) - Instructions for setting up new systems
- [System Configurations](./systems/README.md) - Detailed information about each system
- [Home Assistant](./home-assistant/README.md) - Documentation for the Home Assistant setup
- [Custom Modules](./modules/README.md) - Information about reusable modules
- [Architecture](./architecture.md) - Overview of the repository architecture
- [Troubleshooting](./troubleshooting.md) - Common issues and solutions

View File

@@ -1,104 +0,0 @@
# Repository Architecture
This document provides an overview of the repository architecture, explaining how the various components fit together.
## 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.
## Directory Structure
```
.
├── checks/ # Pre-commit hooks and other checks
├── flake.nix # Main flake configuration
├── homes/ # Home-manager configurations for users
│ ├── aarch64-darwin/ # macOS home configurations
│ ├── aarch64-linux/ # ARM Linux home configurations
│ └── x86_64-linux/ # x86 Linux home configurations
├── modules/ # Reusable configuration modules
│ ├── home/ # Home-manager modules
│ └── nixos/ # NixOS system modules
│ ├── boot/ # Boot configuration modules
│ ├── 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
├── packages/ # Custom package definitions
├── secrets/ # Encrypted secrets (managed with sops-nix)
└── systems/ # System-specific configurations
├── aarch64-darwin/ # macOS system configurations
├── aarch64-linux/ # ARM Linux system configurations
└── x86_64-linux/ # x86 Linux system configurations
├── jallen-nas/ # NAS server configuration
├── matt-nixos/ # Desktop configuration
├── nuc-nixos/ # NUC configuration
└── ... # Other system configurations
```
## Flake Structure
The `flake.nix` file defines the inputs (external dependencies) and outputs (configurations) of this repository:
### Inputs
- **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
The module system uses a modular approach where:
1. **Common modules** are defined in `modules/nixos/` and `modules/home/`
2. **System-specific modules** are defined in `systems/<architecture>/<hostname>/`
Each module follows the NixOS module pattern, with:
- `default.nix`: Main module implementation
- `options.nix`: Option declarations
## Integration with Snowfall Lib
Snowfall Lib provides:
1. **Automatic discovery** of modules, overlays, and packages
2. **Consistent structure** across the repository
3. **Common utilities** for working with flakes
## Secrets Management
Secrets are managed using [sops-nix](https://github.com/Mic92/sops-nix), with:
- Encrypted secret files in the `secrets/` directory
- `.sops.yaml` configuration file in the root
- Key management integrated into the configuration
## Deployment Process
Systems are built and deployed using:
```bash
nixos-rebuild switch --flake .#hostname
```
This command:
1. Evaluates the flake for the specified hostname
2. Builds the resulting configuration
3. Activates it on the current system

View File

@@ -1,172 +0,0 @@
# Getting Started
This guide will help you get started with this NixOS configuration repository.
## Prerequisites
- Basic knowledge of NixOS and the Nix language
- Git installed on your system
- Physical access to the machine you want to configure
## Initial Setup
### 1. Cloning the Repository
Clone this repository to your local machine:
```bash
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git
cd nix-config
```
### 2. Setting Up a New System
#### Option 1: Using an Existing Configuration
If you're setting up a new machine that should be identical to an existing configuration:
1. Boot from a NixOS installation media
2. Mount your target partitions to `/mnt`
3. Clone this repository:
```bash
nixos-enter
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:
```bash
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
If you're adding a completely new system:
1. Create a new directory for your system configuration:
```bash
mkdir -p systems/$(uname -m)-linux/new-hostname
```
2. Create the basic configuration files:
```bash
cat > systems/$(uname -m)-linux/new-hostname/default.nix << EOF
{ lib, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
# Add other needed module imports here
];
networking.hostName = "new-hostname";
# Add your system-specific configuration here
}
EOF
```
3. Generate the hardware configuration:
```bash
nixos-generate-config --no-filesystems --dir systems/$(uname -m)-linux/new-hostname/
```
4. Add your new system to the flake by adding it to the `hosts` section in `flake.nix`
5. Build and install the configuration:
```bash
sudo nixos-rebuild switch --flake .#new-hostname
```
## Secret Management
### Setting Up Sops-Nix
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
git pull
sudo nixos-rebuild switch --flake .#hostname
```
### Adding a New Package
1. For standard packages, add them to your system or home configuration:
```nix
environment.systemPackages = with 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
cfg = config.${namespace}.new-module;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
# Add your configuration here
};
}
EOF
```
3. Import your module in your system configuration:
```nix
imports = [
# ...
../../../modules/nixos/new-module
];
${namespace}.new-module.enable = true;
```

View File

@@ -1,188 +0,0 @@
# Home Assistant Configuration
This document provides comprehensive information about the Home Assistant setup in this NixOS configuration.
## Overview
Home Assistant is configured as a NixOS service with custom components, integrations, and automations. The configuration uses a modular approach with separate files for different aspects of the setup.
## Module Structure
The Home Assistant configuration is organized in the following structure:
```
modules/nixos/homeassistant/
├── automations/ # Automation configurations
│ ├── lightswitch/ # Light switch automations
│ └── motion-light/ # Motion-activated light automations
├── default.nix # Main module configuration
├── options.nix # Module options definition
└── services/ # Related service configurations
├── govee2mqtt/ # Govee integration via MQTT
├── homeassistant/ # Core Home Assistant service
├── music-assistant/ # Music Assistant integration
├── thread/ # Thread border router
└── zigbee2mqtt/ # Zigbee to MQTT bridge
```
## Installation
The Home Assistant module is enabled in the system configuration by setting:
```nix
mjallen.services.home-assistant.enable = true;
```
This activates Home Assistant and related services such as MQTT, Zigbee2MQTT, and the Matter server.
## Configuration Options
The module provides several configuration options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable` | boolean | `false` | Enable Home Assistant and related services |
| `mosquittoPort` | integer | `1883` | Port for the MQTT broker |
| `zigbee2mqttPort` | integer | `8080` | Port for the Zigbee2MQTT web interface |
| `zigbeeDevicePath` | string | `/dev/ttyUSB0` | Path to the Zigbee USB device |
## Core Services
### Home Assistant
The main Home Assistant service is configured in `services/homeassistant/default.nix` with:
- PostgreSQL database backend
- Custom components
- Custom Lovelace modules
- HTTPS access with authentication
- Integration with other services
### MQTT
MQTT is used as a messaging protocol for various smart home devices. The Mosquitto MQTT broker is automatically configured when Home Assistant is enabled.
### Zigbee2MQTT
Zigbee2MQTT allows integration with Zigbee devices. It's configured with:
- Automatic discovery for Home Assistant
- OTA updates for Zigbee devices
- Web interface for management
### Thread Border Router
The Thread Border Router provides integration with Thread-based devices like Matter devices.
## Custom Components
The following custom components are included:
- `ha-anycubic` - Anycubic 3D printer integration
- `ha-bambulab` - Bambu Lab 3D printer integration
- `ha-bedjet` - BedJet climate control integration
- `ha-gehome` - GE Home appliance integration
- `ha-icloud3` - Enhanced iCloud device tracking
- `ha-local-llm` - Local LLM integration
- `ha-mail-and-packages` - Mail and package delivery tracking
- `ha-nanokvm` - NanoKVM integration
- `ha-openhasp` - openHASP integration for DIY displays
- `ha-overseerr` - Overseerr media request integration
- `ha-petlibro` - PetLibro pet feeder integration
- `ha-wyzeapi` - Wyze device integration
## Automations
### Light Switch Automations
The light switch automations handle physical switch inputs for controlling smart lights.
### Motion Light Automations
Motion light automations turn lights on when motion is detected and off after a period of inactivity.
### Custom Automations
Additional automations are placed in the `/etc/hass` directory and are included in the Home Assistant configuration. These include:
- `fountain_automation.yaml` - Toggles the water dispensing mode on the Dockstream Smart RFID Fountain every 15 minutes between constant and intermittent flow.
## Smart Home Devices
The configuration includes support for various smart home devices:
### Lighting
- Various smart lights throughout the home
### Climate
- Smart thermostat
- Humidifier control
### Pet Care
- Dockstream Smart RFID Fountain with scheduling
- Smart pet feeders for pets named Joey and Luci
- Litter-Robot 4 smart litter box
### Media
- Google Cast devices
- Smart TVs
- Media players
### Sensors
- Temperature, humidity, and motion sensors
- Door and window sensors
- Presence detection
## Integration with Other Services
Home Assistant is integrated with:
- **Music Assistant** - For enhanced music streaming capabilities
- **Govee Integration** - For Govee smart devices
- **Matter** - For Matter-compatible devices
## Adding New Automations
To add a new automation:
1. Create a YAML file with the automation definition
2. Place it in `/etc/hass`
3. The automation will be automatically included in Home Assistant
Example automation format:
```yaml
alias: "Automation Name"
description: "Description of what the automation does"
trigger:
- platform: state
entity_id: binary_sensor.motion_sensor
to: "on"
condition: []
action:
- service: light.turn_on
target:
entity_id: light.living_room
mode: single
```
## Troubleshooting
### Common Issues
1. **Zigbee Device Pairing Issues**
- Make sure the Zigbee coordinator is properly connected
- Check the Zigbee2MQTT logs for errors
2. **Service Unavailable**
- Check if all related services are running
- Verify firewall rules allow access to the services
3. **Database Issues**
- Check PostgreSQL service status
- Verify database connection settings

View File

@@ -1,148 +0,0 @@
# Home Assistant Automations
This document details the automations configured in the Home Assistant setup.
## Automation Types
Automations in this configuration are managed in several ways:
1. **Module-Based Automations**: Defined in Nix modules within the `modules/nixos/homeassistant/automations/` directory
2. **YAML Automations**: Defined in YAML files and included via the `automation manual` directive
3. **UI-Created Automations**: Created through the Home Assistant UI and stored in `automations.yaml`
## Module-Based Automations
### Light Switch Automations
**Location**: `modules/nixos/homeassistant/automations/lightswitch/`
These automations link physical light switches to smart lights:
- **Bedroom Light Switch**: Controls the bedroom lights
- **Living Room Light Switch**: Controls the living room lights
- **Bedroom Closet Lights**: Controls the closet lights
### Motion-Activated Light Automations
**Location**: `modules/nixos/homeassistant/automations/motion-light/`
These automations turn lights on when motion is detected and off after a period of inactivity.
## YAML Automations
### Fountain Cycling Automation
**Location**: `/etc/nixos/fountain_automation.yaml`
This automation toggles the water dispensing mode on the Dockstream Smart RFID Fountain every 15 minutes:
```yaml
alias: "Fountain Cycle Mode"
description: "Toggles fountain water mode every 15 minutes between constant and intermittent flow"
trigger:
- platform: time_pattern
minutes: "/15" # Every 15 minutes
condition: []
action:
- service: select.select_next
target:
entity_id: select.dockstream_smart_rfid_fountain_water_dispensing_mode
mode: single
id: fountain_cycle_mode
```
This automation:
1. Triggers every 15 minutes
2. Uses the `select.select_next` service to toggle between the two available options:
- "Flowing Water (Constant)"
- "Intermittent Water (Scheduled)"
The fountain is also configured with:
- Water Interval: 10 minutes
- Water Dispensing Duration: 15 minutes
## Creating New Automations
### Method 1: Module-Based Automation
For reusable, complex automations that should be managed in code:
1. Create a new directory in `modules/nixos/homeassistant/automations/`
2. Create a `default.nix` file with the automation logic
Example:
```nix
{ config, lib, ... }:
{
config = {
services.home-assistant.config."automation manual" = [
{
alias = "Example Automation";
description = "Example automation created via Nix module";
trigger = [
{
platform = "state";
entity_id = "binary_sensor.example_sensor";
to = "on";
}
];
action = [
{
service = "light.turn_on";
target.entity_id = "light.example_light";
}
];
mode = "single";
}
];
};
}
```
### Method 2: YAML Automation
For simpler automations:
1. Create a YAML file with the automation definition
2. Place it in `/etc/hass/`
Example:
```yaml
alias: "Example Automation"
description: "Example automation in YAML"
trigger:
- platform: state
entity_id: binary_sensor.example_sensor
to: "on"
action:
- service: light.turn_on
target:
entity_id: light.example_light
mode: single
```
### Method 3: UI Creation
For quick prototyping or simple automations:
1. Go to Home Assistant UI > Settings > Automations & Scenes
2. Click "+ Add Automation"
3. Configure using the UI editor
## Testing Automations
To test an automation:
1. In the Home Assistant UI, go to Developer Tools > Services
2. Select `automation.trigger` as the service
3. Enter the entity_id of your automation in the service data field
4. Click "Call Service" to trigger the automation manually
## Troubleshooting
If an automation isn't working as expected:
1. Check the Home Assistant logs for errors
2. Verify entity names and service calls are correct
3. Test individual triggers and actions separately
4. Use the "Debug" section in the automation editor to trace execution

View File

@@ -1,96 +0,0 @@
# Pet Fountain Automation
This document details the automation for the Dockstream Smart RFID Fountain device.
## Overview
The Dockstream Smart RFID Fountain is a smart pet fountain controlled through Home Assistant. A custom automation has been created to toggle the water dispensing mode between constant flow and intermittent flow every 15 minutes. This cycling helps keep the water fresh while reducing energy consumption.
## Fountain Configuration
The Dockstream Smart RFID Fountain has the following settings in Home Assistant:
| Setting | Entity ID | Value | Description |
|---------|-----------|-------|-------------|
| Water Dispensing Mode | `select.dockstream_smart_rfid_fountain_water_dispensing_mode` | Toggles between modes | Controls how water flows |
| Water Interval | `number.dockstream_smart_rfid_fountain_water_interval` | 10 minutes | Time between water dispensing in intermittent mode |
| Water Dispensing Duration | `number.dockstream_smart_rfid_fountain_water_dispensing_duration` | 15 minutes | How long water flows in intermittent mode |
| Cleaning Cycle | `number.dockstream_smart_rfid_fountain_cleaning_cycle` | 14 days | Reminder interval for cleaning |
## Available Modes
The fountain supports two water dispensing modes:
1. **Flowing Water (Constant)** - Water flows continuously
2. **Intermittent Water (Scheduled)** - Water flows according to the interval and duration settings
## Automation Details
The fountain cycling automation is defined in `/etc/nixos/fountain_automation.yaml`:
```yaml
alias: "Fountain Cycle Mode"
description: "Toggles fountain water mode every 15 minutes between constant and intermittent flow"
trigger:
- platform: time_pattern
minutes: "/15" # Every 15 minutes
condition: []
action:
- service: select.select_next
target:
entity_id: select.dockstream_smart_rfid_fountain_water_dispensing_mode
mode: single
id: fountain_cycle_mode
```
### How It Works
1. **Trigger**: The automation runs every 15 minutes based on the time pattern trigger
2. **Action**: It uses the `select.select_next` service to toggle to the next available option
3. **Mode**: Set to "single" to prevent multiple executions if triggers overlap
## Installation
The automation is included in Home Assistant via the `automation manual` directive in the Home Assistant configuration:
```yaml
"automation manual" = "!include_dir_merge_list /etc/hass";
```
The YAML file needs to be placed in the `/etc/hass` directory to be loaded.
## Testing
To manually test the automation:
1. In Home Assistant UI, go to Developer Tools > Services
2. Select `automation.trigger` as the service
3. Enter the following service data:
```yaml
entity_id: automation.fountain_cycle_mode
```
4. Click "Call Service" to trigger the automation
## Customizing
To adjust the cycling interval:
1. Edit the YAML file at `/etc/nixos/fountain_automation.yaml`
2. Change the `minutes` value in the trigger section (e.g., from `"/15"` to `"/30"` for every 30 minutes)
3. Save the file
4. Restart Home Assistant or reload automations
To adjust fountain settings:
1. In Home Assistant UI, go to Settings > Devices & Services
2. Find the Dockstream Smart RFID Fountain device
3. Adjust the water interval or dispensing duration settings
## Troubleshooting
If the automation is not working as expected:
1. Check that the entity ID is correct and the fountain is online
2. Verify that Home Assistant is including the automation file correctly
3. Look for errors in the Home Assistant logs related to the automation or the fountain
4. Try manually controlling the fountain to ensure it responds to commands

View File

@@ -1,116 +0,0 @@
# Custom Modules
This directory contains documentation for the custom modules used in this NixOS configuration.
## Module Types
The repository uses two main types of modules:
1. **NixOS Modules** - System-level configurations in `modules/nixos/`
2. **Home Manager Modules** - User-level configurations in `modules/home/`
## NixOS Modules
These modules configure the system-level aspects of NixOS:
- [Boot Modules](./boot.md) - Boot loader and kernel configurations
- [Desktop Modules](./desktop.md) - Desktop environment configurations
- [Development Modules](./development.md) - Development tools and environments
- [Hardware Modules](./hardware.md) - Hardware-specific configurations
- [Home Assistant Modules](./homeassistant.md) - Home automation configuration
- [Networking Modules](./network.md) - Network configuration and services
- [Security Modules](./security.md) - Security-related configurations
- [Services Modules](./services.md) - Various service configurations
- [System Modules](./system.md) - General system configurations
- [Virtualization Modules](./virtualization.md) - Virtualization and containerization
## Home Manager Modules
These modules configure user environments:
- [Applications](./home/applications.md) - User applications
- [Desktop](./home/desktop.md) - User desktop environments
- [Development](./home/development.md) - User development environments
- [Media](./home/media.md) - Media applications
- [Shell](./home/shell.md) - Shell configurations
## Module Structure
Each module follows a standard structure:
```
modules/nixos/example-module/
├── default.nix # Main implementation
├── options.nix # Option declarations
└── submodule/ # Optional submodules
└── default.nix # Submodule implementation
```
### default.nix
The `default.nix` file contains the main implementation of the module:
```nix
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.example-module;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
# Module implementation when enabled
};
}
```
### options.nix
The `options.nix` file declares the module's configuration options:
```nix
{ lib, namespace, ... }:
with lib;
let
inherit (lib.${namespace}) mkOpt;
in
{
options.${namespace}.example-module = {
enable = mkEnableOption "enable example module";
# Other option declarations
};
}
```
## Using Modules
To use a module in your system configuration:
1. Enable the module in your system configuration:
```nix
{ config, ... }:
{
mjallen.example-module = {
enable = true;
# Other options
};
}
```
## 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.

View File

@@ -1,190 +0,0 @@
# Home Assistant Module
This document details the Home Assistant module configuration.
## Module Structure
The Home Assistant module is organized in the following structure:
```
modules/nixos/homeassistant/
├── automations/ # Automation configurations
│ ├── lightswitch/ # Light switch automations
│ └── motion-light/ # Motion-activated light automations
├── default.nix # Main module configuration
├── options.nix # Module options definition
└── services/ # Related service configurations
├── govee2mqtt/ # Govee integration via MQTT
├── homeassistant/ # Core Home Assistant service
├── music-assistant/ # Music Assistant integration
├── thread/ # Thread border router
└── zigbee2mqtt/ # Zigbee to MQTT bridge
```
## Module Options
The module is configured through options defined in `options.nix`:
```nix
options.${namespace}.services.home-assistant = {
enable = mkEnableOption "enable home-assistant";
mosquittoPort = mkOpt types.int 1883 "Port for MQTT";
zigbee2mqttPort = mkOpt types.int 8080 "Port for zigbee2mqtt web interface";
zigbeeDevicePath = mkOpt types.str "/dev/ttyUSB0" "Path to zigbee usb device";
};
```
## Main Configuration
The main module configuration in `default.nix` includes:
1. **Activation Scripts** - For setting up custom components
2. **Service Configurations** - For Matter, PostgreSQL, etc.
3. **Firewall Rules** - For allowing required ports
```nix
config = lib.mkIf cfg.enable {
# Activation script for custom components
system.activationScripts.installCustomComponents = ''
chown -R hass:hass ${config.services.home-assistant.configDir}
chmod -R 750 ${config.services.home-assistant.configDir}
'';
# Service configurations
services = {
matter-server.enable = true;
postgresql = {
enable = false;
ensureDatabases = [ "hass" ];
ensureUsers = [
{
name = "hass";
ensureDBOwnership = true;
}
];
};
};
# Firewall rules
networking.firewall.allowedTCPPorts = [
cfg.mosquittoPort
cfg.zigbee2mqttPort
8095 # music-assistant
8097 # home-assistant
5580 # matter-server
];
};
```
## Home Assistant Service
The core Home Assistant service configuration in `services/homeassistant/default.nix` includes:
1. **Package Selection** - Using the standard Home Assistant package
2. **Component Configuration** - Enabling required components
3. **Custom Components** - Adding custom components from packages
4. **Lovelace Modules** - Adding custom UI components
5. **Integration Configuration** - Setting up integrations with other systems
```nix
services.home-assistant = {
enable = true;
package = pkgs.home-assistant;
openFirewall = true;
configDir = "/var/lib/homeassistant";
configWritable = true;
# Components
extraComponents = [
"mqtt"
"zha"
"homekit"
# ... many more components
];
# Custom components
customComponents = [
# ... custom components
];
# Lovelace modules
customLovelaceModules = [
# ... custom UI modules
];
# Configuration
config = {
# ... Home Assistant configuration
};
};
```
## Related Services
### Zigbee2MQTT
The Zigbee2MQTT service in `services/zigbee2mqtt/default.nix` connects Zigbee devices to MQTT:
```nix
services.zigbee2mqtt = {
enable = true;
settings = {
mqtt = {
server = "mqtt://localhost:${toString cfg.mosquittoPort}";
};
serial = {
port = cfg.zigbeeDevicePath;
};
# ... additional settings
};
};
```
### MQTT
MQTT is configured as a dependency for the Home Assistant module.
### Thread Border Router
The Thread Border Router in `services/thread/default.nix` provides Thread network connectivity for Matter devices.
## Automations
The module includes predefined automations in the `automations/` directory:
1. **Light Switch Automations** - For controlling lights via physical switches
2. **Motion Light Automations** - For motion-activated lighting
## Using the Module
To use this module in a system configuration:
```nix
{ config, ... }:
{
mjallen.services.home-assistant = {
enable = true;
# Optional: customize ports and device paths
mosquittoPort = 1883;
zigbee2mqttPort = 8080;
zigbeeDevicePath = "/dev/ttyUSB0";
};
}
```
## Extending the Module
### Adding Custom Components
To add a custom component:
1. Add the package to `packages/`
2. Add it to the `customComponents` list in `services/homeassistant/default.nix`
### Adding Custom Automations
To add a custom automation:
1. Create a new directory in `automations/`
2. Implement the automation in `default.nix`
3. Import it in the system configuration

View File

@@ -1,22 +0,0 @@
# System Configurations
This directory contains documentation for each system configuration in this repository.
## Systems
- [Desktop (matt-nixos)](./matt-nixos.md) - Main desktop computer
- [NAS (jallen-nas)](./jallen-nas.md) - Home server and NAS
- [NUC (nuc-nixos)](./nuc-nixos.md) - Intel NUC
- [Raspberry Pi 5](./pi5.md) - Raspberry Pi 5
- [MacBook Pro (nixOS)](./macbook-pro-nixos.md) - MacBook Pro running NixOS
## Common Configuration
All systems share certain common configurations through the modules system. These include:
- Base system configuration
- User management
- Network configuration
- Security settings
Each system then adds its specific configurations on top of these common modules.

View File

@@ -1,101 +0,0 @@
# NAS Server (jallen-nas)
This document describes the configuration for the NAS server system.
## Hardware
The NAS server is built on AMD hardware:
- CPU: AMD processor
- 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
The NAS hosts various services:
### Media Services
- **Jellyfin** - Media server
- **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
- **Transmission** - Torrent client
- **NZBGet** - Usenet downloader
- **Prowlarr** - Indexer manager
### Document Management
- **Paperless-ngx** - Document management system
### File Sharing
- **Samba** - Windows file sharing
- **Nextcloud** - Self-hosted cloud storage
### AI Services
- **Ollama** - Local AI model hosting
### Smart Home
- **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

@@ -1,213 +0,0 @@
# Troubleshooting Guide
This guide provides solutions for common issues that may arise when using this NixOS configuration.
## System Issues
### Failed System Build
**Problem**: `nixos-rebuild switch` fails with an error.
**Solutions**:
1. **Syntax Errors**:
- Check the error message for file and line number information
- Verify the syntax in the mentioned file
- 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**:
- Check PostgreSQL is running: `systemctl status postgresql`
- Verify database connection settings in Home Assistant configuration
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
**Problem**: Automations don't run as expected.
**Solutions**:
1. **Check Automation Status**:
- In Home Assistant UI, verify the automation is enabled
- Check Home Assistant logs for automation execution errors
2. **Entity Issues**:
- Verify entity IDs are correct
- Check if entities are available/connected
- Test direct service calls to verify entity control works
3. **Trigger Issues**:
- Test the automation manually via Developer Tools > Services
- Use `automation.trigger` service with the automation's entity_id
## Flake Issues
### Flake Input Update Errors
**Problem**: `nix flake update` fails or causes issues.
**Solutions**:
1. **Selective Updates**:
- Update specific inputs instead of all at once:
```
nix flake lock --update-input nixpkgs
```
2. **Rollback Flake Lock**:
- If an update causes issues, revert to previous flake.lock:
```
git checkout HEAD^ -- flake.lock
```
3. **Pin to Specific Revisions**:
- In `flake.nix`, pin problematic inputs to specific revisions:
```nix
nixpkgs-stable.url = "github:NixOS/nixpkgs/5233fd2ba76a3accb05f88b08917450363be8899";
```
## Secret Management Issues
### Sops Decryption Errors
**Problem**: Sops fails to decrypt secrets.
**Solutions**:
1. **Key Issues**:
- Verify your GPG key is available and unlocked
- Check `.sops.yaml` includes your key fingerprint
2. **Permission Issues**:
- Check file permissions on secret files
- Make sure the user running `nixos-rebuild` has access to the GPG key
## Network Issues
### Firewall Blocks Services
**Problem**: Services are not accessible due to firewall rules.
**Solutions**:
1. **Check Firewall Status**:
```
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
If you encounter an issue not covered in this guide:
1. Check the NixOS Wiki: https://nixos.wiki/
2. Search the NixOS Discourse forum: https://discourse.nixos.org/
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

View File

@@ -1,208 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.invalid/version.schema.json",
"title": "Unified Package Version Schema",
"description": "Schema for a unified version.json used by packages/",
"type": "object",
"additionalProperties": false,
"required": [
"schemaVersion",
"sources"
],
"properties": {
"schemaVersion": {
"type": "integer",
"enum": [1],
"description": "Schema version. Start at 1; bump on breaking changes."
},
"variables": {
"type": "object",
"description": "Common variables available for template substitution in string fields.",
"additionalProperties": {
"type": "string"
}
},
"defaultVariant": {
"type": "string",
"description": "Optional default variant name for consumers."
},
"sources": {
"type": "object",
"description": "Base component sources keyed by component name.",
"minProperties": 1,
"additionalProperties": {
"$ref": "#/$defs/SourceSpec"
}
},
"variants": {
"type": "object",
"description": "Optional variants/channels/flavors; each overlays the base.",
"additionalProperties": {
"$ref": "#/$defs/VariantSpec"
}
},
"notes": {
"type": "object",
"description": "Optional free-form human notes/documentation.",
"additionalProperties": true
}
},
"$defs": {
"SourceSpecBase": {
"type": "object",
"additionalProperties": false,
"properties": {
"fetcher": {
"type": "string",
"enum": ["github", "git", "url", "pypi", "none"],
"description": "Fetcher type for this source."
},
"hash": {
"type": "string",
"pattern": "^sha[0-9]+-",
"description": "SRI hash for the fetched artifact. Required unless fetcher is 'none'."
},
"version": {
"type": "string",
"description": "Optional version string metadata for this component."
},
"extra": {
"type": "object",
"description": "Optional free-form metadata for consumer logic.",
"additionalProperties": true
},
"owner": { "type": "string", "description": "GitHub owner/org (github fetcher)." },
"repo": { "type": "string", "description": "GitHub repository (github fetcher)." },
"tag": { "type": "string", "description": "Git tag (github fetcher). Mutually exclusive with 'rev'." },
"rev": { "type": "string", "description": "Commit revision (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." },
"urlTemplate": { "type": "string", "description": "Template for URL (url fetcher); supports ${var}." },
"name": { "type": "string", "description": "PyPI dist name (pypi fetcher)." }
}
},
"SourceSpec": {
"allOf": [
{ "$ref": "#/$defs/SourceSpecBase" },
{
"if": {
"properties": { "fetcher": { "const": "github" } },
"required": ["fetcher"]
},
"then": {
"required": ["owner", "repo"],
"oneOf": [
{ "required": ["tag"] },
{ "required": ["rev"] }
]
}
},
{
"if": {
"properties": { "fetcher": { "const": "git" } },
"required": ["fetcher"]
},
"then": {
"required": ["url", "rev"]
}
},
{
"if": {
"properties": { "fetcher": { "const": "url" } },
"required": ["fetcher"]
},
"then": {
"oneOf": [
{ "required": ["url"] },
{ "required": ["urlTemplate"] }
]
}
},
{
"if": {
"properties": { "fetcher": { "const": "pypi" } },
"required": ["fetcher"]
},
"then": {
"required": ["name", "version"]
}
},
{
"if": {
"properties": { "fetcher": { "enum": ["github", "git", "url", "pypi"] } },
"required": ["fetcher"]
},
"then": {
"required": ["hash"]
}
}
]
},
"SourceOverride": {
"type": "object",
"additionalProperties": false,
"description": "Partial override of a source within a variant. All fields optional.",
"properties": {
"fetcher": { "type": "string", "enum": ["github", "git", "url", "pypi", "none"] },
"hash": { "type": "string", "pattern": "^sha[0-9]+-" },
"version": { "type": "string" },
"extra": { "type": "object", "additionalProperties": true },
"owner": { "type": "string" },
"repo": { "type": "string" },
"tag": { "type": "string" },
"rev": { "type": "string" },
"submodules": { "type": "boolean" },
"url": { "type": "string" },
"urlTemplate": { "type": "string" },
"name": { "type": "string" }
}
},
"VariantSpec": {
"type": "object",
"additionalProperties": false,
"properties": {
"inherits": {
"type": "string",
"description": "Optional base variant to inherit from."
},
"variables": {
"type": "object",
"description": "Variant-level variables that overlay top-level variables.",
"additionalProperties": { "type": "string" }
},
"sources": {
"type": "object",
"description": "Per-component overrides for this variant.",
"additionalProperties": { "$ref": "#/$defs/SourceOverride" }
},
"platforms": {
"type": "object",
"description": "Optional per-system overrides to support differing hashes/fields by platform.",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"sources": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/SourceOverride" }
},
"variables": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
}
}
}
}
}
}

1
echo Normal file
View File

@@ -0,0 +1 @@
{"text": "\ue312 49\u00b0F", "tooltip": " Overcast 49\u00b0\n<span foreground=\"#585858\" font-weight=\"bold\"> .--. </span>Feels like: 49\u00b0\n<span foreground=\"#585858\" font-weight=\"bold\"> .-( ). </span>Wind: 2mph \u2199\n<span foreground=\"#585858\" font-weight=\"bold\"> (___.__)__) </span>Humidity: 80%\n Moon phase: Waxing Crescent \ud83c\udf12\n\nToday, <b>Mon Nov 24 2025</b>\n\uf2c7 53\u00b0F \uf2ca 38\u00b0F\ue34c 07:23 AM \ue34d 04:36 PM\n03 PM \udb81\udd95 52\u00b0 Partly Cloudy , Overcast 33%, Sunshine 73%\n06 PM \ue313 44\u00b0 Mist, Overcast 83%, Sunshine 8%\n09 PM \ue313 43\u00b0 Fog, Overcast 93%, Sunshine 5%\nTomorrow, <b>Tue Nov 25 2025</b>\n\uf2c7 43\u00b0F \uf2ca 34\u00b0F\ue34c 07:24 AM \ue34d 04:36 PM\n12 AM \ue313 43\u00b0 Fog, Fog 6%, Overcast 81%, Sunshine 19%\n03 AM \ue313 42\u00b0 Fog, Overcast 89%, Sunshine 8%\n06 AM \ue313 41\u00b0 Fog, Fog 6%, Overcast 92%, Sunshine 11%\n09 AM \ue313 40\u00b0 Fog, Fog 6%, Overcast 88%, Sunshine 5%\n12 PM \ue317 39\u00b0 Moderate rain at times, Overcast 90%, Rain 100%\n03 PM \ue308 34\u00b0 Light rain, Overcast 93%, Rain 100%\n06 PM \ue318 31\u00b0 Moderate rain, Overcast 88%, Rain 100%\n09 PM \ue31a 24\u00b0 Moderate snow, Overcast 89%, Rain 100%, Snow 100%\n<b>Wed Nov 26 2025</b>\n\uf2c7 36\u00b0F \uf2ca 25\u00b0F\ue34c 07:26 AM \ue34d 04:35 PM\n12 AM \ue312 21\u00b0 Overcast , Overcast 87%, Sunshine 8%\n03 AM \ue312 14\u00b0 Overcast , Frost 25%, Overcast 94%, Sunshine 13%\n06 AM \ue312 11\u00b0 Overcast , Frost 80%, Overcast 89%, Sunshine 8%\n09 AM \ue312 13\u00b0 Overcast , Frost 79%, Overcast 80%, Sunshine 5%\n12 PM \ue33d 18\u00b0 Cloudy , Frost 77%, Overcast 89%, Sunshine 17%\n03 PM \ue30d 24\u00b0 Sunny, Frost 29%, Sunshine 90%\n06 PM \udb81\udd94 22\u00b0 Clear , Frost 78%, Sunshine 94%\n09 PM \udb83\udf31 15\u00b0 Partly Cloudy , Frost 85%, Overcast 39%, Sunshine 83%\n"}

1009
flake.lock generated

File diff suppressed because it is too large Load Diff

169
flake.nix
View File

@@ -1,59 +1,43 @@
{
inputs = rec {
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11";
# Fork required: openthread-border-router is not yet in nixpkgs-unstable.
# 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 = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs-unstable";
};
nixpkgs = nixpkgs-unstable;
home-manager = home-manager-unstable;
# The name "snowfall-lib" is required due to how Snowfall Lib processes your
# flake's inputs. Using a personal fork for custom changes.
# flake's inputs.
snowfall-lib = {
url = "github:mjallen18/snowfall-lib";
url = "github:mjallen18/lib";
inputs.nixpkgs.follows = "nixpkgs";
};
chaotic.url = "github:chaotic-cx/nyx/nyxpkgs-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
impermanence.url = "github:nix-community/impermanence";
lanzaboote.url = "github:nix-community/lanzaboote/v1.0.0";
lanzaboote.url = "github:nix-community/lanzaboote/v0.4.3";
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
sops-nix.url = "github:Mic92/sops-nix";
nix-cachyos-kernel.url = "github:xddxdd/nix-cachyos-kernel/release";
steam-rom-manager = {
url = "github:mjallen18/nix-steam-rom-manager";
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
};
cosmic = {
url = "github:lilyinstarlight/nixos-cosmic";
inputs.nixpkgs.follows = "nixpkgs";
};
cosmic.url = "github:lilyinstarlight/nixos-cosmic";
nix-vscode-extensions.url = "github:nix-community/nix-vscode-extensions";
authentik-nix = {
url = "github:nix-community/authentik-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
authentik-nix.url = "github:nix-community/authentik-nix";
nixai.url = "github:olafkfreund/nix-ai-help";
disko = {
# the fork is needed for partition attributes support
@@ -62,7 +46,11 @@
inputs.nixpkgs.follows = "nixpkgs";
};
darwin.url = "github:nix-darwin/nix-darwin/master";
nixos-raspberrypi.url = "github:mjallen18/nixos-raspberrypi";
jovian.url = "github:Jovian-Experiments/Jovian-NixOS";
darwin.url = "github:LnL7/nix-darwin";
nix-homebrew.url = "github:zhaofengli/nix-homebrew";
@@ -78,10 +66,7 @@
nixos-apple-silicon.url = "github:nix-community/nixos-apple-silicon";
pre-commit-hooks-nix = {
url = "github:cachix/pre-commit-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
treefmt-nix = {
url = "github:numtide/treefmt-nix";
@@ -111,11 +96,6 @@
url = "github:nix-community/stylix";
inputs.nixpkgs.follows = "nixpkgs";
};
jovian = {
url = "github:Jovian-Experiments/Jovian-NixOS";
inputs.nixpkgs.follows = "nixpkgs";
};
};
# We will handle this in the next section.
@@ -130,16 +110,12 @@
# Nix files to a separate directory.
src = ./.;
overlays = with inputs; [
nix-vscode-extensions.overlays.default
nix-cachyos-kernel.overlays.default
];
# Add a module to a specific host.
systems = {
# common modules
modules.nixos = with inputs; [
authentik-nix.nixosModules.default
chaotic.nixosModules.default
disko.nixosModules.disko
impermanence.nixosModules.impermanence
lanzaboote.nixosModules.lanzaboote
@@ -149,11 +125,6 @@
stylix.nixosModules.stylix
];
modules.home = with inputs; [
nix-index-database.homeManagerModules.nix-index
steam-rom-manager.homeManagerModules.default
];
# common darwin modules
modules.darwin = with inputs; [
nix-homebrew.darwinModules.nix-homebrew
@@ -173,7 +144,7 @@
modules = with inputs; [
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
@@ -185,13 +156,30 @@
# NAS #
# ######################################################
jallen-nas = {
# home-manager is already in systems.modules.nixos above
modules = with inputs; [
nixos-hardware.nixosModules.common-pc
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-hidpi
home-manager.nixosModules.home-manager
];
};
# ######################################################
# Steamdeck #
# ######################################################
steamdeck = {
modules = with inputs; [
disko.nixosModules.disko
jovian.nixosModules.jovian
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
lsfg-vk.nixosModules.default
];
};
@@ -199,23 +187,53 @@
# NUC #
# ######################################################
nuc-nixos = {
# disko is already in systems.modules.nixos above
modules = with inputs; [
disko.nixosModules.disko
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
];
};
# ######################################################
# Pi4 #
# ######################################################
pi4 = {
specialArgs = {
nixpkgs = inputs.nixpkgs-stable;
};
modules = with inputs; [
disko.nixosModules.disko
nixos-raspberrypi.nixosModules.raspberry-pi-4.base
nixos-raspberrypi.nixosModules.raspberry-pi-4.display-vc4
nixos-raspberrypi.nixosModules.nixpkgs-rpi
nixos-raspberrypi.nixosModules.trusted-nix-caches
nixos-raspberrypi.lib.inject-overlays
nixos-raspberrypi.lib.inject-overlays-global
];
};
# ######################################################
# Pi5 #
# ######################################################
pi5 = {
# disko is already in systems.modules.nixos above
modules = [ ];
specialArgs = {
nixpkgs = inputs.nixpkgs-stable;
};
modules = with inputs; [
disko.nixosModules.disko
nixos-raspberrypi.nixosModules.raspberry-pi-5.base
nixos-raspberrypi.nixosModules.raspberry-pi-5.display-vc4
nixos-raspberrypi.nixosModules.raspberry-pi-5.bluetooth
nixos-raspberrypi.nixosModules.raspberry-pi-5.page-size-16k
nixos-raspberrypi.nixosModules.nixpkgs-rpi
nixos-raspberrypi.nixosModules.trusted-nix-caches
nixos-raspberrypi.lib.inject-overlays
nixos-raspberrypi.lib.inject-overlays-global
];
};
# ######################################################
@@ -227,23 +245,11 @@
lsfg-vk.nixosModules.default
];
};
# ######################################################
# AllyX #
# ######################################################
allyx = {
modules = with inputs; [
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
lsfg-vk.nixosModules.default
jovian.nixosModules.jovian
];
};
};
overlays = with inputs; [
nix-vscode-extensions.overlays.default
];
};
# Configure Snowfall Lib, all of these settings are optional.
@@ -264,17 +270,22 @@
channels-config = {
allowUnfree = true;
allowUnsupportedSystem = true;
permittedInsecurePackages = [
# ...
# "libsoup-2.74.3"
# "mbedtls-2.28.10"
"libsoup-2.74.3"
"mbedtls-2.28.10"
];
};
outputs-builder = channels: {
formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix;
# mjallen-lib overlay is auto-discovered from overlays/mjallen-lib/default.nix
# Add mjallen-lib to the flake outputs
overlays = {
mjallen-lib = _final: _prev: {
mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib;
};
};
};
};
}

View File

@@ -15,9 +15,7 @@ let
age
cpufetch
deadnix
iproute2mac
nebula
nixfmt
nixfmt-rfc-style
nodePackages.nodejs
uv
sops
@@ -43,6 +41,220 @@ in
};
};
programs.nix-plist-manager = {
enable = true;
options = {
applications = {
finder = {
settings = {
general = {
showTheseItemsOnTheDesktop = {
hardDisks = false;
externalDisks = true;
cdsDvdsAndiPods = false;
connectedServers = false;
};
openFoldersInTabsInsteadOfNewWindows = true;
};
sidebar = {
recentTags = true;
};
advanced = {
removeItemsFromTheTrashAfter30Days = true;
showAllFilenameExtensions = true;
showWarningBeforeChangingAnExtension = true;
showWarningBeforeRemovingFromiCloudDrive = true;
showWarningBeforeEmptyingTheTrash = true;
keepFoldersOnTop = {
inWindowsWhenSortingByName = true;
onDesktop = true;
};
whenPerformingASearch = "Search This Mac";
};
};
menuBar = {
view = {
showTabBar = true;
showSidebar = true;
showPathBar = true;
showStatusBar = true;
};
};
};
systemSettings = {
appearance = {
appearance = "Dark";
accentColor = "Multicolor";
# clickInTheScrollBarTo = "Jump to the next page";
sidebarIconSize = "Medium";
showScrollBars = "When scrolling";
};
controlCenter = {
wifi = true;
bluetooth = true;
airdrop = true;
stageManager = true;
focusModes = "active";
screenMirroring = "active";
display = "never";
sound = "always";
nowPlaying = "active";
accessibilityShortcuts = "unset";
musicRecognition = {
showInMenuBar = false;
showInControlCenter = true;
};
hearing = "unset";
fastUserSwitching = {
showInMenuBar = false;
showInControlCenter = true;
};
keyboardBrightness = {
showInMenuBar = false;
showInControlCenter = true;
};
battery = {
showInMenuBar = false;
showInControlCenter = false;
};
batteryShowPercentage = true;
# menuBarOnly = {
# spotlight = false;
# siri = true;
# };
# automaticallyHideAndShowTheMenuBar = "In Full Screen Only";
};
desktopAndDock = {
desktopAndStageManager = {
showItems = {
onDesktop = true;
inStageManager = true;
};
clickWallpaperToRevealDesktop = "Always";
stageManager = false;
showRecentAppsInStageManager = true;
showWindowsFromAnApplication = "All at Once";
};
dock = {
animateOpeningApplications = true;
automaticallyHideAndShowTheDock = enabled;
doubleClickAWindowsTitleBarTo = "Minimize";
magnification = disabled;
minimizeWindowsIntoApplicationIcon = true;
minimizeWindowsUsing = "Genie Effect";
positionOnScreen = "Bottom";
showIndicatorsForOpenApplications = true;
showSuggestedAndRecentAppsInDock = false;
size = 64; # 16 - 128
# persistentApps = [
# { app = "/Applications/Clock.app"; }
# { folder = "/Applications"; }
# { app = "/Applications/Safari.app"; }
# { app = "/Applications/Firefox.app"; }
# { app = "/Applications/Tabby.app"; }
# { app = "/Applications/Termius.app"; }
# { app = "/Applications/Muic.app"; }
# { app = "/Applications/Vesktop.app"; }
# { app = "/Applications/Messages.app"; }
# { app = "/Applications/Calendar.app"; }
# { app = "/Applications/Reminders.app"; }
# { app = "/Applications/Notes.app"; }
# { app = "/Applications/Weather.app"; }
# { app = "/Applications/Maps.app"; }
# { app = "/Applications/App Store.app"; }
# { app = "/Applications/System Settings.app"; }
# { app = "/Applications/ChatGPT.app"; }
# { app = "/Applications/Nextcloud.app"; }
# { app = "/Applications/VSCodium.app"; }
# { app = "/Applications/Omnissa Horizon Client.app"; }
# { app = "/Applications/Proton Pass.app"; }
# { app = "/Applications/OrcaSlicer.app"; }
# { app = "/Applications/AlDente.app"; }
# ];
# persistentOthers = [
# "~/Downloads"
# ];
};
hotCorners = {
# ["-" "Mission Control" "Application Windows" "Desktop" "Start Screen Saver" "Disable Screen Saver" "Dashboard" "Put Display to Sleep" "Launchpad" "Notification Center" "Lock Screen" "Quick Note"]
topLeft = "-";
topRight = "-";
bottomLeft = "-";
bottomRight = "-";
};
missionControl = {
automaticallyRearrangeSpacesBasedOnMostRecentUse = true;
displaysHaveSeparateSpaces = true;
dragWindowsToTopOfScreenToEnterMissionControl = true;
groupWindowsByApplication = true;
whenSwitchingToAnApplicationSwitchToAspaceWithOpenWindowsForTheApplication = true;
};
widgets = {
showWidgets = {
onDesktop = true;
inStageManager = true;
};
widgetStyle = "Automatic";
useIphoneWidgets = true;
};
windows = {
askToKeepChangesWhenClosingDocuments = true;
closeWindowsWhenQuittingAnApplication = true;
dragWindowsToScreenEdgesToTile = true;
dragWindowsToMenuBarToFillScreen = true;
holdOptionKeyWhileDraggingWindowsToTile = true;
preferTabsWhenOpeningDocuments = "In Full Screen";
tiledWindowsHaveMargin = false;
};
};
focus = {
shareAcrossDevices = true;
};
# general.dateAndTime."24HourTime" = false;
notifications = {
notificationCenter = {
showPreviews = "When Unlocked";
summarizeNotifications = true;
};
};
sound = {
soundEffects = {
alertSound = "Boop";
alertVolume = 0.7;
playFeedbackWhenVolumeIsChanged = true;
playUserInterfaceSoundEffects = true;
};
};
spotlight = {
helpAppleImproveSearch = false;
# searchResults = {
# applications = true;
# calculator = true;
# contacts = true;
# conversion = true;
# definition = true;
# developer = true;
# documents = true;
# eventsAndReminders = true;
# folders = true;
# fonts = false;
# images = true;
# mailAndMessages = true;
# movies = true;
# music = true;
# other = false;
# pdfDocuments = true;
# presentations = true;
# siriSuggestions = false;
# systemSettings = true;
# tips = false;
# websites = true;
};
};
};
};
};
# Manage bug in compilations - who uses manpages in 2024 anyways? :P
manual.manpages = enabled;

View File

@@ -6,6 +6,12 @@
}:
let
inherit (lib.${namespace}) enabled disabled;
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.3";
update-switch = "sudo nixos-rebuild switch --max-jobs 10 --build-host admin@10.0.1.3";
update-flake = "nix flake update mac-nixpkgs mac-nixos-apple-silicon mac-home-manager mac-impermanence mac-sops-nix --flake /etc/nixos";
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";
};
# Displays
display = {
input = "eDP-1";
@@ -20,9 +26,8 @@ in
home.stateVersion = "23.11";
${namespace} = {
desktop.gnome = enabled;
programs.hyprland = {
enable = false;
enable = true;
primaryDisplay = "eDP-1";
debug.disableScaleChecks = true;
@@ -52,7 +57,7 @@ in
];
windowRule = [
# "size 2160 3356, tag:horizonrdp"
"size 2160 3356, tag:horizonrdp"
];
hyprpaper = {
@@ -62,30 +67,31 @@ in
keybinds = {
bind = [
"$mod, A, exec, chromium --app=\"https://music.apple.com\""
"SHIFT, XF86MonBrightnessUp, exec, lightctl -D kbd_backlight up"
"SHIFT, XF86MonBrightnessDown, exec, lightctl -D kbd_backlight down"
];
};
defaultApps = {
browser = pkgs.firefox;
};
extraConfig = ''
exec-once = brightnessctl -d kbd_backlight s 50%
'';
};
programs = {
btop = enabled;
kitty = disabled;
mako = disabled;
nwg-dock = disabled;
nwg-drawer = disabled;
nwg-panel = disabled;
opencode = enabled;
kitty = {
enable = true;
};
mako = {
enable = true;
};
nwg-dock = enabled;
nwg-drawer = enabled;
nwg-panel = {
enable = true;
defaultApps = {
browser = pkgs.firefox;
};
};
waybar = {
enable = false;
enable = true;
layer = "bottom";
@@ -119,64 +125,24 @@ in
windowOffset = 75;
};
wlogout = disabled;
wofi = disabled;
wlogout = enabled;
wofi = enabled;
};
};
home.packages =
with pkgs.${namespace};
[
# librepods
librepods-beta
]
++ (with pkgs; [
bolt-launcher
iw
iwd
orca-slicer
vscodium
home.packages = with pkgs; [
pkgs.${namespace}.bolt-launcher
pkgs.${namespace}.librepods
gnomeExtensions.notch-clock-offset
]);
services = {
kdeconnect = {
enable = lib.mkForce true;
indicator = lib.mkForce true;
};
};
iw
iwd
orca-slicer
vscodium
];
programs = {
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/"
];
};
zsh.shellAliases = shellAliases;
};
}

View File

@@ -0,0 +1,69 @@
{ lib, namespace, ... }:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "matt";
${namespace} = {
shell-aliases = {
enable = true;
flakeInputs = [
"pi4-nixpkgs"
"pi4-home-manager"
"pi4-impermanence"
"pi4-sops-nix"
"pi4-nixos-hardware"
"pi4-nixos-raspberrypi"
"pi4-disko"
];
};
};
sops = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/pi4" = {
path = "/home/matt/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/pi4" = {
path = "/home/matt/.ssh/id_ed25519";
mode = "0600";
};
# "ssh-keys-public/desktop-nixos" = {
# path = "/home/matt/.ssh/authorized_keys";
# mode = "0600";
# };
# "ssh-keys-public/desktop-nixos-root" = {
# path = "/home/matt/.ssh/authorized_keys2";
# mode = "0600";
# };
# "ssh-keys-public/desktop-windows" = {
# path = "/home/matt/.ssh/authorized_keys3";
# mode = "0600";
# };
# "ssh-keys-public/macbook-macos" = {
# path = "/home/matt/.ssh/authorized_keys4";
# mode = "0600";
# };
};
};
programs = {
mangohud = lib.mkForce enabled;
};
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -5,7 +5,14 @@
...
}:
let
inherit (lib.${namespace}) disabled;
inherit (lib.${namespace}) enabled disabled;
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.3";
update-switch = "sudo nixos-rebuild switch --max-jobs 10 --build-host admin@10.0.1.3";
update-flake = "nix flake update pi5-nixpkgs pi5-home-manager pi5-impermanence pi5-nixos-hardware pi5-sops-nix nixos-raspberrypi --flake /etc/nixos";
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";
nas-ssh = "kitten ssh admin@10.0.1.3";
};
in
{
@@ -50,6 +57,10 @@ in
};
};
programs = {
zsh.shellAliases = shellAliases;
};
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,41 +1,22 @@
{ pkgs, namespace, ... }:
{
pkgs,
config,
lib,
inputs,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled;
in
{
# steam-rom-manager HM module is needed for the steam-rom-manager program
# options. On NixOS hosts it's provided via sharedModules; here we add it
# explicitly so the standalone homeConfiguration build also includes it.
imports = [
inputs.steam-rom-manager.homeManagerModules.default
];
home = {
username = "admin";
packages =
with pkgs;
[
heroic
python3
python3Packages.requests
python3Packages.mcp
jq
]
++ (with pkgs.${namespace}; [
moondeck-buddy
]);
};
home.username = "admin";
${namespace} = {
sops.enable = true;
programs.opencode = enabled;
shell-aliases = {
enable = true;
buildHost = ""; # NAS builds locally
flakeInputs = [
"nas-nixpkgs"
"nas-authentik-nix"
"nas-cosmic"
"nas-home-manager"
"nas-impermanence"
"nas-lanzaboote"
"nas-nixos-hardware"
"nas-sops-nix"
];
};
};
sops = {
@@ -74,13 +55,6 @@ in
};
programs = {
bash = {
shellAliases = {
"llama-status" =
"curl -s http://localhost:8127/health 2>/dev/null && echo 'LLaMA.cpp server is running' || echo 'LLaMA.cpp server is not responding'";
};
};
neovim = {
enable = true;
viAlias = true;
@@ -94,23 +68,6 @@ in
}
];
};
steam-rom-manager = {
enable = true;
steamUsername = "mjallen18";
# Optional: override default paths if needed
environmentVariables = {
romsDirectory = "/home/admin/Emulation/roms";
steamDirectory = "/home/admin/.local/share/Steam";
};
emulators = {
"Non-SRM Shortcuts" = {
enable = true;
parserType = "Non-SRM Shortcuts";
extraArgs = "";
};
};
};
};
}

View File

@@ -1,15 +1,18 @@
{
lib,
pkgs,
namespace,
...
}:
{ pkgs, ... }:
let
inherit (lib.${namespace}) disabled;
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10";
update-switch = "sudo nixos-rebuild switch --max-jobs 10";
update-flake = "nix flake update nas-nixpkgs nas-authentik-nix nas-cosmic nas-crowdsec nas-home-manager nas-impermanence nas-lanzaboote nas-nixos-hardware nas-sops-nix --flake /etc/nixos";
};
in
{
home.username = "admin";
programs = {
zsh.shellAliases = shellAliases;
};
# Configure systemd user service for protonmail-bridge
systemd.user.services.protonmail-bridge = {
Service = {
@@ -21,17 +24,9 @@ in
};
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
protonmail-bridge = {
enable = true;
extraPackages = with pkgs; [
pass
libsecret
];
extraPackages = with pkgs; [ pass libsecret ];
};
};
}

View File

@@ -0,0 +1,84 @@
{ lib, pkgs, namespace, ... }:
let
inherit (lib.${namespace}) enabled disabled;
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.3";
update-switch = "sudo nixos-rebuild switch --max-jobs 10";
update-flake = "nix flake update steamdeck-nixpkgs steamdeck-chaotic steamdeck-home-manager steamdeck-impermanence steamdeck-jovian steamdeck-lanzaboote steamdeck-nixos-hardware steamdeck-sops-nix steamdeck-steam-rom-manager --flake /etc/nixos";
nas-ssh = "ssh admin@10.0.1.3";
};
in
{
home.username = "deck";
${namespace}.desktop.gnome = enabled;
sops = {
age.keyFile = "/home/deck/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/deck" = {
path = "/home/deck/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/deck" = {
path = "/home/deck/.ssh/id_ed25519";
mode = "0600";
};
};
};
programs = {
steam-rom-manager = {
enable = true;
steamUsername = "mjallen18";
# Optional: override default paths if needed
environmentVariables = {
romsDirectory = "/home/deck/Emulation/roms";
steamDirectory = "/home/deck/.local/share/Steam";
};
emulators = {
ryujinx = enabled;
dolphin-gamecube = {
enable = true;
package = pkgs.dolphin-emu;
romFolder = "gc";
fileTypes = [
".iso"
".ISO"
".gcm"
".GCM"
".ciso"
".CISO"
"rvz"
];
extraArgs = "-b -e \"\${filePath}\"";
};
pcsx2 = enabled;
mgba = enabled;
"Non-SRM Shortcuts" = {
enable = true;
parserType = "Non-SRM Shortcuts";
extraArgs = "";
};
};
};
zsh.shellAliases = shellAliases;
};
home.packages = with pkgs; [
dolphin-emu
heroic
mgba
prismlauncher
ryubing
omnissa-horizon-client
];
}

View File

@@ -1,92 +0,0 @@
{
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled;
in
{
home.username = "matt";
${namespace}.desktop.gnome = enabled;
sops = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/matt" = {
path = "/home/matt/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/matt" = {
path = "/home/matt/.ssh/id_ed25519";
mode = "0600";
};
};
};
programs = {
steam-rom-manager = {
enable = true;
steamUsername = "mjallen18";
environmentVariables = {
romsDirectory = "/media/sdcard/Emulation/roms";
steamDirectory = "/home/matt/.local/share/Steam";
};
enabledProviders = [
"sgdb"
"steamCDN"
];
imageProviderSettings.sgdb = {
nsfw = false;
humor = false;
imageMotionTypes = [ "static" ];
};
emulators = {
# --- Nintendo ---
ryujinx.enable = true; # Switch (ryubing fork)
yuzu.enable = true; # Switch (eden fork)
dolphin-emu.enable = true; # GameCube / Wii
cemu.enable = true; # Wii U
melonDS.enable = true; # DS
citra.enable = true; # 3DS (azahar fork)
mgba.enable = true; # Game Boy / GBC
mgba-gba.enable = true; # Game Boy Advance
# --- Sony ---
duckstation.enable = false; # PS1
pcsx2.enable = true; # PS2
rpcs3.enable = true; # PS3
ppsspp.enable = true; # PSP
# --- Microsoft ---
xemu.enable = true; # Xbox
# --- Platform parsers (no ROM scanning; artwork only / launcher integration) ---
"Non-SRM Shortcuts".enable = true;
};
};
};
home.packages =
with pkgs;
[
dolphin-emu
heroic
mgba
moonlight-qt
prismlauncher
ryubing
omnissa-horizon-client
]
++ (with pkgs.${namespace}; [
discord-krisp
# librepods-beta
]);
}

View File

@@ -2,6 +2,7 @@
lib,
pkgs,
namespace,
config,
...
}:
let
@@ -16,6 +17,7 @@ let
resolution = "3840x2160";
refreshRate = "240.00000";
};
theme = config.mjallen.theme.palette;
in
{
home.username = "matt";
@@ -28,11 +30,9 @@ in
enable = true;
};
desktop.gnome = enabled;
programs = {
hyprland = {
enable = false;
enable = true;
primaryDisplay = "DP-1";
monitorv2 = [
@@ -42,14 +42,14 @@ in
position = "0x0";
scale = 1.0;
extra = [
# "bitdepth"
# "10"
# "cm"
# "hdredid"
# "sdrbrightness"
# "1.2"
# "sdrsaturation"
# "0.98"
"bitdepth"
"10"
"cm"
"hdr"
"sdrbrightness"
"1.2"
"sdrsaturation"
"0.98"
];
}
{
@@ -58,14 +58,14 @@ in
position = "3840x0";
scale = 1.0;
extra = [
# "bitdepth"
# "10"
# "cm"
# "hdredid"
# "sdrbrightness"
# "1.5"
# "sdrsaturation"
# "0.98"
"bitdepth"
"10"
"cm"
"hdr"
"sdrbrightness"
"1.5"
"sdrsaturation"
"0.98"
];
}
];
@@ -77,7 +77,7 @@ in
];
windowRule = [
"match:tag horizonrdp, size 2160 7680"
"size 2160 7680, tag:horizonrdp"
];
autostartCommands = [
@@ -104,13 +104,18 @@ in
};
};
btop = enabled;
kitty = disabled;
mako = disabled;
nwg-dock = disabled;
nwg-drawer = disabled;
nwg-panel = disabled;
kitty = enabled;
mako = enabled;
nwg-dock = enabled;
nwg-drawer = enabled;
nwg-panel = {
enable = true;
defaultApps = {
browser = pkgs.firefox;
};
};
waybar = {
enable = false;
enable = true;
layer = "bottom";
@@ -144,8 +149,8 @@ in
}
'';
};
wlogout = disabled;
wofi = disabled;
wlogout = enabled;
wofi = enabled;
};
};
@@ -160,37 +165,34 @@ in
password-store = enabled;
};
home.packages =
with pkgs;
[
bolt-launcher
clevis
compose2nix
distrobox
goverlay
heroic
home-manager
omnissa-horizon-client
jq
lzip
morph
orca-slicer
piper
prismlauncher
protontricks
protonvpn-gui
runelite
smile
via
virt-manager
vorta
waydroid-helper
winboat
]
++ (with pkgs.${namespace}; [
discord-krisp
# librepods
]);
home.packages = with pkgs; [
pkgs.${namespace}.bolt-launcher
pkgs.${namespace}.librepods
bottles
compose2nix
discord
distrobox
heroic
omnissa-horizon-client
jq
lutris
lzip
morph
orca-slicer
piper
prismlauncher
protontricks
protonvpn-gui
python3
runelite
smile
unigine-heaven
via
virt-manager
vorta
waydroid-helper
];
specialisation = {
"cosmic".configuration = {

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,18 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,44 +1,130 @@
# mjallen-lib Utility Functions
Utility functions for the NixOS/nix-darwin configuration. Exposed via Snowfall Lib as `lib.mjallen.*`.
This directory contains utility functions that can be used to enhance your Nix configuration. These functions are inspired by the khanelinix repository and provide a more explicit and modular approach to building Nix configurations.
## Directory Structure
- `default.nix`: Main entry point — exports `module`, `file`, and `versioning`
- `module/`: Module creation helpers (`mkModule`, `mkOpt`, `mkBoolOpt`, etc.)
- `file/`: File and path utilities
- `versioning/`: Multi-source version pinning helpers (used by packages)
- `default.nix`: Main entry point that imports and exposes all utility functions
- `module/`: Utilities for module creation and option handling
- `file/`: Utilities for file handling and module discovery
- `system/`: Utilities for system configuration building
## Module Utilities (`lib.mjallen.module`)
## How to Use
| 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 |
| `force-attrs` | Apply `lib.mkForce` to every value in an attrset |
| `nested-default-attrs` | Apply `default-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 |
### 1. Import the Library
## File Utilities (`lib.mjallen.file`)
The library is already imported in your flake.nix file through the outputs-builder:
| Function | Description |
|---|---|
| `getFile` | Resolve a path relative to the flake root |
| `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 |
```nix
outputs-builder = channels: {
formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix;
# Add mjallen-lib to the flake outputs
overlays = {
mjallen-lib = final: prev: {
mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib;
};
};
};
```
## Versioning Utilities (`lib.mjallen.versioning`)
This makes the mjallen-lib available to all your modules through the extended lib.
Used by packages that track multiple upstream variants (e.g. `linux-rpi`, `proton-cachyos`).
See `lib/versioning/default.nix` for the full API.
### 2. Use the Module Utilities
The module utilities provide functions for creating modules with consistent options:
```nix
{ lib, ... }:
let
inherit (lib.mjallen.module) mkModule mkOpt mkBoolOpt;
in
mkModule {
name = "mymodule";
description = "My awesome module";
options = {
setting1 = mkOpt lib.types.str "default" "Description of setting1";
setting2 = mkBoolOpt false "Description of setting2";
};
config = {
# Module implementation
};
}
```
### 3. Use the File Utilities
The file utilities provide functions for file handling and module discovery:
```nix
{ lib, ... }:
let
inherit (lib.mjallen.file) safeImport importModulesRecursive;
in
{
# Import a file with error handling
myConfig = safeImport ./my-config.nix {};
# Import all modules recursively
imports = importModulesRecursive ./modules;
}
```
### 4. Use the System Utilities
The system utilities provide functions for building system configurations:
```nix
{ lib, ... }:
let
inherit (lib.mjallen.system.common) mkHomeManagerConfig;
in
{
# Build home-manager configurations
homeManagerConfig = mkHomeManagerConfig {
extendedLib = lib;
inputs = inputs;
system = "x86_64-linux";
matchingHomes = { ... };
};
}
```
## Available Functions
### Module Utilities
- `mkModule`: Create a module with common options
- `mkOpt`: Create an option with a type, default value, and description
- `mkOpt'`: Create an option with a type and default value (no description)
- `mkBoolOpt`: Create a boolean option with a default value and description
- `mkBoolOpt'`: Create a boolean option with a default value (no description)
- `enabled`: Standard enable pattern
- `disabled`: Standard disable pattern
- `capitalize`: Capitalize a string
- `boolToNum`: Convert a boolean to a number
- `default-attrs`: Apply mkDefault to all attributes
- `force-attrs`: Apply mkForce to all attributes
- `nested-default-attrs`: Apply default-attrs to nested attributes
- `nested-force-attrs`: Apply force-attrs to nested attributes
### File Utilities
- `readFile`: Read a file and return its contents
- `pathExists`: Check if a file exists
- `safeImport`: Import a nix file with error handling
- `scanDir`: Scan a directory and return directory names
- `getFile`: Get a file path relative to the flake root
- `importModulesRecursive`: Recursively discover and import all Nix modules in a directory tree
- `scanSystems`: Recursively scan systems directory structure
- `filterNixOSSystems`: Filter systems for NixOS (Linux)
- `filterDarwinSystems`: Filter systems for Darwin (macOS)
- `scanHomes`: Scan homes directory structure for home configurations
### System Utilities
- `mkExtendedLib`: Extend the nixpkgs lib with mjallen-lib
- `mkNixpkgsConfig`: Create a nixpkgs configuration
- `mkHomeConfigs`: Create home configurations for a system and hostname
- `mkHomeManagerConfig`: Create a home-manager configuration
- `mkSpecialArgs`: Create special arguments for a system configuration

3
lib/base64/ascii Normal file
View File

@@ -0,0 +1,3 @@

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ

62
lib/base64/default.nix Normal file
View File

@@ -0,0 +1,62 @@
{ inputs }:
let
inherit (inputs.nixpkgs.lib)
concatLists
concatMapStrings
foldl'
genList
hasSuffix
imap0
length
mod
nameValuePair
stringToCharacters
sublist
substring
take
;
in
rec {
base64Table = builtins.listToAttrs (
imap0 (i: c: nameValuePair c i) (
# The '=' is included so the main algorithm doesn't fail before we can trim the result
stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
)
);
# Generated using python3:
# print(''.join([ chr(n) for n in range(1, 256) ]), file=open('ascii', 'w'))
ascii = builtins.readFile ./ascii;
decode =
str:
let
paddingCount =
if hasSuffix "==" str then
2
else if hasSuffix "=" str then
1
else
0;
numbers64 = map (c: base64Table.${c}) (stringToCharacters str);
allBytes = concatLists (
genList (
i:
let
v = foldl' (acc: el: acc * 64 + el) 0 (sublist (i * 4) 4 numbers64);
in
[
(mod (v / 256 / 256) 256)
(mod (v / 256) 256)
(mod v 256)
]
) (length numbers64 / 4)
);
finalBytes = take (length allBytes - paddingCount) allBytes;
in
concatMapStrings (n: substring (n - 1) 1 ascii) finalBytes;
}

View File

@@ -1,11 +1,19 @@
{ inputs, ... }:
{
mjallen-lib = {
# Import module utilities
module = import ./module { inherit inputs; };
# Import file utilities
file = import ./file { inherit inputs; };
versioning = import ./versioning {
lib = inputs.nixpkgs.lib;
inherit inputs;
};
# Import system utilities
system = import ./system { inherit inputs; };
# Import reverse proxy utilities
reverseproxy = import ./reverseproxy { inherit inputs; };
# Import examples
examples = import ./examples { inherit inputs; };
};
}

8
lib/examples/default.nix Normal file
View File

@@ -0,0 +1,8 @@
{ ... }:
{
# Import all examples
sops = import ./sops.nix;
homeSops = import ./home-sops.nix;
fileUtils = import ./file-utils.nix;
systemUtils = import ./system-utils.nix;
}

View File

@@ -0,0 +1,60 @@
{ lib, ... }:
let
inherit (lib.mjallen.file)
readFile
pathExists
safeImport
scanDir
getFile
importModulesRecursive
scanSystems
filterNixOSSystems
filterDarwinSystems
scanHomes
;
in
{
# Example of reading a file
myFileContent = readFile ./example.txt;
# Example of checking if a file exists
fileExists = pathExists ./example.txt;
# Example of safely importing a file
myConfig = safeImport ./my-config.nix { };
# Example of scanning a directory
directoryContents = scanDir ./modules;
# Example of getting a file path relative to the flake root
flakeFile = getFile "flake.nix";
# Example of importing modules recursively
modules = importModulesRecursive ./modules;
# Example of scanning systems
allSystems = scanSystems ./systems;
# Example of filtering systems
nixosSystems = filterNixOSSystems allSystems;
darwinSystems = filterDarwinSystems allSystems;
# Example of scanning homes
allHomes = scanHomes ./homes;
# Example of using these functions together
nixosConfigurations = lib.mapAttrs' (
_name:
{ system, hostname, ... }:
{
name = hostname;
value = lib.nixosSystem {
inherit system;
modules = [
{ networking.hostName = hostname; }
]
++ importModulesRecursive ./modules/nixos;
};
}
) nixosSystems;
}

View File

@@ -0,0 +1,36 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib.mjallen.module) mkModule mkOpt;
in
mkModule {
name = "sops";
description = "SOPS secret management for home-manager";
options = {
defaultSopsFile = mkOpt lib.types.path null "Default sops file.";
sshKeyPaths = mkOpt (lib.types.listOf lib.types.str) [ ] "SSH Key paths to use.";
};
config = {
home.packages = with pkgs; [
age
sops
ssh-to-age
];
sops = {
inherit (config.mjallen.sops) defaultSopsFile;
defaultSopsFormat = "yaml";
age = {
generateKey = true;
keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/id_ed25519" ] ++ config.mjallen.sops.sshKeyPaths;
};
};
};
}

View File

@@ -0,0 +1,117 @@
# Example usage of the reverse proxy utilities
{ lib, ... }:
let
inherit (lib.mjallen-lib.reverseproxy)
mkReverseProxy
mkReverseProxies
templates
middlewares
urls
;
in
{
# Example 1: Simple reverse proxy for a local service
simpleProxy = mkReverseProxy {
name = "myapp";
subdomain = "myapp";
url = "http://127.0.0.1:3000";
};
# Example 2: Authenticated service with custom middlewares
authProxy = mkReverseProxy {
name = "admin-panel";
subdomain = "admin";
url = "http://127.0.0.1:8080";
middlewares = middlewares.authBasic;
};
# Example 3: Container-based service
containerProxy = mkReverseProxy {
name = "nextcloud";
subdomain = "cloud";
url = urls.container "nextcloud" 80;
middlewares = middlewares.basic;
};
# Example 4: Multiple proxies at once
multipleProxies = mkReverseProxies [
{
name = "grafana";
subdomain = "grafana";
url = urls.localhost 3000;
middlewares = middlewares.authBasic;
}
{
name = "prometheus";
subdomain = "prometheus";
url = urls.localhost 9090;
middlewares = middlewares.internal;
}
{
name = "alertmanager";
subdomain = "alerts";
url = urls.localhost 9093;
middlewares = middlewares.authBasic;
}
];
# Example 5: Using templates for common patterns
webappExample = templates.webapp {
name = "webapp";
subdomain = "app";
port = 8080;
};
authWebappExample = templates.authWebapp {
name = "secure-app";
subdomain = "secure";
port = 9000;
};
containerExample = templates.containerService {
name = "gitea";
subdomain = "git";
containerName = "gitea";
port = 3000;
};
internalExample = templates.internalService {
name = "internal-api";
subdomain = "api-internal";
port = 8000;
};
# Example 6: Custom domain and advanced configuration
customProxy = mkReverseProxy {
name = "custom-service";
subdomain = "custom";
url = "http://10.0.1.100:8080";
domain = "example.com";
priority = 20;
rule = "Host(`custom.example.com`) && PathPrefix(`/api`)";
middlewares = [
"crowdsec"
"whitelist-geoblock"
"rate-limit"
];
};
# Example usage in a Traefik configuration:
#
# mjallen.services.traefik = {
# enable = true;
# extraServices = multipleProxies.extraServices;
# extraRouters = multipleProxies.extraRouters;
# };
#
# Or for individual proxies:
#
# mjallen.services.traefik = {
# enable = true;
# extraServices = [ simpleProxy.service ];
# extraRouters = [{
# inherit (simpleProxy.router) subdomain entryPoints middlewares;
# service = simpleProxy.router.service;
# }];
# };
}

40
lib/examples/sops.nix Normal file
View File

@@ -0,0 +1,40 @@
{ config, lib, ... }:
let
inherit (lib.mjallen.module) mkModule mkOpt mkBoolOpt;
in
mkModule {
name = "sops";
description = "SOPS secret management";
options = {
defaultSopsFile = mkOpt lib.types.path null "Default sops file.";
generateAgeKey = mkBoolOpt true "Whether to automatically generate an age key if one doesn't exist.";
ageKeyPath =
mkOpt (lib.types.nullOr lib.types.str) null
"Custom path to the age key file. If null, will use the default path.";
sshKeyPaths = mkOpt (lib.types.listOf lib.types.str) [
"/etc/ssh/ssh_host_ed25519_key"
] "SSH Key paths to use.";
validateSopsFiles = mkBoolOpt false "Whether to validate that sops files exist.";
};
config = {
sops = {
inherit (config.mjallen.sops) defaultSopsFile validateSopsFiles;
age = {
inherit (config.mjallen.sops) generateAgeKey;
keyFile =
if config.mjallen.sops.ageKeyPath != null then
config.mjallen.sops.ageKeyPath
else
"${config.users.users.${config.mjallen.user.name}.home}/.config/sops/age/keys.txt";
sshKeyPaths = config.mjallen.sops.sshKeyPaths;
};
};
};
}

View File

@@ -0,0 +1,132 @@
{ inputs, ... }:
let
inherit (inputs.self.mjallen-lib.system.common)
mkExtendedLib
mkNixpkgsConfig
mkHomeConfigs
mkHomeManagerConfig
mkSpecialArgs
;
in
{
# Example of creating NixOS configurations
nixosConfigurations =
let
# Get all systems
allSystems = inputs.self.mjallen-lib.file.scanSystems ../systems;
# Filter for NixOS systems
nixosSystems = inputs.self.mjallen-lib.file.filterNixOSSystems allSystems;
in
inputs.nixpkgs.lib.mapAttrs' (
_name:
{ system, hostname, ... }:
let
# Create extended lib with mjallen-lib
extendedLib = mkExtendedLib inputs.self inputs.nixpkgs;
# Find matching home configurations for this system
matchingHomes = mkHomeConfigs {
flake = inputs.self;
inherit system hostname;
};
# Create home-manager configuration
homeManagerConfig = mkHomeManagerConfig {
inherit
extendedLib
inputs
system
matchingHomes
;
isNixOS = true;
};
in
{
name = hostname;
value = inputs.nixpkgs.lib.nixosSystem {
inherit system;
# Pass special arguments to modules
specialArgs = mkSpecialArgs {
inherit inputs hostname extendedLib;
username = "mjallen";
};
modules = [
# Set lib to extended lib
{ _module.args.lib = extendedLib; }
# Configure nixpkgs
{
nixpkgs = {
inherit system;
}
// mkNixpkgsConfig inputs.self;
}
# Import home-manager module
inputs.home-manager.nixosModules.home-manager
# Auto-inject home configurations
homeManagerConfig
# Import all nixos modules recursively
../${system}/${hostname}
]
++ (extendedLib.mjallen.file.importModulesRecursive ../modules/nixos);
};
}
) nixosSystems;
# Example of creating home-manager configurations
homeConfigurations =
let
# Get all homes
allHomes = inputs.self.mjallen-lib.file.scanHomes ../homes;
in
inputs.nixpkgs.lib.mapAttrs' (
_name:
{
system,
username,
hostname,
userAtHost,
path,
...
}:
let
# Create extended lib with mjallen-lib
extendedLib = mkExtendedLib inputs.self inputs.nixpkgs;
in
{
name = userAtHost;
value = inputs.home-manager.lib.homeManagerConfiguration {
pkgs = import inputs.nixpkgs {
inherit system;
inherit ((mkNixpkgsConfig inputs.self)) config overlays;
};
extraSpecialArgs = {
inherit
inputs
hostname
username
system
;
inherit (inputs) self;
lib = extendedLib;
};
modules = [
# Set lib to extended lib
{ _module.args.lib = extendedLib; }
# Import the home configuration
path
]
++ (extendedLib.mjallen.file.importModulesRecursive ../modules/home);
};
}
) allHomes;
}

View File

@@ -1,8 +1,4 @@
{
inputs,
lib,
namespace,
}:
{ inputs }:
let
inherit (inputs.nixpkgs.lib)
mapAttrs
@@ -14,330 +10,115 @@ let
mkDefault
mkForce
;
base64Lib = import ../base64 { inherit inputs; };
in
rec {
# ---------------------------------------------------------------------------
# NixOS service module helpers
# ---------------------------------------------------------------------------
# Conditionally enable modules based on system
enableForSystem =
system: modules:
builtins.filter (
mod: mod.systems or [ ] == [ ] || builtins.elem system (mod.systems or [ ])
) modules;
# Create a NixOS module with standard options (enable, port, reverseProxy,
# firewall, user, postgresql, redis) and optional caller-supplied options and
# config. All config is gated behind `cfg.enable`.
# Create a module with common options
mkModule =
{
name,
description ? "",
options ? { },
moduleConfig ? { },
domain ? "services",
config,
serviceName ? name,
config ? { },
}:
let
cfg = config.${namespace}.${domain}.${name};
upstreamUrl =
if cfg.reverseProxy.upstreamUrl != null then
cfg.reverseProxy.upstreamUrl
else
"http://127.0.0.1:${toString cfg.port}";
fqdn = "${cfg.reverseProxy.subdomain}.${cfg.reverseProxy.domain}";
defaultConfig = {
# Caddy reverse proxy: when reverseProxy.enable = true, contribute this
# service's named-matcher block into the shared wildcard virtual host.
services.caddy.virtualHosts."*.${cfg.reverseProxy.domain}" = lib.mkIf cfg.reverseProxy.enable {
extraConfig = ''
@${name} host ${fqdn}
handle @${name} {
reverse_proxy ${upstreamUrl}
${cfg.reverseProxy.extraCaddyConfig}
}
'';
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
allowedUDPPorts = [ cfg.port ];
};
users = lib.mkIf cfg.createUser {
users.${name} = {
isSystemUser = true;
group = name;
home = cfg.configDir;
};
groups.${name} = { };
};
# RequiresMountsFor is silently ignored when the paths live on the root
# filesystem, so this is safe on non-NAS hosts too.
systemd.services.${serviceName}.unitConfig.RequiresMountsFor = [
cfg.configDir
cfg.dataDir
];
services = {
postgresql = lib.mkIf cfg.configureDb {
enable = true;
ensureDatabases = [ name ];
ensureUsers = [
{
name = name;
ensureDBOwnership = true;
}
];
};
redis.servers.${name} = lib.mkIf cfg.redis.enable {
enable = true;
port = cfg.redis.port;
};
};
};
in
{ lib, ... }:
{
imports = [
{ config = lib.mkIf cfg.enable defaultConfig; }
{ config = lib.mkIf cfg.enable moduleConfig; }
];
options.${namespace}.${domain}.${name} = lib.mkOption {
options.mjallen.${name} = lib.mkOption {
type = lib.types.submodule {
options = {
enable = lib.mkEnableOption description;
}
// options;
};
default = { };
};
port = mkOpt types.int 80 "Port for ${name} to listen on";
config = lib.mkIf config.mjallen.${name}.enable config;
};
configDir = mkOpt types.str "/var/lib/${name}" "Path to the config directory";
mkContainer =
{
name,
localAddress ? "127.0.0.1",
ports ? [ "80" ],
bindMounts ? { },
config ? { },
}:
{ lib, ... }:
{
containers.${name} = {
inherit localAddress bindMounts;
dataDir = mkOpt types.str "/var/lib/${name}/data" "Path to the data directory";
createUser = mkBoolOpt false "Create a dedicated system user for this service";
configureDb = mkBoolOpt false "Manage a PostgreSQL database for this service";
environmentFile =
mkOpt (types.nullOr types.str) null
"Path to an environment file (EnvironmentFile=)";
puid = mkOpt types.str "911" "User ID for container-based services";
pgid = mkOpt types.str "100" "Group ID for container-based services";
timeZone = mkOpt types.str "UTC" "Timezone for container-based services";
listenAddress = mkOpt types.str "0.0.0.0" "Listen address";
openFirewall = mkBoolOpt true "Open firewall ports for this service";
redis = {
enable = lib.mkEnableOption "a dedicated Redis server for this service";
port = mkOpt types.int 6379 "Redis port for ${name}";
config = config // {
networking = {
firewall = {
enable = true;
allowedTCPPorts = ports;
};
# Use systemd-resolved inside the container
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
useHostResolvConf = lib.mkForce false;
};
hashedPassword =
mkOpt (types.nullOr types.str) null
"Hashed password (e.g. for web-based authentication)";
extraEnvironment =
mkOpt (types.attrsOf types.str) { }
"Extra environment variables passed to the service";
reverseProxy = mkReverseProxyOpt name;
}
// options;
services.resolved.enable = true;
system.stateVersion = "23.11";
};
autoStart = lib.mkDefault true;
privateNetwork = lib.mkDefault true;
hostAddress = lib.mkDefault "10.0.1.3";
};
networking = {
nat.forwardPorts = map (port: {
destination = lib.mkDefault "${localAddress}:${toString port}";
sourcePort = lib.mkDefault port;
}) ports;
firewall = {
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};
default = { };
};
};
# Wraps mkModule for Podman/OCI container services. Generates all the
# standard mkModule options plus the container definition. The serviceName
# is set to "podman-<name>" automatically.
#
# Required args:
# config — the NixOS config attrset (pass through from the module args)
# name — service name (used for the container name and option path)
# image — OCI image reference string
# internalPort — port the container listens on internally
#
# Optional args:
# description — human-readable description (defaults to name)
# options — extra mkModule options attrset
# volumes — extra volume strings (in addition to none)
# environment — extra environment variables (merged with PUID/PGID/TZ)
# environmentFiles — list of paths to env-files (e.g. sops template paths)
# extraOptions — list of extra --opt strings passed to the container runtime
# devices — list of device mappings
# extraConfig — extra NixOS config merged into moduleConfig
mkContainerService =
{
config,
name,
image,
internalPort,
description ? name,
options ? { },
volumes ? [ ],
environment ? { },
environmentFiles ? [ ],
extraOptions ? [ ],
devices ? [ ],
extraConfig ? { },
}:
let
cfg = config.${namespace}.services.${name};
in
mkModule {
inherit
config
name
description
options
;
serviceName = "podman-${name}";
moduleConfig = lib.recursiveUpdate {
virtualisation.oci-containers.containers.${name} = {
autoStart = true;
inherit
image
volumes
environmentFiles
extraOptions
devices
;
ports = [ "${toString cfg.port}:${toString internalPort}" ];
environment = {
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
}
// environment;
};
} extraConfig;
};
# Generates a sops secrets block + a sops template env-file in a single call.
#
# secrets — attrset of sops secret keys → extra attrs (e.g. owner/group).
# The sopsFile is set automatically to nas-secrets.yaml unless
# overridden per-secret via { sopsFile = ...; }.
# name — template file name, e.g. "glance.env"
# content — the template body string (use config.sops.placeholder."key")
# restartUnit — systemd unit to restart when the secret changes
# owner, group, mode — file ownership/permissions (defaults match NAS convention)
# sopsFile — default sops file for all secrets (can be overridden per-secret)
mkSopsEnvFile =
{
secrets,
name,
content,
restartUnit,
owner ? "nix-apps",
group ? "jallen-nas",
mode ? "660",
sopsFile ? (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"),
}:
{
sops.secrets = mapAttrs (_key: extra: { inherit sopsFile; } // extra) secrets;
sops.templates.${name} = {
inherit
mode
owner
group
content
;
restartUnits = [ restartUnit ];
};
};
# ---------------------------------------------------------------------------
# Home Manager module helper
# ---------------------------------------------------------------------------
# Create a Home Manager module with a standard enable option and optional
# extra options, gating all config behind `cfg.enable`.
#
# domain — option namespace domain, e.g. "programs" or "desktop"
# name — module name, e.g. "btop"
# description — text for mkEnableOption (defaults to name)
# options — attrset of extra options merged into the submodule
# config — the NixOS/HM config attrset passed through from module args
# moduleConfig — the Home Manager config body (already gated behind cfg.enable)
mkHomeModule =
{
config,
domain,
name,
description ? name,
options ? { },
moduleConfig,
}:
let
cfg = config.${namespace}.${domain}.${name};
in
{ lib, ... }:
{
options.${namespace}.${domain}.${name} = lib.mkOption {
type = lib.types.submodule {
options = {
enable = lib.mkEnableOption description;
}
// options;
};
default = { };
};
config = lib.mkIf cfg.enable moduleConfig;
};
# ---------------------------------------------------------------------------
# Migrated mjallen utilities
# Option creation helpers
# ---------------------------------------------------------------------------
mkOpt =
type: default: description:
mkOption { inherit type default description; };
mkOpt' = type: default: mkOpt type default "";
mkOpt' = type: default: mkOpt type default null;
mkBoolOpt = mkOpt types.bool;
mkBoolOpt' = mkOpt' types.bool;
mkReverseProxyOpt = name: {
enable = mkBoolOpt false "Enable Caddy reverse proxy for this service";
mkReverseProxyOpt = {
enable = mkBoolOpt false "Enable reverse proxy support";
subdomain = mkOpt types.str name "Subdomain for the service (default: service name)";
subdomain = mkOpt types.str "" "subdomain of the service";
domain = mkOpt types.str "mjallen.dev" "Base domain for the reverse proxy";
upstreamUrl =
mkOpt (types.nullOr types.str) null
"Override upstream URL (e.g. for a service on a different host). Defaults to http://127.0.0.1:<port>.";
extraCaddyConfig = mkOpt types.lines "" "Extra Caddyfile directives inside this virtual host block";
middlewares = mkOpt (types.listOf types.str) [ ] "List of middlewares to use";
};
# ---------------------------------------------------------------------------
# Convenience shorthands
# ---------------------------------------------------------------------------
# Standard enable/disable patterns
enabled = {
enable = true;
};
disabled = {
enable = false;
};
# ---------------------------------------------------------------------------
# String utilities
# ---------------------------------------------------------------------------
capitalize =
s:
let
@@ -345,16 +126,10 @@ rec {
in
if len == 0 then "" else (toUpper (substring 0 1 s)) + (substring 1 len s);
# ---------------------------------------------------------------------------
# Boolean utilities
# ---------------------------------------------------------------------------
boolToNum = bool: if bool then 1 else 0;
# ---------------------------------------------------------------------------
# Attribute manipulation utilities
# ---------------------------------------------------------------------------
default-attrs = mapAttrs (_key: mkDefault);
force-attrs = mapAttrs (_key: mkForce);
@@ -363,3 +138,4 @@ rec {
nested-force-attrs = mapAttrs (_key: force-attrs);
}
// base64Lib

View File

@@ -0,0 +1,220 @@
{ inputs }:
let
inherit (inputs.nixpkgs.lib)
listToAttrs
nameValuePair
;
in
rec {
# Create a service configuration for Traefik
mkService =
{
name,
url,
loadBalancer ? { },
}:
{
inherit name url;
config = {
loadBalancer = {
servers = [ { inherit url; } ];
}
// loadBalancer;
};
};
# Create a router configuration for Traefik
mkRouter =
{
subdomain,
domain ? "mjallen.dev",
service,
entryPoints ? [ "websecure" ],
middlewares ? [
"crowdsec"
"whitelist-geoblock"
],
priority ? null,
rule ? null,
tls ? {
certResolver = "letsencrypt";
},
}:
{
inherit
subdomain
service
entryPoints
middlewares
;
config = {
inherit
entryPoints
service
middlewares
tls
;
rule = if rule != null then rule else "Host(`${subdomain}.${domain}`)";
}
// (if priority != null then { inherit priority; } else { });
};
# Create both service and router for a simple reverse proxy setup
mkReverseProxy =
{
name,
subdomain,
url,
domain ? "mjallen.dev",
entryPoints ? [ "websecure" ],
middlewares ? [
"crowdsec"
"whitelist-geoblock"
],
priority ? null,
rule ? null,
tls ? {
certResolver = "letsencrypt";
},
loadBalancer ? { },
}:
{
service = mkService {
inherit name url loadBalancer;
};
router = mkRouter {
inherit
subdomain
domain
entryPoints
middlewares
priority
rule
tls
;
service = name;
};
};
# Convert a list of services to the format expected by Traefik module
servicesToConfig =
services: listToAttrs (map (service: nameValuePair service.name service.config) services);
# Convert a list of routers to the format expected by Traefik module
routersToConfig =
routers: listToAttrs (map (router: nameValuePair router.subdomain router.config) routers);
# Helper to create multiple reverse proxies at once
mkReverseProxies =
proxies:
let
results = map mkReverseProxy proxies;
services = map (result: result.service) results;
routers = map (result: result.router) results;
in
{
services = servicesToConfig services;
routers = routersToConfig routers;
extraServices = services;
extraRouters = map (router: {
inherit (router) subdomain entryPoints middlewares;
service = router.service;
}) routers;
};
# Common middleware configurations
middlewares = {
# Authentication middleware
auth = [ "authentik" ];
# Basic security (default)
basic = [
"crowdsec"
"whitelist-geoblock"
];
# Internal only access
internal = [
"crowdsec"
"whitelist-geoblock"
"internal-ipallowlist"
];
# WebSocket support
websocket = [
"crowdsec"
"whitelist-geoblock"
"onlyoffice-websocket"
];
# Authenticated with basic security
authBasic = [
"crowdsec"
"whitelist-geoblock"
"authentik"
];
};
# Common service URL builders
urls = {
# Local container service
container =
containerName: port: "http://\${config.containers.${containerName}.localAddress}:${toString port}";
# Local host service
localhost = port: "http://127.0.0.1:${toString port}";
# Network service
network = ip: port: "http://${ip}:${toString port}";
# Server IP service (using your server IP pattern)
server = port: "http://\${serverIp}:${toString port}";
};
# Pre-configured reverse proxy templates
templates = {
# Standard web application
webapp =
{ port, ... }@args:
mkReverseProxy (
{
url = urls.localhost port;
middlewares = middlewares.basic;
}
// args
);
# Authenticated web application
authWebapp =
{ port, ... }@args:
mkReverseProxy (
{
url = urls.localhost port;
middlewares = middlewares.authBasic;
}
// args
);
# Container-based service
containerService =
{ containerName, port, ... }@args:
mkReverseProxy (
{
url = urls.container containerName port;
middlewares = middlewares.basic;
}
// args
);
# Internal-only service
internalService =
{ port, ... }@args:
mkReverseProxy (
{
url = urls.localhost port;
middlewares = middlewares.internal;
}
// args
);
};
}

103
lib/system/common.nix Normal file
View File

@@ -0,0 +1,103 @@
{ inputs }:
let
inherit (inputs.nixpkgs.lib) filterAttrs mapAttrs';
in
{
mkExtendedLib =
flake: nixpkgs:
nixpkgs.lib.extend (
_final: _prev: {
mjallen = flake.mjallen-lib;
}
);
mkNixpkgsConfig = flake: {
overlays = builtins.attrValues flake.overlays;
config = {
allowAliases = false;
allowUnfree = true;
permittedInsecurePackages = [
# Add any permitted insecure packages here
"mbedtls-2.28.10"
];
};
};
mkHomeConfigs =
{
flake,
system,
hostname,
}:
let
inherit (flake.mjallen-lib.file) scanHomes;
homesPath = ../../homes;
allHomes = scanHomes homesPath;
in
filterAttrs (
_name: homeConfig: homeConfig.system == system && homeConfig.hostname == hostname
) allHomes;
mkHomeManagerConfig =
{
extendedLib,
inputs,
system,
matchingHomes,
isNixOS ? true,
}:
if matchingHomes != { } then
{
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
inherit inputs system;
inherit (inputs) self;
lib = extendedLib;
};
sharedModules = [
{ _module.args.lib = extendedLib; }
]
++ (extendedLib.mjallen.file.importModulesRecursive ../../modules/home);
users = mapAttrs' (_name: homeConfig: {
name = homeConfig.username;
value = {
imports = [ homeConfig.path ];
home = {
inherit (homeConfig) username;
homeDirectory = inputs.nixpkgs.lib.mkDefault (
if isNixOS then "/home/${homeConfig.username}" else "/Users/${homeConfig.username}"
);
};
}
// (
if isNixOS then
{
_module.args.username = homeConfig.username;
}
else
{ }
);
}) matchingHomes;
};
}
else
{ };
mkSpecialArgs =
{
inputs,
hostname,
username,
extendedLib,
}:
{
inherit inputs hostname username;
inherit (inputs) self;
lib = extendedLib;
namespace = "mjallen";
format = "system";
host = hostname;
};
}

5
lib/system/default.nix Normal file
View File

@@ -0,0 +1,5 @@
{ inputs }:
{
# Common utilities used by system builders
common = import ./common.nix { inherit inputs; };
}

View File

@@ -1,212 +0,0 @@
{
lib,
inputs,
system ? "aarch64-linux",
}:
let
pkgs = inputs.nixpkgs.legacyPackages.${system};
in
let
inherit (builtins)
isAttrs
isList
isString
hasAttr
getAttr
attrNames
toString
replaceStrings
;
mapAttrs = lib.mapAttrs;
recursiveUpdate = lib.recursiveUpdate;
# Deep-merge attrsets (right-biased).
deepMerge = a: b: recursiveUpdate a b;
# Merge component sources: base.sources overlaid by overrides (component-wise deep merge).
mergeSources =
baseSources: overrides:
baseSources
// mapAttrs (
name: ov: if hasAttr name baseSources then deepMerge (getAttr name baseSources) ov else ov
) overrides;
# Apply a single variant overlay (variables + sources).
applyVariantOnce =
selected: variant:
let
vVars = if variant ? variables then variant.variables else { };
vSrcs = if variant ? sources then variant.sources else { };
in
{
variables = selected.variables // vVars;
sources = mergeSources selected.sources vSrcs;
};
# Apply platform-specific overrides if present for the given system.
applyPlatforms =
selected: variant: system:
if system == null || !(variant ? platforms) || !(hasAttr system variant.platforms) then
selected
else
let
p = variant.platforms.${system};
pVars = if p ? variables then p.variables else { };
pSrcs = if p ? sources then p.sources else { };
in
{
variables = selected.variables // pVars;
sources = mergeSources selected.sources pSrcs;
};
# Resolve variant chain via inherits (ancestor first), then apply platforms.
resolveVariant =
spec: baseSelected: variantName: system:
if variantName == null || !(spec ? variants) || !(hasAttr variantName spec.variants) then
baseSelected
else
let
v = spec.variants.${variantName};
parentSelected =
if v ? inherits then resolveVariant spec baseSelected v.inherits system else baseSelected;
withVariant = applyVariantOnce parentSelected v;
in
applyPlatforms withVariant v system;
# Render ${var} substitutions in any string within attrs/lists.
renderValue =
value: vars:
if isString value then
let
keys = attrNames vars;
patterns = map (k: "\${" + k + "}") keys;
replacements = map (k: toString (getAttr k vars)) keys;
in
replaceStrings patterns replacements value
else if isAttrs value then
mapAttrs (_: v: renderValue v vars) value
else if isList value then
map (v: renderValue v vars) value
else
value;
# Decide fetcher for URL type based on optional extra.unpack hint.
useFetchZip = comp: comp ? extra && comp.extra ? unpack && comp.extra.unpack == "zip";
# Build a single src from a rendered component spec.
mkSrcFromRendered =
comp:
let
fetcher = if comp ? fetcher then comp.fetcher else "none";
in
if fetcher == "github" then
pkgs.fetchFromGitHub (
{
owner = comp.owner;
repo = comp.repo;
# Allow tag as rev (ignore null/empty tag)
rev = if comp ? tag && comp.tag != null && comp.tag != "" then comp.tag else comp.rev;
fetchSubmodules = if comp ? submodules then comp.submodules else false;
hash = comp.hash;
}
// lib.optionalAttrs (comp ? name) { name = comp.name; }
)
else if fetcher == "git" then
pkgs.fetchgit {
url = comp.url;
rev = comp.rev;
fetchSubmodules = if comp ? submodules then comp.submodules else false;
hash = comp.hash;
}
else if fetcher == "url" then
let
url = if comp ? url then comp.url else comp.urlTemplate;
in
if useFetchZip comp then
pkgs.fetchzip (
{
inherit url;
hash = comp.hash;
}
// lib.optionalAttrs (comp ? extra && comp.extra ? stripRoot) { stripRoot = comp.extra.stripRoot; }
)
else
pkgs.fetchurl {
inherit url;
hash = comp.hash;
}
else if fetcher == "pypi" then
pkgs.python3Packages.fetchPypi {
pname = comp.name;
version = comp.version;
hash = comp.hash;
}
else
# fetcher == "none": pass-through (e.g., linux version/hash consumed by custom logic)
comp;
in
rec {
/*
Select a variant from a loaded version.json specification.
Usage:
let selected = versioning.selectVariant spec variantName system;
- spec: attrset from lib.importJSON ./version.json
- variantName: string or null (when null, uses spec.defaultVariant if present)
- system: string like "x86_64-linux" or null (to apply platforms overrides)
*/
selectVariant =
spec: variantName: system:
let
chosen =
if variantName != null then
variantName
else
(if spec ? defaultVariant then spec.defaultVariant else null);
baseSelected = {
variables = if spec ? variables then spec.variables else { };
sources = if spec ? sources then spec.sources else { };
};
in
resolveVariant spec baseSelected chosen system;
/*
Render ${var} template substitutions across any value using provided variables.
Strings, attrsets, and lists are traversed.
*/
render = value: variables: renderValue value variables;
/*
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.
*/
mkSrc =
comp: variables:
let
rendered = renderValue comp variables;
in
mkSrcFromRendered rendered;
/*
Produce an attrset of all sources for a selected spec:
mkAllSources selected
Where:
selected = selectVariant spec variantName system
Returns:
{ componentName = src | renderedComp (for "none"); ... }
*/
mkAllSources =
selected:
mapAttrs (
_name: comp:
if comp ? fetcher && comp.fetcher == "none" then
renderValue comp selected.variables
else
mkSrc (renderValue comp selected.variables) selected.variables
) selected.sources;
# Expose deepMerge for convenience (right-biased).
inherit deepMerge;
}

View File

@@ -35,6 +35,9 @@
# Pass inputs so external modules can access them
extraSpecialArgs = {
inherit inputs namespace;
overlays = with inputs; [
nix-vscode-extensions.overlays.default
];
};
# Make ALL external HM modules available globally

View File

@@ -1,57 +0,0 @@
{
lib,
...
}:
{
nix = {
settings = {
# extra-sandbox-paths = [ config.programs.ccache.cacheDir ];
substituters = [
"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";
};
optimise.automatic = lib.mkDefault true;
};
nixpkgs = {
config = {
# CUDA and ROCm are not applicable on Darwin; those hardware modules are
# NixOS-only. Unfree allowance is handled globally via channels-config in
# the flake.
allowUnsupportedSystem = true;
};
};
}

View File

@@ -2,11 +2,10 @@
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.desktop.gnome;
cfg = config.mjallen.desktop.gnome;
in
{
imports = [ ./options.nix ];
@@ -23,14 +22,11 @@ in
gnomeExtensions.bing-wallpaper-changer
gnomeExtensions.dash-to-dock
gnomeExtensions.dash-to-panel
gnomeExtensions.caffeine
gnomeExtensions.gsconnect
gnomeExtensions.nasa-apod
gnomeExtensions.random-wallpaper
gnomeExtensions.tiling-assistant
gnomeExtensions.user-themes
gnomeExtensions.wikiart-wallpaper
gnomeExtensions.boatman-winboat-monitor
papirus-icon-theme
pop-gtk-theme
];
@@ -38,22 +34,17 @@ in
dconf = {
enable = true;
settings = {
"io/missioncenter/MissionCenter".performance-page-cpu-graph = 2; # logical processors
"org/gnome/desktop/interface" = {
clock-format = "12h";
color-scheme = "prefer-dark";
cursor-theme = lib.mkDefault "macOS";
enable-hot-corners = false;
font-antialiasing = "grayscale";
font-hinting = "slight";
gtk-theme = lib.mkDefault "Colloid-Dark";
icon-theme = lib.mkDefault "Colloid-Dark";
};
"org/gnome/desktop/interface".clock-format = "12h";
"org/gnome/desktop/interface".color-scheme = "prefer-dark";
"org/gnome/desktop/interface".cursor-theme = lib.mkDefault "macOS";
"org/gnome/desktop/interface".enable-hot-corners = false;
"org/gnome/desktop/interface".font-antialiasing = "grayscale";
"org/gnome/desktop/interface".font-hinting = "slight";
"org/gnome/desktop/interface".gtk-theme = lib.mkDefault "Colloid-Dark";
"org/gnome/desktop/interface".icon-theme = lib.mkDefault "Colloid-Dark";
"org/gnome/desktop/peripherals/mouse".accel-profile = "flat";
"org/gnome/desktop/peripherals/touchpad" = {
two-finger-scrolling-enabled = true;
tap-to-click = true;
};
"org/gnome/desktop/peripherals/touchpad".two-finger-scrolling-enabled = true;
"org/gnome/desktop/peripherals/touchpad".tap-to-click = true;
"org/gnome/mutter".experimental-features = [
"scale-monitor-framebuffer"
"variable-refresh-rate"
@@ -62,36 +53,20 @@ in
"org/gnome/shell".enabled-extensions = [
"allowlockedremotedesktop@kamens.us"
"appindicatorsupport@rgcjonas.gmail.com"
"caffeine@patapon.info"
"user-theme@gnome-shell-extensions.gcampax.github.com"
"tiling-assistant@leleat-on-github"
"dash-to-dock@micxgx.gmail.com"
"BingWallpaper@ineffable-gmail.com"
"gsconnect@andyholmes.github.io"
];
"org/gnome/shell/extensions/bingwallpaper" = {
override-lockscreen-blur = true;
random-mode-enabled = false;
selected-image = "current";
revert-to-current-image = false;
};
"org/gnome/shell/extensions/caffeine" = {
enable-fullscreen = true;
enable-mpris = true;
inhibit-apps = [
"horizon-client.desktop"
];
};
"org/gnome/shell/extensions/dash-to-panel" = {
primary-monitor = 1;
multi-monitors = false;
};
"org/gnome/shell/extensions/gsconnect" = {
id = "4db35bd2-0dcd-42a3-9f77-ef3e8bb83182";
name = "matt-nixos";
};
"org/gnome/shell/extensions/bingwallpaper".override-lockscreen-blur = true;
"org/gnome/shell/extensions/bingwallpaper".random-mode-enabled = true;
"org/gnome/shell/extensions/bingwallpaper".revert-to-current-image = false;
"org/gnome/shell/extensions/dash-to-panel".primary-monitor = 1;
"org/gnome/shell/extensions/dash-to-panel".multi-monitors = false;
"org/gnome/shell/extensions/gsconnect".id = "4db35bd2-0dcd-42a3-9f77-ef3e8bb83182";
"org/gnome/shell/extensions/gsconnect".name = "matt-nixos";
"org/gnome/shell/extensions/user-theme".name = lib.mkDefault "Colloid-Dark";
"org/gnome/system/location".enabled = true;
"org/gtk/settings/file-chooser".clock-format = "12h";
};
};

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.desktop.gnome = {
options.mjallen.desktop.gnome = {
enable = mkEnableOption "enable gnome settings";
};
}

View File

@@ -3,7 +3,6 @@
programs = {
gpg = {
enable = true;
scdaemonSettings = {
disable-ccid = true;
pcsc-shared = true;

View File

@@ -4,94 +4,71 @@
pkgs,
namespace,
hasDestopEnvironment ? true,
system,
...
}:
let
inherit (lib.${namespace}) enabled;
isArm = ("aarch64-linux" == system) || ("aarch64-darwin" == system);
# Non-login / system accounts (root, nixos installer, etc.) should not get
# desktop packages, tmux, nh, kdeconnect, nextcloud-client, etc.
# Detect them by username so individual host home files are not needed.
isSystemUser = lib.elem config.home.username [
"root"
"nixos"
];
inherit (lib.${namespace}) enabled disabled;
in
{
home = {
enableNixpkgsReleaseCheck = lib.mkDefault false;
homeDirectory = lib.mkDefault (
if config.home.username == "root" then "/root" else "/home/${config.home.username}"
);
homeDirectory = lib.mkDefault "/home/${config.home.username}";
packages =
with pkgs;
(
if isSystemUser then
[ ]
else
[
age
clinfo
cpufetch
deadnix
lm_sensors
nano
nixfmt-rfc-style
pciutils
protonup-ng
rsync
smartmontools
sops
tailscale
tree
usbutils
vim
vulkan-tools
wget
]
++ (
if hasDestopEnvironment then
[
age
clinfo
cpufetch
dbus
deadnix
lm_sensors
nano
nebula
nix-prefetch-scripts
nixfmt
pciutils
protonup-ng
rsync
smartmontools
sops
tailscale
tree
usbutils
vim
vulkan-tools
wget
chromium
firefox
gamescope
gamescope-wsi
gparted
goverlay
mission-center
vesktop
]
++ (
if (hasDestopEnvironment) then
[
boxbuddy
stable.chromium
firefox
gamescope
gamescope-wsi
gparted
mission-center
parted
vesktop
]
else
[ ]
)
else
[ ]
);
stateVersion = lib.mkDefault "23.11";
};
programs = {
# nix-index-database is not available in all home configs (e.g. iso-minimal
# standalone homes don't load the nix-index-database HM module).
# Set it per-host in homes that explicitly load the module.
btop = {
enable = lib.mkDefault (!isSystemUser);
package = pkgs.btop;
};
fastfetch.enable = lib.mkDefault (!isSystemUser);
nix-index-database.comma = enabled;
btop = lib.mkDefault enabled;
fastfetch = lib.mkDefault enabled;
home-manager = lib.mkDefault enabled;
java.enable = lib.mkDefault (!isSystemUser);
mangohud.enable = lib.mkDefault (hasDestopEnvironment && !isSystemUser);
password-store.enable = lib.mkDefault (!isSystemUser);
java = {
enable = lib.mkDefault true;
};
mangohud.enable = lib.mkDefault hasDestopEnvironment;
password-store = enabled;
nh = {
enable = lib.mkDefault (!isSystemUser);
enable = true;
flake = "/etc/nixos";
clean = {
enable = lib.mkDefault (!isSystemUser);
enable = true;
extraArgs = "--keep 5";
};
};
@@ -108,7 +85,7 @@ in
};
tmux = {
enable = lib.mkDefault (!isSystemUser);
enable = lib.mkDefault true;
terminal = "screen-256color";
sensibleOnTop = true;
focusEvents = true;
@@ -130,7 +107,7 @@ in
tmuxPlugins.better-mouse-mode
];
extraConfig = ''
set -g status-right '#[fg=black,bg=color15] #{cpu_percentage} %H:%M '
set -g status-right '#[fg=black,bg=color15] #{cpu_percentage} %H:%M '
run-shell ${pkgs.tmuxPlugins.cpu}/share/tmux-plugins/cpu/cpu.tmux
set -g default-terminal "xterm-256color"
set -ga terminal-overrides ",*256col*:Tc"
@@ -148,14 +125,11 @@ in
};
services = {
# nextcloud-client is disabled by default for all users; systems that
# want it enabled must opt in explicitly in their home configuration.
nextcloud-client.enable = lib.mkDefault false;
pass-secret-service.enable = lib.mkDefault (!isSystemUser);
nextcloud-client.enable = lib.mkDefault hasDestopEnvironment;
pass-secret-service = lib.mkDefault enabled;
kdeconnect = {
enable = lib.mkDefault (hasDestopEnvironment && !isSystemUser);
indicator = lib.mkDefault (hasDestopEnvironment && !isSystemUser);
package = pkgs.kdePackages.kdeconnect-kde;
enable = lib.mkDefault hasDestopEnvironment;
indicator = lib.mkDefault true;
};
};
}

View File

@@ -1,84 +1,77 @@
{ config, lib, ... }:
with lib;
let
cfg = config.mjallen.programs.btop;
in
{
config,
lib,
namespace,
...
}:
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "btop";
moduleConfig = {
programs.btop = {
enable = true;
settings = {
truecolor = true;
force_tty = false;
presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty";
vim_keys = true;
rounded_corners = true;
graph_symbol = "braille";
graph_symbol_cpu = "default";
graph_symbol_mem = "default";
graph_symbol_net = "default";
graph_symbol_proc = "default";
shown_boxes = "cpu mem net proc";
update_ms = 2000;
proc_sorting = "cpu lazy";
proc_reversed = false;
proc_tree = false;
proc_colors = true;
proc_gradient = true;
proc_per_core = false;
proc_mem_bytes = true;
proc_cpu_graphs = true;
proc_info_smaps = false;
proc_left = false;
proc_filter_kernel = false;
cpu_graph_upper = "total";
cpu_graph_lower = "total";
cpu_invert_lower = true;
cpu_single_graph = false;
cpu_bottom = false;
show_uptime = true;
check_temp = true;
cpu_sensor = "Auto";
show_coretemp = true;
cpu_core_map = "";
temp_scale = "celsius";
base_10_sizes = false;
show_cpu_freq = true;
clock_format = "%X";
background_update = true;
custom_cpu_name = "";
disks_filter = "";
mem_graphs = true;
mem_below_net = false;
zfs_arc_cached = true;
show_swap = true;
swap_disk = true;
show_disks = true;
only_physical = true;
use_fstab = true;
zfs_hide_datasets = false;
disk_free_priv = false;
show_io_stat = true;
io_mode = false;
io_graph_combined = false;
io_graph_speeds = "";
net_download = 100;
net_upload = 100;
net_auto = true;
net_sync = true;
net_iface = "";
show_battery = true;
selected_battery = "Auto";
log_level = "WARNING";
};
};
imports = [ ./options.nix ];
config = mkIf cfg.enable {
programs.btop = {
enable = true;
settings = {
truecolor = true;
force_tty = false;
presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty";
vim_keys = true;
rounded_corners = true;
graph_symbol = "braille";
graph_symbol_cpu = "default";
graph_symbol_mem = "default";
graph_symbol_net = "default";
graph_symbol_proc = "default";
shown_boxes = "cpu mem net proc";
update_ms = 2000;
proc_sorting = "cpu lazy";
proc_reversed = false;
proc_tree = false;
proc_colors = true;
proc_gradient = true;
proc_per_core = false;
proc_mem_bytes = true;
proc_cpu_graphs = true;
proc_info_smaps = false;
proc_left = false;
proc_filter_kernel = false;
cpu_graph_upper = "total";
cpu_graph_lower = "total";
cpu_invert_lower = true;
cpu_single_graph = false;
cpu_bottom = false;
show_uptime = true;
check_temp = true;
cpu_sensor = "Auto";
show_coretemp = true;
cpu_core_map = "";
temp_scale = "celsius";
base_10_sizes = false;
show_cpu_freq = true;
clock_format = "%X";
background_update = true;
custom_cpu_name = "";
disks_filter = "";
mem_graphs = true;
mem_below_net = false;
zfs_arc_cached = true;
show_swap = true;
swap_disk = true;
show_disks = true;
only_physical = true;
use_fstab = true;
zfs_hide_datasets = false;
disk_free_priv = false;
show_io_stat = true;
io_mode = false;
io_graph_combined = false;
io_graph_speeds = "";
net_download = 100;
net_upload = 100;
net_auto = true;
net_sync = true;
net_iface = "";
show_battery = true;
selected_battery = "Auto";
log_level = "WARNING";
};
})
];
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
with lib;
{
options.mjallen.programs.btop = {
enable = mkEnableOption "enable btop";
};
}

View File

@@ -12,6 +12,7 @@ let
x86_only = with pkgs; [
vscode-extensions.redhat.vscode-xml
];
open-remote-ssh = pkgs.${namespace}.open-remote-ssh;
in
{
home.packages = with pkgs; [
@@ -45,37 +46,38 @@ in
vscode-extensions.redhat.vscode-yaml
vscode-extensions.yy0931.vscode-sqlite3-editor
nix-vscode-extensions.open-vsx.jeanp413.open-remote-ssh
# open-remote-ssh
# nix-vscode-extensions.open-vsx.jeanp413.open-remote-ssh
open-remote-ssh
]
++ (if !isArm then x86_only else [ ]);
# ++ (if !isDarwin then [ open-remote-ssh ] else [ ]);
# ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
# {
# name = "copilot-mcp";
# publisher = "automatalabs";
# version = "0.0.49";
# sha256 = "sha256-+G2OQl5SCN7bh7MzGdYiRclIZefBE7lWnGg1kNpCvnA=";
# }
# {
# name = "mcp-server-runner";
# publisher = "zebradev";
# version = "0.1.0";
# sha256 = "sha256-StydVt3VzQUSS/pYp76jnIwtZlEj8gWAGzOARs93J+E=";
# }
# {
# name = "claude-dev";
# publisher = "saoudrizwan";
# version = "3.17.9";
# sha256 = "sha256-y3bFtMe5vZrO3DFb31KDvkzjD2jM76wK89mKhgJXC70=";
# }
# ];
++ (if !isArm then x86_only else [ ])
++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
{
name = "copilot-mcp";
publisher = "automatalabs";
version = "0.0.49";
sha256 = "sha256-+G2OQl5SCN7bh7MzGdYiRclIZefBE7lWnGg1kNpCvnA=";
}
{
name = "mcp-server-runner";
publisher = "zebradev";
version = "0.1.0";
sha256 = "sha256-StydVt3VzQUSS/pYp76jnIwtZlEj8gWAGzOARs93J+E=";
}
{
name = "claude-dev";
publisher = "saoudrizwan";
version = "3.17.9";
sha256 = "sha256-y3bFtMe5vZrO3DFb31KDvkzjD2jM76wK89mKhgJXC70=";
}
];
userSettings = {
"database-client.autoSync" = true;
"editor" = {
"defaultFormatter" = "brettm12345.nixfmt-vscode";
"fontFamily" = "fira-code-nerd, FiraCode Nerd Font, Consolas, 'Courier New', monospace";
"fontLigatures" = true;
"renderWhitespace" = "all";
};
@@ -84,10 +86,6 @@ in
"confirmDragAndDrop" = false;
};
"extensions." = {
"autoCheckUpdates" = false;
};
"git" = {
"confirmSync" = false;
"enableSmartCommit" = true;
@@ -143,8 +141,6 @@ in
"security.workspace.trust.untrustedFiles" = "open";
"update.mode" = "none";
"workbench" = {
"colorCustomizations" = null;
"editorAssociations" = {
@@ -158,8 +154,8 @@ in
};
};
direnv = {
enable = true;
nix-direnv.enable = true;
enable = false;
nix-direnv.enable = false;
enableZshIntegration = true;
};
};

View File

@@ -1,46 +0,0 @@
# Shared defaultApps submodule options, used by both the hyprland and
# nwg-panel modules. Import this file and pass the result as the `options`
# argument to types.submodule to avoid duplicating the definition.
{ pkgs, lib, ... }:
{
browser = lib.mkOption {
type = lib.types.package;
default = pkgs.firefox;
description = "Default web browser";
};
editor = lib.mkOption {
type = lib.types.package;
default = pkgs.micro;
description = "Default text editor";
};
fileExplorer = lib.mkOption {
type = lib.types.package;
default = pkgs.nautilus;
description = "Default file explorer";
};
visual = lib.mkOption {
type = lib.types.package;
default = pkgs.vscodium;
description = "Default visual/IDE editor";
};
terminal = lib.mkOption {
type = lib.types.package;
default = pkgs.kitty;
description = "Default terminal emulator";
};
office = lib.mkOption {
type = lib.types.package;
default = pkgs.onlyoffice-desktopeditors;
description = "Default office suite";
};
video = lib.mkOption {
type = lib.types.package;
default = pkgs.vlc;
description = "Default video player";
};
imageViewer = lib.mkOption {
type = lib.types.package;
default = pkgs.nomacs;
description = "Default image viewer";
};
}

View File

@@ -1,25 +0,0 @@
{
config,
namespace,
lib,
...
}:
let
cfg = config.${namespace}.programs.hyprland;
in
{
config = lib.mkIf cfg.enable {
services.avizo = {
enable = true;
settings = {
default = {
time = 1.0;
y-offset = 0.5;
fade-in = 0.1;
fade-out = 0.2;
padding = 10;
};
};
};
};
}

View File

@@ -2,17 +2,15 @@
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.programs.hyprland;
cfg = config.mjallen.programs.hyprland;
drawer = "nwg-drawer -fm nautilus -term kitty -mb 10 -mt 10 -ml 10 -mr 10 -pbuseicontheme -i ${config.stylix.icons.dark}";
in
{
imports = [
./avizo.nix
./options.nix
];
@@ -64,13 +62,14 @@ in
wl-clipboard
wlogout
wlroots
xhost
xorg.xhost
xsettingsd
xwayland
pkgs.mjallen.pipewire-python
]
++ (if cfg.notificationDaemon == "mako" then [ mako ] else [ dunst ])
++ (if cfg.launcher == "wofi" then [ wofi ] else [ rofi ])
++ (with pkgs.${namespace}; [ pipewire-python ])
);
# Session variables
@@ -90,7 +89,7 @@ in
NIXOS_XDG_OPEN_USE_PORTAL = "1";
QT_AUTO_SCREEN_SCALE_FACTOR = "1";
QT_QPA_PLATFORM = "wayland-egl";
QT_QPA_PLATFORMTHEME = lib.mkDefault "gtk3";
QT_QPA_PLATFORMTHEME = "gtk3";
QT_SCALE_FACTOR = "1";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
SDL_VIDEODRIVER = "wayland";
@@ -112,12 +111,22 @@ in
enable = true;
settings = {
preload = [ cfg.hyprpaper.wallpaperPath ];
wallpaper = [
{
monitor = "";
path = cfg.hyprpaper.wallpaperPath;
}
];
wallpaper =
let
useMonitorV2 = (lib.versionAtLeast pkgs.hyprland.version "0.40.0") && (cfg.monitorv2 != [ ]);
names =
if useMonitorV2 then
map (m: m.name) cfg.monitorv2
else
[
cfg.display1.input
cfg.display2.input
];
in
if cfg.hyprpaper.usePerMonitor then
map (n: "${n}, ${cfg.hyprpaper.wallpaperPath}") names
else
[ ", ${cfg.hyprpaper.wallpaperPath}" ];
splash = false;
};
};
@@ -162,18 +171,18 @@ in
hyprlock = {
enable = true;
settings = {
background = mkForce [
background = [
{
monitor = "";
path = "/run/wallpaper.jpg"; # supports png, jpg, webp (no animations, though)
color = mkDefault "rgba(25, 20, 20, 1.0";
color = mkForce "rgba(25, 20, 20, 1.0)";
# all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations
blur_passes = mkDefault "3"; # 0 disables blurring
blur_size = mkDefault "7";
blur_passes = mkForce "3"; # 0 disables blurring
blur_size = mkForce "7";
noise = "0.0117";
contrast = "0.8916";
brightness = mkDefault "0.8172";
brightness = mkForce "0.8172";
vibrancy = "0.1696";
vibrancy_darkness = "0.0";
}
@@ -215,7 +224,7 @@ in
halign = "center";
valign = "center";
}
# weather
# weather
{
monitor = cfg.primaryDisplay;
text = "cmd[update:30000] waybar-weather --hyprlock";
@@ -226,7 +235,7 @@ in
halign = "right";
valign = "bottom";
}
# media
# media
{
monitor = cfg.primaryDisplay;
text = "cmd[update:1000] waybar-media";
@@ -241,9 +250,9 @@ in
# user box
shape = [
{
monitor = cfg.primaryDisplay;
monitor = "";
size = "200, 50";
color = "rgba(46, 52, 64, .25";
color = "rgba(46, 52, 64, .25)";
rounding = -1;
border_size = "0";
position = "0, 0";
@@ -410,20 +419,23 @@ in
++ cfg.keybinds.bindm;
bindel = [
", XF86AudioRaiseVolume, exec, volumectl -u up"
", XF86AudioLowerVolume, exec, volumectl -u down"
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+"
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
]
++ cfg.keybinds.bindel;
bindl = [
", XF86AudioMute, exec, volumectl toggle-mute"
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
", XF86AudioPlay, exec, playerctl play-pause"
", XF86AudioPrev, exec, playerctl previous"
", XF86AudioNext, exec, playerctl next"
", XF86AudioMicMute, exec, volumectl -m toggle-mute"
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
", XF86MonBrightnessUp, exec, lightctl up"
", XF86MonBrightnessDown, exec, lightctl down"
", XF86MonBrightnessUp, exec, brightnessctl set +5%"
", XF86MonBrightnessDown, exec, brightnessctl set 5%-"
"$mod, XF86MonBrightnessUp, exec, brightnessctl -d kbd_backlight set +10%"
"$mod, XF86MonBrightnessDown, exec, brightnessctl -d kbd_backlight set 10%-"
]
++ cfg.keybinds.bindl;
@@ -516,78 +528,80 @@ in
workspace = cfg.workspace;
windowrule = [
"match:title file_progress, float 1"
"match:title .*[Cc]onfirm.*, float 1"
"match:title .*[Dd]ialog.*, float 1"
"match:title .*[Dd]ownload.*, float 1"
"match:title .*[Nn]otification.*, float 1"
"match:title .*[Ee]rror.*, float 1"
"match:title .*[Ss]plash.*, float 1"
"match:title .*[Cc]onfirmreset.*, float 1"
"match:title .*[Ss]ign [Ii]n - .*, float 1"
"match:title .*[Oo]pen [Ff]ile.*, float 1"
"match:title .*branchdialog.*, float 1"
"match:class .*pavucontrol.*, float 1"
"match:class .*pavucontrol.*, move onscreen cursor 0% 0%"
"match:class .*[Oo]verskride.*, float 1"
"match:class .*FileRoller.*, float 1"
"match:class .*wlogout.*, float 1"
"match:title .*mpv.*, idle_inhibit stayfocused"
"float, title:(file_progress)"
"float, title:(.*[Cc]onfirm.*)"
"float, title:(.*[Dd]ialog.*)"
"float, title:(.*[Dd]ownload.*)"
"float, title:(.*[Nn]otification.*)"
"float, title:(.*[Ee]rror.*)"
"float, title:(.*[Ss]plash.*)"
"float, title:(.*[Cc]onfirmreset.*)"
"float, title:(.*[Ss]ign [Ii]n - .*)"
"float, title:(.*[Oo]pen [Ff]ile.*)"
"float, title:(.*branchdialog.*)"
"float, class:(.*pavucontrol.*)"
"move onscreen cursor 0% 0%, class:(.*pavucontrol.*)"
"float, class:(.*[Oo]verskride.*)"
"float, class:(.*FileRoller.*)"
"float, class:(.*wlogout.*)"
"idleinhibit stayfocused, title:(.*mpv.*)"
"match:class .*nm-connection-editor.*, float 1"
"match:class .*nm-connection-editor.*, move onscreen cursor 0% 0%"
"float, class:(.*nm-connection-editor.*)"
"move onscreen cursor 0% 0%, class:(.*nm-connection-editor.*)"
"match:title Media viewer, float 1"
"match:class it.mijorus.smile),match:title Smile, float 1"
"match:class .blueman-manager-wrapped)$,match:title Bluetooth Devices, float 1"
"float, title:(Media viewer)"
"float, class:(it.mijorus.smile),title:(Smile)"
"float, class:(.blueman-manager-wrapped)$,title:(Bluetooth Devices)"
# Picture in picture windows
"match:title .*Picture-in-Picture.*, float 1"
"match:title .*Picture-in-Picture.*, pin 1"
"float, title:(.*Picture-in-Picture.*)"
"pin, title::(.*Picture-in-Picture.*)"
# discord/vesktop
# "workspace: name:discord, match:class .*vesktop"
# "match:class .*vesktop),match:title .*Discord Popout.*, float 1"
# "pin, match:class .*vesktop),match:title .*Discord Popout.*"
# "workspace: name:discord, class:(.*vesktop)"
# "float, class:(.*vesktop),title:(.*Discord Popout.*)"
# "pin, class:(.*vesktop),title:(.*Discord Popout.*)"
# Music
# "workspace: name:discord, match:class Apple Music.*"
# "workspace: name:discord, class:(Apple Music.*)"
# Steam
"match:class .*[Ss]team, match:title .*[Ss]team.*, float 1"
"match:class .*[Ss]team, match:title .*[Ss]team.*, workspace name:steam silent"
"match:class .*[Ss]team, match:title .*[Ss]team.*, tile 1"
"match:class .*steam,match:title .*Friends List.*, float 1"
"float, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"workspace name:steam silent, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"tile, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"float, class:(.*steam),title:(.*Friends List.*)"
# Code
"match:class .*codium.*, match:title Save As, pin 1"
"match:class .*codium.*, match:title Save As, float 1"
"match:class xdg-desktop-portal-gtk, match:title Open Workspace from File, float 1"
"pin, class:(.*codium.*),title:(Save As)"
"float, class:(.*codium.*),title:(Save As)"
"float, class:(xdg-desktop-portal-gtk),title:(Open Workspace from File)"
# Game Tearing??? https://wiki.hypr.land/Configuring/Tearing/
"match:class .*gamescope.*, idle_inhibit fullscreen, content game, immediate 1"
"match:xdg_tag proton-game, idle_inhibit fullscreen, content game, immediate 1"
"match:class steam_app_.*, idle_inhibit fullscreen, content game, immediate 1"
"immediate, class:(.*gamescope)"
# vmware
# this tag will set the below options to the vdi window
# this will have it auto open as a 2160x7680 window
# and makes multi-monitor work
"match:class .*[Hh]orizon-client, match:title USPS Next VDI, tag +horizonrdp"
"tag +horizonrdp, class:(.*[Hh]orizon-client),title:(USPS Next VDI)"
"match:tag horizonrdp, no_anim 1"
"match:tag horizonrdp, no_blur 1"
"match:tag horizonrdp, rounding 0"
"match:tag horizonrdp, no_shadow 1"
"match:tag horizonrdp, immediate 1"
"match:tag horizonrdp, allows_input 1"
"match:tag horizonrdp, border_size 0"
"match:tag horizonrdp, max_size 2160 7680"
"match:tag horizonrdp, min_size 1920 1080"
"match:tag horizonrdp, render_unfocused 1"
"match:tag horizonrdp, idle_inhibit 1"
"match:tag horizonrdp, float 1"
"noanim, tag:horizonrdp"
"noblur, tag:horizonrdp"
"norounding, tag:horizonrdp"
"noshadow, tag:horizonrdp"
"immediate, tag:horizonrdp"
"allowsinput, tag:horizonrdp"
"noborder, tag:horizonrdp"
"nodim, tag:horizonrdp"
"nomaxsize, tag:horizonrdp"
"renderunfocused, tag:horizonrdp"
"idleinhibit, tag:horizonrdp"
"float, tag:horizonrdp"
# float the vmware window cause its annoying to use in fullscreen
"match:class .*[Hh]orizon-client),match:title [Oo]mnissa [Hh]orizon [Cc]lient, float 1"
"float, class:(.*[Hh]orizon-client),title:([Oo]mnissa [Hh]orizon [Cc]lient)"
"tag +waydroid, class:([Ww]aydroid.*)"
"float, tag:waydroid"
"pin, tag:waydroid"
]
++ cfg.windowRule;
@@ -682,12 +696,12 @@ in
sensitivity = 0; # -1.0 - 1.0, 0 means no modification.
};
# experimental = {
# xx_color_management_v4 = true;
# };
experimental = {
xx_color_management_v4 = true;
};
debug = {
# full_cm_proto = cfg.debug.fullCmProto;
full_cm_proto = cfg.debug.fullCmProto;
disable_logs = cfg.debug.disableLogs;
disable_scale_checks = cfg.debug.disableScaleChecks;
};

View File

@@ -1,11 +1,7 @@
{
lib,
namespace,
...
}:
{ lib, pkgs, ... }:
with lib;
{
options.${namespace}.programs.hyprland = {
options.mjallen.programs.hyprland = {
enable = mkEnableOption "enable hyprland";
primaryDisplay = mkOption {
@@ -152,12 +148,55 @@ with lib;
extraConfig = mkOption {
type = with types; str;
default = "";
default = '''';
description = "Any extra configuration options";
};
defaultApps = mkOption {
type = types.submodule (import ../common/default-apps.nix);
type = types.submodule {
options = {
browser = mkOption {
type = types.package;
default = pkgs.firefox;
description = "Default browser";
};
editor = mkOption {
type = types.package;
default = pkgs.micro;
description = "Default text editor";
};
fileExplorer = mkOption {
type = types.package;
default = pkgs.nautilus;
description = "Default file explorer";
};
visual = mkOption {
type = types.package;
default = pkgs.vscodium;
description = "Default visual editor";
};
terminal = mkOption {
type = types.package;
default = pkgs.kitty;
description = "Default terminal";
};
office = mkOption {
type = types.package;
default = pkgs.onlyoffice-desktopeditors;
description = "Default office suite";
};
video = mkOption {
type = types.package;
default = pkgs.vlc;
description = "Default video player";
};
imageViewer = mkOption {
type = types.package;
default = pkgs.nomacs;
description = "Default image viewer";
};
};
};
description = "Default applications used across the system";
};
@@ -165,7 +204,7 @@ with lib;
type = with types; listOf str;
default = [
"nwg-look -a"
"nwg-dock-hyprland -x"
"nwg-dock-hyprland -d"
];
description = "Commands to run via Hyprland exec-once";
};

View File

@@ -1,30 +1,25 @@
{ lib, config, ... }:
with lib;
let
cfg = config.mjallen.programs.kitty;
in
{
config,
lib,
namespace,
...
}:
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "kitty";
moduleConfig = {
programs.kitty = {
enable = true;
shellIntegration.enableZshIntegration = true;
settings = {
bold_font = "auto";
italic_font = "auto";
bold_italic_font = "auto";
mouse_hide_wait = "2.0";
cursor_shape = "block";
url_style = "dotted";
confirm_os_window_close = "0";
};
};
imports = [ ./options.nix ];
config = mkIf cfg.enable {
programs.kitty = {
enable = true;
shellIntegration.enableZshIntegration = true;
settings = {
bold_font = "auto";
italic_font = "auto";
bold_italic_font = "auto";
mouse_hide_wait = "2.0";
cursor_shape = "block";
url_style = "dotted";
confirm_os_window_close = "0";
};
})
];
};
};
}

View File

@@ -0,0 +1,10 @@
{ lib, namespace, ... }:
with lib;
let
inherit (lib.${namespace}) mkOpt;
in
{
options.mjallen.programs.kitty = {
enable = mkEnableOption "enable kitty terminal";
};
}

View File

@@ -1,40 +1,31 @@
{ config, lib, ... }:
with lib;
let
cfg = config.mjallen.programs.mako;
in
{
config,
lib,
namespace,
...
}:
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "mako";
options = {
fontName = lib.mkOption {
type = lib.types.str;
default = "DejaVu Sans";
description = "Font name for mako notifications.";
};
imports = [ ./options.nix ];
config = mkIf cfg.enable {
services.mako = {
enable = true;
settings = {
font = mkDefault cfg.fontName;
icons = true;
ignore-timeout = true;
sort = "-time";
width = 500;
height = 110;
layer = "overlay";
border-radius = 15;
border-size = 1;
max-icon-size = 64;
default-timeout = 5000;
# background-color = mkDefault config.lib.stylix.colors.base00;
# text-color = mkDefault config.lib.stylix.colors.base06;
# border-color = mkDefault config.lib.stylix.colors.base0F;
# progress-color = mkDefault "over ${config.lib.stylix.colors.base0C}";
};
moduleConfig = {
services.mako = {
enable = true;
settings = {
font = lib.mkDefault config.${namespace}.programs.mako.fontName;
icons = true;
ignore-timeout = true;
sort = "-time";
width = 500;
height = 110;
layer = "overlay";
border-radius = 15;
border-size = 1;
max-icon-size = 64;
default-timeout = 5000;
};
};
};
})
];
};
};
}

View File

@@ -0,0 +1,12 @@
{ lib, ... }:
with lib;
{
options.mjallen.programs.mako = {
enable = mkEnableOption "enable mako";
fontName = mkOption {
type = types.str;
default = "DejaVu Sans";
};
};
}

View File

@@ -2,134 +2,64 @@
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.nwg-dock;
palette = import cfg.theme.file;
in
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "nwg-dock";
moduleConfig = {
home.packages = with pkgs; [ nwg-dock-hyprland ];
imports = [ ./options.nix ];
home.file = {
".config/nwg-dock-hyprland/config.json".text = ''
{
"position": "bottom",
"anchor": "center",
"margin": 12,
"icon_size": 48,
"icon_size_hover": 64,
"spacing": 6,
"padding": 8,
"autohide": false,
"autohide_timeout": 0.3,
"exclusive": true,
"layer": "top",
"height": 72,
"background_alpha": 0.55,
"rounded_corners": 16,
"show_labels": false,
"show_running": true,
"show_pinned": true,
"pinned": [
"firefox.desktop",
"org.wezfurlong.wezterm.desktop",
"codium.desktop",
"org.gnome.Nautilus.desktop"
]
}
'';
config = mkIf cfg.enable {
home.packages = with pkgs; [ nwg-dock-hyprland ];
".config/nwg-dock-hyprland/style.css".text = ''
window {
background: #36364f;
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: rgba(156, 142, 122, 0.7)
}
home.file = {
".config/nwg-dock-hyprland/drawer.css".text = ''
window {
background: ${config.lib.stylix.colors.base00};
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: ${config.lib.stylix.colors.base0E}b0
}
#box {
padding: 10px
}
#box {
/* Define attributes of the box surrounding icons here */
padding: 10px
}
#active {
border-bottom: solid 1px;
border-color: rgba(255, 255, 255, 0.3)
}
active {
/* This is to underline the button representing the currently active window */
border-bottom: solid 1px;
border-color: ${config.lib.stylix.colors.base0B}1a
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: #999
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: ${config.lib.stylix.colors.base0F}
}
button {
padding: 4px;
margin-left: 4px;
margin-right: 4px;
color: #eee;
font-size: 12px
}
button {
padding: 4px;
margin-left: 4px;
margin-right: 4px;
color: #eee;
font-size: 12px
}
button:hover {
background-color: rgba(255, 255, 255, 0.15);
border-radius: 2px;
}
button:hover {
background-color: ${config.lib.stylix.colors.base00}1a;
border-radius: 2px;
}
button:focus {
box-shadow: none
}
'';
".config/nwg-dock-hyprland/drawer.css".text = ''
window {
background: ${config.lib.stylix.colors.base00};
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: ${config.lib.stylix.colors.base0E}b0
}
#box {
padding: 10px
}
active {
border-bottom: solid 1px;
border-color: ${config.lib.stylix.colors.base0B}1a
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: ${config.lib.stylix.colors.base0F}
}
button {
padding: 4px;
margin-left: 4px;
margin-right: 4px;
color: #eee;
font-size: 12px
}
button:hover {
background-color: ${config.lib.stylix.colors.base00}1a;
border-radius: 2px;
}
button:focus {
box-shadow: none
}
'';
};
};
})
];
button:focus {
box-shadow: none
}
'';
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
with lib;
{
options.mjallen.programs.nwg-dock = {
enable = mkEnableOption "enable nwg-dock";
};
}

View File

@@ -2,53 +2,56 @@
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.nwg-drawer;
palette = import cfg.theme.file;
in
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "nwg-drawer";
moduleConfig = {
home.packages = with pkgs; [ nwg-drawer ];
imports = [ ./options.nix ];
home.file.".config/nwg-drawer/drawer.css".text = ''
window {
background-color: ${config.lib.stylix.colors.base00}bf;
color: ${config.lib.stylix.colors.base05}00
}
config = mkIf cfg.enable {
home.packages = with pkgs; [ nwg-drawer ];
entry {
background-color: ${config.lib.stylix.colors.base01}0f
}
home.file = {
".config/nwg-drawer/drawer.css".text = ''
window {
background-color: ${config.lib.stylix.colors.base00}bf;
color: ${config.lib.stylix.colors.base05}00
}
button, image {
background: none;
border: none
}
/* search entry */
entry {
background-color: ${config.lib.stylix.colors.base01}0f
}
button:hover {
background-color: ${config.lib.stylix.colors.base0F}1a
}
button, image {
background: none;
border: none
}
#category-button {
margin: 0 10px 0 10px
}
button:hover {
background-color: ${config.lib.stylix.colors.base0F}1a
}
#pinned-box {
padding-bottom: 5px;
border-bottom: 1px dotted ${config.lib.stylix.colors.base03}
}
/* in case you wanted to give category buttons a different look */
#category-button {
margin: 0 10px 0 10px
}
#files-box {
padding: 5px;
border: 1px dotted ${config.lib.stylix.colors.base03};
border-radius: 15px
}
'';
};
})
];
#pinned-box {
padding-bottom: 5px;
border-bottom: 1px dotted ${config.lib.stylix.colors.base03}
}
#files-box {
padding: 5px;
border: 1px dotted ${config.lib.stylix.colors.base03};
border-radius: 15px
}
'';
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
with lib;
{
options.mjallen.programs.nwg-drawer = {
enable = mkEnableOption "enable nwg-drawer";
};
}

View File

@@ -1,12 +1,7 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.nwg-panel;
cfg = config.mjallen.programs.nwg-panel;
in
{
imports = [ ./options.nix ];

View File

@@ -1,14 +1,46 @@
{ lib, pkgs, ... }:
with lib;
{
lib,
namespace,
...
}:
{
options.${namespace}.programs.nwg-panel = {
enable = lib.mkEnableOption "nwg-panel";
options.mjallen.programs.nwg-panel = {
enable = mkEnableOption "enable nwg-panel";
defaultApps = lib.mkOption {
type = lib.types.submodule (import ../common/default-apps.nix);
defaultApps = mkOption {
type = types.submodule {
options = {
browser = mkOption {
type = types.package;
default = pkgs.firefox;
};
editor = mkOption {
type = types.package;
default = pkgs.micro;
};
fileExplorer = mkOption {
type = types.package;
default = pkgs.nautilus;
};
visual = mkOption {
type = types.package;
default = pkgs.vscodium;
};
terminal = mkOption {
type = types.package;
default = pkgs.kitty;
};
office = mkOption {
type = types.package;
default = pkgs.onlyoffice-desktopeditors;
};
video = mkOption {
type = types.package;
default = pkgs.vlc;
};
imageViewer = mkOption {
type = types.package;
default = pkgs.gnome-photos;
};
};
};
description = "Default applications used across the system.";
};
};

View File

@@ -5,7 +5,7 @@
...
}:
let
isArm = "aarch64-linux" == system;
isArm = builtins.match "aarch64*" system != null;
in
{
programs.onlyoffice = {

View File

@@ -1,87 +0,0 @@
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.programs.opencode;
in
{
options.${namespace}.programs.opencode = {
enable = lib.mkEnableOption "opencode";
};
config = lib.mkIf cfg.enable {
sops.secrets."hass-mcp/token" = { };
sops.templates."hass-mcp.env" = {
mode = "0600";
content = ''
HA_URL=http://nuc-nixos.local:8123
HA_TOKEN=${config.sops.placeholder."hass-mcp/token"}
'';
};
programs.opencode = {
enable = true;
enableMcpIntegration = true;
settings = {
provider = {
nas = {
npm = "@ai-sdk/openai-compatible";
name = "llama-server (local)";
options = {
baseURL = "http://jallen-nas.local:8127/v1";
};
models = {
Qwen3-Coder-Next-Q4_0 = {
name = "Qwen3 Coder (local)";
modalities = {
input = [
"image"
"text"
];
output = [ "text" ];
};
limit = {
context = 262144;
output = 262144;
};
};
};
};
};
};
};
programs.mcp = {
enable = true;
servers = {
nixos = {
command = "nix";
args = [
"run"
"github:utensils/mcp-nixos"
"--"
];
};
hass-mcp = {
command = "bash";
args = [
"-c"
"set -a; source ${config.sops.templates."hass-mcp.env".path}; set +a; exec uvx hass-mcp"
];
};
mcp-server-code-runner = {
command = "${pkgs.nodejs_24}/bin/npm";
args = [
"-y"
"@iflow-mcp/mcp-server-code-runner"
];
};
};
};
};
}

View File

@@ -1,290 +0,0 @@
{
config,
namespace,
pkgs,
...
}:
let
git-token = config.sops.secrets."github-token".path;
update-checker = pkgs.writeScriptBin "update-checker" ''
#!/usr/bin/env nix-shell
#! nix-shell -i python3 --pure
#! nix-shell -p python3 python3Packages.pygithub python3Packages.feedparser python3Packages.requests nix-prefetch-scripts nix
import os
import json
import subprocess
from github import Github
from github import Auth
import feedparser
import requests
token = None
with open('${git-token}', 'r') as token_file:
token = token_file.readline()
auth = Auth.Token(token)
def check_github(owner, repo, version):
try:
release = None
result = None
prefetch = None
ghub = Github(auth=auth)
print(' getting repo ' + owner + '/' + repo)
repo = ghub.get_repo(owner + '/' + repo)
if '-b' in version:
release = repo.get_releases()[0]
latest_version = release.name
else:
try:
release = repo.get_latest_release()
latest_version = release.tag_name
except:
tags = repo.get_tags()
try:
if tags is not None:
latest_version = tags[0].name
except:
commits = repo.get_commits()
latest_version = commits[0].sha
if latest_version is not None:
if latest_version.replace('v',''\'') != version.replace('v',''\''):
print(' update found')
print(' Current version: ' + version)
print(' Latest version: ' + latest_version)
result = subprocess.check_output(['nix-prefetch-git', '--quiet', repo.clone_url, '--rev', latest_version])
prefetch = json.loads(result)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
ghub.close()
except Exception as e:
print(e)
def check_codeberg(owner, repo, version):
feed = feedparser.parse('https://codeberg.org/{0}/{1}/releases.rss'.format(owner, repo))
if feed.status == 200:
entry = feed.entries[0]
if entry.title.replace('v',''\'') != version.replace('v',''\''):
print(' update found')
print(' Current version: ' + version)
print(' Latest version: ' + entry.title)
sha256 = subprocess.check_output(['nix-prefetch-url', url.replace(''\'''\${version}', entry.title.replace('v', ''\''))])
prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())])
print(' New hash: ' + prefetch.decode('utf-8').strip())
else:
print(' no update')
def check_open_vsx(publisher, name, version):
open_vsx = requests.get('https://open-vsx.org/api/' + publisher + '/' + name)
if open_vsx.status_code == 200:
extension = open_vsx.json()
latest_version = extension.get('version')
url = extension.get('files').get('download')
if latest_version.replace('v',''\'') != version.replace('v',''\''):
print(' update found')
print(' Current version: ' + version)
print(' Latest version: ' + latest_version)
sha256 = subprocess.check_output(['nix-prefetch-url', url])
prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())])
print(' New hash: ' + prefetch.decode('utf-8').strip())
else:
print(' no update')
def parse_nix(package_spec):
version = None
url = None
current_hash = None
owner = None
repo = None
pname = None
name = None
publisher = None
for line in package_spec.readlines():
if 'owner = "' in line and owner is None:
owner = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'repo = "' in line and repo is None:
repo = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'version = "' in line and version is None:
version = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'rev = "' in line and ''\'''\${version}' not in line:
version = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'url = "' in line and url is None:
url = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'sha256 = "' in line or ' hash = "' in line and current_hash is None:
current_hash = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'pname = "' in line and pname is None:
pname = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if ' name = "' in line and name is None:
name = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'publisher = "' in line and publisher is None:
publisher = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if url is None and repo is not None:
if 'pname' in repo:
repo = repo.replace(''\'''\${pname}', pname)
url = 'https://github.com/{0}/{1}/releases/tag/{2}'.format(owner, repo, version)
if url is not None and repo is None and 'github' in url:
owner = url.split('github.com/')[-1].split('/')[0]
repo = url.split('github.com/')[-1].split('/')[1]
if url is not None and repo is None and 'codeberg' in url:
owner = url.split('codeberg.org/')[-1].split('/')[0]
repo = url.split('codeberg.org/')[-1].split('/')[1]
if url is not None and version is None:
version = url.split('/')[-1].replace('.tar.gz', ''\'')
if url is not None and publisher is not None:
url = url.replace(''\'''\${publisher}', publisher).replace(''\'''\${name}', name)
return url, current_hash, owner, repo, pname, name, publisher, version
def parse_json(json_versions, flavor=''\''):
versions = json.load(json_versions)
linux_versions = versions.get('linux')
config_versions = versions.get('config')
patch_versions = versions.get('patches')
zfs_versions = versions.get('zfs')
check_kernel(linux_versions, flavor)
check_cachy_config(config_versions, flavor)
check_patch_versions(patch_versions, flavor)
check_zfs_versions(zfs_versions, flavor)
def check_kernel(linux_versions, flavor=''\''):
srcinfo = requests.get('https://raw.githubusercontent.com/CachyOS/linux-cachyos/master/linux-cachyos' + flavor + '/.SRCINFO')
for line in srcinfo.text.split('\n'):
if 'pkgver = ' in line:
kernel_version = line.split('=')[-1].strip()
if kernel_version[-2:] == '.0':
kernel_version = kernel_version[:-2]
if flavor in [''\'', '-lts', '-server', '-gcc', '-hardened']:
release_src = 'https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-' + kernel_version + '.tar.xz'
if flavor == '-rc':
release_src = 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/snapshot/linux-' + kernel_version.replace('.rc', '-rc') + '.tar.gz'
sha256 = subprocess.check_output(['nix-prefetch-url', release_src])
prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())])
current_version = linux_versions.get('version')
current_hash = linux_versions.get('hash')
latest_hash = prefetch.decode('utf-8').strip()
print(' Checking linux versions...')
if current_hash != latest_hash:
print(' Current rev: ' + current_version)
print(' Current hash: ' + current_hash)
print(' New rev: ' + kernel_version)
print(' New hash: ' + latest_hash)
else:
print(' no update')
def check_cachy_config(config_versions, flavor=''\''):
result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/linux-cachyos.git'])
prefetch = json.loads(result)
current_version = config_versions.get('rev')
latest_version = prefetch.get('rev')
print(' Checking config versions...')
if current_version != latest_version:
print(' Current rev: ' + current_version)
print(' New rev: ' + latest_version)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
def check_patch_versions(patch_versions, flavor=''\''):
result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/kernel-patches.git'])
prefetch = json.loads(result)
current_version = patch_versions.get('rev')
latest_version = prefetch.get('rev')
print(' Checking patch versions...')
if current_version != latest_version:
print(' Current rev: ' + current_version)
print(' New rev: ' + latest_version)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
def kconfig_to_nix(flavor=''\''):
kconfig_result = subprocess.check_output(['nix', 'build', '.#nixosConfigurations.jallen-nas.pkgs.linuxPackages_cachyos' + flavor + '.kernel.kconfigToNix', '--no-link', '--print-out-paths'])
config_file = kconfig_result.decode('utf-8').strip()
if flavor == ''\'':
cachy_flavor = '-gcc'
result = subprocess.check_output(['cat', config_file])
with open('/etc/nixos/packages/linux-cachyos/config-nix/cachyos' + cachy_flavor + '.x86_64-linux.nix', 'w') as config:
config.write(result.decode('utf-8').strip())
def check_zfs_versions(zfs_versions, flavor=''\''):
result = requests.get('https://raw.githubusercontent.com/CachyOS/linux-cachyos/master/linux-cachyos' + flavor + '/PKGBUILD')
for line in result.text.split('\n'):
if 'git+https://github.com/cachyos/zfs.git#commit=' in line:
zfs_rev = line.split('zfs.git#commit=')[-1].replace('")', ''\'')
result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/zfs.git', '--rev', zfs_rev])
prefetch = json.loads(result)
current_version = zfs_versions.get('rev')
latest_version = prefetch.get('rev')
print(' Checking zfs versions...')
if current_version != latest_version:
print(' Current rev: ' + current_version)
print(' New rev: ' + latest_version)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
for (root,dirs,files) in os.walk('/etc/nixos/packages',topdown=True):
if 'default.nix' in files and 'versions.json' not in files:
print(root.split('/')[-1])
with open(root + '/default.nix', 'r') as package_spec:
url, current_hash, owner, repo, pname, name, publisher, version = parse_nix(package_spec)
if owner is not None and repo is not None and 'codeberg' in url:
check_codeberg(owner, repo, version)
elif owner is not None and repo is not None and 'github' in url:
check_github(owner, repo, version)
elif publisher is not None and 'open-vsx' in url:
check_open_vsx(publisher, name, version)
else:
if url is not None:
print(url)
if 'default.nix' in files and 'versions.json' in files:
with open(root + '/versions.json', 'r') as json_versions:
print('Checking Linux CachyOS')
parse_json(json_versions)
with open(root + '/versions-rc.json', 'r') as json_versions:
print('Checking Linux CachyOS RC')
parse_json(json_versions, '-rc')
with open(root + '/versions-lts.json', 'r') as json_versions:
print('Checking Linux CachyOS LTS')
parse_json(json_versions, '-lts')
with open(root + '/versions-hardened.json', 'r') as json_versions:
print('Checking Linux CachyOS Hardened')
parse_json(json_versions, '-hardened')
'';
in
{
config = {
sops = {
age.keyFile = "/home/${config.${namespace}.user.name}/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"github-token" = { };
};
templates = {
".env".content = ''
GITHUB_TOKEN = "${config.sops.placeholder.github-token}"
'';
};
};
home.packages = [ update-checker ];
};
}

View File

@@ -1,12 +1,7 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.waybar;
cfg = config.mjallen.programs.waybar;
baseStyle =
if cfg.style.file != null then
@@ -388,15 +383,15 @@ in
"custom/power" = {
format = " ";
tooltip = false;
tooltip = false;
menu = "on-click";
menu-file = "~/.config/waybar/power_menu.xml";
menu-actions = {
shutdown = "shutdown";
reboot = "reboot";
suspend = "systemctl suspend";
hibernate = "systemctl hibernate";
lock = "pidof hyprlock || hyprlock";
shutdown = "shutdown";
reboot = "reboot";
suspend = "systemctl suspend";
hibernate = "systemctl hibernate";
lock = "pidof hyprlock || hyprlock";
};
};
}

View File

@@ -1,4 +1,4 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
let
inherit (types)
@@ -13,7 +13,7 @@ let
;
in
{
options.${namespace}.programs.waybar = {
options.mjallen.programs.waybar = {
enable = mkEnableOption "Waybar status bar";
# Legacy/compat options (kept for backwards compatibility)

View File

@@ -6,13 +6,11 @@
...
}:
let
cfg = config.${namespace}.programs.waybar;
cfg = config.mjallen.programs.waybar;
pythonEnv = pkgs.python3.withPackages (
_ps: with pkgs.${namespace}; [
homeassistant-api
]
);
pythonEnv = pkgs.python3.withPackages (_ps: [
pkgs.${namespace}.homeassistant-api
]);
waybar-hass = pkgs.writeScriptBin "waybar-hass" ''
#!${pythonEnv}/bin/python

View File

@@ -2,11 +2,10 @@
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.programs.waybar;
cfg = config.mjallen.programs.waybar;
waybar-weather = pkgs.writeScriptBin "waybar-weather" ''
#!/usr/bin/env nix-shell

View File

@@ -1,93 +1,104 @@
{ config, lib, ... }:
with lib;
let
cfg = config.mjallen.programs.wlogout;
palette = import cfg.theme.file;
in
{
config,
lib,
namespace,
...
}:
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "wlogout";
moduleConfig = {
programs.wlogout = {
enable = false;
layout = {
lock = {
label = "lock";
action = "hyprlock --immediate";
text = "Lock";
keybind = "l";
};
hibernate = {
label = "hibernate";
action = "systemctl hibernate";
text = "Hibernate";
keybind = "h";
};
logout = {
label = "logout";
action = "sleep 1; hyprctl dispatch exit";
text = "Logout";
keybind = "e";
};
shutdown = {
label = "shutdown";
action = "systemctl poweroff";
text = "Shutdown";
keybind = "s";
};
suspend = {
label = "suspend";
action = "systemctl suspend";
text = "Suspend";
keybind = "u";
};
reboot = {
label = "reboot";
action = "reboot";
text = "Reboot";
keybind = "r";
};
};
style = ''
* {
background-image: none;
}
window {
background-color: ${config.lib.stylix.colors.base00}f0
}
button {
margin: 8px;
color: ${config.lib.stylix.colors.base0C};
background-color: ${config.lib.stylix.colors.base01};
border-style: solid;
border-width: 2px;
background-repeat: no-repeat;
background-position: center;
background-size: 25%;
}
button:active,
button:focus,
button:hover {
color: ${config.lib.stylix.colors.base0C};
background-color: ${config.lib.stylix.colors.base02Alt};
outline-style: none;
}
#lock { background-image: image(url("icons/lock.png")); }
#logout { background-image: image(url("icons/logout.png")); }
#suspend { background-image: image(url("icons/suspend.png")); }
#hibernate { background-image: image(url("icons/hibernate.png")); }
#shutdown { background-image: image(url("icons/shutdown.png")); }
#reboot { background-image: image(url("icons/reboot.png")); }
'';
imports = [ ./options.nix ];
config = mkIf cfg.enable {
programs.wlogout = {
enable = false;
layout = {
lock = {
label = "lock";
action = "hyprlock --immediate";
text = "Lock";
keybind = "l";
};
hibernate = {
label = "hibernate";
action = "systemctl hibernate";
text = "Hibernate";
keybind = "h";
};
logout = {
label = "logout";
action = "sleep 1; hyprctl dispatch exit";
text = "Logout";
keybind = "e";
};
shutdown = {
label = "shutdown";
action = "systemctl poweroff";
text = "Shutdown";
keybind = "s";
};
suspend = {
label = "suspend";
action = "systemctl suspend";
text = "Suspend";
keybind = "u";
};
reboot = {
label = "reboot";
action = "reboot";
text = "Reboot";
keybind = "r";
};
};
})
];
style = ''
* {
background-image: none;
}
window {
background-color: ${config.lib.stylix.colors.base00}f0
}
button {
margin: 8px;
color: ${config.lib.stylix.colors.base0C};
background-color: ${config.lib.stylix.colors.base01};
border-style: solid;
border-width: 2px;
background-repeat: no-repeat;
background-position: center;
background-size: 25%;
}
button:active,
button:focus,
button:hover {
color: ${config.lib.stylix.colors.base0C};
background-color: ${config.lib.stylix.colors.base02Alt};
outline-style: none;
}
#lock {
background-image: image(url("icons/lock.png"));
}
#logout {
background-image: image(url("icons/logout.png"));
}
#suspend {
background-image: image(url("icons/suspend.png"));
}
#hibernate {
background-image: image(url("icons/hibernate.png"));
}
#shutdown {
background-image: image(url("icons/shutdown.png"));
}
#reboot {
background-image: image(url("icons/reboot.png"));
}
'';
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
with lib;
{
options.mjallen.programs.wlogout = {
enable = mkEnableOption "enable wlogout";
};
}

View File

@@ -1,107 +1,102 @@
{ config, lib, ... }:
with lib;
let
cfg = config.mjallen.programs.wofi;
palette = import cfg.theme.file;
in
{
config,
lib,
namespace,
...
}:
{
imports = [
(lib.${namespace}.mkHomeModule {
inherit config;
domain = "programs";
name = "wofi";
options = {
fontName = lib.mkOption {
type = lib.types.str;
default = "DejaVu Sans";
description = "Font name for wofi.";
};
};
moduleConfig = {
programs.wofi = {
enable = true;
style = ''
* {
font-family: "${config.${namespace}.programs.wofi.fontName}", monospace;
font-size: 14px;
}
imports = [ ./options.nix ];
window {
margin: 0px;
padding: 10px;
border: 0.16em solid ${config.lib.stylix.colors.base0E};
border-radius: 0.1em;
background-color: ${config.lib.stylix.colors.base00};
}
config = mkIf cfg.enable {
programs.wofi = {
enable = true;
style = ''
* {
font-family: "${cfg.fontName}", monospace;
font-size: 14px;
}
#inner-box {
margin: 5px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
}
/* Window */
window {
margin: 0px;
padding: 10px;
border: 0.16em solid ${config.lib.stylix.colors.base0E};
border-radius: 0.1em;
background-color: ${config.lib.stylix.colors.base00};
}
#outer-box {
margin: 5px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
}
/* Inner Box */
#inner-box {
margin: 5px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
}
#scroll {
margin: 0px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
}
/* Outer Box */
#outer-box {
margin: 5px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
}
#input {
margin: 5px 20px;
padding: 10px;
border: none;
border-radius: 0.1em;
color: ${config.lib.stylix.colors.base06};
background-color: ${config.lib.stylix.colors.base00};
}
/* Scroll */
#scroll {
margin: 0px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
}
#input image {
border: none;
color: ${config.lib.stylix.colors.base08};
}
/* Input */
#input {
margin: 5px 20px;
padding: 10px;
border: none;
border-radius: 0.1em;
color: ${config.lib.stylix.colors.base06};
background-color: ${config.lib.stylix.colors.base00};
}
#input * {
outline: 4px solid ${config.lib.stylix.colors.base08}!important;
}
#input image {
border: none;
color: ${config.lib.stylix.colors.base08};
}
#text {
margin: 5px;
border: none;
color: ${config.lib.stylix.colors.base06};
}
#input * {
outline: 4px solid ${config.lib.stylix.colors.base08}!important;
}
#entry {
background-color: ${config.lib.stylix.colors.base00};
}
/* Text */
#text {
margin: 5px;
border: none;
color: ${config.lib.stylix.colors.base06};
}
#entry arrow {
border: none;
color: ${config.lib.stylix.colors.base0E};
}
#entry {
background-color: ${config.lib.stylix.colors.base00};
}
#entry:selected {
border: 0.11em solid ${config.lib.stylix.colors.base0E};
}
#entry arrow {
border: none;
color: ${config.lib.stylix.colors.base0E};
}
#entry:selected #text {
color: ${config.lib.stylix.colors.base0C};
}
/* Selected Entry */
#entry:selected {
border: 0.11em solid ${config.lib.stylix.colors.base0E};
}
#entry:drop(active) {
background-color: ${config.lib.stylix.colors.base0E}!important;
}
'';
};
};
})
];
#entry:selected #text {
color: ${config.lib.stylix.colors.base0C};
}
#entry:drop(active) {
background-color: ${config.lib.stylix.colors.base0E}!important;
}
'';
};
};
}

View File

@@ -0,0 +1,12 @@
{ lib, ... }:
with lib;
{
options.mjallen.programs.wofi = {
enable = mkEnableOption "enable wofi";
fontName = mkOption {
type = types.str;
default = "Deja Vu Sans";
};
};
}

View File

@@ -1,4 +1,8 @@
{
config,
lib,
pkgs,
namespace,
...
}:
{

View File

@@ -1,14 +1,13 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.shell-aliases;
cfg = config.mjallen.shell-aliases;
in
{
options.${namespace}.shell-aliases = {
options.mjallen.shell-aliases = {
enable = lib.mkEnableOption "Common shell aliases";
buildHost = lib.mkOption {

View File

@@ -1,28 +1,29 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.sops;
cfg = config.mjallen.sops;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
sops = {
age.keyFile = "/home/${config.${namespace}.user.name}/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
# secrets = {
# "github-token" = { };
# };
# templates = {
# ".env".content = ''
# GITHUB_TOKEN = "${config.sops.placeholder.github-token}"
# '';
# };
};
# sops = {
# age.keyFile = "/home/${user}/.config/sops/age/keys.txt";
# defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
# validateSopsFiles = false;
# secrets = {
# "ssh-keys-public/desktop-nixos" = {
# path = "/home/${user}/.ssh/id_ed25519.pub";
# mode = "0644";
# };
# "ssh-keys-private/desktop-nixos" = {
# path = "/home/${user}/.ssh/id_ed25519";
# mode = "0600";
# };
# };
# };
};
}

View File

@@ -1,13 +1,12 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.sops = {
options.mjallen.sops = {
enable = mkEnableOption "enable sops";
defaultSopsFile = mkOption {
type = types.nullOr types.path;
type = types.str;
default = null;
description = "Path to the default sops secrets file.";
};
};
}

View File

@@ -1,9 +1,4 @@
{
config,
pkgs,
system,
...
}:
{ config, pkgs, ... }:
let
# # Pull from global theme options
# themeSize = "standard"; # "standard" | "compact"
@@ -28,15 +23,12 @@ let
# schemeVariants = [ iconScheme ];
# colorVariants = [ iconThemeVariant ];
# };
isDarwin = system == "aarch64-darwin";
in
{
stylix = {
enable = true;
overlays.enable = false;
enableReleaseChecks = false;
base16Scheme = "${pkgs.base16-schemes}/share/themes/nord.yaml";
polarity = "dark";
cursor = {
name = "macOS";
@@ -66,8 +58,8 @@ in
};
sizes = {
applications = if isDarwin then 10 else 12;
desktop = if isDarwin then 12 else 14;
applications = 12;
desktop = 14;
popups = config.stylix.fonts.sizes.desktop;
terminal = config.stylix.fonts.sizes.applications;
};
@@ -75,12 +67,9 @@ in
icons = {
enable = true;
package = pkgs.colloid-icon-theme.override {
schemeVariants = [ "nord" ];
colorVariants = [ "default" ];
};
dark = "Colloid-Nord-Dark";
light = "Colloid-Nord-Light";
package = pkgs.colloid-icon-theme;
dark = "Colloid-nord-dark";
light = "Colloid-nord-light";
};
opacity = {
@@ -88,18 +77,10 @@ in
};
targets = {
hyprlock = {
enable = false;
useWallpaper = false;
};
kde.enable = false;
firefox = {
enable = false;
profileNames = [
"default"
"954lxlok.default"
];
};
hyprlock.enable = false;
gnome.enable = false;
# gtk.enable = false;
qt.enable = false;
};
};
}
}

View File

@@ -31,7 +31,7 @@ in
};
fullName = mkOption {
type = types.str;
default = "Matt Jallen";
default = "Austin Horstman";
description = "The full name of the user.";
};
home = mkOption {
@@ -41,8 +41,8 @@ in
};
icon = mkOption {
type = (types.nullOr types.package);
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).";
default = pkgs.${namespace}.user-icon;
description = "The profile picture to use for the user.";
};
name = mkOption {
type = (types.nullOr types.str);
@@ -115,8 +115,8 @@ in
tarnow = "${getExe pkgs.gnutar} -acf ";
untar = "${getExe pkgs.gnutar} -zxvf ";
wget = "${getExe pkgs.wget} -c ";
remove-empty = "${getExe' pkgs.findutils "find"} . -type d --empty --delete";
print-empty = "${getExe' pkgs.findutils "find"} . -type d --empty --print";
remove-empty = ''${getExe' pkgs.findutils "find"} . -type d --empty --delete'';
print-empty = ''${getExe' pkgs.findutils "find"} . -type d --empty --print'';
dfh = "${getExe' pkgs.coreutils "df"} -h";
duh = "${getExe' pkgs.coreutils "du"} -h";
usage = "${getExe' pkgs.coreutils "du"} -ah -d1 | sort -rn 2>/dev/null";
@@ -145,7 +145,7 @@ in
myip = "${getExe pkgs.curl} ifconfig.me";
# Cryptography
genpass = "${getExe pkgs.openssl} rand -base64 20"; # Generate a random, 20-character password
genpass = "${getExe pkgs.openssl} rand - base64 20"; # Generate a random, 20-character password
sha = "shasum -a 256"; # Test checksum
};

View File

@@ -22,26 +22,8 @@ in
};
config = mkIf cfg.enable {
assertions = [
{
assertion = !cfg.yubikeyEncryption || config.${namespace}.hardware.disko.enableLuks;
message = "mjallen.boot.common.yubikeyEncryption requires mjallen.hardware.disko.enableLuks = true.";
}
{
assertion = !cfg.yubikeyEncryption || config.${namespace}.hardware.disko.enable;
message = "mjallen.boot.common.yubikeyEncryption requires mjallen.hardware.disko.enable = true (disko-managed disk layout).";
}
];
boot = {
kernelModules = [ "kvm" ];
kernelParams = lib.mkDefault [
"quiet"
"splash"
"udev.log_level=3"
];
binfmt = lib.mkIf isArm {
registrations."x86_64-linux" = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
@@ -54,30 +36,12 @@ in
};
};
supportedFilesystems = {
bcachefs = lib.mkOverride 90 true;
btrfs = lib.mkOverride 90 true;
};
supportedFilesystems = [ "bcachefs" ];
bcachefs.package = lib.mkOverride 90 pkgs.${namespace}.bcachefs;
consoleLogLevel = lib.mkDefault 0;
consoleLogLevel = lib.mkForce 3;
bootspec.enable = (!isArm);
initrd = {
verbose = lib.mkDefault false;
# availableKernelModules = {
# bcachefs = lib.mkOverride 90 true;
# btrfs = lib.mkOverride 90 true;
# };
# kernelModules = {
# bcachefs = lib.mkOverride 90 true;
# btrfs = lib.mkOverride 90 true;
# };
# systemd.storePaths = with pkgs; [
# bcachefs-tools
# ];
luks = mkIf cfg.yubikeyEncryption {
devices = {
"${config.disko.devices.disk.main.content.partitions.root.name}" = {
@@ -89,7 +53,7 @@ in
};
slot = 2;
twoFactor = false;
gracePeriod = cfg.yubikeyGracePeriod;
gracePeriod = yubikeyGracePeriod;
};
};
};

View File

@@ -17,13 +17,6 @@ in
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.configLimit > 0;
message = "mjallen.bootloader.lanzaboote.configLimit must be a positive integer (got ${toString cfg.configLimit}).";
}
];
boot = {
loader = {
efi = {

View File

@@ -6,52 +6,31 @@
...
}:
let
inherit (lib.${namespace}) enabled disabled;
cfg = config.${namespace}.desktop.gnome;
in
{
options.${namespace}.desktop.gnome = {
enable = lib.mkEnableOption "GNOME desktop environment";
};
imports = [ ../../../home/desktop/gnome/options.nix ];
config = lib.mkIf cfg.enable {
services = {
desktopManager.gnome = enabled;
displayManager.gdm = {
enable = lib.mkDefault true;
wayland = lib.mkDefault true;
# Enable Desktop Environment.
desktopManager.gnome.enable = true;
# Enable Desktop Environment.
displayManager = {
gdm.enable = lib.mkDefault true;
gdm.wayland = lib.mkDefault true;
};
gnome = lib.mkOverride 90 {
at-spi2-core = disabled;
core-apps = enabled;
core-developer-tools = disabled;
core-os-services = enabled;
core-shell = enabled;
evolution-data-server = enabled;
games = disabled;
gcr-ssh-agent = enabled;
glib-networking = enabled;
gnome-browser-connector = enabled;
gnome-initial-setup = disabled;
gnome-keyring = enabled;
gnome-online-accounts = enabled;
gnome-remote-desktop = enabled;
gnome-settings-daemon = enabled;
gnome-software = disabled;
gnome-user-share = enabled;
localsearch = enabled;
rygel = enabled;
sushi = enabled;
tinysparql = enabled;
};
gnome.gnome-remote-desktop.enable = true;
};
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
programs.kdeconnect = {
enable = false;
package = pkgs.gnomeExtensions.gsconnect;
programs = {
kdeconnect = {
enable = false;
package = pkgs.gnomeExtensions.gsconnect;
};
};
};
}

View File

@@ -58,8 +58,6 @@ in
};
gnome.gnome-keyring.enable = true;
geoclue2.enable = true;
upower.enable = true;
dbus.enable = true;
ddccontrol.enable = false;

View File

@@ -15,7 +15,7 @@ let
'';
in
{
options.${namespace}.desktop.hyprland = {
options.mjallen.desktop.hyprland = {
enable = mkEnableOption "enable hyprland desktop environment";
wallpaperSource = mkOpt (types.enum [

View File

@@ -155,7 +155,7 @@ in
];
script = ''
${wallpaper-command}
${lib.getExe' pkgs.hyprland "hyprctl"} hyprpaper wallpaper ,${cfg.wallpaper},
${lib.getExe' pkgs.hyprland "hyprctl"} hyprpaper reload ,${cfg.wallpaper}
'';
serviceConfig = {
Type = "oneshot";

View File

@@ -37,14 +37,14 @@ let
size = "100%";
content = {
type = cfg.filesystem;
# Subvolumes must set a mountpoint in order to be mounted,
# unless their parent is mounted
subvolumes = subvolumes;
}
// (
if cfg.filesystem == "btrfs" then
{
extraArgs = [ "-f" ]; # Override existing partition
# Subvolumes must set a mountpoint in order to be mounted,
# unless their parent is mounted
subvolumes = subvolumes;
}
else
{
@@ -64,7 +64,7 @@ let
size = "100%";
content = {
type = "luks";
name = "${config.${namespace}.network.hostName}-cryptroot";
name = "cryptroot";
extraOpenArgs = [
"--allow-discards"
"--perf-no_read_workqueue"
@@ -72,21 +72,20 @@ let
];
settings = {
crypttabExtraOpts = [
"tpm2-device=auto"
"fido2-device=auto"
"token-timeout=10"
];
};
content = {
type = cfg.filesystem;
# Subvolumes must set a mountpoint in order to be mounted,
# unless their parent is mounted
subvolumes = subvolumes;
}
// (
if cfg.filesystem == "btrfs" then
{
extraArgs = [ "-f" ]; # Override existing partition
# Subvolumes must set a mountpoint in order to be mounted,
# unless their parent is mounted
subvolumes = subvolumes;
}
else
{
@@ -104,21 +103,6 @@ in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.rootDisk != "";
message = "mjallen.hardware.disko.rootDisk must be set to a non-empty device path (e.g. \"/dev/nvme0n1\").";
}
{
assertion = !(cfg.enableSwap && cfg.swapSize == "");
message = "mjallen.hardware.disko.swapSize must be a non-empty size string when enableSwap is true (e.g. \"16G\").";
}
{
assertion = cfg.compression != "";
message = "mjallen.hardware.disko.compression must be a non-empty compression type (e.g. \"zstd\").";
}
];
disko.devices = lib.mkMerge [
{
nodev."/" = {
@@ -137,12 +121,12 @@ in
content = {
type = "gpt";
partitions = {
firmware = lib.mkIf cfg.firmware.enableFirmware {
FIRMWARE = lib.mkIf cfg.enableFirmware {
priority = 1;
type = "0700";
name = "${config.${namespace}.network.hostName}-FIRMWARE";
name = "FIRMWARE";
start = "1M";
end = "1G";
type = "0700";
content = {
type = "filesystem";
format = "vfat";
@@ -151,10 +135,9 @@ in
};
};
ESP = {
priority = if cfg.firmware.enableFirmware then 2 else 1;
priority = if cfg.enableFirmware then 2 else 1;
type = "EF00";
size = "500M";
name = "${config.${namespace}.network.hostName}-EFI";
content = {
type = "filesystem";
format = "vfat";
@@ -172,35 +155,13 @@ in
};
};
};
# firmware = lib.mkIf cfg.firmware.enableFirmware {
# device = cfg.firmware.firmwareDisk;
# type = "disk";
# imageSize = "1G";
# content = {
# type = "table";
# format = "msdos";
# partitions = [
# {
# name = "${config.${namespace}.network.hostName}-FIRMWARE";
# start = "1M";
# end = "1G";
# content = {
# type = "filesystem";
# format = "vfat";
# mountpoint = "/boot/firmware";
# mountOptions = [ "umask=0077" ];
# };
# }
# ];
# };
# };
};
# configure Bcachefs
bcachefs_filesystems = lib.mkIf (cfg.filesystem == "bcachefs") {
mounted_subvolumes_in_multi = {
type = "bcachefs_filesystem";
# passwordFile = "/etc/nixos/test.key";
# passwordFile = "/etc/nixos/pool.jwe";
extraFormatArgs = [
"--compression=${cfg.compression}"
];

View File

@@ -19,10 +19,7 @@ in
enableLuks = mkBoolOpt false "Enable Luks";
firmware = {
enableFirmware = mkBoolOpt false "Enable rpi firmware part";
firmwareDisk = mkOpt types.str "/dev/mmcblk0" "UEFI firmware disk";
};
enableFirmware = mkBoolOpt false "Enable rpi firmware part";
swapSize = mkOpt types.str "16G" "size of swap part";

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