Compare commits

..
Author SHA1 Message Date
aaron dd50c4b4e5 feature(disk): allow discards on cryptroot 2026-10-02 17:35:53 +02:00
aaron 8a1067b324 feature(trim): add trim support and change partuuid to disk-labels 2026-10-02 17:34:45 +02:00
aaron fc4f0afc46 chore(guide): add corrections and updates to the install guide 2026-10-02 17:33:34 +02:00
aaron 006290ef05 Merge pull request 'feature(boot): attatch /tmp to tmpfs, but keep nix build in /var/tmp' (#84) from feature/tmpfs-tmp into main
Reviewed-on: #84
2026-10-02 16:40:44 +02:00
aaron 6a080b2319 feature(boot): attatch /tmp to tmpfs, but keep nix build in /var/tmp 2026-10-02 16:39:53 +02:00
aaron 3e0e1d48f9 Merge pull request 'chore: repository cleanup and noctalia baseline' (#83) from chore/cleanup into main
Reviewed-on: #83
2026-10-02 09:51:23 +02:00
aaronandClaude Opus 5.5 3fed9c1fc8 feature(noctalia): take argon's gui overrides into the config
- idle: 300s screen-off, 600s lock, 5s fade, and explicit actions (without them the behaviours do nothing once settings.toml is gone)
- font without Mono, launcher without categories or global emoji, control-center logo from syncthing
- drop shell.ui_scale and shell.panel.launcher_compact, which v5 ignores

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:39:08 +02:00
aaronandClaude Opus 5.5 87eb1bcb72 refactor(docker): rootless only
Drops the root daemon and the root-equivalent docker group; the daemon settings now apply to the rootless daemon. compose ships with the docker package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:25:40 +02:00
aaronandClaude Opus 5.5 06b656477b docs: move explanations into short module headers
Non-obvious context sits in a brief header at the top of a module, everything else uses single-line comments. niri binds use spawn-sh strings, so neon only overrides the command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:25:40 +02:00
aaronandClaude Opus 5.5 8d19be9527 refactor: fold host-only modules into the hosts
- argon owns its gpu settings, calibre and the luks drives, now generated from one table
- claudecode.nix is gone, claude-code lives in packages.nix
- home-manager options live next to the home-manager wiring in flake.nix
- settings.nix: one nix block, extra-substituters instead of repeating the cache.nixos.org defaults
- README: current layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:25:40 +02:00
aaronandClaude Opus 5.5 1abb1ca6a1 chore: drop redundant packages and options
- packages.nix is the baseline: drop neovim (nixvim), nvd, sof-firmware (enableAllFirmware), qtmultimedia (v4 leftover); vial moves to vial.nix, wl-clipboard to noctalia.nix, claude-code becomes a plain package here
- drop packages and options already provided elsewhere: noctalia (home-manager), gnupg/pinentry-qt (agent), gtk/qt themes, sddm Theme.Current, zsh plugins (home-manager), group = users, empty firewall lists
- single-package lists without `with pkgs;`, steam package inside its block

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:25:40 +02:00
aaronandClaude Opus 5.5 4633687ccb chore: remove unused gnuradio module
It isn't imported by any host and doesn't build reliably on unstable; gnuradio moves to a devenv in the projects that need it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:25:14 +02:00
aaron 99a910265f Merge pull request 'feature(niri): configure niri via home-manager's niri module' (#82) from feature/niri-hm into main
Reviewed-on: #82
2026-10-02 08:37:31 +02:00
38 changed files with 252 additions and 490 deletions
+20 -9
View File
@@ -2,8 +2,13 @@
- The installations presented in this repository are always luks encrypted
- For simplicity I'm using device labels rather than uuids
- Secure Boot has to be disabled in the firmware, the installer iso isn't signed
1. the partitioning layout should look somewhat like this after the installation
1. create the partitions with `cfdisk` or `fdisk` (gpt)
- `nvme0n1p1`: 2G, type `EFI System`, otherwise the firmware won't find the bootloader
- `nvme0n1p2`: the rest, type `Linux filesystem`
the layout should look somewhat like this after the installation
```bash
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 476.9G 0 disk
@@ -30,12 +35,13 @@ cryptsetup luksOpen /dev/nvme0n1p2 cryptroot
pvcreate /dev/mapper/cryptroot
# create a volume group inside
vgcreate lvmroot /dev/mapper/cryptroot
# create the swap volume
lvcreate --size 8G lvmroot --name swap
# create the swap volume, half the ram (no hibernation)
lvcreate --size 16G lvmroot --name swap
# if you desire, create a home volume
lvcreate --size 150G lvmroot --name home
# create the root volume
lvcreate -l 100%FREE lvmroot --name root
# create the root volume, leave some space in the vg to grow volumes later
# (lvextend -r -L +50G lvmroot/home works while mounted)
lvcreate -l 90%FREE lvmroot --name root
# format as usual for root partition
mkfs.ext4 -L "nixroot" /dev/mapper/lvmroot-root
@@ -47,7 +53,7 @@ mkswap -L "nixswap" /dev/mapper/lvmroot-swap
# mount root
mount /dev/disk/by-label/nixroot /mnt
# mount boot
mount --mkdir /dev/nvme0n1p1 /mnt/boot
mount --mkdir /dev/disk/by-label/nixboot /mnt/boot
# again, if you did the home volume
mount --mkdir /dev/disk/by-label/nixhome /mnt/home
# turn on swap
@@ -59,8 +65,7 @@ swapon /dev/disk/by-label/nixswap
# generate templates and update the hardware-configuration.nix
nixos-generate-config --root /mnt
# add dm-crypt and dm-mod to the kernelModules
boot.initrd.kernelModules = [ "dm-crypt" "dm-mod" ];
# no extra kernelModules needed, luks and lvm load dm_crypt and dm_mod themselves
# add file systems using labels
fileSystems."/" =
@@ -81,7 +86,13 @@ swapDevices =
];
# point the bootloader to the luks device
boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-label/nixcrypt";
boot.initrd.luks.devices."cryptroot" = {
device = "/dev/disk/by-label/nixcrypt";
# without this fstrim never reaches the ssd
allowDiscards = true;
# lower latency on nvme
bypassWorkqueues = true;
};
```
4. install nixos
+10 -10
View File
@@ -6,20 +6,20 @@ My personal NixOS configurations.
```bash
.
├── flake.lock
├── flake.nix # flake definition
├── flake.nix # hosts and home-manager wiring
├── hosts
│   └── neon
│   ├── configuration.nix # import nix-modules for specific host
│   └── hardware-configuration.nix # hardware configs for specific host
│ ├── argon # desktop
│ ├── neon # laptop
│ └── default # test vm
│ ├── configuration.nix # host-specific settings and module imports
│ ├── hardware-configuration.nix # generated by nixos-generate-config
│ └── niri.nix # host-specific niri settings (outputs, input)
├── modules
│   ├── home-manager
│   │   ├── xyz_module.nix
│   └── nixos
│   └── xyz_module.nix
│ ├── home-manager # user modules, imported by users/aaron/home.nix
│ └── nixos # system modules, imported by the hosts
└── users
└── aaron
└── home.nix # import home-manager modules for specific user
└── home.nix # imports home-manager modules
```
## installation
+3
View File
@@ -35,6 +35,9 @@
./hosts/${hostName}/configuration.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.backupCommand = "mv -f {file} {file}.hm-bak-$(date +%Y%m%d%H%M%S)";
home-manager.extraSpecialArgs = { inherit inputs; };
home-manager.users.aaron.imports = [
nixvim.homeModules.nixvim
+44 -8
View File
@@ -1,15 +1,25 @@
# argon: desktop with an amd gpu and three luks-encrypted data drives.
# The drives are unlocked in the initrd with keyfiles from /etc/nixos/keys.
{ lib, pkgs, ... }:
let
# luks name -> partition uuid, mounted at /mnt/<name>
drives = {
data1 = "dfae62cc-bad1-4879-bf9a-461bde833625";
data2 = "8312edae-9247-481b-a313-52a7f848f027";
nvmecache = "2352250e-4ebe-4f9a-bf66-0d4aaa961bd8";
};
key = name: "/etc/nixos/keys/${name}.key";
in
{
imports = [
../../modules/nixos/appimage.nix
../../modules/nixos/astro.nix
../../modules/nixos/audio.nix
../../modules/nixos/bootloader.nix
../../modules/nixos/calibre.nix
../../modules/nixos/certificates.nix
../../modules/nixos/claudecode.nix
../../modules/nixos/drives.nix
../../modules/nixos/gnupg.nix
../../modules/nixos/graphics.nix
../../modules/nixos/greetd.nix
../../modules/nixos/locales.nix
../../modules/nixos/networking.nix
@@ -29,9 +39,35 @@
# host-specific niri config (outputs, input devices)
home-manager.users.aaron.imports = [ ./niri.nix ];
# set hostname
networking.hostName = "argon";
# amd gpu: mesa/vulkan, and amdgpu in the initrd for plymouth
hardware.graphics = {
enable = true;
enable32Bit = true;
};
hardware.amdgpu.initrd.enable = true;
# install state version
system.stateVersion = "25.11"; # Don't change
# encrypted data drives
boot.initrd.secrets = lib.mapAttrs' (name: _: lib.nameValuePair (key name) (key name)) drives;
boot.initrd.luks.devices = lib.mapAttrs (name: uuid: {
device = "/dev/disk/by-uuid/${uuid}";
keyFile = key name;
# trim for ssds, ignored by drives without discard support
allowDiscards = true;
}) drives;
fileSystems = lib.mapAttrs' (
name: _:
lib.nameValuePair "/mnt/${name}" {
device = "/dev/mapper/${name}";
fsType = "ext4";
options = [ "nofail" ];
}
) drives;
environment.systemPackages = with pkgs; [
amdgpu_top
calibre # ebook management and kobo syncing
];
networking.hostName = "argon";
system.stateVersion = "25.11"; # don't change
}
+9 -6
View File
@@ -22,18 +22,21 @@
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ "dm-crypt dm-mod" ];
boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-label/nixcrypt";
boot.initrd.luks.devices."cryptroot" = {
device = "/dev/disk/by-label/nixcrypt";
allowDiscards = true;
bypassWorkqueues = true;
};
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/mapper/lvmroot-root";
device = "/dev/disk/by-label/nixroot";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/AC1C-20EB";
device = "/dev/disk/by-label/nixboot";
fsType = "vfat";
options = [
"fmask=0022"
@@ -42,12 +45,12 @@
};
fileSystems."/home" = {
device = "/dev/mapper/lvmroot-home";
device = "/dev/disk/by-label/nixhome";
fsType = "ext4";
};
swapDevices = [
{ device = "/dev/mapper/lvmroot-swap"; }
{ device = "/dev/disk/by-label/nixswap"; }
];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+1
View File
@@ -1,4 +1,5 @@
# argon: desktop with two 1440p monitors side by side
{
wayland.windowManager.niri.settings = {
input = {
+1 -1
View File
@@ -1,4 +1,4 @@
# 0x29a nixos conifg
# 0x29a nixos config
{ pkgs, ... }:
+1 -5
View File
@@ -5,7 +5,6 @@
../../modules/nixos/audio.nix
../../modules/nixos/bootloader.nix
../../modules/nixos/certificates.nix
../../modules/nixos/claudecode.nix
../../modules/nixos/docker.nix
../../modules/nixos/gnupg.nix
../../modules/nixos/locales.nix
@@ -26,9 +25,6 @@
# host-specific niri config (input devices, laptop binds)
home-manager.users.aaron.imports = [ ./niri.nix ];
# set hostname
networking.hostName = "neon";
# install state version
system.stateVersion = "25.11"; # Don't change
system.stateVersion = "25.11"; # don't change
}
+5 -1
View File
@@ -25,7 +25,11 @@
"dm-snapshot"
"cryptd"
];
boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-label/nixcrypt";
boot.initrd.luks.devices."cryptroot" = {
device = "/dev/disk/by-label/nixcrypt";
allowDiscards = true;
bypassWorkqueues = true;
};
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
+5 -15
View File
@@ -1,17 +1,7 @@
# neon: laptop, built-in display is auto-configured by niri
# neon: laptop, the built-in display is auto-configured by niri
{ lib, ... }:
let
brightness = step: {
_props.allow-when-locked = true;
spawn = [
"brightnessctl"
"--class=backlight"
"set"
step
];
};
in
{
wayland.windowManager.niri.settings = {
input.touchpad = {
@@ -26,9 +16,9 @@ in
"Ctrl+Print".screenshot-screen = { };
"Mod+Shift+P".power-off-monitors = { };
# finer brightness steps; mkForce, since spawn lists would otherwise be concatenated
"XF86MonBrightnessUp" = lib.mkForce (brightness "+1%");
"XF86MonBrightnessDown" = lib.mkForce (brightness "1%-");
# finer brightness steps
"XF86MonBrightnessUp".spawn-sh = lib.mkForce "brightnessctl --class=backlight set +1%";
"XF86MonBrightnessDown".spawn-sh = lib.mkForce "brightnessctl --class=backlight set 1%-";
};
};
}
+6 -11
View File
@@ -1,3 +1,7 @@
# Commits are signed with each machine's ~/.ssh/id_ed25519 through the ssh
# agent. gitea verifies them against the account keys; allowed_signers gives
# the local git the same trust, so `git log --show-signature` resolves too.
{
config,
lib,
@@ -7,18 +11,12 @@
let
email = "aaron@0x29a.ch";
# public half of every machine's ~/.ssh/id_ed25519, each one verified as a
# signing key in gitea. the key a host signs with is picked up from the key
# file itself, this list only tells the local git which machines to trust
signingKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHRhwzo1oxaT3fEySSmILKNnu9v30cfjx5G7FKpmfqeX aaron@argon"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGDkhvvTUcBSQdtXjX+Mw2Bp8HHhtiBm8aJi4ZxiBgZR aaron@neon"
];
in
{
# gitea verifies signatures against the account keys, this teaches the local
# git the same trust so `git log --show-signature` resolves as well
xdg.configFile."git/allowed_signers".text = lib.concatMapStrings (
key: "${email} ${key}\n"
) signingKeys;
@@ -26,9 +24,7 @@ in
programs.git = {
enable = true;
settings = {
push = {
autoSetupRemote = true;
};
push.autoSetupRemote = true;
user = {
name = "aaron";
inherit email;
@@ -37,8 +33,7 @@ in
};
signing = {
format = "ssh";
# point at the *public* key so ssh-keygen signs through the ssh agent
# instead of reading the passphrase protected private key from disk
# the public key makes ssh-keygen sign through the agent
key = "${config.home.homeDirectory}/.ssh/id_ed25519.pub";
signer = "${pkgs.openssh}/bin/ssh-keygen";
signByDefault = true;
+12 -40
View File
@@ -1,7 +1,11 @@
# Only renders ~/.config/niri/config.kdl; niri itself, its session and portals
# come from modules/nixos/niri.nix. Outputs and input devices that differ
# per machine live in hosts/<host>/niri.nix.
{ lib, osConfig, ... }:
let
# Mod+1..9 focus a workspace, Mod+Ctrl+1..9 move the column there.
# Mod+1..9 focus a workspace, Mod+Ctrl+1..9 move the column there
workspaceBinds = lib.mergeAttrsList (
map (n: {
"Mod+${toString n}".focus-workspace = n;
@@ -9,24 +13,18 @@ let
}) (lib.range 1 9)
);
# Shorthand for binds that only run spawn-sh while allowed on the lock screen.
# shell command that also works on the lock screen
lockedSh = cmd: {
_props.allow-when-locked = true;
spawn-sh = cmd;
};
in
{
# Niri config, rendered to ~/.config/niri/config.kdl by home-manager's built-in
# wayland.windowManager.niri module. The compositor itself, its session, systemd
# units and portals are provided by the NixOS module (modules/nixos/niri.nix), so
# this module only writes the config. Host-specific outputs and input devices
# live in hosts/<host>/niri.nix.
wayland.windowManager.niri = {
# only on hosts that run niri (see modules/nixos/niri.nix)
# only on hosts that run niri
enable = osConfig.programs.niri.enable;
# Use the system's niri so the config is validated against the running version.
# validate the config against the installed niri
package = osConfig.programs.niri.package;
systemd.enable = false;
portalPackage = null;
@@ -125,21 +123,11 @@ in
};
"Mod+D" = {
_props.hotkey-overlay-title = "Run an Application";
spawn = [
"noctalia"
"msg"
"panel-toggle"
"launcher"
];
spawn-sh = "noctalia msg panel-toggle launcher";
};
"Super+Alt+L" = {
_props.hotkey-overlay-title = "Lock the Screen";
spawn = [
"noctalia"
"msg"
"session"
"lock"
];
spawn-sh = "noctalia msg session lock";
};
# media keys (PipeWire / WirePlumber)
@@ -151,24 +139,8 @@ in
"XF86AudioStop" = lockedSh "playerctl stop";
"XF86AudioPrev" = lockedSh "playerctl previous";
"XF86AudioNext" = lockedSh "playerctl next";
"XF86MonBrightnessUp" = {
_props.allow-when-locked = true;
spawn = [
"brightnessctl"
"--class=backlight"
"set"
"+10%"
];
};
"XF86MonBrightnessDown" = {
_props.allow-when-locked = true;
spawn = [
"brightnessctl"
"--class=backlight"
"set"
"10%-"
];
};
"XF86MonBrightnessUp" = lockedSh "brightnessctl --class=backlight set +10%";
"XF86MonBrightnessDown" = lockedSh "brightnessctl --class=backlight set 10%-";
"Mod+O" = {
_props.repeat = false;
+3 -8
View File
@@ -4,10 +4,7 @@
programs.nixvim = {
enable = true;
# We keep `inputs.nixvim.inputs.nixpkgs.follows = "nixpkgs"` in flake.nix so
# the whole config shares a single nixpkgs. Setting `source` explicitly to
# that same nixpkgs acknowledges the override and silences nixvim's warning
# about its pinned nixpkgs being bypassed.
# same nixpkgs as the flake's `follows`, silences nixvim's pin warning
nixpkgs.source = inputs.nixpkgs;
# set aliases
@@ -104,8 +101,6 @@
};
};
# install dependencies
home.packages = with pkgs; [
ripgrep
];
# telescope live_grep
home.packages = [ pkgs.ripgrep ];
}
+15 -8
View File
@@ -24,15 +24,18 @@
# general
shell = {
font_family = "0xProto Nerd Font Mono";
ui_scale = 1.2;
font_family = "0xProto Nerd Font";
avatar_path = "/home/aaron/syncthing/pictures/Logo-Aaron-Totenkopf-rund-schwarz.png";
telemetry_enabled = false;
clipboard_enabled = true;
password_style = "random";
launcher = {
categories = false;
providers.emoji.global = false;
};
panel = {
launcher_compact = true;
open_near_click_control_center = true;
open_near_click_session = true;
open_near_click_wallpaper = true;
@@ -97,7 +100,7 @@
bluetooth.capsule = true;
control-center = {
capsule_radius = 8;
custom_image = "/home/aaron/Pictures/nix_flake_logo.png";
custom_image = "/home/aaron/syncthing/pictures/nix_flake_logo.png";
scale = 1.4;
};
cpu.capsule = true;
@@ -116,6 +119,7 @@
# idle behavior
idle = {
pre_action_fade_seconds = 5;
behavior_order = [
"screen-off"
"lock"
@@ -123,14 +127,17 @@
];
behavior = {
"screen-off" = {
action = "screen_off";
enabled = true;
timeout = 300;
};
"lock" = {
action = "lock";
enabled = true;
timeout = 600;
};
"lock" = {
enabled = true;
timeout = 660;
};
"lock-and-suspend" = {
action = "lock_and_suspend";
enabled = true;
timeout = 1800;
};
+9 -25
View File
@@ -1,25 +1,26 @@
# zsh with oh-my-zsh: agnoster where glyphs render, gentoo on the console.
# Deep paths are shortened to `…/last/two` so the prompt stays on one line:
# `%(4~|…/%2~|%~)` shows the last two components from four levels down.
{ lib, ... }:
{
# configure z-shell to use omz with some plugins
programs.zsh = {
enable = true;
autosuggestion.enable = true;
syntaxHighlighting.enable = true;
oh-my-zsh = {
enable = true;
# add git and agents as plugins
plugins = [
"git"
"ssh-agent"
"gpg-agent"
];
# everything here lands before `source $ZSH/oh-my-zsh.sh`
# runs before oh-my-zsh is sourced
extraConfig = ''
# make omz faster on large repositories
# faster git status on large repositories
DISABLE_UNTRACKED_FILES_DIRTY=true
# only display a fancy theme when glyphs are rendered
if [[ "$TERM" == "linux" || "$TERM" == "screen" ]]; then
ZSH_THEME="gentoo"
else
@@ -28,37 +29,20 @@
'';
};
# Unlike oh-my-zsh.extraConfig above, this lands *after*
# `source $ZSH/oh-my-zsh.sh`, which is where the theme's prompt functions
# come into existence.
# runs after oh-my-zsh, once the theme's prompt exists
initContent = lib.mkAfter ''
# Keep the prompt on one line in deeply nested trees.
#
# Both themes render the working directory as `%~`, the full path with
# $HOME collapsed to `~`. Somewhere like
# ~/git/bfh/cas-pml-sem/documents/bericht that is 39 columns on its own,
# and together with user@host and a long branch name the line wraps.
#
# `%(4~|…/%2~|%~)` is a prompt ternary: at four or more components show
# an ellipsis and the last two, otherwise show the path whole. Short
# paths like ~/git/nixconfig are left alone.
if [[ "$ZSH_THEME" == "agnoster" ]]; then
# agnoster calls prompt_dir on every render, so redefining it is
# enough. AGNOSTER_DIR_* keep the segment's own colours.
# agnoster renders prompt_dir on every prompt, so override it
prompt_dir() {
prompt_segment "$AGNOSTER_DIR_BG" "$AGNOSTER_DIR_FG" '%(4~|…/%2~|%~)'
}
else
# gentoo builds PROMPT once at load time, so patch the string. Its
# `%~` is the non-root branch of `%(!.%1~.%~)`, and it is the first
# literal `%~` in there, so the root branch is untouched. ASCII `...`
# because this branch is the Linux console, whose font may lack U+2026.
# gentoo builds PROMPT once; ascii dots, the console font lacks …
PROMPT="''${PROMPT/\%~/%(4~|.../%2~|%~)}"
fi
'';
};
# set important env vars
home.sessionVariables = {
EDITOR = "vim";
NH_FLAKE = "/home/aaron/git/nixconfig";
-8
View File
@@ -1,7 +1,6 @@
{ pkgs, ... }:
{
# set gtk theme
gtk = {
enable = true;
theme = {
@@ -13,7 +12,6 @@
gtk4.extraConfig.gtk-application-prefer-dark-theme = 1;
};
# set qt theme
qt = {
enable = true;
platformTheme.name = "qt6";
@@ -22,10 +20,4 @@
package = pkgs.adwaita-qt;
};
};
# ensure packages are installed
home.packages = with pkgs; [
gnome-themes-extra
adwaita-qt
];
}
+16 -42
View File
@@ -1,54 +1,37 @@
# Nord-style status line built natively, no theme plugin.
# The powerline separators (U+E0B0..U+E0B3) are written as escapes via
# fromJSON: literal private-use glyphs get stripped silently on copy/paste.
# Commas inside #{?...} separate arguments, hence the escaped `#,` below.
let
# Powerline separators, U+E0B0..U+E0B3.
#
# Written as escapes rather than literal glyphs. These are Private Use Area
# codepoints: they render only with a patched font, they survive copy/paste
# badly, and when they get stripped the loss is invisible, the config still
# parses, the status bar just quietly loses its separators. Nix has no \u
# escape of its own, but fromJSON does.
sep = builtins.fromJSON ''
{
"right": "\ue0b0",
"rightThin": "\ue0b1",
"left": "\ue0b2",
"leftThin": "\ue0b3"
"right": "",
"rightThin": "",
"left": "",
"leftThin": ""
}
'';
in
{
programs.tmux = {
# defaults
enable = true;
prefix = "C-a";
keyMode = "vi";
mouse = true;
# tmux-256color gives truecolor, italics and undercurl in nvim.
terminal = "tmux-256color";
# Default is 500ms. Causes lag you feel when leaving insert mode in nvim,
# because tmux is waiting to see whether Esc starts an escape sequence.
escapeTime = 10;
# nvim autoread / :checktime react to focus.
focusEvents = true;
# History limit.
terminal = "tmux-256color"; # truecolor, italics and undercurl in nvim
escapeTime = 10; # the 500ms default lags leaving insert mode in nvim
focusEvents = true; # nvim autoread
historyLimit = 50000;
# Window numbers matching the number row.
baseIndex = 1;
baseIndex = 1; # window numbers match the number row
extraConfig = ''
# Status keys
set -g status-keys vi
# Tell tmux the outer terminal can do 24-bit colour (tmux >= 3.2).
# outer terminal does 24-bit colour
set -sa terminal-features ",*:RGB"
# Shift+Enter / extended keys
# These make tmux forward CSI-u sequences unconditionally.
# Needs tmux >= 3.5 for the format option,
# forward Shift+Enter and other extended keys as CSI-u (tmux >= 3.5)
set -s extended-keys always
set -s extended-keys-format csi-u
set -as terminal-features '*:extkeys'
@@ -88,27 +71,18 @@ in
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# Wayland clipboard integration
# Copy selection to both clipboard (Ctrl+V / Shift+Insert) and primary (middle-click)
# copy to both the clipboard and primary selection
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "wl-copy && wl-copy --primary"
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "wl-copy && wl-copy --primary"
bind -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "wl-copy && wl-copy --primary"
# Uncomment if you want yanks to also travel over SSH via OSC52.
# Locally redundant with wl-copy above.
#set -g set-clipboard on
# Kill commands
bind q confirm-before -p "kill window #W? (y/n)" kill-window
bind Q confirm-before -p "kill session #S? (y/n)" kill-session
# Bars
# This is the nord-tmux status line. #{prefix_highlight} came from that
# theme's tmux-prefix-highlight integration -- a plugin you never loaded,
# so the token expanded to nothing. tmux can do it natively. Commas inside
# #{?...} are argument separators and have to be escaped as #, hence the
# look of the style spec.
set -g status-left-length 24
set -g status-left "#[fg=black,bg=blue,bold] #{=20:session_name} #[fg=blue,bg=black,nobold,noitalics,nounderscore]${sep.right}"
set -g status-right "#{?client_prefix,#[fg=black#,bg=yellow#,bold] ^A ,}#[fg=brightblack,bg=black,nobold,noitalics,nounderscore]${sep.left}#[fg=white,bg=brightblack] %Y-%m-%d #[fg=white,bg=brightblack,nobold,noitalics,nounderscore]${sep.leftThin}#[fg=white,bg=brightblack] %H:%M #[fg=cyan,bg=brightblack,nobold,noitalics,nounderscore]${sep.left}#[fg=black,bg=cyan,bold] #H "
+5 -12
View File
@@ -1,17 +1,10 @@
# Running an AppImage directly fails on NixOS: its runtime dlopens
# libfuse.so.2, which nix-ld doesn't cover. appimage-run unpacks the image
# into an FHS sandbox instead. Used for the BitBox02 wallet from bitbox.swiss.
{
# AppImages ship a squashfs payload that the bundled runtime mounts through
# libfuse.so.2 at startup. nix-ld resolves the ELF interpreter but not that
# dlopen, so running one directly dies with "dlopen(): error loading
# libfuse.so.2". appimage-run sidesteps the mount entirely: it unpacks the
# image and runs the payload inside an FHS sandbox, which the bundled Qt and
# electron style binaries need anyway.
#
# Used for the BitBox02 wallet AppImage, downloaded fresh from
# https://bitbox.swiss/download/ rather than installed from nixpkgs.
programs.appimage = {
enable = true;
# register AppImages with binfmt_misc so ./Something.AppImage runs as-is,
# no appimage-run prefix to remember.
binfmt = true;
binfmt = true; # ./Something.AppImage runs without the appimage-run prefix
};
}
+31 -54
View File
@@ -1,37 +1,23 @@
# Stellarium for target finding, Siril for stacking.
#
# Siril's python plugins run in a venv of foreign manylinux wheels (numpy,
# PyQt6, ...), dlopened by nixpkgs python, so nix-ld doesn't help. The wrapper
# puts their libs on LD_LIBRARY_PATH, a python on PATH to bootstrap the venv,
# and adwaita-qt6 on QT_PLUGIN_PATH so the dark style override resolves.
# The python comes from /etc/siril/bin, a stable symlink: a /nix/store path
# would leave the venv dangling after the next python bump and gc.
#
# StarNet++ has no package: unzip the v2 ORT cli build from starnetastro.com
# to ~/.local/share/siril/starnet/ and point Siril's preferences at ./starnet2.
# It runs through nix-ld and finds its own libs in the bundled ./lib.
{ lib, pkgs, ... }:
let
# Siril's Python plugins (sirilpy) run in a venv that pip-installs foreign
# manylinux wheels (numpy, GraXpert deps, ...). Those .so files need
# libstdc++ at runtime. nix-ld does NOT cover this: it only handles the
# initial exec of a foreign binary, but here a *native* nixpkgs python
# dlopen()s the foreign wheel. So we put the libs on LD_LIBRARY_PATH, which
# the python subprocess inherits from the Siril process.
sirilWithPlugins = pkgs.symlinkJoin {
name = "siril-with-plugins";
paths = [ pkgs.siril ];
nativeBuildInputs = [ pkgs.makeWrapper ];
# Siril bootstraps its sirilpy venv at first run by locating a `python3`
# on PATH. nixpkgs only *propagates* python3 from the siril derivation (it
# isn't on the runtime PATH), so without the --prefix PATH below the GUI
# fails with "Python not found in system PATH" and never creates
# ~/.local/share/siril/venv.
#
# We deliberately do NOT put ${pkgs.python3}/bin on PATH directly: `venv`
# symlinks bin/python3 to whatever sys.executable was, so the venv would
# hard-link a /nix/store hash that gets garbage-collected after the next
# python bump, leaving a dangling symlink ("Error finding venv python
# path, unable to spawn python"). Instead we go through the stable
# /etc/siril/bin/python3 symlink (see environment.etc below), which NixOS
# re-points at the current python on every rebuild.
#
# The VeraLux PyQt6 wheel ships only the built-in Windows/Fusion styles, so
# the global QT_STYLE_OVERRIDE=adwaita-dark (inherited from the session) is
# rejected ("invalid style override") and windows fall back to a light
# theme. We expose nixpkgs adwaita-qt6's style plugin on QT_PLUGIN_PATH so
# the override resolves. This works because nixpkgs qt6 and the bundled Qt
# share a major.minor (6.11); if they ever drift the plugin is simply
# ignored again (harmless warning + Fusion fallback, no loss of function).
postBuild = ''
wrapProgram $out/bin/siril \
--prefix PATH : /etc/siril/bin \
@@ -40,21 +26,19 @@ let
lib.makeLibraryPath (
with pkgs;
[
stdenv.cc.cc.lib # libstdc++ / libgcc_s / libgomp (numpy etc.)
stdenv.cc.cc.lib # libstdc++, libgcc_s, libgomp (numpy)
zlib
zstd # libzstd.so.1 (PyQt6)
libGL # libGL.so.1 (PyQt6)
# PyQt6 (VeraLux) — Qt bundles xcb support so it needs these even
# on Wayland; libxkbcommon is the keymap lib used by Wayland too.
zstd # PyQt6
libGL # PyQt6
# Qt needs these even on wayland
glib
fontconfig
freetype
dbus
libxkbcommon
# Qt platform plugins: the wayland plugin (libqwayland.so) needs the
# wayland client libs; the xcb fallback needs libxcb-cursor.so.0.
wayland # libwayland-client/cursor/egl (wayland plugin)
libxcb-cursor # libxcb-cursor.so.0 (xcb plugin)
# Qt platform plugins: wayland, and the xcb fallback
wayland
libxcb-cursor
libx11
libxcb
libxcb-util
@@ -69,27 +53,20 @@ let
};
in
{
# install stellarium for target finding and siril for stacking
environment.systemPackages = with pkgs; [
stellarium
environment.systemPackages = [
pkgs.stellarium
sirilWithPlugins
];
# Stable, GC-safe interpreter path for Siril's venv (see sirilWithPlugins).
# Same python as siril itself propagates, so sirilpy's ABI matches.
# same python siril propagates, so sirilpy's abi matches
environment.etc."siril/bin/python3".source = "${pkgs.python3}/bin/python3";
# StarNet++ has no nixpkgs package. Download the StarNet v2 ORT CLI build
# (starnet2_linux_*_ORT_x64_cli) from https://www.starnetastro.com/download/
# and unzip it to ~/.local/share/siril/starnet/. Then in Siril set
# Preferences -> Miscellaneous -> StarNet executable
# to the extracted ./starnet2 binary.
#
# The binary is a generic dynamically-linked ELF, so NixOS needs nix-ld to
# run it. Its own opencv/onnxruntime libs are found via the bundled ./lib.
programs.nix-ld.enable = true;
programs.nix-ld.libraries = with pkgs; [
stdenv.cc.cc.lib # libstdc++ / libgcc_s
zlib
];
# for StarNet++
programs.nix-ld = {
enable = true;
libraries = with pkgs; [
stdenv.cc.cc.lib
zlib
];
};
}
+6
View File
@@ -24,6 +24,12 @@
boot.kernelPackages = pkgs.linuxPackages_latest;
boot.consoleLogLevel = 2;
# /tmp in RAM, nix builds go to /var/tmp instead (see settings.nix)
boot.tmp = {
useTmpfs = true;
tmpfsSize = "50%";
};
# Add boot-related packages
environment.systemPackages = with pkgs; [
efibootmgr
-8
View File
@@ -1,8 +0,0 @@
{ pkgs, ... }:
{
# install calibre for ebook management and kobo syncing
environment.systemPackages = with pkgs; [
calibre
];
}
-7
View File
@@ -1,7 +0,0 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
claude-code
];
}
+3 -17
View File
@@ -1,12 +1,8 @@
{ pkgs, ... }:
{
# add docker group to user
users.users.aaron.extraGroups = [ "docker" ];
virtualisation.docker = {
# rootless only: no root daemon and no root-equivalent docker group
virtualisation.docker.rootless = {
enable = true;
# Customize Docker daemon settings
setSocketVariable = true;
daemon.settings = {
dns = [
"1.1.1.1"
@@ -14,16 +10,6 @@
];
log-driver = "journald";
registry-mirrors = [ "https://mirror.gcr.io" ];
storage-driver = "overlay2";
};
# Use the rootless mode
rootless = {
enable = true;
setSocketVariable = true;
};
# Install docker-compose
extraPackages = with pkgs; [
docker-compose
];
};
}
-45
View File
@@ -1,45 +0,0 @@
# Add encrypted drives to argon
{
# copy keyfiles into initrd to make them available during early boot
boot.initrd.secrets = {
"/etc/nixos/keys/data1.key" = "/etc/nixos/keys/data1.key";
"/etc/nixos/keys/data2.key" = "/etc/nixos/keys/data2.key";
"/etc/nixos/keys/nvmecache.key" = "/etc/nixos/keys/nvmecache.key";
};
# decrypt data drives with keyfiles for argon
boot.initrd.luks.devices = {
"data1" = {
device = "/dev/disk/by-uuid/dfae62cc-bad1-4879-bf9a-461bde833625";
keyFile = "/etc/nixos/keys/data1.key";
};
"data2" = {
device = "/dev/disk/by-uuid/8312edae-9247-481b-a313-52a7f848f027";
keyFile = "/etc/nixos/keys/data2.key";
};
"nvmecache" = {
device = "/dev/disk/by-uuid/2352250e-4ebe-4f9a-bf66-0d4aaa961bd8";
keyFile = "/etc/nixos/keys/nvmecache.key";
};
};
# mount decrypted filesystems
fileSystems."/mnt/data1" = {
device = "/dev/mapper/data1";
fsType = "ext4";
options = [ "nofail" ];
};
fileSystems."/mnt/data2" = {
device = "/dev/mapper/data2";
fsType = "ext4";
options = [ "nofail" ];
};
fileSystems."/mnt/nvmecache" = {
device = "/dev/mapper/nvmecache";
fsType = "ext4";
options = [ "nofail" ];
};
}
+7 -12
View File
@@ -1,29 +1,24 @@
# A graphical pinentry never grabs the tty, so a passphrase prompt can't take
# over a terminal driven by a coding agent. The cache lasts a working day, and
# an unattended signature fails after two minutes instead of blocking forever.
{ config, pkgs, ... }:
{
# enable gnupg agent
programs.gnupg.agent = {
enable = true;
# a graphical pinentry never grabs the tty, so a passphrase prompt can no
# longer take over a terminal that a coding agent is driving
pinentryPackage = pkgs.pinentry-qt;
settings = {
# keep the key unlocked for a full working day instead of 10 minutes,
# so signing commits asks at most once per session
default-cache-ttl = 86400;
max-cache-ttl = 86400;
# fail an unattended signature instead of blocking on a prompt forever
pinentry-timeout = 120;
};
};
environment.systemPackages = with pkgs; [
gnupg
pinentry-qt
# fallback for sessions without a display, switch pinentryPackage to use it
pinentry-curses
environment.systemPackages = [
pkgs.pinentry-curses # fallback for sessions without a display
# prime the passphrase cache on demand, e.g. before an agent session
(writeShellScriptBin "gpg-unlock" ''
(pkgs.writeShellScriptBin "gpg-unlock" ''
echo | ${config.programs.gnupg.package}/bin/gpg --clearsign --output /dev/null
echo "gpg key unlocked"
'')
-12
View File
@@ -1,12 +0,0 @@
{ pkgs, ... }:
{
# install gnuradio companion along with it's osmocom library
environment.systemPackages = with pkgs; [
(gnuradio.override {
extraPackages = with gnuradio.pkgs; [ osmosdr ];
})
gqrx
hackrf
];
}
-17
View File
@@ -1,17 +0,0 @@
{ pkgs, ... }:
{
# enable amd GPU acceleration (mesa, vulkan, egl)
hardware.graphics = {
enable = true;
enable32Bit = true;
};
# install amdgpu_top
environment.systemPackages = with pkgs; [
amdgpu_top
];
# add amdgpu to the initrd for plymouth
hardware.amdgpu.initrd.enable = true;
}
+1 -9
View File
@@ -1,20 +1,12 @@
{ pkgs, ... }:
{
# user networkmanager
networking.networkmanager.enable = true;
# firewall default configs
networking.firewall.allowedTCPPorts = [ ];
networking.firewall.allowedUDPPorts = [ ];
# enable wifi firmware
# wifi firmware and bluetooth
hardware.enableAllFirmware = true;
# enable bluetooth
hardware.bluetooth.enable = true;
# Add network-related packages
environment.systemPackages = with pkgs; [
wireguard-tools
update-systemd-resolved
+2 -6
View File
@@ -1,11 +1,7 @@
{ pkgs, ... }:
{
# just enable and install niri
# compositor and session; the config itself lives in home-manager
programs.niri.enable = true;
# Add compositor-related packages
environment.systemPackages = with pkgs; [
xwayland-satellite
];
environment.systemPackages = [ pkgs.xwayland-satellite ];
}
+4 -4
View File
@@ -1,14 +1,14 @@
{ pkgs, inputs, ... }:
{ pkgs, ... }:
{
# install noctalia and helper packages
# helpers for the noctalia shell (the shell itself comes from home-manager)
environment.systemPackages = with pkgs; [
inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default
adw-gtk3
adwaita-qt
adwaita-qt6
brightnessctl
ddcutil
playerctl
wl-clipboard
wl-mirror
];
}
+2 -7
View File
@@ -1,10 +1,11 @@
{ pkgs, ... }:
{
# system packages
# baseline tools for every host
environment.systemPackages = with pkgs; [
btop
cifs-utils
claude-code
cowsay
dnsutils
ethtool
@@ -14,31 +15,25 @@
imv
iperf3
jq
kdePackages.qtmultimedia
ldns
lm_sensors
lsof
mtr
neovim
nfs-utils
nh
nix-output-monitor
nmap
nvd
p7zip
pciutils
socat
sof-firmware
strace
sysstat
tree
unzip
usbutils
vial
vim
wget
which
wl-clipboard
xz
zip
zstd
+2 -7
View File
@@ -1,13 +1,8 @@
{ pkgs, ... }:
{
# protonvpn uses wireguard tunnels, which break strict reverse path filtering
# because packets arrive on the tunnel interface but may be routed back differently.
# "loose" checks that the source is routable through *any* interface (not necessarily
# the same one), which is sufficient for wireguard while still preventing IP spoofing.
# wireguard replies may leave on another interface, so strict rpfilter drops them
networking.firewall.checkReversePath = "loose";
environment.systemPackages = with pkgs; [
proton-vpn
];
environment.systemPackages = [ pkgs.proton-vpn ];
}
+3 -13
View File
@@ -1,25 +1,15 @@
{ pkgs, ... }:
{
# enable sddm and use astronaut theme
services.displayManager.sddm = {
enable = true;
wayland.enable = true;
autoNumlock = true;
enableHidpi = true;
theme = "sddm-astronaut-theme";
settings = {
Theme = {
Current = "sddm-astronaut-theme";
};
};
extraPackages = with pkgs; [
sddm-astronaut
];
extraPackages = [ pkgs.sddm-astronaut ]; # theme's qml dependencies
};
# Make the theme available in the system path so sddm can find it
environment.systemPackages = with pkgs; [
sddm-astronaut
];
# sddm looks for themes in the system path
environment.systemPackages = [ pkgs.sddm-astronaut ];
}
+11 -25
View File
@@ -1,31 +1,25 @@
{
nix = {
# nix settings
settings = {
# enable flakes and nix-command
experimental-features = [
"nix-command"
"flakes"
];
# auto-optimize my nix-store
auto-optimise-store = true;
# use all cores
# parallel builds, each using all cores
max-jobs = "auto";
# use all available cores per job
cores = 0;
# add trusted substituters (binary caches)
substituters = [
"https://cache.nixos.org"
"https://nix-community.cachix.org"
];
# add keys
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
# cache.nixos.org is the default, these come on top
extra-substituters = [ "https://nix-community.cachix.org" ];
extra-trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
trusted-users = [
"root"
"@wheel"
];
};
# enable automatic garbage collection
gc = {
automatic = true;
dates = "weekly";
@@ -33,20 +27,12 @@
};
};
# add trusted users (able to modify the nix store)
nix.settings.trusted-users = [
"root"
"@wheel"
];
# build on disk, big builds would fill the /tmp tmpfs
systemd.services.nix-daemon.environment.TMPDIR = "/var/tmp";
# allow unfree packages (steam, protonvpn, discord, etc.)
# steam, protonvpn, discord, etc.
nixpkgs.config.allowUnfree = true;
# links /libexec from derivations to /run/current-system/sw
environment.pathsToLink = [ "/libexec" ];
# enable home-manager globally
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.backupCommand = "mv -f {file} {file}.hm-bak-$(date +%Y%m%d%H%M%S)";
}
+3 -10
View File
@@ -1,20 +1,13 @@
{ pkgs, ... }:
{
# enable steam and open firewall
programs.steam = {
enable = true;
# fix black screen when running under xwayland-satellite
package = pkgs.steam.override { extraArgs = "-system-composer"; };
remotePlay.openFirewall = true;
dedicatedServer.openFirewall = true;
localNetworkGameTransfers.openFirewall = true;
# add proton-glorious-eggroll
extraCompatPackages = with pkgs; [
proton-ge-bin
];
};
# fix black screen in steam when using xwayland-satellite
programs.steam.package = pkgs.steam.override {
extraArgs = "-system-composer";
extraCompatPackages = [ pkgs.proton-ge-bin ];
};
}
+2 -7
View File
@@ -1,14 +1,9 @@
{ pkgs, ... }:
{
# Enable Thunar
programs.thunar.enable = true;
# Install Tumbler thumbnailer service
environment.systemPackages = with pkgs; [
tumbler
];
# Ensure Thunar can locate the thumbnailer extensions
# thumbnails: tumbler service plus the path it loads extensions from
environment.systemPackages = [ pkgs.tumbler ];
environment.pathsToLink = [ "share/thumbnailers" ];
}
+2 -8
View File
@@ -1,10 +1,8 @@
{ pkgs, ... }:
{
# create users
users.users.aaron = {
isNormalUser = true;
group = "users";
extraGroups = [
"wheel"
"networkmanager"
@@ -13,10 +11,6 @@
shell = pkgs.zsh;
};
# add default zsh config
programs.zsh = {
enable = true;
enableCompletion = true;
autosuggestions.enable = true;
};
# login shell; plugins and prompt are configured in home-manager
programs.zsh.enable = true;
}
+8 -13
View File
@@ -1,26 +1,21 @@
# Vial keyboards (lily58 pro r2g) expose a raw HID interface that vial.rocks
# drives over WebHID; its /dev/hidraw* node is root-only by default.
# The rule ships as 60-vial.rules because uaccess is only applied by
# 73-seat-late.rules, and services.udev.extraRules lands at 99, too late.
{ pkgs, ... }:
{
# Vial-capable keyboards (lily58 pro r2g) expose a second, non-keyboard raw
# HID interface that vial.rocks drives over WebHID. Its /dev/hidraw* node is
# root-only by default, so neither chromium nor the native app can open it.
#
# This has to ship as a numbered rules file rather than via
# services.udev.extraRules: extraRules lands in 99-local.rules, but the
# builtin that turns TAG+="uaccess" into an actual ACL is invoked from
# systemd's 73-seat-late.rules. A tag set at 99 is set too late to be seen,
# so the device ends up correctly tagged and still unreadable. 60- sorts
# safely ahead of 73.
services.udev.packages = [
(pkgs.writeTextFile {
name = "vial-udev-rules";
destination = "/lib/udev/rules.d/60-vial.rules";
# Vial firmware advertises itself through a magic USB serial, so this
# matches any vial board rather than just the lily58. uaccess hands the
# device to whoever owns the active seat, no group membership needed.
# the magic serial matches any vial board; uaccess grants the seat owner
text = ''
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{serial}=="*vial:f64c2b3c*", TAG+="uaccess"
'';
})
];
environment.systemPackages = [ pkgs.vial ];
}