Files
nixos/Droidnix/README.org
T
2026-03-23 19:51:09 +00:00

20 KiB
Raw Blame History

Droidnix: A Dendritic NixOS + Home Manager Configuration NixOS Configuration Structure

Introduction   intro

What is Droidnix

Droidnix is a modular, declarative NixOS + Home Manager configuration system. It allows users to choose between Hyprland and Mangowc as their window manager, with shared and WM-specific configurations managed via Emacs Org and Nix Flakes. The project is designed for reproducibility, maintainability, and cross-machine compatibility.

Installed components:

Core
Hyprland
Mangowc

Goals, project Structure, import hierarchy

This project uses a modular NixOS configuration with Hyprland and MangoWC support, designed for literate programming and cross-device reusability. The Droidnix repository is organized into two main parts:

  1. .assets/: Static, non-generated files (e.g., configs, scripts, themes).
  2. Generated folders (system, hyprland, mangowc): NixOS and Home Manager configurations, generated from Org files.

Root Level

  • flake.nix is the entry point and imports:

    • generated/assets/
    • generated/<host>/modules/
    • generated/hosts/

Generated Structure

The generated/ directory contains all generated configurations, divided into three main groups: system, hyprland, and mangowc.

First Setup

  1. Clone this repository.
  2. Run the setup script: ./setup_droid.
  3. Edit .assets/system/conf/base.conf to choose your window manager (wm = "hyprland" or wm = "mangowc").
  4. Tangle this Org file to generate Nix configurations: C-c C-v t in Emacs or use this: emacs README.org --batch -f org-babel-tangle && emacs --batch --eval "(setq org-html-htmlize-output-type nil)" README.org -f org-html-export-to-html
  5. Build and switch: sudo nixos-rebuild switch --flake .#<hostname>.

The Assets Folder   assets

The .assets/ folder contains all static files, such as configs, scripts, and themes. These files are not generated and can be edited directly.

The Actual Code   code

This section contains the Org blocks for tangling Nix code into the generated folders.

flake.nix

The Nix flake definition for Droidnix.

{
  description = "Droidnix: A dendritic NixOS + Home Manager configuration";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    import-tree.url = "github:vic/import-tree";

    stylix = {
      url = "github:nix-community/stylix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    zen-browser = {
      url = "github:youwen5/zen-browser-flake";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    hyprland.url = "github:hyprwm/Hyprland";
  };

  outputs = { self, nixpkgs, home-manager, import-tree, stylix, hyprland, zen-browser, ... }:
    let
      system = "x86_64-linux";
      flakeRoot = self;
    in {
      nixosConfigurations = {
        traveldroid = nixpkgs.lib.nixosSystem {
          inherit system;

          modules = [
            ./generated/hosts/traveldroid/host.nix
          ];

          specialArgs = {
            inherit flakeRoot;
            inherit home-manager import-tree stylix hyprland zen-browser;
          };
        };
      };
    };
}

generated/hosts/traveldroid/host.nix

{ lib, config, pkgs, flakeRoot, import-tree, home-manager, ... }:

let
  hostname = "traveldroid";

  modulesPath = "${flakeRoot}/generated/modules/${hostname}";
  usersPath   = "${flakeRoot}/generated/users";

  hostModules = import-tree modulesPath;
  globalUsers = import-tree usersPath;

  allModules = hostModules.imports ++ globalUsers.imports;

in
{
  #################################
  # Core system config
  #################################

  networking.hostName = hostname;
  system.stateVersion = "26.05";

  #################################
  # Imports
  #################################

  imports =
    [
      ./boot.nix
      ./hardware-configuration.nix

      # REQUIRED for Home Manager
      home-manager.nixosModules.home-manager
    ]
    ++ allModules;

  #################################
  # Home Manager integration
  #################################

  home-manager.useGlobalPkgs = true;
  home-manager.useUserPackages = true;
}

generated/hosts/traveldroid/hardware-configuration.nix

  1. Boot into NixOS Live ISO or your installed system.
  2. Open a terminal.
  3. Run: <code>sudo nixos-generate-config root /mnt</code> (Omit root /mnt if already running NixOS.)
{
  hostname,
  pkgs,
  lib,
  modulesPath,
  user,
  config,
  ...
}:
{
  imports = [
    # (modulesPath + "/installer/scan/not-detected.nix")
    #../../hardware/hardware.nix
  ];

  boot.initrd.availableKernelModules = [
    "xhci_pci"
    "nvme"
    "usb_storage"
    "sd_mod"
    "rtsx_usb_sdmmc"
  ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" = {
    device = "/dev/disk/by-uuid/69433a14-fbaf-401b-af85-cd1bbf02b4e2";
    fsType = "ext4";
  };

  fileSystems."/boot" = {
    device = "/dev/disk/by-uuid/811D-0676";
    fsType = "vfat";
    options = [
      "fmask=0077"
      "dmask=0077"
    ];
  };

  swapDevices = [
    { device = "/dev/disk/by-uuid/b6c557c2-7682-460b-a5e7-8f6f2f429a3a"; }
  ];

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

generated/hosts/traveldroid/boot.nix

{ pkgs, config, lib, flakeRoot, ... }:

{
  ############################
  # Bootloader (GRUB)
  ############################
  boot.loader = {
    grub = {
      enable = true;
      efiSupport = true;
      devices = [ "nodev" ]; # pas aan naar je echte EFI-device indien nodig
      useOSProber = true;
    };
    timeout = 5;
  };

  ############################
  # Kernel / boot settings
  ############################
  boot.kernelPackages = pkgs.linuxPackages_latest;

  boot.kernelParams = [
    "quiet"
    "splash"                 # REQUIRED for Plymouth
    "udev.log_level=3"
    "rd.systemd.show_status=false"
  ];

  boot.consoleLogLevel = 0;
  boot.supportedFilesystems = [ "ntfs" ];

  ############################
  # Plymouth
  ############################
  boot.plymouth = {
    enable = true;
    theme = "rings";

    themePackages = [
      (pkgs.adi1090x-plymouth-themes.override {
        selected_themes = [ "rings" ];
      })
    ];
  };

  boot.initrd.systemd.enable = true;

  ############################
  # Clean state
  ############################
  # Remove any old theme environment.etc symlinks
  #environment.etc = lib.mkForce {};
  system.stateVersion = "26.05";
}

Following are the imported modules

generated/traveldroid/modules/apps

generated/modules/traveldroid/apps/packages.nix

This installs a list of apps

{ lib, config, pkgs, flakeRoot, ... }:

let
  #################################
  # Read package list from config file
  #################################
  packagesConfPath = "${flakeRoot}/assets/traveldroid/conf/packages.conf";
  raw = builtins.readFile packagesConfPath;

  rawLines = lib.splitString "\n" raw;

  # Guard against splitting into characters accidentally
  _guard = assert !(builtins.stringLength raw > 1 && builtins.length rawLines == builtins.stringLength raw); true;

  # Clean each line: remove CRs, comments, trim whitespace
  cleanLine = line:
    let
      noCR = lib.replaceStrings [ "\r" ] [ "" ] line;
      noInlineComment = lib.head (lib.splitString "#" noCR);
    in
      lib.strings.trim noInlineComment;

  # Filter out empty lines
  entries = builtins.filter (l: l != "") (map cleanLine rawLines);

  # Resolve attribute paths in pkgs
  resolvePkg = name:
    let
      parts = lib.splitString "." name;
      found = lib.attrByPath parts null pkgs;
    in
      if found == null then
        (throw ''
          packages.nix: package not found in pkgs
          Token          : ${builtins.toJSON name}
          packages.conf  : ${packagesConfPath}
          Hint           : check the attribute name on search.nixos.org/packages
        '')
      else
        found;

  # Final system-wide package list
  packages = builtins.seq _guard (map resolvePkg entries);

in {
  #################################
  # Allow unfree packages globally
  #################################
  nixpkgs.config = { allowUnfree = true; };

  #################################
  # System packages
  #################################
  environment.systemPackages = packages;
}

generated/modules/traveldroid/apps/kitty.nix

This file sets up Kitty terminal

{ lib, pkgs, config, ... }:

let
  #################################
  # Determine default username
  #################################
  username   = config.defaultUser or "henrov";
  moduleName = "kitty";

  #################################
  # Paths to assets
  #################################
  assetPath    = ../../../assets/traveldroid/conf/${moduleName};
  programFiles = builtins.readDir assetPath;

  # Convert asset files into a nix attribute set
  files = lib.genAttrs (builtins.attrNames programFiles) (name: {
    source = "${assetPath}/${name}";
  });

in
{
  #################################
  # System-wide packages
  #################################
  environment.systemPackages = [
    pkgs.kitty
  ];

  #################################
  # Home Manager user configuration
  #################################
  _module.args.hmUsers = {
    ${username} = {

      # Enable Kitty through Home Manager
      programs.kitty.enable = true;

      # Extra user-specific config snippet
      programs.kitty.extraConfig = ''
        # Include the Catppuccin-Mocha theme
        include themes/Catppuccin-Mocha.conf
      '';

      # Map all asset files into ~/.config/kitty/
      home.file = lib.mkMerge (
        map (name: { ".config/${moduleName}/${name}" = { source = files.${name}.source; }; })
            (builtins.attrNames files)
      );
    };
  };
}

generated/modules/traveldroid/apps/starship.nix

This file sets up starship prompt

{ lib, config, pkgs, flakeRoot, ... }:

let
  # Default username fallback
  username = config.defaultUser or "henrov";

  # Path to the starship config in assets
  starshipConfSrc = "${flakeRoot}/assets/traveldroid/conf/starship.toml";
in
{
  #################################
  # Enable Starship system-wide
  #################################
  environment.systemPackages = [ pkgs.starship ];

  #################################
  # Home Manager user configuration
  #################################
  _module.args.hmUsers = {
    ${username} = {
      programs.starship = {
        enable = true;
      };

      # Copy the starship.toml from assets to ~/.config/starship.toml
      home.file = {
        ".config/starship.toml" = { source = starshipConfSrc; };
      };
    };
  };
}

generated/modules/traveldroid/desktop

generated/modules/traveldroid/desktop/hyprland.nix

Setting up Hyprland

{ lib, config, pkgs, flakeRoot, home-manager, inputs, ... }:

let
  username = config.defaultUser or "henrov";
  assetPath = "${flakeRoot}/assets/traveldroid/conf/hypr/";

  # Read all files in the asset directory
  assetFiles = builtins.attrNames (builtins.readDir assetPath);

  # Convert files to Home Manager xdg config entries
  hyprFiles = lib.genAttrs assetFiles (f: {
    # Destination path in home directory
    name = ".config/hypr/${f}";
    # Source file path
    value = { source = "${assetPath}/${f}"; };
  });

  # Determine Hyprland package
  hyprlandPkg =
    pkgs.hyprland or
    pkgs.hyprland-git or
    inputs.hyprland.packages.${pkgs.system}.default;
in
{
  environment.systemPackages = [ hyprlandPkg ];

  _module.args.hmUsers = {
    ${username} = {
      home.packages = [ hyprlandPkg ];

      # Merge all files in the asset folder into ~/.config/hypr/
      home.file = lib.mkMerge hyprFiles;

      # Optional: Hyprland settings
      settings.general."col.active_border" = "0xff97cbcd 0xff89b4fa";
    };
  };
}

generated/modules/traveldroid/desktop/stylix.nix

{ lib, config, pkgs, flakeRoot, ... }:

let
  # Determine the default username from host config
  username = config.defaultUser or "henrov";

  moduleName = "stylix";
  assetPath  = "${flakeRoot}/assets/traveldroid/conf/";

  # Read all files in the asset directory
  programFiles = builtins.readDir assetPath;

  files = lib.genAttrs (builtins.attrNames programFiles) (name: {
    source = "${assetPath}/${name}";
  });

  # Optional stylix.conf
  stylixConfFile = "${assetPath}/stylix.conf";
  stylixConf =
    if builtins.pathExists stylixConfFile
    then builtins.readFile stylixConfFile
    else "";

  # Cursor defaults
  cursorName = "phinger-cursors-light";
  cursorSize = 24;
in
{
  ############################
  # System-level packages
  ############################
  environment.systemPackages = [
    pkgs.feh
    pkgs.st
  ];

  ############################
  # Home Manager user config
  ############################
  _module.args.hmUsers = {
    ${username} = {

      # Map all config files into ~/.config/stylix/
      xdg.configFile =
        lib.mapAttrs' (name: value: {
          name = "${moduleName}/${name}";
          value = { inherit (value) source; };
        }) files;

      # Environment variables for the session
      home.sessionVariables = {
        STYLIX_CONF      = "$HOME/.config/stylix/stylix.conf";

        XCURSOR_THEME    = cursorName;
        XCURSOR_SIZE     = toString cursorSize;
        HYPRCURSOR_THEME = cursorName;
        HYPRCURSOR_SIZE  = toString cursorSize;
      };
    };
  };
}

generated/modules/traveldroid/desktop/wayland.nix

{ lib, config, pkgs, ... }:

{
  #################################
  # Core Wayland packages
  #################################
  environment.systemPackages = with pkgs; [
    wayland
    wl-clipboard      # optional but commonly used for copy/paste
  ];

  #################################
  # Optional: enable graphics stack
  #################################
  hardware.graphics.enable = true;

  #################################
  # Optional session variables for Wayland
  #################################
  environment.sessionVariables = {
    # Forces some apps to use Wayland
    NIXOS_OZONE_WL = "1";
  };
}

generated/modules/traveldroid/desktop/xdg.nix

This sets the XDG implementation

{ lib, config, pkgs, inputs, ... }:

let
  #################################
  # Default username fallback
  #################################
  username = config.defaultUser or "henrov";

  #################################
  # Determine XDG portal package
  #################################
  xdgPortalHyprlandPkg =
    pkgs.xdg-desktop-portal-hyprland or
    inputs.xdgPortalHyprland.packages.${pkgs.system}.default;
in
{
  #################################
  # System-wide packages
  #################################
  environment.systemPackages = [
    xdgPortalHyprlandPkg
  ];

  #################################
  # Home Manager user config
  #################################
  _module.args.hmUsers = {
    ${username} = {
      home.packages = [
        xdgPortalHyprlandPkg
      ];

      # Enable XDG portal integration for Hyprland
      xdg.portal = {
        enable = true;
        extraPortals = [ xdgPortalHyprlandPkg ];
        config.hyprland = {
          "org.freedesktop.impl.portal.Screencast" = [ "hyprland" ];
        };
      };
    };
  };
}

generated/modules/traveldroid/system

generated/modules/traveldroid/system/nix.nix

{ lib, config, ... }:

{
    nix.settings = {
      experimental-features = [ "nix-command" "flakes" ];
      download-buffer-size = 536870912; # 512 MB
      cores = 2;
      max-jobs = 1;
    };
}

generated/users

generated/users/copy_2_home.nix

This copies stuff to the user home-folder

{ config, pkgs, lib, flakeRoot, ... }:

let
  username  = config.users.users.defaultUser or "henrov";
  homeDir   = "/home/${username}";
  assetPath = "${flakeRoot}/assets/copy_2_home";
in
{
  environment.systemPackages = [ pkgs.rsync ];

  systemd.services.copyAssets = {
    description = "Copy assets to ${username}'s home directory";
    wantedBy = [ "multi-user.target" ];

    # oneshot service runs once at boot
    serviceConfig.Type = "oneshot";

    # Always use /bin/sh -c for multi-line commands
    serviceConfig.ExecStart = ''
      /bin/sh -c '
        echo "Copying assets from ${assetPath} to ${homeDir} ..."

        if [ ! -d "${assetPath}" ]; then
          echo "ERROR: ${assetPath} does not exist"
          exit 1
        fi

        mkdir -p "${homeDir}"
        chown ${username}:${username} "${homeDir}"

        ${pkgs.rsync}/bin/rsync -a --no-owner --no-group "${assetPath}/" "${homeDir}/"

        echo "Done copying assets."
      '
    '';
  };
}

generated/users/henrov.nix

This is the default user, just search and replace henrov another name if you want to change

{ lib, config, pkgs, ... }:

let
  username = "henrov";
in
{
  #################################
  # NixOS system user
  #################################
  users.users.${username} = {
    isNormalUser = true;
    home = "/home/${username}";
    hashedPassword = "$6$S7iShgBxB.77CwmP$i0njK.2r3OL5UEvgZbmwZ0rnpZ4QyJcv8p9uCmJ4AiVPSMXkQkIwMLzyAOnJ0q8.tPLIp/7EquEIZeK8qbmgw/";
    extraGroups = [ "wheel" "networkmanager" ];
  };

  #################################
  # Home Manager user definition
  #################################
  _module.args.hmUsers = {
    ${username} = {
      # Minimal required
      home.username      = username;
      home.homeDirectory = "/home/${username}";
      home.stateVersion  = "26.05";

      # Add user-specific packages here
      home.packages = [
      ];

      # Add user dotfiles, session variables, etc. here if needed
      home.file = {
        # Example:
        # ".bashrc" = { source = /path/to/bashrc; };
      };
    };
  };
}