nixos: gen 113 @ nix-pad — 2026-07-22 23:02
26.05.20260717.293d6ab (Yarara)
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
NixOS dotfiles using Flakes + Home Manager for a single user (`jashton`) across multiple hosts (`thinkpad`, `desktop`, `framework`). Pinned to `nixos-26.05`.
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rebuild and switch the current system (thinkpad)
|
||||||
|
sudo nixos-rebuild switch --flake ~/.dotfiles#thinkpad
|
||||||
|
|
||||||
|
# Check the flake for errors without applying
|
||||||
|
nix flake check
|
||||||
|
|
||||||
|
# Update flake inputs (e.g. nixpkgs, home-manager)
|
||||||
|
nix flake update
|
||||||
|
|
||||||
|
# Open the flake entrypoint in nvim
|
||||||
|
enix # alias: nvim ~/.dotfiles/flake.nix
|
||||||
|
|
||||||
|
# Open the home-manager user config in nvim
|
||||||
|
ehome # alias: nvim ~/.dotfiles/home/jashton.nix
|
||||||
|
|
||||||
|
# List registered ports
|
||||||
|
ports # alias: cat ~/.dotfiles/ports.registry
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
The repo is structured as a standard Nix Flakes configuration. `flake.nix` defines `nixosConfigurations` for each host and wires in Home Manager as a NixOS module. Each host's Home Manager is pointed at a single shared user config (`home/jashton.nix`).
|
||||||
|
|
||||||
|
```
|
||||||
|
flake.nix # Entrypoint; defines per-host nixosConfigurations
|
||||||
|
hosts/<host>/default.nix # Host-specific config (imports hardware.nix + system/)
|
||||||
|
hosts/<host>/hardware.nix # nixos-generate-config output (don't manually edit)
|
||||||
|
system/ # Shared NixOS system config (all hosts)
|
||||||
|
default.nix # Aggregates: packages, core, network, security, services, virtualisation
|
||||||
|
packages.nix # System-level packages + allowUnfree
|
||||||
|
core/ # Zsh, fonts, nix settings, locale, boot, audio, power
|
||||||
|
security/ # Users, sudo, polkit, TPM2, systemd hardening
|
||||||
|
services/ # Display manager (GDM), Xserver, i3 WM, picom, printing, Bluetooth
|
||||||
|
network/ # Pi-hole config
|
||||||
|
virtualisation/ # VM/container support
|
||||||
|
home/jashton.nix # Home Manager user config; shared across all hosts
|
||||||
|
home/programs/ # Per-program HM config: alacritty, git, nvim
|
||||||
|
home/desktop/ # Desktop environment: i3, polybar, rofi, dunst, gnome dconf
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Design Decisions
|
||||||
|
|
||||||
|
- **Dual desktop environment**: Both GNOME (GDM display manager) and i3 (window manager via Xserver) are configured and co-exist. GNOME extensions are declared via `dconf.settings` in `home/desktop/gnome.nix`.
|
||||||
|
- **Shell scripts as Nix packages**: Custom scripts (`find-open-port`, `lock-screen`, `power-menu`, `weather-cache`) are defined inline in `home/jashton.nix` using `pkgs.writeShellScriptBin` so they are on `$PATH` without a separate scripts directory.
|
||||||
|
- **Port registry**: `ports.registry` is a plain-text file tracking assigned dev ports 8000–8999. The `find-open-port` script appends to it; don't assign ports manually without checking it first.
|
||||||
|
- **Zsh configured at system level**: `programs.zsh` (aliases, Oh My Zsh, history) lives in `system/core/env.nix`. The `~/.zshrc` written by Home Manager is intentionally a stub to suppress the zsh-newuser-install prompt.
|
||||||
|
- **Host hardware files**: `hosts/thinkpad/hardware.nix` is auto-generated by `nixos-generate-config`. Edits here (e.g. Howdy IR camera path `/dev/video66`) are intentional overrides — don't regenerate and overwrite.
|
||||||
|
- **`stateVersion`**: Both `system.stateVersion` and `home.stateVersion` are set to `"26.05"`. Do not change these.
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./dunst.nix
|
./dunst.nix
|
||||||
|
./gnome.nix
|
||||||
./i3.nix
|
./i3.nix
|
||||||
./polybar.nix
|
./polybar.nix
|
||||||
./rofi.nix
|
./rofi.nix
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
dconf.settings = {
|
||||||
|
"org/gnome/desktop/interface" = {
|
||||||
|
color-scheme = "prefer-dark";
|
||||||
|
accent-color = "purple";
|
||||||
|
};
|
||||||
|
|
||||||
|
"org/gnome/shell" = {
|
||||||
|
enabled-extensions = [
|
||||||
|
pkgs.gnomeExtensions.blur-my-shell.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.caffeine.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.clipboard-indicator.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.dash-to-panel.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.gjs-osk.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.gsconnect.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.just-perfection.extensionUuid
|
||||||
|
pkgs.gnomeExtensions.removable-drive-menu.extensionUuid
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
qt = {
|
||||||
|
enable = true;
|
||||||
|
platformTheme.name = "gnome";
|
||||||
|
style.name = "adwaita-dark";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
config = null;
|
config = null;
|
||||||
extraConfig = (builtins.readFile ./i3/config) + ''
|
extraConfig = (builtins.readFile ./i3/config) + ''
|
||||||
exec --no-startup-id ${pkgs.feh}/bin/feh --bg-fill ${./assets/samuraii.jpg}
|
exec --no-startup-id ${pkgs.feh}/bin/feh --bg-fill ${./assets/samuraii.jpg}
|
||||||
|
exec --no-startup-id ${pkgs.picom}/bin/picom --backend glx --vsync
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -13,24 +13,24 @@
|
|||||||
# This file exists solely to prevent the zsh-newuser-install prompt.
|
# This file exists solely to prevent the zsh-newuser-install prompt.
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
WINIT_X11_SCALE_FACTOR = "1.0";
|
|
||||||
};
|
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
aider-chat
|
aider-chat
|
||||||
animdl
|
animdl
|
||||||
asciinema
|
asciinema
|
||||||
claude-code
|
claude-code
|
||||||
discord
|
discord
|
||||||
|
ffmpeg
|
||||||
freetube
|
freetube
|
||||||
gemini-cli
|
gemini-cli
|
||||||
intelli-shell
|
intelli-shell
|
||||||
jrnl
|
jrnl
|
||||||
keepass
|
keepass
|
||||||
|
libreoffice
|
||||||
mc
|
mc
|
||||||
scrot
|
scrot
|
||||||
spotify
|
spotify
|
||||||
|
vlc
|
||||||
|
yt-dlp
|
||||||
|
|
||||||
(pkgs.writeShellScriptBin "find-open-port" ''
|
(pkgs.writeShellScriptBin "find-open-port" ''
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
family = "Hack Nerd Font";
|
family = "Hack Nerd Font";
|
||||||
style = "Mono";
|
style = "Mono";
|
||||||
};
|
};
|
||||||
size = 8.0;
|
size = 14.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "usbhid" "sd_mod" ];
|
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "usbhid" "sd_mod" "uvcvideo" ];
|
||||||
boot.initrd.kernelModules = [ ];
|
boot.initrd.kernelModules = [ ];
|
||||||
boot.kernelModules = [ "kvm-intel" ];
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
boot.extraModulePackages = [ ];
|
boot.extraModulePackages = [ ];
|
||||||
@@ -25,12 +25,46 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
swapDevices =
|
swapDevices =
|
||||||
[ { device = "/dev/disk/by-uuid/332e7db3-3f68-4fd7-be2a-0d091ac936ae"; }
|
[ { device = "/dev/disk/by-uuid/332e7db3-3f68-4fd7-be2a-0d091ac936ae"; } ];
|
||||||
];
|
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
SUBSYSTEM=="video4linux", ATTRS{interface}=="Integrated IR Camera", ATTR{index}=="0", SYMLINK+="video-ir"
|
||||||
|
'';
|
||||||
|
|
||||||
|
services.howdy = {
|
||||||
|
enable = true;
|
||||||
|
control = "sufficient";
|
||||||
|
settings = {
|
||||||
|
video = {
|
||||||
|
device_path = "/dev/video-ir";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.linux-enable-ir-emitter.enable = true;
|
||||||
|
|
||||||
|
powerManagement.resumeCommands = ''
|
||||||
|
${pkgs.linux-enable-ir-emitter}/bin/linux-enable-ir-emitter run
|
||||||
|
'';
|
||||||
|
|
||||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
hardware = {
|
hardware = {
|
||||||
cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
bluetooth.enable = true;
|
sensor.iio.enable = true;
|
||||||
|
|
||||||
|
bluetooth = {
|
||||||
|
enable = true;
|
||||||
|
powerOnBoot = true;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
General = {
|
||||||
|
Experimental = true;
|
||||||
|
KernelExperimental = true;
|
||||||
|
|
||||||
|
ControllerMode = "dual";
|
||||||
|
Enable = "Source,Sink,Media,Socket";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
security.rtkit.enable = true;
|
||||||
|
services.avahi.enable = true;
|
||||||
|
services.pulseaudio.enable = false;
|
||||||
|
|
||||||
|
systemd.user.services.mpris-proxy = {
|
||||||
|
description = "Mpris proxy";
|
||||||
|
after = [ "network.target" "sound.target" ];
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa = {
|
||||||
|
enable = true;
|
||||||
|
support32Bit = true;
|
||||||
|
};
|
||||||
|
pulse.enable = true;
|
||||||
|
wireplumber.enable = true;
|
||||||
|
raopOpenFirewall = true;
|
||||||
|
|
||||||
|
# Dynamic, optimized buffer sizes to eliminate data starvation
|
||||||
|
extraConfig.pipewire = {
|
||||||
|
"context.properties" = {
|
||||||
|
"default.clock.rate" = 48000;
|
||||||
|
"default.clock.quantum" = 1024;
|
||||||
|
"default.clock.min-quantum" = 512;
|
||||||
|
"default.clock.max-quantum" = 2048;
|
||||||
|
};
|
||||||
|
|
||||||
|
"10-airplay" = {
|
||||||
|
"context-modules" = [
|
||||||
|
{
|
||||||
|
name = "libpipewire-module-raop-discover";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
wireplumber.extraConfig = {
|
||||||
|
"10-bluetooth-policy" = {
|
||||||
|
"wireplumber.settings" = {
|
||||||
|
"bluetooth.autoswitch-to-headset" = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Properly disables node suspension using WirePlumber 0.5+ syntax
|
||||||
|
"10-disable-suspend" = {
|
||||||
|
"monitor.bluez.rules" = [
|
||||||
|
{
|
||||||
|
matches = [
|
||||||
|
{
|
||||||
|
"node.name" = "~bluez_output.*";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
"session.suspend-timeout-seconds" = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Force High Quality Audio profiles ONLY (Blocks Handsfree Mic Downgrades)
|
||||||
|
"11-bluetooth-enhancements" = {
|
||||||
|
"monitor.bluez.properties" = {
|
||||||
|
"bluez5.roles" = [ "a2dp_sink" "a2dp_source" ];
|
||||||
|
"bluez5.codecs" = [ "aac" "aptx" "sbc" ];
|
||||||
|
"bluez5.enable-sbc-xq" = false;
|
||||||
|
"bluez5.enable-hw-volume" = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
./audio.nix
|
||||||
./boot.nix
|
./boot.nix
|
||||||
./env.nix
|
./env.nix
|
||||||
./locale.nix
|
./locale.nix
|
||||||
|
|||||||
+5
-1
@@ -8,6 +8,10 @@
|
|||||||
nerd-fonts.hack
|
nerd-fonts.hack
|
||||||
];
|
];
|
||||||
|
|
||||||
|
environment.sessionVariables = {
|
||||||
|
NIXOS_OZONE_WL = "1";
|
||||||
|
};
|
||||||
|
|
||||||
nix.settings = {
|
nix.settings = {
|
||||||
experimental-features = [ "nix-command" "flakes" ];
|
experimental-features = [ "nix-command" "flakes" ];
|
||||||
};
|
};
|
||||||
@@ -26,10 +30,10 @@
|
|||||||
|
|
||||||
shellAliases = {
|
shellAliases = {
|
||||||
enix = "nvim $HOME/.dotfiles/flake.nix";
|
enix = "nvim $HOME/.dotfiles/flake.nix";
|
||||||
unix = "sudo nixos-rebuild switch --flake $HOME/.dotfiles#thinkpad";
|
|
||||||
ehome = "nvim $HOME/.dotfiles/home/jashton.nix";
|
ehome = "nvim $HOME/.dotfiles/home/jashton.nix";
|
||||||
l = "ls -la";
|
l = "ls -la";
|
||||||
ports = "cat $HOME/.dotfiles/ports.registry";
|
ports = "cat $HOME/.dotfiles/ports.registry";
|
||||||
|
accentum = "bluetoothctl connect 80:C3:BA:50:43:DF";
|
||||||
};
|
};
|
||||||
|
|
||||||
ohMyZsh = {
|
ohMyZsh = {
|
||||||
|
|||||||
@@ -13,7 +13,16 @@
|
|||||||
firefox
|
firefox
|
||||||
git
|
git
|
||||||
github-cli
|
github-cli
|
||||||
|
gnomeExtensions.blur-my-shell
|
||||||
|
gnomeExtensions.caffeine
|
||||||
|
gnomeExtensions.clipboard-indicator
|
||||||
|
gnomeExtensions.dash-to-panel
|
||||||
|
gnomeExtensions.gjs-osk
|
||||||
|
gnomeExtensions.gsconnect
|
||||||
|
gnomeExtensions.just-perfection
|
||||||
|
gnomeExtensions.removable-drive-menu
|
||||||
gnome-keyring
|
gnome-keyring
|
||||||
|
gnome-network-displays
|
||||||
google-chrome
|
google-chrome
|
||||||
libnotify
|
libnotify
|
||||||
mypy
|
mypy
|
||||||
@@ -23,13 +32,54 @@
|
|||||||
picom
|
picom
|
||||||
polkit_gnome
|
polkit_gnome
|
||||||
pulseaudioFull
|
pulseaudioFull
|
||||||
|
rnote
|
||||||
tldr
|
tldr
|
||||||
tmux
|
tmux
|
||||||
unrar
|
unrar
|
||||||
unzip
|
unzip
|
||||||
|
v4l-utils
|
||||||
vim
|
vim
|
||||||
wget
|
wget
|
||||||
xclip
|
xclip
|
||||||
|
xournalpp
|
||||||
|
|
||||||
|
(pkgs.writeShellScriptBin "unix" ''
|
||||||
|
set -u
|
||||||
|
|
||||||
|
DOTFILES="$HOME/.dotfiles"
|
||||||
|
ERRFILE=$(mktemp)
|
||||||
|
trap "rm -f '$ERRFILE'" EXIT
|
||||||
|
|
||||||
|
echo "Building NixOS..."
|
||||||
|
sudo nixos-rebuild switch --flake "$DOTFILES#thinkpad" 2>&1 | tee "$ERRFILE"
|
||||||
|
STATUS=''${PIPESTATUS[0]}
|
||||||
|
|
||||||
|
if [ "$STATUS" -ne 0 ]; then
|
||||||
|
PATTERN=$(find "$DOTFILES" -type f -name "*.nix" -printf "%f\n" | sort -u | tr '\n' '|' | sed 's/|$//')
|
||||||
|
MATCHES=$(grep -E "$PATTERN" "$ERRFILE" | sort -u)
|
||||||
|
if [ -n "$MATCHES" ]; then
|
||||||
|
printf '\nErrors in repo files:\n%s\n' "$MATCHES"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
GEN=$(readlink /nix/var/nix/profiles/system | sed 's/system-\([0-9]*\)-link/\1/')
|
||||||
|
VER=$(nixos-version)
|
||||||
|
TIMESTAMP=$(date '+%Y-%m-%d %H:%M')
|
||||||
|
|
||||||
|
cd "$DOTFILES"
|
||||||
|
|
||||||
|
if [ -z "$(${pkgs.git}/bin/git status --porcelain)" ]; then
|
||||||
|
echo "Generation $GEN active — no config changes to commit."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.git}/bin/git add -A
|
||||||
|
${pkgs.git}/bin/git commit -m "nixos: gen $GEN @ $(hostname) — $TIMESTAMP
|
||||||
|
|
||||||
|
$VER"
|
||||||
|
${pkgs.git}/bin/git push
|
||||||
|
'')
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.firefox.enable = true;
|
programs.firefox.enable = true;
|
||||||
|
|||||||
@@ -10,5 +10,11 @@
|
|||||||
security = {
|
security = {
|
||||||
polkit.enable = true;
|
polkit.enable = true;
|
||||||
rtkit.enable = true;
|
rtkit.enable = true;
|
||||||
|
|
||||||
|
tpm2 = {
|
||||||
|
enable = true;
|
||||||
|
pkcs11.enable = true;
|
||||||
|
tctiEnvironment.enable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
description = "Josh Ashton";
|
description = "Josh Ashton";
|
||||||
group = "jashton";
|
group = "jashton";
|
||||||
extraGroups = [ "networkmanager" "wheel" ];
|
extraGroups = [ "networkmanager" "wheel" "tss" "video" ];
|
||||||
|
|
||||||
shell = pkgs.zsh;
|
shell = pkgs.zsh;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,8 +2,12 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
services = {
|
services = {
|
||||||
displayManager = {
|
displayManager.gdm.enable = true;
|
||||||
ly.enable = true;
|
desktopManager.gnome.enable = true;
|
||||||
|
gnome = {
|
||||||
|
core-apps.enable = true;
|
||||||
|
core-developer-tools.enable = true;
|
||||||
|
games.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
xserver = {
|
xserver = {
|
||||||
@@ -27,13 +31,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
picom = {
|
|
||||||
enable = true;
|
|
||||||
backend = "glx";
|
|
||||||
vSync = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
libinput = {
|
libinput = {
|
||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
@@ -46,13 +43,5 @@
|
|||||||
gvfs.enable = true;
|
gvfs.enable = true;
|
||||||
gnome.gnome-keyring.enable = true;
|
gnome.gnome-keyring.enable = true;
|
||||||
blueman.enable = true;
|
blueman.enable = true;
|
||||||
pipewire = {
|
|
||||||
enable = true;
|
|
||||||
alsa = {
|
|
||||||
enable = true;
|
|
||||||
support32Bit = true;
|
|
||||||
};
|
|
||||||
pulse.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user