commit 11ce3ba32fc66f7584920849c50e41afd57b3ac9
Author: DerGrumpf
Date: Wed Feb 18 21:23:56 2026 +0100
Init
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6bc3095
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,43 @@
+# Nix build outputs
+result
+result-*
+*.img
+*.img.zst
+*.qcow2
+
+# Nix store
+.dirlocals
+
+# Build artifacts
+*.o
+*.a
+*.so
+*.dylib
+
+# IDE/Editor
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+.DS_Store
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Archives
+*.tar.gz
+*.tar.bz2
+*.zip
+
+# Local development
+.envrc
+direnv.allow
+
+# Flake lock (optional - usually committed, but some prefer not to)
+# flake.lock
+
+# Temporary files
+*.tmp
+*.bak
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ed59ff0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,110 @@
+# cyper-servers
+
+NixOS flake configuration for x86_64 server infrastructure.
+
+## Hosts
+
+| Host | IP | DNS | Role |
+|------|----|-----|------|
+| `cyper-controller` | `192.168.2.2` (static) | `127.0.0.1`, `1.1.1.1` | k3s master, PostgreSQL, DNS/DHCP |
+| `cyper-node1` | `192.168.2.30` (static) | `192.168.2.2` | k3s agent |
+| `cyper-node2` | `192.168.2.31` (static) | `192.168.2.2` | k3s agent |
+| `cyper-cluster` | DHCP | `1.1.1.1`, `8.8.8.8` | k3s agent, Helm |
+| `cyper-cloud` | DHCP | `1.1.1.1`, `8.8.8.8` | Cloud tooling (Terraform, AWS CLI) |
+
+## Directory Structure
+
+```
+cyper-servers/
+├── flake.nix # Main flake — declares all hosts
+├── nixos/
+│ ├── default.nix # Shared NixOS config (users, SSH, Nix settings)
+│ ├── hardware.nix # x86_64 bootloader & filesystem config
+│ ├── settings.nix # Locale & timezone
+│ └── packages.nix # Common system packages
+├── home/ # Home Manager (shared across all hosts)
+│ ├── default.nix
+│ ├── packages.nix
+│ ├── git.nix
+│ ├── shell.nix
+│ └── neovim/
+└── hosts/
+ ├── services/
+ │ ├── k3s-master.nix # Reusable k3s server module
+ │ └── k3s-agent.nix # Reusable k3s agent module
+ ├── cyper-controller/
+ │ ├── configuration.nix # Static IP, imports master + postgres + dns
+ │ ├── postgres.nix # PostgreSQL (x86_64 tuned)
+ │ └── dns.nix # dnsmasq DNS + DHCP server
+ ├── cyper-node1/
+ │ └── configuration.nix # Static 192.168.2.30, k3s agent
+ ├── cyper-node2/
+ │ └── configuration.nix # Static 192.168.2.31, k3s agent
+ ├── cyper-cluster/
+ │ └── configuration.nix # DHCP, k3s agent + Helm
+ └── cyper-cloud/
+ └── configuration.nix # DHCP, Terraform + AWS CLI
+```
+
+## Quick Start
+
+### 1. Install NixOS on each machine
+
+Boot from a standard NixOS x86_64 ISO and partition your disk with labels `boot` (FAT32) and `nixos` (ext4), then:
+
+```bash
+nixos-generate-config --root /mnt
+```
+
+### 2. Clone and apply
+
+```bash
+git clone /etc/nixos
+cd /etc/nixos
+nixos-rebuild switch --flake .#cyper-controller # on the controller
+nixos-rebuild switch --flake .#cyper-node1 # on node1
+# ... etc
+```
+
+### 3. k3s cluster setup
+
+After `cyper-controller` is up, retrieve the node token and apply it on each agent:
+
+```bash
+# On cyper-controller:
+cat /var/lib/rancher/k3s/server/node-token
+
+# On each agent, set the token in the k3s service environment:
+# Edit hosts/services/k3s-agent.nix and add:
+# tokenFile = "/etc/k3s-token";
+# Then create /etc/k3s-token with the token value and rebuild.
+```
+
+## Customization
+
+### Change username
+
+Edit `flake.nix`:
+```nix
+primaryUser = "your-username";
+```
+
+### Add packages per host
+
+Edit `hosts//configuration.nix` and add to `environment.systemPackages`.
+
+### Adjust PostgreSQL
+
+Edit `hosts/cyper-controller/postgres.nix` — memory settings are pre-tuned for x86_64 with 8GB+ RAM.
+
+### DNS entries
+
+Edit `hosts/cyper-controller/dns.nix` to add static A records or adjust DHCP ranges.
+
+## Locale & Timezone
+
+Defaults (same as cyper-rpi):
+- **Timezone**: `Europe/Berlin`
+- **Locale**: `en_US.UTF-8` with German regional settings
+
+Change in `nixos/settings.nix`.
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..502c2c3
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,122 @@
+{
+ "nodes": {
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "nixvim",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1769996383,
+ "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "home-manager": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1770995331,
+ "narHash": "sha256-MZOF7PVKDOMAOp6bJpzuKOb1DVcyUT84568r8y3iVGg=",
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "rev": "5e90b62996d56da9acb21e502c078e7c4e6ab40f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "master",
+ "repo": "home-manager",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1770843696,
+ "narHash": "sha256-LovWTGDwXhkfCOmbgLVA10bvsi/P8eDDpRudgk68HA8=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "2343bbb58f99267223bc2aac4fc9ea301a155a16",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1770380644,
+ "narHash": "sha256-P7dWMHRUWG5m4G+06jDyThXO7kwSk46C1kgjEWcybkE=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "ae67888ff7ef9dff69b3cf0cc0fbfbcd3a722abe",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixvim": {
+ "inputs": {
+ "flake-parts": "flake-parts",
+ "nixpkgs": "nixpkgs_2",
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1770954048,
+ "narHash": "sha256-TEXS8Z7K+GsOOtL0QD1hrMxL0lVJjKDl3qZq/mJHu2k=",
+ "owner": "nix-community",
+ "repo": "nixvim",
+ "rev": "e49b8deda7b1732f5a2ea2a90446e45adb2a121d",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "nixvim",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "home-manager": "home-manager",
+ "nixpkgs": "nixpkgs",
+ "nixvim": "nixvim"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..8a36585
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,125 @@
+{
+ description = "NixOS Configuration for x86_64 Servers";
+
+ # Binary Cache configuration
+ nixConfig = {
+ extra-substituters = [ "https://nix-community.cachix.org" ];
+ extra-trusted-public-keys = [
+ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
+ ];
+
+ http-connections = 4;
+ download-buffer-size = 268435456; # 256MB
+ };
+
+ # External Dependencies
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+ home-manager.url = "github:nix-community/home-manager/master";
+ home-manager.inputs.nixpkgs.follows = "nixpkgs";
+ nixvim.url = "github:nix-community/nixvim";
+ };
+
+ outputs =
+ {
+ self,
+ nixpkgs,
+ home-manager,
+ nixvim,
+ ...
+ }@inputs:
+ let
+ primaryUser = "phil";
+ system = "x86_64-linux";
+
+ # Configure Home Manager
+ homeManagerModule = {
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users.${primaryUser} = import ./home/default.nix;
+ extraSpecialArgs = { inherit inputs primaryUser; };
+ backupFileExtension = "backup";
+ };
+ };
+
+ # Modules needed regardless of config
+ commonModules = hostName: [
+ home-manager.nixosModules.home-manager
+ homeManagerModule
+ ./hosts/${hostName}/configuration.nix
+ ];
+
+ # Wrapper around nixpkgs.lib.nixosSystem; pins system and specialArgs
+ mkSystem =
+ modules:
+ nixpkgs.lib.nixosSystem {
+ inherit system;
+ modules = modules;
+ specialArgs = { inherit inputs self primaryUser; };
+ };
+
+ # Builds a full installed NixOS system for given Host
+ mkNixosConfig =
+ hostName:
+ mkSystem (
+ [
+ ./nixos/default.nix
+ ./nixos/hardware.nix
+ ]
+ ++ commonModules hostName
+ );
+
+ # Build a bootable installer ISO for given Host
+ mkISOConfig =
+ hostName:
+ (mkSystem (
+ [
+ "${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
+ ./nixos/settings.nix
+ ./nixos/packages.nix
+ # Re-declare the user for the ISO context — default.nix is excluded
+ # because it imports hardware.nix which conflicts with the ISO profile,
+ # but Home Manager still needs a valid user to activate against.
+ {
+ nixpkgs.config.allowUnfree = true;
+ programs.fish.enable = true;
+ users.users.${primaryUser} = {
+ isNormalUser = true;
+ group = primaryUser;
+ hashedPassword = "$6$TqAclAMz/DFP90Ve$HEN4t1pqK36rACeWctJOmLArkTWb/rIBYamu4sY8bPuDnqkVVyfOLqXKkgX8zBf9LKz02.mo4EKFRnYWIzcAX1";
+ extraGroups = [ "wheel" ];
+ shell = nixpkgs.legacyPackages.${system}.fish;
+ openssh.authorizedKeys.keys = [
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuYuGhqRC/QLoRBH91c3DG5JHlAdRLQsvde18k5ipY2 phil@cyperpunk.de"
+ ];
+ };
+ users.groups.${primaryUser} = { };
+ }
+ ]
+ ++ commonModules hostName
+ )).config.system.build.isoImage;
+ in
+ {
+ # Installed system configurations
+ # nixos-rebuild switch --flake .#
+ nixosConfigurations = {
+ "cyper-controller" = mkNixosConfig "cyper-controller";
+ "cyper-node1" = mkNixosConfig "cyper-node1";
+ "cyper-node2" = mkNixosConfig "cyper-node2";
+ "cyper-cluster" = mkNixosConfig "cyper-cluster";
+ "cyper-cloud" = mkNixosConfig "cyper-cloud";
+ };
+
+ # Create installer ISOs
+ # nix build .#isoImages.
+ isoImages = {
+ "cyper-controller" = mkISOConfig "cyper-controller";
+ "cyper-node1" = mkISOConfig "cyper-node1";
+ "cyper-node2" = mkISOConfig "cyper-node2";
+ "cyper-cluster" = mkISOConfig "cyper-cluster";
+ "cyper-cloud" = mkISOConfig "cyper-cloud";
+ };
+ };
+
+}
diff --git a/home/default.nix b/home/default.nix
new file mode 100644
index 0000000..3bb8a86
--- /dev/null
+++ b/home/default.nix
@@ -0,0 +1,21 @@
+{ primaryUser, inputs, ... }:
+{
+ imports = [
+ ./packages.nix
+ ./git.nix
+ ./shell.nix
+
+ inputs.nixvim.homeModules.nixvim
+ ./neovim
+ # ./python.nix
+
+ ];
+
+ home = {
+ username = primaryUser;
+ stateVersion = "25.11";
+ sessionVariables = {
+ GROQ_API_KEY = "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";
+ };
+ };
+}
diff --git a/home/fastfetch.jsonc b/home/fastfetch.jsonc
new file mode 100644
index 0000000..fa90e1b
--- /dev/null
+++ b/home/fastfetch.jsonc
@@ -0,0 +1,171 @@
+{
+ "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
+ "logo": {
+ "type": "kitty-icat",
+ "source": "nixos",
+ // "height": 15,
+ "width": 12,
+ "padding": {
+ "top": 0,
+ "left": 0
+ }
+ },
+ "modules": [
+ "break",
+ {
+ "type": "custom",
+ "format": "\u001b[90m┌──────────────────────Hardware──────────────────────┐"
+ },
+ {
+ "type": "host",
+ "key": " PC",
+ "keyColor": "green"
+ },
+ {
+ "type": "cpu",
+ "key": "│ ├",
+ "keyColor": "green"
+ },
+ {
+ "type": "gpu",
+ "key": "│ ├",
+ "keyColor": "green"
+ },
+ {
+ "type": "disk",
+ "key": "│ ├",
+ "keyColor": "green"
+ },
+ {
+ "type": "memory",
+ "key": "└ └",
+ "keyColor": "green"
+ },
+ {
+ "type": "custom",
+ "format": "\u001b[90m└────────────────────────────────────────────────────┘"
+ },
+ "break",
+ {
+ "type": "custom",
+ "format": "\u001b[90m┌──────────────────────Software──────────────────────┐"
+ },
+ {
+ "type": "os",
+ "key": " OS",
+ "keyColor": "yellow"
+ },
+ {
+ "type": "kernel",
+ "key": "│ ├",
+ "keyColor": "yellow"
+ },
+ {
+ "type": "bios",
+ "key": "│ ├",
+ "keyColor": "yellow"
+ },
+ {
+ "type": "packages",
+ "key": "│ ├",
+ "keyColor": "yellow"
+ },
+ {
+ "type": "shell",
+ "key": "└ └",
+ "keyColor": "yellow"
+ },
+ "break",
+ {
+ "type": "de",
+ "key": " DE",
+ "keyColor": "blue"
+ },
+ {
+ "type": "lm",
+ "key": "│ ├",
+ "keyColor": "blue"
+ },
+ {
+ "type": "wm",
+ "key": "│ ├",
+ "keyColor": "blue"
+ },
+ {
+ "type": "wmtheme",
+ "key": "│ ├",
+ "keyColor": "blue"
+ },
+ {
+ "type": "terminal",
+ "key": "└ └",
+ "keyColor": "blue"
+ },
+ {
+ "type": "custom",
+ "format": "\u001b[90m└────────────────────────────────────────────────────┘"
+ },
+ "break",
+ {
+ "type": "custom",
+ "format": "\u001b[90m┌─────────────────Uptime / Age / DT──────────────────┐"
+ },
+ {
+ "type": "command",
+ "key": " OS Age ",
+ "keyColor": "magenta",
+ "text": "birth_install=$(stat -c %W /); current=$(date +%s); time_progression=$((current - birth_install)); days_difference=$((time_progression / 86400)); echo $days_difference days"
+ },
+ {
+ "type": "uptime",
+ "key": " Uptime ",
+ "keyColor": "magenta"
+ },
+ {
+ "type": "datetime",
+ "key": " DateTime ",
+ "keyColor": "magenta"
+ },
+ {
+ "type": "custom",
+ "format": "\u001b[90m└────────────────────────────────────────────────────┘"
+ },
+ "break",
+ {
+ "type": "custom",
+ "format": "\u001b[90m┌─────────────────────Networking─────────────────────┐"
+ },
+ {
+ "type": "publicip",
+ "key": " Public ",
+ "keyColor": "magenta"
+ },
+ {
+ "type": "localip",
+ "key": " Local ",
+ "keyColor": "magenta"
+ },
+ {
+ "type": "dns",
+ "key": " DNS ",
+ "keyColor": "magenta"
+ },
+ {
+ "type": "netio",
+ "key": " Net I/O ",
+ "keyColor": "magenta"
+ },
+ {
+ "type": "custom",
+ "format": "\u001b[90m└────────────────────────────────────────────────────┘"
+ },
+ {
+ "type": "colors",
+ "paddingLeft": 2,
+ "symbol": "circle"
+ },
+ "break",
+ ]
+}
+
+
diff --git a/home/git.nix b/home/git.nix
new file mode 100644
index 0000000..daf61f0
--- /dev/null
+++ b/home/git.nix
@@ -0,0 +1,26 @@
+{ pkgs, primaryUser, ... }:
+{
+ programs.git = {
+ enable = true;
+ settings = {
+ user = {
+ name = "DerGrumpf"; # TODO replace
+ email = "p.keier@beyerstedt-it.de"; # TODO replace
+ };
+ github = {
+ user = primaryUser;
+ };
+ init = {
+ defaultBranch = "main";
+ };
+ };
+ lfs.enable = true;
+ ignores = [ "**/.DS_STORE" ];
+ };
+
+ home.packages = with pkgs; [
+ gh
+ gitui
+ ];
+
+}
diff --git a/home/neovim/alpha.nix b/home/neovim/alpha.nix
new file mode 100644
index 0000000..52357f4
--- /dev/null
+++ b/home/neovim/alpha.nix
@@ -0,0 +1,147 @@
+{ pkgs, ... }: {
+ # Alpha: Start screen/dashboard for Neovim
+ # Shows a custom ASCII art header and quick action buttons on startup.
+ programs.nixvim.plugins.alpha = {
+ enable = true;
+ settings.layout = [
+ {
+ type = "padding";
+ val = 2;
+ }
+ {
+ type = "text";
+ val = [
+ "⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣯⣿⠿⣟⣷⣯⣛⢿⣿⣿⣾⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿"
+ "⣿⣿⣿⣿⣿⣿⣿⡿⣵⣿⡿⣴⣽⡟⣳⢿⢽⣽⣕⣽⢿⡿⣿⣟⣿⣿⣿⣿⣿⣿⣿"
+ "⣿⣿⣿⣷⣿⣿⢟⣫⣿⢟⢟⣾⣾⣿⣿⣞⢳⣻⢞⣎⠿⢞⣊⣿⣞⣿⣿⣿⣿⣿⢽"
+ "⣿⣿⣿⣿⣿⣏⢯⣿⣏⣏⠔⢇⣿⢢⢆⢀⢆⣧⣼⢻⢰⡧⢻⣝⣏⡸⣧⣾⣿⣿⣿"
+ "⣿⣿⣿⣿⡟⣻⣿⣿⡾⡿⡼⢸⡝⣝⡳⢢⣧⢳⣳⢷⡇⣗⢺⡺⣿⡧⣿⣿⣿⢿⢿"
+ "⣿⡿⣿⣼⡼⣿⣿⡗⡧⣧⠁⡝⣧⣳⠅⡾⠈⣎⢮⣧⣿⣿⣗⣷⣻⢷⣏⣼⢏⣺⣿"
+ "⣿⣿⣿⣻⣿⣿⣿⢧⣿⢹⠉⢷⢿⣧⣲⡏⡀⡈⢆⠳⣿⡿⢿⣿⣱⢿⢫⣷⣝⣿⣿"
+ "⣿⣿⣿⡯⡟⣿⣿⢽⣡⠟⢿⣮⠁⠙⠛⠈⡴⢿⣿⡷⣬⣽⢽⠧⣷⡏⣿⡇⣧⣽⣿"
+ "⣿⠟⢻⡧⡇⣿⡇⣇⣆⢄⡜⢃⡀⡀⡀⡀⡀⢎⣁⠁⣸⣗⣸⣿⣧⣼⡿⢹⢿⢾⣿"
+ "⣿⣷⣾⣿⢻⣿⢧⢻⣽⡀⡀⡀⡀⢄⡀⡀⡀⡀⡀⢀⣷⡸⡟⣿⣶⣻⣧⡛⡱⢝⣿"
+ "⣿⣿⣿⣿⢸⡿⢚⡜⣿⣇⡀⡀⡀⡀⡀⡀⡀⡀⠚⢁⢣⣜⡿⣿⡇⢼⣿⠨⣸⣿⣿"
+ "⣿⣄⣿⣗⢾⢻⣧⢿⣾⣿⣦⡀⡀⠑⠚⠉⡀⡀⣤⣿⢨⣿⠗⣻⢣⣿⢹⢈⣽⣿⣿"
+ "⣿⣿⣿⣿⢎⡄⢿⣞⡇⣿⠹⣿⣶⣀⡀⣀⡴⡩⢸⢏⣿⣿⣶⢻⣾⢏⡞⠡⢽⣇⣾"
+ "⣿⣿⣿⣮⣼⢬⣦⢿⣳⣌⠧⡉⠈⣇⣛⣁⣈⣼⣿⡸⠫⠛⠐⠛⠕⣙⣻⣬⣼⣿⣿"
+ "⢟⢿⣿⣿⣿⡢⣃⣪⣭⣡⣤⣶⠟⡿⠿⠿⠿⠛⢁⣿⣿⢩⠉⡀⠈⠓⡝⣿⣿⣿⣿"
+ "⣾⣿⣿⣿⣿⠞⢔⡣⡴⣾⣿⠓⣤⢧⡼⣉⠠⢤⣿⣿⠇⠃⡀⡀⡀⡀⡸⢿⣾⣿⣿"
+ "⣿⣿⣿⡿⣺⡸⢗⢠⣇⣿⣿⠊⠃⡀⠉⡀⢠⣿⣿⠟⡸⡀⡀⡀⡀⡀⣃⣬⠽⠿⣿"
+ "⣿⣿⣿⣿⡇⡏⢸⣿⠟⣽⡇⡀⡀⡀⡀⣴⣟⢭⣾⣿⡇⠎⣠⠒⠉⠈⢀⡀⢨⡋⣿"
+ "⠛⠛⠛⠋⠃⠓⠚⠛⠘⠛⠃⡀⠊⡀⠛⠛⠛⠂⠛⠛⠓⠁⠚⡀⠂⠒⠒⠐⠒⠋⠛"
+ ];
+ opts = {
+ position = "center";
+ hl = "Type";
+ };
+ }
+ {
+ type = "padding";
+ val = 2;
+ }
+ {
+ type = "group";
+ val = [
+ {
+ type = "button";
+ val = "[+] New file";
+ on_press.__raw =
+ "function() vim.cmd[[ene]] vim.cmd[[startinsert]] end";
+ opts = {
+ keymap = [ "n" "e" ":ene startinsert " { } ];
+ shortcut = "e";
+ position = "center";
+ cursor = 3;
+ width = 50;
+ align_shortcut = "right";
+ hl_shortcut = "Keyword";
+ };
+ }
+ {
+ type = "button";
+ val = "[?] Find file";
+ on_press.__raw = "function() vim.cmd[[Telescope find_files]] end";
+ opts = {
+ keymap = [ "n" "f" ":Telescope find_files " { } ];
+ shortcut = "f";
+ position = "center";
+ cursor = 3;
+ width = 50;
+ align_shortcut = "right";
+ hl_shortcut = "Keyword";
+ };
+ }
+ {
+ type = "button";
+ val = "[~] Recent files";
+ on_press.__raw = "function() vim.cmd[[Telescope oldfiles]] end";
+ opts = {
+ keymap = [ "n" "r" ":Telescope oldfiles " { } ];
+ shortcut = "r";
+ position = "center";
+ cursor = 3;
+ width = 50;
+ align_shortcut = "right";
+ hl_shortcut = "Keyword";
+ };
+ }
+ {
+ type = "button";
+ val = "[Y] Yazi";
+ on_press.__raw = "function() require('yazi').yazi() end";
+ opts = {
+ keymap = [ "n" "y" ":Yazi" { } ];
+ shortcut = "y";
+ position = "center";
+ cursor = 3;
+ width = 50;
+ align_shortcut = "right";
+ hl_shortcut = "Keyword";
+ };
+ }
+ {
+ type = "button";
+ val = "[A] Open Prompt";
+ #on_press.__raw = "function() require('yazi').yazi() end";
+ opts = {
+ keymap = [ "n" "a" ":AvanteChatNew" { } ];
+ shortcut = "a";
+ position = "center";
+ cursor = 3;
+ width = 50;
+ align_shortcut = "right";
+ hl_shortcut = "Keyword";
+ };
+ }
+ {
+ type = "button";
+ val = "[X] Quit";
+ on_press.__raw = "function() vim.cmd[[qa]] end";
+ opts = {
+ keymap = [ "n" "q" ":qa" { } ];
+ shortcut = "q";
+ position = "center";
+ cursor = 3;
+ width = 50;
+ align_shortcut = "right";
+ hl_shortcut = "Keyword";
+ };
+ }
+ ];
+ }
+ {
+ type = "padding";
+ val = 2;
+ }
+ {
+ type = "text";
+ val = "Circuits hum in anticipation of your will.";
+ opts = {
+ position = "center";
+ hl = "Comment";
+ };
+ }
+ ];
+ };
+}
diff --git a/home/neovim/avante.nix b/home/neovim/avante.nix
new file mode 100644
index 0000000..edbbf9e
--- /dev/null
+++ b/home/neovim/avante.nix
@@ -0,0 +1,106 @@
+{ pkgs, ... }: {
+ # Avante: AI-powered coding assistant (Cursor-like experience in Neovim)
+ programs.nixvim = {
+
+ plugins = {
+ markdown-preview.enable = true;
+ render-markdown.enable = true;
+ #extraConfigLuaPre = ''
+ # vim.env.GROQ_API_KEY = os.getenv("GROQ_API_KEY")
+ #'';
+ # TODO: Integrate CoPilot https://github.com/settings/copilot/features
+ avante = {
+ enable = true;
+ autoLoad = true;
+ settings = {
+ provider = "groq";
+
+ providers.groq = {
+ __inherited_from = "openai";
+ api_key_name = "GROQ_API_KEY";
+ endpoint = "https://api.groq.com/openai/v1/";
+ model = "groq/compound-mini";
+ disable_tools = true;
+ extra_request_body = {
+ temperature = 1;
+ max_tokens = 8192;
+ tools = null;
+ tool_choice = "none";
+ };
+ };
+
+ # auto_suggestions_provider = "copilot";
+
+ render = { markdown = true; };
+
+ behaviour = {
+ auto_suggestions = false;
+ auto_set_highlight_group = true;
+ auto_set_keymaps = true;
+ auto_apply_diff_after_generation = false;
+ support_paste_from_clipboard = false;
+ };
+
+ mappings = {
+ ask = "aa";
+ edit = "ae";
+ refresh = "ar";
+ diff = {
+ ours = "co";
+ theirs = "ct";
+ all_theirs = "ca";
+ both = "cb";
+ cursor = "cc";
+ next = "]x";
+ prev = "[x";
+ };
+ suggestion = {
+ accept = "";
+ next = "";
+ prev = "";
+ dismiss = "";
+ };
+ jump = {
+ next = "]]";
+ prev = "[[";
+ };
+ submit = {
+ normal = "";
+ insert = "";
+ };
+ sidebar = {
+ switch_windows = "";
+ reverse_switch_windows = "";
+ };
+ };
+
+ hints = { enabled = true; };
+
+ windows = {
+ position = "right";
+ wrap = true;
+ width = 30;
+ sidebar_header = {
+ align = "center";
+ rounded = true;
+ };
+ };
+
+ highlights = {
+ diff = {
+ current = "DiffText";
+ incoming = "DiffAdd";
+ };
+ };
+
+ diff = {
+ autojump = true;
+ list_opener = "copen";
+ };
+ };
+ };
+
+ extraPackages = with pkgs; [ curl ];
+ };
+ };
+}
diff --git a/home/neovim/catppuccin.nix b/home/neovim/catppuccin.nix
new file mode 100644
index 0000000..98ba46c
--- /dev/null
+++ b/home/neovim/catppuccin.nix
@@ -0,0 +1,34 @@
+{ pkgs, ... }:
+{
+ # Catppuccin: Soothing pastel theme for Neovim
+ # Provides consistent theming across plugins with transparency support.
+ programs.nixvim = {
+ colorschemes.catppuccin = {
+ enable = true;
+ settings = {
+ flavour = "mocha";
+ transparent_background = true;
+ term_colors = true;
+ integrations = {
+ treesitter = true;
+ cmp = true;
+ gitsigns = true;
+ telescope = {
+ enabled = true;
+ };
+ notify = true;
+ mini = {
+ enabled = true;
+ };
+ };
+ };
+ };
+
+ # Custom highlight overrides
+ extraConfigLua = ''
+ local colors = require("catppuccin.palettes").get_palette("mocha")
+ vim.api.nvim_set_hl(0, "LineNr", { fg = colors.text, bg = "NONE" })
+ vim.api.nvim_set_hl(0, "CursorLineNr", { fg = colors.pink, bg = "NONE", bold = true })
+ '';
+ };
+}
diff --git a/home/neovim/conform.nix b/home/neovim/conform.nix
new file mode 100644
index 0000000..271ab5d
--- /dev/null
+++ b/home/neovim/conform.nix
@@ -0,0 +1,33 @@
+{ pkgs, ... }: {
+ # Conform: Code formatter that runs external formatting tools
+ # Automatically formats code on save for consistent style.
+ programs.nixvim = {
+ plugins.conform-nvim = {
+ enable = true;
+
+ settings = {
+ formatters_by_ft = {
+ lua = [ "stylua" ];
+ nix = [ "nixfmt" ];
+ python = [ "black" ];
+ rust = [ "rustfmt" ];
+ rasi = [ "prettierd" ];
+ };
+
+ format_on_save = {
+ timeout_ms = 2000;
+ lsp_fallback = true;
+ };
+ };
+ };
+
+ # Install formatters
+ extraPackages = with pkgs; [
+ stylua
+ nixfmt
+ black
+ rustfmt
+ prettierd
+ ];
+ };
+}
diff --git a/home/neovim/default.nix b/home/neovim/default.nix
new file mode 100644
index 0000000..df19ab4
--- /dev/null
+++ b/home/neovim/default.nix
@@ -0,0 +1,95 @@
+{ ... }:
+{
+ imports = [
+ ./treesitter.nix
+ ./lint.nix
+ ./lsp.nix
+ ./conform.nix
+ ./lualine.nix
+ ./yazi.nix
+ ./toggleterm.nix
+ ./telescope.nix
+ ./catppuccin.nix
+ ./alpha.nix
+ ./avante.nix
+ ./openscad.nix
+ # ./molten.nix
+ ./which-key.nix
+ ];
+
+ programs.nixvim = {
+ enable = true;
+ defaultEditor = true;
+
+ # Leader key
+ globals.mapleader = " ";
+
+ plugins.web-devicons.enable = true;
+
+ opts = {
+ number = true; # Show line numbers
+ cursorline = true; # Highlight current line
+ showmode = true; # already in statusline
+ hlsearch = true; # Highlight search result
+ incsearch = true; # Incremental Search
+ tabstop = 4;
+ termguicolors = true; # Enable 24-bit colormode
+ };
+
+ # Clipboard keymaps - yank to system clipboard
+ keymaps = [
+ # Yank operations
+ {
+ mode = "n";
+ key = "y";
+ action = ''"+y'';
+ options.desc = "Yank to clipboard";
+ }
+ {
+ mode = "v";
+ key = "y";
+ action = ''"+y'';
+ options.desc = "Yank to clipboard";
+ }
+ {
+ mode = "n";
+ key = "Y";
+ action = ''"+Y'';
+ options.desc = "Yank line to clipboard";
+ }
+ # Delete operations
+ {
+ mode = "n";
+ key = "d";
+ action = ''"+d'';
+ options.desc = "Delete to clipboard";
+ }
+ {
+ mode = "v";
+ key = "d";
+ action = ''"+d'';
+ options.desc = "Delete to clipboard";
+ }
+ {
+ mode = "n";
+ key = "D";
+ action = ''"+D'';
+ options.desc = "Delete line to clipboard";
+ }
+ # Paste operations
+ {
+ mode = "n";
+ key = "p";
+ action = ''"+p'';
+ options.desc = "Paste from clipboard";
+ }
+ {
+ mode = "v";
+ key = "p";
+ action = ''"+p'';
+ options.desc = "Paste from clipboard";
+ }
+ ];
+ };
+
+}
diff --git a/home/neovim/lint.nix b/home/neovim/lint.nix
new file mode 100644
index 0000000..ac178c6
--- /dev/null
+++ b/home/neovim/lint.nix
@@ -0,0 +1,42 @@
+{ pkgs, ... }:
+{
+ # nvim-lint: Asynchronous linter that runs external linting tools
+ # to find errors and style issues without blocking the editor.
+ # Runs automatically after saving files.
+ programs.nixvim = {
+ plugins.lint = {
+ enable = true;
+
+ # Configure linters for each filetype
+ lintersByFt = {
+ lua = [ "luacheck" ];
+ nix = [ "statix" ]; # Nix static analyzer
+ python = [ "ruff" ];
+ javascript = [ "eslint" ];
+ rust = [ "clippy" ];
+ # rasi has no common linter
+ };
+
+ # Trigger linting after saving a file
+ autoCmd = {
+ event = [ "BufWritePost" ];
+ callback = {
+ __raw = ''
+ function()
+ require('lint').try_lint()
+ end
+ '';
+ };
+ };
+ };
+
+ # Install linter binaries
+ extraPackages = with pkgs; [
+ lua54Packages.luacheck
+ statix
+ ruff
+ nodePackages.eslint
+ clippy
+ ];
+ };
+}
diff --git a/home/neovim/live-server.nix b/home/neovim/live-server.nix
new file mode 100644
index 0000000..70dea7e
--- /dev/null
+++ b/home/neovim/live-server.nix
@@ -0,0 +1,20 @@
+{ pkgs, ... }:
+{
+ # Live Server: Auto-reload browser for web development
+ # Uses browser-sync for live reload functionality
+ programs.nixvim = {
+ keymaps = [
+ {
+ mode = "n";
+ key = "ls";
+ action = "terminal browser-sync start --server --files '*.html, *.css, *.js' --no-notify";
+ options.desc = "Start live server (browser-sync)";
+ }
+ ];
+
+ extraPackages = with pkgs; [
+ nodePackages.browser-sync
+ biome
+ ];
+ };
+}
diff --git a/home/neovim/lsp.nix b/home/neovim/lsp.nix
new file mode 100644
index 0000000..8113fb3
--- /dev/null
+++ b/home/neovim/lsp.nix
@@ -0,0 +1,91 @@
+{ pkgs, ... }:
+{
+ # LSP configuration: Language Server Protocol provides IDE features
+ # like autocomplete, go-to-definition, diagnostics, and more.
+ programs.nixvim = {
+ plugins = {
+ # LSP configuration
+ lsp = {
+ enable = true;
+
+ # Language servers for each language
+ servers = {
+ lua_ls = {
+ enable = true;
+ settings = {
+ Lua = {
+ runtime.version = "LuaJIT";
+ diagnostics.globals = [ "vim" ];
+ workspace.library = [ ]; # Populated by nixvim
+ telemetry.enable = false;
+ };
+ };
+ };
+
+ nil_ls.enable = true; # Nix language server
+ rust_analyzer = {
+ enable = true; # Rust language server
+ installCargo = true;
+ installRustc = true;
+ };
+ pylsp.enable = true; # Python language server
+ };
+
+ # Keymaps for LSP actions
+ keymaps = {
+ diagnostic = {
+ "e" = "open_float";
+ "[d" = "goto_prev";
+ "]d" = "goto_next";
+ };
+ lspBuf = {
+ "gd" = "definition";
+ "K" = "hover";
+ "rn" = "rename";
+ "ca" = "code_action";
+ };
+ };
+ };
+
+ # Autocompletion
+ cmp = {
+ enable = true;
+ autoEnableSources = true;
+
+ settings = {
+ snippet.expand = ''
+ function(args)
+ require('luasnip').lsp_expand(args.body)
+ end
+ '';
+
+ mapping = {
+ "" = "cmp.mapping.scroll_docs(-4)";
+ "" = "cmp.mapping.scroll_docs(4)";
+ "" = "cmp.mapping.complete()";
+ "" = "cmp.mapping.abort()";
+ "" = "cmp.mapping.confirm({ select = true })";
+ };
+
+ sources = [
+ { name = "nvim_lsp"; }
+ { name = "luasnip"; }
+ { name = "buffer"; }
+ { name = "path"; }
+ ];
+ };
+ };
+
+ # Snippet engine (required for completion)
+ luasnip.enable = true;
+ };
+
+ # Install LSP servers
+ extraPackages = with pkgs; [
+ lua-language-server
+ nil
+ rust-analyzer
+ # python311Packages.python-lsp-server
+ ];
+ };
+}
diff --git a/home/neovim/lualine.nix b/home/neovim/lualine.nix
new file mode 100644
index 0000000..4f85435
--- /dev/null
+++ b/home/neovim/lualine.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+{
+ # Lualine: Fast and customizable statusline for Neovim
+ # Displays file info, git status, diagnostics, and mode at the bottom of the editor.
+ programs.nixvim.plugins.lualine = {
+ enable = true;
+
+ settings = {
+ options = {
+ theme = "catppuccin";
+ component_separators = {
+ left = "|";
+ right = "|";
+ };
+ section_separators = {
+ left = "";
+ right = "";
+ };
+ };
+ };
+ };
+}
diff --git a/home/neovim/molten.nix b/home/neovim/molten.nix
new file mode 100644
index 0000000..6b816ff
--- /dev/null
+++ b/home/neovim/molten.nix
@@ -0,0 +1,43 @@
+{ pkgs, ... }: {
+ programs.nixvim = {
+ plugins.molten = {
+ enable = true;
+ python3Dependencies = p:
+ with p; [
+ pynvim
+ jupyter-client
+ cairosvg
+ ipython
+ nbformat
+ ipykernel
+ pnglatex
+ plotly
+ kaleido
+ pyperclip
+ ];
+ settings = {
+ kernel_name = "python3";
+ auto_open_output = true;
+ output_win_max_width = 80;
+ output_win_max_height = 20;
+ };
+ };
+
+ keymaps = [
+ {
+ mode = "n";
+ key = "ml";
+ action = "MoltenEvaluateLine";
+ options.desc = "Molten: Evaluate line";
+ options.silent = true;
+ }
+ {
+ mode = "v";
+ key = "mv";
+ action = "MoltenEvaluateVisual";
+ options.desc = "Molten: Evaluate selection";
+ options.silent = true;
+ }
+ ];
+ };
+}
diff --git a/home/neovim/openscad.nix b/home/neovim/openscad.nix
new file mode 100644
index 0000000..b4934ab
--- /dev/null
+++ b/home/neovim/openscad.nix
@@ -0,0 +1,28 @@
+{ pkgs, ... }: {
+ # OpenSCAD: 3D modeling language support with syntax highlighting,
+ # cheatsheet, snippets, offline manual and fuzzy help
+ programs.nixvim = {
+ plugins.openscad = {
+ enable = true;
+ autoLoad = true;
+ settings = {
+ fuzzy_finder = "fzf";
+ auto_open = true;
+ cheatsheet_toggle_key = "os";
+ default_mappings = true;
+ exec_openscad_trig_key = "oo";
+ help_manual_trig_key = "om";
+ help_trig_key = "oh";
+ top_toggle = "oc";
+
+ };
+ };
+
+ # Install OpenSCAD binary for preview/compilation
+ extraPackages = with pkgs; [
+ openscad
+ zathura # PDF viewer for manual
+ fzf
+ ];
+ };
+}
diff --git a/home/neovim/telescope.nix b/home/neovim/telescope.nix
new file mode 100644
index 0000000..1d0e330
--- /dev/null
+++ b/home/neovim/telescope.nix
@@ -0,0 +1,27 @@
+{ pkgs, ... }:
+{
+ # Telescope: Fuzzy finder for files, buffers, grep, and more
+ # Provides fast search and navigation throughout your project.
+ programs.nixvim.plugins.telescope = {
+ enable = true;
+
+ keymaps = {
+ "ff" = {
+ action = "find_files";
+ options.desc = "Telescope find files";
+ };
+ "fg" = {
+ action = "live_grep";
+ options.desc = "Telescope live grep";
+ };
+ "fb" = {
+ action = "buffers";
+ options.desc = "Telescope buffers";
+ };
+ "fh" = {
+ action = "help_tags";
+ options.desc = "Telescope help tags";
+ };
+ };
+ };
+}
diff --git a/home/neovim/toggleterm.nix b/home/neovim/toggleterm.nix
new file mode 100644
index 0000000..3eca8a4
--- /dev/null
+++ b/home/neovim/toggleterm.nix
@@ -0,0 +1,64 @@
+{ pkgs, ... }:
+{
+ # ToggleTerm: Terminal emulator inside Neovim
+ # Provides floating, horizontal, and vertical terminal windows.
+ programs.nixvim.plugins.toggleterm = {
+ enable = true;
+
+ settings = {
+ size = 20;
+ open_mapping = "[[]]";
+ direction = "float";
+ float_opts = {
+ border = "single";
+ width = 200;
+ height = 40;
+ };
+ };
+ };
+
+ programs.nixvim.keymaps = [
+ {
+ mode = "n";
+ key = "h";
+ action.__raw = ''
+ function()
+ require("toggleterm").toggle(1, 10, vim.loop.cwd(), "horizontal")
+ end
+ '';
+ options.desc = "Toggle terminal (horizontal)";
+ }
+ {
+ mode = "n";
+ key = "v";
+ action.__raw = ''
+ function()
+ require("toggleterm").toggle(2, 60, vim.loop.cwd(), "vertical")
+ end
+ '';
+ options.desc = "Toggle terminal (vertical)";
+ }
+ {
+ mode = "n";
+ key = "ft";
+ action.__raw = ''
+ function()
+ require("toggleterm").toggle(3, 20, vim.loop.cwd(), "float")
+ end
+ '';
+ options.desc = "Toggle terminal (float)";
+ }
+ {
+ mode = "t";
+ key = "";
+ action = "ToggleTerm";
+ options.desc = "Toggle terminal";
+ }
+ {
+ mode = "t";
+ key = "";
+ action = "v";
+ options.desc = "Exit terminal and enter visual mode";
+ }
+ ];
+}
diff --git a/home/neovim/treesitter.nix b/home/neovim/treesitter.nix
new file mode 100644
index 0000000..58e174a
--- /dev/null
+++ b/home/neovim/treesitter.nix
@@ -0,0 +1,24 @@
+{ pkgs, ... }:
+{
+
+ # Install language parsers declaratively
+ # Syntax Highlighting
+ programs.nixvim.plugins.treesitter = {
+ enable = true;
+ grammarPackages = with pkgs.vimPlugins.nvim-treesitter.builtGrammars; [
+ lua
+ nix
+ python
+ javascript
+ rust
+ rasi
+ ];
+
+ settings = {
+ highlight = {
+ enable = true;
+ additional_vim_regex_highlighting = false;
+ };
+ };
+ };
+}
diff --git a/home/neovim/which-key.nix b/home/neovim/which-key.nix
new file mode 100644
index 0000000..ade48c6
--- /dev/null
+++ b/home/neovim/which-key.nix
@@ -0,0 +1,94 @@
+{ pkgs, ... }: {
+ # Which-key: Display available keybindings in popup
+ # Shows all possible key combinations after pressing leader or other prefix keys
+ programs.nixvim.plugins.which-key = {
+ enable = true;
+
+ settings = {
+ delay = 500; # Time in ms before popup shows
+
+ icons = {
+ breadcrumb = "»";
+ separator = "➜";
+ group = "+";
+ };
+
+ # Organize keymaps into named groups
+ spec = [
+ # Leader key groups
+ {
+ __unkeyed-1 = "a";
+ group = "Avante AI";
+ icon = "🤖";
+ }
+ {
+ __unkeyed-1 = "f";
+ group = "Find/Files/Terminal";
+ icon = "🔍";
+ }
+ {
+ __unkeyed-1 = "m";
+ group = "Molten (Jupyter)";
+ icon = "📓";
+ }
+ {
+ __unkeyed-1 = "o";
+ group = "OpenSCAD";
+ icon = "🔧";
+ }
+
+ # Bracket navigation groups
+ {
+ __unkeyed-1 = "[";
+ group = "Previous";
+ icon = "⬅️";
+ }
+ {
+ __unkeyed-1 = "]";
+ group = "Next";
+ icon = "➡️";
+ }
+
+ # g prefix groups
+ {
+ __unkeyed-1 = "g";
+ group = "Go/LSP";
+ icon = "🎯";
+ }
+ {
+ __unkeyed-1 = "gr";
+ group = "LSP References/Rename";
+ icon = "🔗";
+ }
+ {
+ __unkeyed-1 = "gc";
+ group = "Comments";
+ icon = "💬";
+ }
+
+ # l prefix
+ {
+ __unkeyed-1 = "l";
+ group = "Live Server";
+ icon = "🌐";
+ }
+
+ # z prefix
+ {
+ __unkeyed-1 = "z";
+ group = "Folds/Spell";
+ icon = "📋";
+ }
+ ];
+
+ # Hide specific mappings to reduce clutter
+ disable = {
+ builtin_keys = {
+ # Hide these default vim keys from which-key
+ i = [ "" "" ];
+ n = [ "" ];
+ };
+ };
+ };
+ };
+}
diff --git a/home/neovim/yazi.nix b/home/neovim/yazi.nix
new file mode 100644
index 0000000..06d6e0a
--- /dev/null
+++ b/home/neovim/yazi.nix
@@ -0,0 +1,41 @@
+{ pkgs, ... }: {
+ # Yazi: Terminal file manager integration for Neovim
+ # Provides a fast, visual way to browse and manage files.
+ programs.nixvim = {
+ # Use extraPlugins to manually load yazi.nvim
+ extraPlugins = with pkgs.vimPlugins; [ yazi-nvim ];
+
+ # Configure yazi after it's loaded
+ extraConfigLua = ''
+ require('yazi').setup({
+ open_for_directories = true,
+ })
+ '';
+
+ keymaps = [
+ {
+ mode = "n";
+ key = "fy";
+ action.__raw = ''
+ function()
+ require('yazi').yazi(nil, vim.loop.cwd())
+ end
+ '';
+ options.desc = "Open Yazi file manager";
+ }
+ {
+ mode = "n";
+ key = "fd";
+ action.__raw = ''
+ function()
+ require('yazi').yazi(nil, vim.fn.expand("%:p:h"))
+ end
+ '';
+ options.desc = "Open Yazi in current file directory";
+ }
+ ];
+
+ # Install yazi terminal program
+ extraPackages = with pkgs; [ yazi ];
+ };
+}
diff --git a/home/packages.nix b/home/packages.nix
new file mode 100644
index 0000000..a734616
--- /dev/null
+++ b/home/packages.nix
@@ -0,0 +1,27 @@
+{ pkgs, ... }:
+{
+ home = {
+ packages = with pkgs; [
+ # dev tools
+ curl
+ wget
+ vim
+ htop
+ tree
+ ripgrep
+ unrar
+
+ # programming languages
+ #mise # node, deno, bun, rust, python, etc.
+
+ # PDF Tools
+ #pandoc
+ #texlive.combined.scheme-full
+ #wkhtmltopdf
+
+ # misc
+ yt-dlp
+ ffmpeg
+ ];
+ };
+}
diff --git a/home/python.nix b/home/python.nix
new file mode 100644
index 0000000..be4b85d
--- /dev/null
+++ b/home/python.nix
@@ -0,0 +1,26 @@
+{ pkgs, ... }: {
+ home.packages = with pkgs; [
+ # Python 3.13 (newest stable)
+ python313
+ python313Packages.pip
+ python313Packages.virtualenv
+
+ # Additional useful tools
+ python313Packages.pipx # Install Python apps in isolated environments
+ uv # Fast Python package installer (alternative to pip)
+ ];
+
+ # Set up default Python version
+ home.sessionVariables = { PYTHON = "${pkgs.python313}/bin/python3"; };
+
+ # Shell aliases for convenience
+ programs.zsh.shellAliases = {
+ venv = "python3 -m venv";
+ activate = "source venv/bin/activate";
+ };
+
+ programs.fish.shellAliases = {
+ venv = "python3 -m venv";
+ activate = "source venv/bin/activate.fish";
+ };
+}
diff --git a/home/shell.nix b/home/shell.nix
new file mode 100644
index 0000000..8500d5c
--- /dev/null
+++ b/home/shell.nix
@@ -0,0 +1,209 @@
+{ pkgs, ... }:
+{
+ home.packages = with pkgs; [
+ eza # ls replacement
+ fzf # FuzzyFinder
+ tdf # terminal pdf viewer
+ jq # json parser
+ tree
+ fastfetch # system stats
+ tabiew # Table viewer
+ glow # MD Viewer
+ btop
+ zoxide # Move to fish
+ llm # LLM in the Terminal
+
+ # Fun stuff
+ lolcat
+ cmatrix
+ ];
+
+ programs.kitty = {
+ enable = true;
+ themeFile = "Catppuccin-Mocha";
+
+ font = {
+ name = "Fira Code Nerd Font";
+ size = 12;
+ };
+
+ settings = {
+ confirm_os_window_close = 0;
+ dynamic_background_opacity = true; # ctrl+shift+a>m/l
+ enable_audio_bell = false;
+ mouse_hide_wait = 3.0;
+ window_padding_width = 10;
+
+ background_opacity = 0.8;
+ background_blur = 5;
+
+ tab_bar_min_tabs = 1;
+ tab_bar_edge = "bottom";
+ tab_bar_style = "custom"; # Should be changed to custom
+ tab_title_template = "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title}";
+
+ symbol_map =
+ let
+ mappings = [
+ "U+23FB-U+23FE"
+ "U+2B58"
+ "U+E200-U+E2A9"
+ "U+E0A0-U+E0A3"
+ "U+E0B0-U+E0BF"
+ "U+E0C0-U+E0C8"
+ "U+E0CC-U+E0CF"
+ "U+E0D0-U+E0D2"
+ "U+E0D4"
+ "U+E700-U+E7C5"
+ "U+F000-U+F2E0"
+ "U+2665"
+ "U+26A1"
+ "U+F400-U+F4A8"
+ "U+F67C"
+ "U+E000-U+E00A"
+ "U+F300-U+F313"
+ "U+E5FA-U+E62B"
+ ];
+ in
+ (builtins.concatStringsSep "," mappings) + " Symbols Nerd Font Mono";
+ };
+ };
+
+ programs.yazi = {
+ enable = true;
+ enableBashIntegration = true;
+ enableZshIntegration = true;
+ enableFishIntegration = true;
+
+ settings = {
+ ration = [
+ 1
+ 3
+ 4
+ ];
+ };
+ };
+
+ programs.zsh = {
+ enable = true;
+ enableCompletion = true;
+ autosuggestion.enable = true;
+ syntaxHighlighting.enable = true;
+
+ shellAliases = {
+ ls = "eza";
+ la = "eza -la";
+ f = "fzf";
+ i = "kitty +kitten icat";
+ "nix-switch" = "sudo nixos-rebuild switch --flake .#rpi-4";
+ };
+
+ initContent = ''
+ fastfetch
+ ai() {
+ llm -m groq/groq/compound "$@" | glow
+ }
+ '';
+ };
+
+ programs.fish = {
+ enable = true;
+
+ shellAliases = {
+ ls = "eza";
+ la = "eza -la";
+ f = "fzf";
+ i = "kitty +kitten icat";
+ "nix-switch" = "sudo nixos-rebuild switch --flake .#rpi-4";
+ };
+
+ interactiveShellInit = ''
+ starship init fish | source
+ fzf --fish | source
+ function fish_greeting
+ fastfetch
+ end
+ '';
+
+ functions.ai = {
+ body = ''
+ llm -m groq/groq/compound $argv | glow
+ '';
+ };
+ };
+
+ programs.starship = {
+ enable = true;
+ settings = {
+ add_newline = true;
+ command_timeout = 500;
+
+ format = ''
+ $username$hostname $directory $git_branch$git_status
+ $character '';
+ right_format = "$cmd_duration";
+
+ username = {
+ style_user = "bold #cba6f7";
+ style_root = "bold #f38ba8";
+ format = "[┌](bold #a6e3a1)[$user]($style)";
+ show_always = true;
+ };
+
+ hostname = {
+ style = "bold #74c7ec";
+ format = "[@](bold #fab387)[$hostname]($style)";
+ ssh_only = false;
+ };
+
+ directory = {
+ style = "bold #a6e3a1";
+ truncation_length = 0;
+ truncation_symbol = "";
+ format = "[⤇ ](bold #f38ba8)[《$path 》]($style)";
+ };
+
+ git_branch = {
+ format = "[⟦$branch⟧]($style)";
+ style = "bold #f9e2af";
+ };
+
+ # Git status module settings
+ git_status = {
+ format = "[[(*$conflicted$untracked$modified$staged$renamed$deleted)](red) ($ahead_behind$stashed)]($style)";
+ style = "bold #a6e3a1";
+ conflicted = "";
+ untracked = "";
+ modified = "";
+ staged = "";
+ renamed = "";
+ deleted = "";
+ };
+
+ # Command duration module
+ cmd_duration = {
+ format = "[$duration]($style)";
+ style = "bold #cdd6f4";
+ min_time = 5000; # Only show if command takes longer than 5 seconds
+ };
+
+ # Character module (prompt symbol)
+ character = {
+ success_symbol = "[└──────⇴ ](bold #a6e3a1)";
+ error_symbol = "[└──────⇴ ](bold #f38ba8)";
+ };
+
+ nix_shell = {
+ format = "[$symbol$state( ($name))]($style)";
+ symbol = "U+02744";
+ style = "bold #89dceb";
+ };
+ };
+ };
+
+ home.file = {
+ ".config/fastfetch/config.jsonc".source = ./fastfetch.jsonc;
+ ".config/tabiew/theme.toml".source = ./tabiew.toml;
+ ".config/kitty/tab_bar.py".source = ./tab_bar.py;
+ };
+}
diff --git a/home/tab_bar.py b/home/tab_bar.py
new file mode 100644
index 0000000..e1bad95
--- /dev/null
+++ b/home/tab_bar.py
@@ -0,0 +1,34 @@
+from datetime import datetime
+from kitty.tab_bar import DrawData, ExtraData, TabBarData, as_rgb
+from kitty.fast_data_types import Screen
+
+
+def draw_tab(
+ draw_data: DrawData,
+ screen: Screen,
+ tab: TabBarData,
+ before: int,
+ max_title_length: int,
+ index: int,
+ is_last: bool,
+ extra_data: ExtraData,
+) -> int:
+
+ # Left side: Current directory or command
+ screen.cursor.fg = as_rgb(int("a6e3a1", 16))
+ screen.cursor.bg = as_rgb(int("1e1e2e", 16))
+
+ # Get the foreground process (command) or use title
+ title = tab.active_fg or tab.title or "shell"
+ screen.draw(f" {title} ")
+
+ # Middle: Nix icon
+ screen.cursor.fg = as_rgb(int("89dceb", 16))
+ screen.draw(" ❄ ")
+
+ # Right: Current time
+ screen.cursor.fg = as_rgb(int("cdd6f4", 16))
+ current_time = datetime.now().strftime("%H:%M")
+ screen.draw(f"{current_time} ")
+
+ return screen.cursor.x
diff --git a/home/tabiew.toml b/home/tabiew.toml
new file mode 100644
index 0000000..514af60
--- /dev/null
+++ b/home/tabiew.toml
@@ -0,0 +1,141 @@
+# Catppuccin Mocha Theme for Tabiew
+# Base colors from Catppuccin Mocha palette
+
+[table_header]
+fg = "#F5E0DC" # Rosewater
+bg = "#181825" # Mantle
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[table_headers]]
+fg = "#F5C2E7" # Pink
+bg = "#181825" # Mantle
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[table_headers]]
+fg = "#CBA6F7" # Mauve
+bg = "#181825" # Mantle
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[table_headers]]
+fg = "#89DCEB" # Sky
+bg = "#181825" # Mantle
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[rows]]
+fg = "#CDD6F4" # Text
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[rows]]
+fg = "#CDD6F4" # Text
+bg = "#181825" # Mantle
+add_modifier = ""
+sub_modifier = ""
+
+[highlight]
+fg = "#181825" # Mantle
+bg = "#F9E2AF" # Yellow
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[table_tags]]
+fg = "#181825" # Mantle
+bg = "#F38BA8" # Red
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[table_tags]]
+fg = "#181825" # Mantle
+bg = "#A6E3A1" # Green
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[block]
+fg = "#FAB387" # Peach
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[block_tag]
+fg = "#181825" # Mantle
+bg = "#FAB387" # Peach
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[text]
+fg = "#CDD6F4" # Text
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[subtext]
+fg = "#9399B2" # Overlay1
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[error]
+fg = "#CDD6F4" # Text
+bg = "#F38BA8" # Red
+add_modifier = "BOLD"
+sub_modifier = ""
+
+[[chart]]
+fg = "#F38BA8" # Red
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#FAB387" # Peach (Orange)
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#F9E2AF" # Yellow
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#A6E3A1" # Green
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#94E2D5" # Teal
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#89DCEB" # Sky (Cyan)
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#89B4FA" # Blue
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#CBA6F7" # Mauve (Purple)
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
+[[chart]]
+fg = "#F5C2E7" # Pink
+bg = "#313244" # Surface0
+add_modifier = ""
+sub_modifier = ""
+
diff --git a/hosts/cyper-cloud/configuration.nix b/hosts/cyper-cloud/configuration.nix
new file mode 100644
index 0000000..fa3b38c
--- /dev/null
+++ b/hosts/cyper-cloud/configuration.nix
@@ -0,0 +1,15 @@
+{ lib, pkgs, ... }:
+
+{
+ networking = {
+ hostName = lib.mkForce "cyper-cloud";
+ useDHCP = true;
+ nameservers = [ "1.1.1.1" "8.8.8.8" ];
+ };
+
+ environment.systemPackages = with pkgs; [
+ kubectl
+ terraform
+ awscli2
+ ];
+}
diff --git a/hosts/cyper-cluster/configuration.nix b/hosts/cyper-cluster/configuration.nix
new file mode 100644
index 0000000..70949c3
--- /dev/null
+++ b/hosts/cyper-cluster/configuration.nix
@@ -0,0 +1,16 @@
+{ lib, pkgs, ... }:
+
+{
+ imports = [ ../services/k3s-agent.nix ];
+
+ networking = {
+ hostName = lib.mkForce "cyper-cluster";
+ useDHCP = true;
+ nameservers = [ "1.1.1.1" "8.8.8.8" ];
+ };
+
+ environment.systemPackages = with pkgs; [
+ kubectl
+ helm
+ ];
+}
diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix
new file mode 100644
index 0000000..716dd6e
--- /dev/null
+++ b/hosts/cyper-controller/configuration.nix
@@ -0,0 +1,30 @@
+{ lib, pkgs, ... }:
+
+{
+ imports = [
+ ../services/k3s-master.nix
+ ./postgres.nix
+ #./dns.nix
+ ];
+
+ networking = {
+ hostName = lib.mkForce "cyper-controller";
+ useDHCP = false;
+ interfaces.eth0.ipv4.addresses = [
+ {
+ address = "192.168.2.2";
+ prefixLength = 24;
+ }
+ ];
+ defaultGateway = "192.168.2.1";
+ nameservers = [
+ "127.0.0.1"
+ "1.1.1.1"
+ ];
+ };
+
+ environment.systemPackages = with pkgs; [
+ kubectl
+ dnsutils
+ ];
+}
diff --git a/hosts/cyper-controller/dns.nix b/hosts/cyper-controller/dns.nix
new file mode 100644
index 0000000..88a579a
--- /dev/null
+++ b/hosts/cyper-controller/dns.nix
@@ -0,0 +1,36 @@
+{ ... }:
+
+{
+ services.dnsmasq = {
+ enable = true;
+ settings = {
+ # DNS forwarding
+ domain-needed = true;
+ bogus-priv = true;
+ no-resolv = true;
+ server = [ "1.1.1.1" "8.8.8.8" ];
+
+ # Local domain
+ local = "/cyper.local/";
+ domain = "cyper.local";
+ expand-hosts = true;
+
+ # Static host entries
+ address = [
+ "/cyper-controller.cyper.local/192.168.2.2"
+ "/cyper-node1.cyper.local/192.168.2.30"
+ "/cyper-node2.cyper.local/192.168.2.31"
+ ];
+
+ # DHCP for dynamic hosts (cyper-cluster, cyper-cloud)
+ dhcp-range = "192.168.2.100,192.168.2.200,24h";
+ dhcp-option = [
+ "3,192.168.2.1" # default gateway
+ "6,192.168.2.2" # DNS server
+ ];
+ };
+ };
+
+ networking.firewall.allowedTCPPorts = [ 53 ];
+ networking.firewall.allowedUDPPorts = [ 53 67 68 ];
+}
diff --git a/hosts/cyper-controller/postgres.nix b/hosts/cyper-controller/postgres.nix
new file mode 100644
index 0000000..1e862cf
--- /dev/null
+++ b/hosts/cyper-controller/postgres.nix
@@ -0,0 +1,57 @@
+{ pkgs, ... }:
+
+{
+ services.postgresql = {
+ enable = true;
+ package = pkgs.postgresql_15;
+ enableTCPIP = true;
+
+ initialScript = pkgs.writeText "backend-init-script" ''
+ CREATE USER postgres WITH SUPERUSER PASSWORD 'postgres';
+ '';
+
+ # x86_64 server optimized settings (8GB+ RAM assumed)
+ settings = {
+ port = 5432;
+
+ # Memory settings
+ shared_buffers = "2GB";
+ effective_cache_size = "6GB";
+ maintenance_work_mem = "512MB";
+ work_mem = "16MB";
+ wal_buffers = "16MB";
+
+ # Connection settings
+ max_connections = 100;
+
+ # Performance tuning for x86_64 SSD
+ random_page_cost = 1.1;
+ effective_io_concurrency = 200;
+
+ # WAL settings
+ wal_level = "replica";
+ checkpoint_timeout = "15min";
+ checkpoint_completion_target = 0.9;
+ min_wal_size = "1GB";
+ max_wal_size = "4GB";
+
+ # Query planning
+ default_statistics_target = 100;
+
+ # Logging
+ log_min_duration_statement = 1000;
+ log_duration = false;
+ };
+
+ authentication = ''
+ local all all trust
+ host all all 127.0.0.1/32 md5
+ host all all ::1/128 md5
+ host all all 192.168.2.0/24 md5
+ '';
+ };
+
+ systemd.services.postgresql.wantedBy = [ "multi-user.target" ];
+
+ networking.firewall.allowedTCPPorts = [ 5432 ];
+}
diff --git a/hosts/cyper-node1/configuration.nix b/hosts/cyper-node1/configuration.nix
new file mode 100644
index 0000000..b5af2ee
--- /dev/null
+++ b/hosts/cyper-node1/configuration.nix
@@ -0,0 +1,18 @@
+{ lib, ... }:
+
+{
+ imports = [ ../services/k3s-agent.nix ];
+
+ networking = {
+ hostName = lib.mkForce "cyper-node1";
+ useDHCP = false;
+ interfaces.eth0.ipv4.addresses = [
+ {
+ address = "192.168.2.30";
+ prefixLength = 24;
+ }
+ ];
+ defaultGateway = "192.168.2.1";
+ nameservers = [ "192.168.2.2" ];
+ };
+}
diff --git a/hosts/cyper-node2/configuration.nix b/hosts/cyper-node2/configuration.nix
new file mode 100644
index 0000000..015c6ff
--- /dev/null
+++ b/hosts/cyper-node2/configuration.nix
@@ -0,0 +1,18 @@
+{ lib, ... }:
+
+{
+ imports = [ ../services/k3s-agent.nix ];
+
+ networking = {
+ hostName = lib.mkForce "cyper-node2";
+ useDHCP = false;
+ interfaces.eth0.ipv4.addresses = [
+ {
+ address = "192.168.2.31";
+ prefixLength = 24;
+ }
+ ];
+ defaultGateway = "192.168.2.1";
+ nameservers = [ "192.168.2.2" ];
+ };
+}
diff --git a/hosts/services/k3s-agent.nix b/hosts/services/k3s-agent.nix
new file mode 100644
index 0000000..1ca22e6
--- /dev/null
+++ b/hosts/services/k3s-agent.nix
@@ -0,0 +1,23 @@
+{ ... }:
+
+{
+ boot.kernelParams = [
+ "cgroup_memory=1"
+ "cgroup_enable=memory"
+ "cgroup_enable=cpuset"
+ ];
+
+ services.k3s = {
+ enable = true;
+ role = "agent";
+ serverAddr = "https://192.168.2.2:6443";
+ };
+
+ networking.firewall = {
+ allowedTCPPortRanges = [
+ { from = 10250; to = 10250; }
+ { from = 30000; to = 32767; }
+ ];
+ trustedInterfaces = [ "cni0" ];
+ };
+}
diff --git a/hosts/services/k3s-master.nix b/hosts/services/k3s-master.nix
new file mode 100644
index 0000000..0e51551
--- /dev/null
+++ b/hosts/services/k3s-master.nix
@@ -0,0 +1,32 @@
+{ pkgs, ... }:
+
+{
+ boot.kernelParams = [
+ "cgroup_memory=1"
+ "cgroup_enable=memory"
+ "cgroup_enable=cpuset"
+ ];
+
+ services.k3s = {
+ enable = true;
+ role = "server";
+ clusterInit = true;
+ extraFlags = ''
+ --disable=traefik
+ --flannel-backend=host-gw
+ '';
+ };
+
+ networking.firewall = {
+ allowedTCPPorts = [ 6443 ];
+ allowedTCPPortRanges = [
+ { from = 10250; to = 10250; }
+ { from = 30000; to = 32767; }
+ ];
+ trustedInterfaces = [ "cni0" ];
+ };
+
+ environment.systemPackages = with pkgs; [
+ kubectl
+ ];
+}
diff --git a/nixos/default.nix b/nixos/default.nix
new file mode 100644
index 0000000..a19ae44
--- /dev/null
+++ b/nixos/default.nix
@@ -0,0 +1,113 @@
+{
+ pkgs,
+ primaryUser,
+ ...
+}:
+
+{
+ imports = [
+ ./hardware.nix
+ ./settings.nix
+ ./packages.nix
+ ];
+
+ nixpkgs.config.allowUnfree = true;
+
+ # Speeding up builds
+ documentation = {
+ enable = false;
+ man = {
+ enable = false;
+ generateCaches = false;
+ };
+ doc.enable = false;
+ info.enable = false;
+ nixos.enable = false;
+ };
+
+ # Override python-lsp-server to skip tests (flaky tests cause timeout)
+ nixpkgs.config.packageOverrides = pkgs: {
+ python3 = pkgs.python3.override {
+ packageOverrides = self: super: {
+ python-lsp-server = super.python-lsp-server.overridePythonAttrs (old: {
+ doCheck = false;
+ });
+ };
+ };
+ };
+
+ networking = {
+ hostName = "cyper-server"; # overridden per host
+ useDHCP = false; # overridden per host
+ networkmanager.enable = false;
+ enableIPv6 = false;
+
+ firewall = {
+ enable = true;
+ allowPing = true;
+ };
+ };
+
+ # SSH configuration
+ services.openssh = {
+ enable = true;
+ settings.PermitRootLogin = "no";
+ settings.PasswordAuthentication = true;
+ };
+
+ # User configuration
+ users.users.${primaryUser} = {
+ isNormalUser = true;
+ home = "/home/${primaryUser}";
+ description = "Phil";
+ hashedPassword = "$6$TqAclAMz/DFP90Ve$HEN4t1pqK36rACeWctJOmLArkTWb/rIBYamu4sY8bPuDnqkVVyfOLqXKkgX8zBf9LKz02.mo4EKFRnYWIzcAX1";
+ extraGroups = [
+ "wheel"
+ ];
+ shell = pkgs.fish;
+ openssh.authorizedKeys.keys = [
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCaLHfxVylghDMYR8t4QMUpeRRqXasNABQKBEy9MmhbUXCcWiPbPMSZH8FMHON34rm2OrXP1kY/8jQxqBJDA+SqpFR2AZ4Khk9iVMaq5GHxxpn2amZUjoBa+fB29WaiE1npV5JVJV3O0ylw6GtiCnpneE6fGx2MO1vOY/7zKrUX/OK7WfwkDpeEzZgV/j/md917HrzUVeZwdeTq3WCRO8Gew6R8Xs6FRjSiGuH0dq14D4Ow5Zf1cI1jx+JfD/5vGasw8HXPu1NdxsOE+6D7/22IKqGr+S74/lAoyyD5qqk0s05lw8UY/PXBLJaNLZu9Fwx0BqTHpJEvftpmvd9wUxgR3msx9VXtKNSrqivIbDgeU+3oGzzkrGZODl7FCp4XKGmbrX85Z6lKwEGgv5jez4MLZcmT86bxB7m1wIbqSbVtfhS+GI7yPTA/kLzzFa14Im/+LTj95pb8qs2ALMwTMP1j2f9A6D3RriOFihL+68qn+YbK58KuV1R0f+CQRmlfVbk= phil@web.cyperpunk.de"
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuYuGhqRC/QLoRBH91c3DG5JHlAdRLQsvde18k5ipY2 phil@cyperpunk.de"
+ ];
+ };
+
+ # Shell
+ programs.zsh.enable = true;
+ programs.fish.enable = true;
+
+ # Nix settings
+ nix = {
+ settings = {
+ experimental-features = [
+ "nix-command"
+ "flakes"
+ ];
+ auto-optimise-store = true;
+ builders-use-substitutes = true;
+ trusted-substituters = [ "ssh://phil@192.168.2.2" ];
+ };
+ gc = {
+ automatic = true;
+ dates = "weekly";
+ options = "--delete-older-than 30d";
+ };
+ buildMachines = [
+ {
+ hostName = "192.168.2.2";
+ system = "x86_64-linux";
+ sshUser = "phil";
+ maxJobs = 8;
+ speedFactor = 2;
+ supportedFeatures = [
+ "nixos-test"
+ "benchmark"
+ "big-parallel"
+ "kvm"
+ ];
+ mandatoryFeatures = [ ];
+ }
+ ];
+ };
+
+ system.stateVersion = "25.11";
+}
diff --git a/nixos/hardware.nix b/nixos/hardware.nix
new file mode 100644
index 0000000..ecd3a63
--- /dev/null
+++ b/nixos/hardware.nix
@@ -0,0 +1,58 @@
+{
+ config,
+ lib,
+ pkgs,
+ modulesPath,
+ ...
+}:
+
+{
+ imports = [
+ (modulesPath + "/profiles/qemu-guest.nix")
+ ];
+
+ # Bootloader
+ boot = {
+ kernelPackages = pkgs.linuxPackages_latest;
+ initrd.availableKernelModules = [
+ "ahci"
+ "xhci_pci"
+ "virtio_pci"
+ "virtio_scsi"
+ "sd_mod"
+ "sr_mod"
+ ];
+ initrd.kernelModules = [ ];
+ kernelModules = [ "kvm-intel" ];
+ extraModulePackages = [ ];
+
+ loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+ };
+
+ # File systems
+ fileSystems."/" = {
+ device = "/dev/disk/by-label/nixos";
+ fsType = "ext4";
+ options = [ "noatime" ];
+ };
+
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-label/boot";
+ fsType = "vfat";
+ };
+
+ # Swap
+ swapDevices = [
+ {
+ device = "/swapfile";
+ size = 4096;
+ }
+ ];
+
+ # x86_64 hardware
+ hardware.enableRedistributableFirmware = true;
+ hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/nixos/packages.nix b/nixos/packages.nix
new file mode 100644
index 0000000..696ed08
--- /dev/null
+++ b/nixos/packages.nix
@@ -0,0 +1,19 @@
+{ config, pkgs, ... }:
+
+{
+ environment.systemPackages = with pkgs; [
+ git
+ curl
+ wget
+ htop
+ neovim
+ tmux
+ ripgrep
+ fd
+ bat
+ eza
+ fzf
+ tree
+ fish
+ ];
+}
diff --git a/nixos/settings.nix b/nixos/settings.nix
new file mode 100644
index 0000000..bab9c20
--- /dev/null
+++ b/nixos/settings.nix
@@ -0,0 +1,21 @@
+{ config, pkgs, ... }:
+
+{
+ # Localization
+ time.timeZone = "Europe/Berlin";
+ i18n.defaultLocale = "en_US.UTF-8";
+ i18n.extraLocaleSettings = {
+ LC_ADDRESS = "de_DE.UTF-8";
+ LC_IDENTIFICATION = "de_DE.UTF-8";
+ LC_MEASUREMENT = "de_DE.UTF-8";
+ LC_MONETARY = "de_DE.UTF-8";
+ LC_NAME = "de_DE.UTF-8";
+ LC_NUMERIC = "de_DE.UTF-8";
+ LC_PAPER = "de_DE.UTF-8";
+ LC_TELEPHONE = "de_DE.UTF-8";
+ LC_TIME = "de_DE.UTF-8";
+ };
+
+ # System settings
+ console.keyMap = "de";
+}