Dotfiles
It’s not “just dotfiles” - it's extreme modularity that looks and feels like a NixOS flake. It's Voice-driven DevOps, it's a declarative home automation system, it's a self-contained auto-documenting monster.
Install / Use
/learn @QuackHack-McBlindy/DotfilesREADME
❄️🦆 QuackHack-McBLindy NixOS dotfiles <br>
<!-- VERSIONS_START -->
This is a <abbr title="Magically automated with duck-powered quackery">automagiduckically</abbr> updated README.md
</sub></div>
<img src="home/profile.png" alt="QuackHack-McBlindy" width="148">[!CAUTION] Do not blindly run this flake. <br> That's my job. 🧑🦯
<br>
Here lives all home machines/phone config files,
and home automations, fully reproducible,
crafted as a tiny Nix flake
Glued together by a Nix-flavoured command line utility,
easiy expanded and used to deploy, doc, and duck around
What Makes This Configuration Unique?
Nix declarative configuration style, custom modules evaluated dynamically for each host. <br> Home Manager - No ducking way! I just auto symlink ./home to /home <br> Home Assistant - Quack no! No assistance needed! <br> Zigbee and smart home tightly integrated with Nix. For not just a declarative house but also deployable apartments. <br> Not only that - my voice assistant is LIGHTNING FAST! (ms) ⚡🏆 <br><br>
<!-- SCRIPT_STATS_START -->- 89 qwacktastic scripts in /bin - 57 scripts have voice commands. <br>
- 2499 dynamically generated regex patterns - makes 272684909 phrases available as commands. <br>
- Smart Home Nix Fu - Managing 3 TV's, 48 devices & 11 scenes. <br>
- Natural Language DevOps support with complete voice pipeline <br>
- Mobile Frontend with Chatbot (no LLM) - Less thinking, more doing! <br>
- Infra as everyday accessibility <br>
- Yubikey encrypted deployment system <br>
- Version controlled ESP32 firmware management <br>
- Self Documenting <br>
List would get long, very quackly. <br> perhaps a more suitable question would be: <br> "What makes this configuration common?" <br>
<br>🦆 Follow My Adventures
This repository is complex, and it's not a typical NixOS dotfiles setup.<br> Since NixOS probably never have been used in such a unique way, understanding how everything is working solely from massive source code will be tricky for newcomers as well as advanced users. <br> I try to simplify that process in my blog. <br>
<br>Duck Challenge
<!-- DUCKS_START -->I have hidden some ducks in the .nix files in this repository. <br> Let's see if you can find all 9395 ducks? <br>
<!-- DUCKS_END --> <br>❄️ Flake
<details><summary><strong> Define yourself at `config.this.user.me`. </strong></summary> <!-- USER_START -->{
discord = "https://discordapp.com/users/675530282849533952";
dotfilesDir = "/home/pungkula/dotfiles";
email = "isthisrandomenough@protonmail.com";
extraGroups = [ "networkmanager" "wheel" "dialout" "docker" "dockeruser" "users" "pungkula" "adbusers" "audio" "2000" "i2c" "mqtt" ];
hashedPassword = "$y$j9T$m8hPD36i1VMaO5rurbZ4j0$KpzQyat.F6NoWFKpisEj77TvpN2wBGB8ezd26QoKDj6";
matrix = "";
mobileDevices = {
iphone = {
pubkey = "UFB0T1Y/uLZi3UBtEaVhCi+QYldYGcOZiF9KKurC5Hw=";
wgip = "10.0.0.7"
};
tablet = {
pubkey = "ETRh93SQaY+Tz/F2rLAZcW7RFd83eofNcBtfyHCBWE4=";
wgip = "10.0.0.8"
}
};
name = "pungkula";
repo = "git@github.com:QuackHack-McBlindy/dotfiles.git"
}
<!-- USER_END -->
</details>
<details><summary><strong>
Define each hosts data at `config.this.host`.
</strong></summary>
<!-- HOST_START -->
{
hostname = "desktop";
interface = [ "enp119s0" ];
ip = "192.168.1.111";
keys = {
privateKeys = {
};
publicKeys = {
adb = "QAAAACEJNfsfRV4PQ9Ah87MbTVbMkbXC6CAMDOR+0K6mIpv/4TSzYMkc2qit3Kryc55IVOjwR3fJRjj/uL549gZ7nEemWtcd3AsYQBp0iIEor8nu1L/V6jfsTY6Xe/pl06xoroy6OwZRWuDbZ4wD2xQRRQjfPd+JtYnMAWneM6r1V15uR67w4ITvjk3ckyfgNeLZMUwahMRjC3wSjaU9sAdKNmg8yPd8uHZ+mK6mstxJFAGEpnnm1lE7Z2r0DF6h6MKY1++dwhU+WM5BRDNiBg+D4i6fDW4+Z1I9ENuFnjT17zAxZXch04SNlG3O94BANYP7jmKp60OvtDL6msfphntuIUzMCkndF9De0Kv4lJdQxe1d+wf+AFpmtd/xtrk45YdMV+eWCJf2OkidaHmSj4ffkAobpun0VrkZN2Z1JymmdsvUbyMjAsby3Zun0xr3EocUS8Jy5TcsK/dcpD6CB5dqzlHhsHSAWt2TDwPzZYXgV1xc+q+PqM09OVN1xActJu75UMkg5b84U15hwQvYdwB8UaopMWWk6p064c7gxYSfH7fSxwkW2Jy1CElgJa55Pp4SZG9b/3B+VcNL1WSf6v/lvJqPbrRvBqvS0+e9wcFMNZtQKTX3n5X0wW1/czZPCQX+hmM8Uu1qrtaz4rKViIEGf4YR0/9eUGYQVfuAxAh8ZmsroJlnAAEAAQA= pungkula@desktop";
age = "age16utg7mmk73cn3glrwthtm0p7mf6g3vrd48h3ucpn6wnf28pgxvcsh4rjjp";
borg = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMVYczAOBSeS7WfSvzYDOS4Q9Ss+yxCf2G5MVfAALOx/";
builder = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQ7c/AeIpmJS6cWQkHOe4ZEq3DXVRnjtTWuWfx6L46n";
cache = "cache:/pbj1Agw2OoSSDZcClS69RHa1aNcwwTOX3GIEGKYwPc=";
host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILdwPkRQxlbrbRGwEO5zMJ4m+7QqUQPZg1iqbd5HRP34";
iPhone = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMcmr+z7k/yCbrFg+JDgo8JCuWqNVYn10ajRbNTp8fq";
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPwZL27kGTQDIlSe03abT9F24nSAizORyjo5cI3BD92s";
wireguard = "Oq0ZaYAnOo5sLpV//OEFwLgjVCxPyeQqf8cZBASluWk="
}
};
modules = {
hardware = [ "cpu/intel" "audio" ];
networking = [ "default" "pool" ];
programs = [ "default" "thunar" "firefox" "vesktop" ];
services = [ "ssh" "default" "adb" "openrgb" "backup" "cache" "keyd" "jelly" "yo-rs" "yo-client" ];
system = [ "nix" "pkgs" "gnome" "crossEnv" "gtk" ];
virtualisation = [ "docker" "vm" ]
};
system = "x86_64-linux";
wgip = "10.0.0.2"
}
<!-- HOST_END -->
</details>
<details><summary><strong>
Define any optional theme configuration at `config.this.theme`.
</strong></summary>
<!-- THEME_START -->
{
cursorTheme = {
name = "Bibata-Modern-Classic";
package = "/nix/store/mghmxh2bw5wqjiffh8277rk7yz5dqlbf-bibata-cursors-2.0.7";
size = 32
};
enable = false;
fonts = {
monospace = "Fira Code";
packages = [ "/nix/store/afyrq8cj49cszjryhm2m7ps8jyp3l91i-fira-code-6.2" ];
system = "Fira Sans"
};
gtkSettings = {
gtk-application-prefer-dark-theme = "1";
gtk-cursor-theme-name = "Bibata-Modern-Classic";
gtk-icon-theme-name = "elementary-xfce-icon-theme"
};
iconTheme = {
name = "Papirus-Dark";
package = "/nix/store/fysbw79j24224x9k1fgi5w1v6snkpv9m-papirus-icon-theme-20250501"
};
name = "gtk3.css";
styles = "/nix/store/5yb5i296sijga5k65cdw2ib3hhwwq6iq-gtk3.css"
}
<!-- THEME_END -->
</details>
<details><summary><strong>
Define Zigbee-devices, scenes, automations, tv's, channels etc at `config.house`.
</strong></summary>
<!-- SMARTHOME_START -->
dotfiles/modules/myHouse.nix ⮞ https://github.com/quackhack-mcblindy/dotfiles
# dotfiles/modules/myHouse.nix ⮞ https://github.com/quackhack-mcblindy/dotfiles
{ # 🦆 says ⮞ my house - qwack
config, # 🦆 says ⮞ more info ⮞ https://quackhack-mcblindy.github.io/blog/house/index.html
lib,
self,
pkgs,
...
} : let # 🦆 say ⮞ load dash pages css files
strip = text:
builtins.replaceStrings [ "/*" "*/" ] [ "" "" ] text;
# 🦆 says ⮞ load custom pages 4 dashboard
customPages = import ./dashboard/customPages.nix { inherit lib config pkgs; };
pages = customPages.pages;
# 🦆 says ⮞ load css files
css = {
tv = builtins.readFile ./themes/css/duckdash/tv.css;
health = builtins.readFile ./themes/css/duckdash/health.css;
chat = builtins.readFile ./themes/css/duckdash/chat.css;
};
# 🦆 says ⮞ get house.tv configuration with debug info
tvConfig = builtins.trace "TV config: ${builtins.toJSON config.house.tv}" config.house.tv;
# 🦆 says ⮞ generate TV selector options with debug
tvOptions = let
tvNames = lib.attrNames tvConfig;
options = lib.concatMapStrings (tvName:
let tv = tvConfig.${tvName};
in if tv.enable then ''<option value="${tv.ip}">${tvName}</option>'' else ""
) tvNames;
in builtins.trace "TV options: ${options}" options;
# 🦆 says ⮞ dis fetch what host has Mosquitto
sysHosts = lib.attrNames self.nixosConfigurations;
mqttAuth = "-u ${config.house.zigbee.mosquitto.username} -P $(cat ${config.house.zigbee.mosquitto.passwordFile})";
# 🦆 says ⮞ icon map
icons = {
light = {
ceiling = "mdi:ceiling-light";
strip = "mdi:light-strip";
spotlight = "mdi:spotlight";
bulb = "mdi:lightbulb";
bul
