The Void
An opinionated dendritic nix configuration
The Concept
I have been trying to get consistent, across device experiences from the second that I started using linux. I tried my best with arch, but I foolishly believed that just remembering what packages I installed would be enough. Then I started managing my dotfiles with GNU stow, but that only allowed for a single host per repo. I moved over to doot, and simultaneously nixos.
I believed a dotfiles manager was my endgame. The final evolution, but it was far from ideal. I had to manage a mess of dotfiles, submodules and nix packages that were completely uncoupled from the apps that used them. Hyprland just assumed that I had all of my apps installed, assumed that otter-launcher's config existed. Just by forgetting an app or a toml file, I had the potential to brick my entire setup.
This is no longer the case.
The solution is similar to that of safely typed languages, like rust. Rust, instead of having optional parameters like typescript, requires that a variable be passed to a function, regardless of whether it contains anything. This leads to what is essentially a fixed dependancy tree, where there are no points of failiure, only allowing for logic errors and such. The same methodology can be applied to nix, using flake parts and wrapper scripts.
Instead of defining the packages beside the app, and its config, you can use the config to
define the required binaries. By wrapping a config that contains a nix variable, ie a
binary, that binary is intrinsically linked to that config, and will therefore always be
installed. No more dependancy issues, and because the configs are defined within nix too,
no more potential for missing config files. Dotfile managers are no more, long live
dotfile managers. Any app with a --config flag can now be fully versioned and self
contained within one repo, config and all, accessible on any machine with nix.
One command for a truly reproducible, fully contained, configured system. This is the endgame.
Mandatory thing on AI
I am not completely against AI. However, asking an agent to write a load of code and then posting it to reddit as if you made it yourself is disingenuous and (in my opinion) at least slightly morally incorrect. Many a time I have seen a cool project on a subreddit just for it to turn out to be ai generated garbage that I refuse to use out of principle.
I would go out on a limb and say that 99% of this codebase was written with no AI assistance. Every config, every module, every obscure fix for a bug that only exists because I'm using a dendritic pattern instead of being normal was programmed by hand by a real human (yours truly). I'm not saying I had no assistance at all, there are sections that are verbatim copied from the wiki of whatever app or language that I was using, but by and large, no AI code has made it into this repo.
There may be commits somewhere saying that opencode refactored something, or that it solved some obscure bug I was having, but after having those changes implemented for me, I took it upon myself to understand what actually happened, in order to make maintaining this config as easy as possible in the future.
This repo is not temporary. I daily drive this, and I intend to for many years to come. Going forward, I will keep to the same standard of only using AI as a last resort, and when needs must, only implementing and commiting changes that I fully understand and could've eventually come to myself. Sometimes, at the end of a long coding session, a man gets lazy. I could spend another 45 minutes fixing some quickshell update order bug, or I could get deepseek to do it. In the end, it was a 5 line fix that, in hindsight, was pretty obvious (lol).
Usage
Usage is similar to any other flake, with everything in the module directory being an output.
The folder structure is simply defined:
modules/
|- features/ - all available apps, every subfolder contains a seperate wrapped binary
|- attrs/ - attributes composed of other modules, no new features defined
|- system/ - basic system modules, no binaries. Should not be run standalone. (Think network and audio config)
|- hosts/ - available presets for machines. Output names match subfolder names, eg #HACKSTATION, and hostnames
Nixos Configurations
Due to the host module referencing /etc/nixos/hardware-configuration.nix, so that it is
seperated from the repo, all rebuild commands will need --impure, unless you copy your
configuration into the repo.
HACKSTATION contains all features available (near enough), with mobile02 being a lighter version of the system, looking the same visually, but with less bloat, only really having firefox and a terminal.
It is recommended to clone the repo beforehand, but the system can be built directly from
remote. When cloning the repo, in order to properly evaluate the vinix and nrs shell
aliases, the config should be built from the directory you cloned it to, not from another
directory. When building from remote, or in any other scenario in which the $PWD
environment variable is not available, the zsh module will throw and evaluation warning,
but the build will not be hindered.
# Local Clone, . is the directory containing flake.nix
sudo nixos-rebuild switch --impure --flake .
# Build from remote
sudo nixos-rebuild switch --impure --flake "git+https://git.voidarc.co.uk/voidarc/nixos.git?ref=dendritic"
Both of these commands can be appended with a desired hostname in order to build that configuration.
# Example of building mobile02 from a local repo
sudo nixos-rebuild switch --impure --flake .#mobile02
There is no default output, so if the current hostname doesn't match a host, you will get
an error. Building this config should be non destructive to any existing dotfiles, but
will remove all users (not home directories) from the system other than user01, who's
default password is qwer. No, that isn't my usual password.
Binaries
Any binary can be run with the same base command (will change when merged to main)
nix run "git+https://git.voidarc.co.uk/voidarc/nixos.git?ref=dendritic#appname"
appname can be substituted for the name of any folder in the modules/features dir, ie
kitty or otter-launcher. Most if not all modules in a subdirectory will have a module
name corresponding to that directory. This only applies for default.nix files, so files
that have different names are not expected to follow this convention, even if there is not
ea default.nix in that directory.
Issues and contributing
Because this is a private git server, there is no inline way to submit issues, contributions, or feature ideas. If you should wish, you may send such requests to admin@voidarc.co.uk, with the format found in CONTRIBUTING.md. Failure to follow the format found there will most likely result in your email being ignored.