Files
nixos/Droidnix_v2/README.org
T
2026-03-23 16:18:38 +00:00

50 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/system/
    • generated/parked/desktop/
    • Machine-specific configurations from assets/machines/

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.

Templates look like this   code

generated/template.nix

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

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

  # Asset folder for configs
  assetPath = ../../../assets/<myModuleName>/conf;

  # Main configuration file
  mainConfig = "${assetPath}/<mainConfigFile>";

  # Determine the package: prefer Nixpkgs, fallback to -git, fallback to flake input
  myPkg =
    pkgs.<myPackage> or
    pkgs.<myPackage>-git or
    inputs.<myPackage>.packages.${pkgs.system}.default;
in
{
  # Install system-wide
  environment.systemPackages = [ myPkg ];

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

      # Copy main config into user's home
      home.file.".config/<myModuleName>/<mainConfigFile>".source = mainConfig;

      # Optional module-specific settings
      settings.general = {
        # Example placeholder
        "example.setting" = "value";
      };

      # Optional: you can add more files dynamically from assetPath if needed
    };
  };
}

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";
    };

    flake-parts.url = "github:hercules-ci/flake-parts";
    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 = inputs@{ flake-parts, nixpkgs, import-tree, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      systems = [ "x86_64-linux" ];

      flake = {
        nixosConfigurations.traveldroid = nixpkgs.lib.nixosSystem {
          system = "x86_64-linux";

          specialArgs = {
            inherit inputs;
            flakeRoot = ./.;  # <-- Pass the absolute path of the flake root
          };

          modules = [
            ./generated/hosts/traveldroid/boot.nix
            ./generated/hosts/traveldroid/hardware-configuration.nix

            # Import all dendritic modules (users, desktops, system modules)
            (import-tree ./generated/traveldroid/todo)

            # Extra modules
            inputs.stylix.nixosModules.default
            inputs.home-manager.nixosModules.home-manager
          ];
        };
      };
    };
}

generated/hosts/traveldroid/traveldroid.nix

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

let
  username = config.defaultUser or "henrov";
  modulesPath = ./generated/traveldroid/todo;

  # Import all modules recursively (DO NOT evaluate them)
  importedModules = inputs.import-tree modulesPath;

  # Collect Home Manager user attrsets from modules
  hmUsersList =
    map (m: m._module.args.hmUsers or {})
      importedModules.imports;

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

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

  #################################
  # Module imports (critical fix)
  #################################

  programs.home-manager.enable = true;

  imports =
    [
      ./boot.nix
      ./hardware-configuration.nix
    ]
    ++ importedModules.imports;

  #################################
  # Home Manager aggregation
  #################################

  home-manager.users = lib.mkMerge hmUsersList;
}

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";
}

We have a nix file that will copy anything from ./assets/copy_2_home to $HOME

generated/traveldroid/todo/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."
      '
    '';
  };
}

Let's define the core of the system

generated/traveldroid/todo/system/networking.nix

This sets the networking.

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

{
  networking = {
    useDHCP = lib.mkDefault true;

    networkmanager = {
      enable = true;
      wifi.backend = "iwd";
    };

    wireless = {
      iwd.enable = true;
      userControlled.enable = true;
    };

    firewall = {
      enable = true;

      # KDE Connect: discovery + encrypted connections
      allowedTCPPortRanges = [
        { from = 1714; to = 1764; }
      ];

      allowedUDPPortRanges = [
        { from = 1714; to = 1764; }
      ];
    };
  };

  # Ensure NetworkManager tools are available
  environment.systemPackages = [
    pkgs.networkmanager
  ];
}

generated/traveldroid/todo/system/services.nix

This sets the networking.

{ lib, config, ... }:

{
  # --- Users & Groups ---
  users.users.rtkit = {
    isSystemUser = true;
    uid = 992;
    group = "rtkit";
    home = "/nonexistent";
    shell = "/usr/bin/nologin";
  };

  users.groups.rtkit = {
    gid = 989;
  };

  # --- Services (Printing & Audio) ---
  services.printing.enable = true;
  #services.pulseaudio.enable = false;

  security.rtkit.enable = true;

  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
  };
}

generated/traveldroid/todo/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 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} = {
      home.username = username;
      home.homeDirectory = "/home/${username}";
      home.stateVersion = "26.05";

      # Example: user packages
      home.packages = [ pkgs.git pkgs.vim ];
    };
  };
}

generated/traveldroid/todo/system/homebase.nix

{ lib, config, ... }:

let
  coreEnabled = config.mySystem.system.core.enable or false;
in
{
  options.mySystem.system.locale.enable =
    lib.mkEnableOption "Home-Manager settings";

  config = lib.mkIf (coreEnabled || config.mySystem.system.locale.enable) {

    # --- Home Manager Base ---
    home-manager = {
      backupFileExtension = "backup";

      users.henrov = {
	  home.sessionVariables = {
	    TERMINAL = "kitty";
	    EDITOR = "emacs";
	    BROWSER = "zen";
	  };

        home.stateVersion = "26.05";
      };
    };

  };
}

generated/traveldroid/todo/system/nix.nix

{ lib, config, ... }:

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

First the nix-files that flake really needs and that do not fit wel in the hierarchical structure

generated/traveldroid/todo/system/dbus.nix

This sets the dbus implementation

{ config, pkgs, lib, ... }:
{
  services.dbus = lib.mkForce {
    enable = true; # Force this to be true
  };

  # Configure dbus-broker via its configuration file
  environment.etc."dbus-broker/launch.conf".text = ''
    [General]
    LogLevel=warning
    MaxConnectionsPerUser=2048
  '';
}

generated/traveldroid/todo/system/bluetooth.nix

This sets the bluetooth implementation

{ config, pkgs, ... }:

{
  ############################
  # Bluetooth hardware
  ############################
  hardware.bluetooth = {
    enable = true;        # turn on the daemon
    powerOnBoot = true;   # auto-power on
    package = pkgs.bluez; # singular, not a list
  };

  ############################
  # GUI Bluetooth manager
  ############################
  environment.systemPackages = with pkgs; [
    blueman       # graphical Bluetooth manager
  ];

  ############################
  # PipeWire for Bluetooth audio
  ############################
  # services.pipewire.enable = true;
}

generated/traveldroid/todo/desktop/xdg.nix

This sets the XDG implementation

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

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

  # Safe package reference with flake input fallback
  xdgPortalHyprlandPkg = pkgs.xdg-desktop-portal-hyprland or
                         inputs.xdgPortalHyprland.packages.${pkgs.system}.default;
in
{
  # System-wide installation of XDG portal package
  environment.systemPackages = [
    xdgPortalHyprlandPkg
  ];

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

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

generated/traveldroid/todo/desktop/stylix.nix

This sets the stylix implementation

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

let
  username = config.defaultUser or "henrov";

  moduleName = "stylix";
  assetPath = ../../../assets/system/conf/${moduleName};

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

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

  # Read 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 packages
  environment.systemPackages = [
    pkgs.feh
    pkgs.st
  ];

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

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

      # Session variables
      home.sessionVariables = {
        STYLIX_CONF = "$HOME/.config/stylix/stylix.conf";

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

generated/traveldroid/todo/system/terminal.nix

Sets theming for the terminal

{ config, pkgs, ... }:

{
  # (NVF = Neovim/terminal flavor)
  stylix.targets.nvf.enable = true;
  # feh wallpaper integration
  stylix.targets.feh.enable = true;
}

generated/parked/desktop/rotating_wallpaper.nix

rotating_wallpaper.nix installs wpaperd and deploys your wallpaper files from the repo (./assets/hyprland/wallpaperstuff/) into ~/Droidnix/wallpaperstuff/. You can edit assets/hyprland/wallpaperstuff/wallpaper.toml to change settings Finally, it creates a systemd user service (wpaperd.service) that automatically starts wpaperd at login and keeps it running, using your override config so wallpapers rotate according to your settings.

{ lib, … }:

{ flake.nixosModules.rotating-wallpaper = { config, pkgs, lib, … }:

let wallpaperConf = ../../../assets/hyprland/wallpaperstuff/wallpaper.toml; in { options.mySystem.desktop.wallpaper.enable = lib.mkEnableOption "Enable rotating wallpaper via wpaperd";

config = lib.mkIf (config.mySystem.desktop.wallpaper.enable or false) {

home-manager.users.henrov = {

home.packages = [ pkgs.wpaperd ];

home.file.".config/wpaperd/wallpaper.toml".source = wallpaperConf;

systemd.user.services.wpaperd = { description = "wpaperd wallpaper daemon"; wantedBy = [ "default.target" ];

serviceConfig = { Type = "simple"; ExecStart = "${pkgs.wpaperd}/bin/wpaperd config ~/.config/wpaperd/wallpaper.toml"; Restart = "on-failure"; RestartSec = 1; }; }; }; }; }; }

generated/traveldroid/todo/desktop/hyprland.nix

Setting up Hyprland

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

let
  username = config.defaultUser or "henrov";

  # Paths
  assetPath = ../../../assets/hyprland/conf/hypr;
  mainConfig = "${assetPath}/hyprland.conf";

  # Determine Hyprland package with fallbacks
  hyprlandPkg =
    pkgs.hyprland or
    pkgs.hyprland-git or
    inputs.hyprland.packages.${pkgs.system}.default;

  # Map all files in the asset folder
  hyprFiles =
    builtins.listToAttrs (
      map (f: {
        name = ".config/hypr/${f}";
        value = { source = "${assetPath}/${f}"; };
      }) (builtins.attrNames (builtins.readDir assetPath))
    );
in
{
  # System-wide package
  environment.systemPackages = [ hyprlandPkg ];

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

      # Merge main config + all other files
      home.file = lib.mkMerge [
        hyprFiles
        {
          ".config/hypr/hyprland.conf" = { source = mainConfig; };
        }
      ];

      # Optional module-specific settings
      settings.general."col.active_border" = "0xff97cbcd 0xff89b4fa";
    };
  };
}

generated/traveldroid/todo/apps/packages.nix

This installs a list of apps

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

let
  packagesConfPath = "${flakeRoot}/assets/system/apps/packages.conf";
  raw = builtins.readFile packagesConfPath;

  # Split lines safely, keep guard against splitting into characters
  rawLines = lib.splitString "\n" raw;
  _guard =
    assert !(builtins.stringLength raw > 1 && builtins.length rawLines == builtins.stringLength raw);
    true;

  # Clean each line: remove CRs, remove comments, trim
  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 path 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
{

  nixpkgs.config = { allowUnfree = true; };
  environment.systemPackages = packages;
}

generated/traveldroid/todo/apps/zenbrowser.nix

This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder

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

let
  # Grab the Zen Browser from the flake overlay for your system
  zenBrowser = inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default;
in
{
  environment.systemPackages = [
    zenBrowser
  ];
}

generated/traveldroid/todo/apps/flatpaks.nix

This will import all packages listed in ../../assets/system/apps/flatpaks.conf

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

let
  # Module name
  moduleName = "flatpaks";

  # Path to your Flatpak list
  assetPath = ../../../assets/system/apps/flatpaks.conf;

  # Resolve user safely
  username = config.defaultUser or "henrov";
in
{
      # Deploy the Flatpak conf file
    environment.etc."flatpak/flatpaks.conf".source = assetPath;

    # Enable system Flatpak service
    services.flatpak.enable = true;


    # Systemd service to install Flatpaks from the list
    systemd.services."${moduleName}-sync" = {
      description = "Install Flatpak apps listed in flatpaks.conf";
      wantedBy    = [ "multi-user.target" ];
      wants       = [ "network-online.target" ];
      after       = [ "network-online.target" ];

      serviceConfig = {
        Type = "oneshot";
        ExecStart = ''
          set -euo pipefail
          CONF="${assetPath}"

          # Add Flathub if not present
          if ! flatpak remotes --system --columns=name | grep -qx flathub; then
            flatpak remote-add --system --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
          fi

          # Install every Flatpak listed in the conf file
          while IFS= read -r app || [ -n "$app" ]; do
            app=$(echo "$app" | sed 's/#.*//;s/^[[:space:]]*//;s/[[:space:]]*$//')
            if [ -n "$app" ]; then
              if ! flatpak info --system "$app" >/dev/null 2>&1; then
                flatpak install --system -y --noninteractive flathub "$app"
              fi
            fi
          done < "$CONF"
        '';
      };

      restartTriggers = [ assetPath ];

      # Include only the packages needed for this service
      path = [ pkgs.flatpak pkgs.coreutils pkgs.gnugrep pkgs.gnused ];
    };
}

generated/traveldroid/todo/desktop/gtk.nix

Setting up GTK

{ pkgs, user, ... }:
{
  environment.systemPackages = with pkgs; [
      gtk3     # GTK target
      gtk4     # GTK target
    ];
  # Stylix GTK target
  stylix.targets.gtk.enable = true;

  home-manager.users.${user.username} = {
    gtk = {
      enable = true;
      theme = {
        name = "Catppuccin-Mocha-Standard-Blue-Dark";
        package = pkgs.magnetic-catppuccin-gtk;
      };
      iconTheme = {
        name = "Papirus-Dark";
        package = pkgs.papirus-icon-theme;
      };
      gtk3.extraConfig = {
        gtk-application-prefer-dark-theme = 1;
      };
      gtk4.extraConfig = {
        gtk-application-prefer-dark-theme = 1;
      };
    };

  };
}

generated/parked/desktop/fonts.nix

This file installs and configures fonts

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

{
  options.enableFonts = lib.mkEnableOption "Enable nerd fonts";

  config = lib.mkIf (config.enableFonts or false) {
    fonts.packages = with pkgs; [
      nerd-fonts.iosevka
      nerd-fonts.fira-code
    ];
  };
}

generated/traveldroid/todo/desktop/waybar.nix

This file installs and configures waybar

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

let
  username  = config.defaultUser or "henrov";
  assetPath = ../../../assets/system/conf/waybar;
in
{
  # Install Waybar globally
  environment.systemPackages = [ pkgs.waybar ];

  # Contribute to the existing Home Manager users map safely
  home-manager.users = lib.recursiveUpdate config.home-manager.users {
    ${username} = {
      home.file = lib.recursiveUpdate (config.home-manager.users.${username}.home.file or {}) {
        ".config/waybar/config"  = { source = "${assetPath}/config"; };
        ".config/waybar/style.css" = { source = "${assetPath}/style.css"; };
      };
    };
  };
}

generated/traveldroid/todo/system/login-tuigreeter.nix

This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder

{ pkgs, user, ... } :
{
environment.systemPackages = with pkgs; [
tuigreet
];
services.greetd = {
enable = true;
settings = {
  default_session = {
  command = pkgs.lib.mkForce "${pkgs.tuigreet}/bin/tuigreet --remember --time --time-format '%I:%M %p | %a • %h | %F'";
  };
};
};
}

generated/traveldroid/todo/desktop/wayland.nix

This file sets up wayland

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

let
  username = config.defaultUser or "henrov";

  # Wayland-specific packages: uwsm
  uwsmPkg =
    if builtins.hasAttr "uwsm" pkgs then
      pkgs.uwsm
    else
      (inputs.uwsm.packages.${pkgs.system}.default or pkgs.uwsm);
in
{
  # System packages
  environment.systemPackages = [ uwsmPkg ];

  # Enable Hyprland via Home Manager / programs
  programs.hyprland.enable = true;

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

      # Optional Hyprland-specific user configs
      # programs.hyprland.enable = true; # not needed if set at global level
    };
  };
}

generated/traveldroid/todo/apps/thunar.nix

This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder

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

let
  username = config.defaultUser or "henrov";
in
{
  # System-wide Thunar with essential plugins
  environment.systemPackages = with pkgs; [
    thunar                  # main file manager
    thunar-archive-plugin    # zip, tar, rar, 7z support
    thunar-volman            # auto-mount removable drives
    gvfs                     # support for external drives and network shares
    xarchiver                 # optional GUI archive manager
  ];

  # Home Manager configuration
  home-manager.users.${username} = {
    home.stateVersion = "26.05";  # required

    home.sessionVariables = {
      FILE_MANAGER = "thunar";
      USERNAME     = username;
    };
  };
}

generated/traveldroid/todo/terminals/kitty.nix

This file sets up Kitty terminal

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

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

  # Paths and files
  assetPath = ../../../assets/system/conf/${moduleName};
  programFiles = builtins.readDir assetPath;
  files = lib.genAttrs (builtins.attrNames programFiles) (name: {
    src = "${assetPath}/${name}";
  });
in
{
  # Install kitty system-wide
  environment.systemPackages = [ pkgs.kitty ];

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

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

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

generated/moduled/terminals/starship.nix

This file sets up starship prompt

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

{
  programs.starship = {
    enable = true;      # enable Starship integration
  };
}

generated/traveldroid/todo/terminals/zsh.nix

This sets up the zsh in the terminal

{ config, pkgs, lib, ... }:
{
  programs.zsh = {
    enable = true;
    enableCompletion = true;
    #autocd = true;
    #dotDir = "${config.xdg.configHome}/zsh";
    ohMyZsh = {
      enable = true;
      theme = "";
      plugins = [
        "git"
        "sudo"
        "extract"
        "colored-man-pages"
        "command-not-found"
        "history"
        "docker"
        "kubectl"
      ];
    };
    #autosuggestion.enable = true;
    syntaxHighlighting.enable = true;
  };
}

generated/parked/apps/emacs/emacs.nix

This sets up the emacs terminal

{ pkgs, config, ... }:

let
  username = config.defaultUser or "henrov";
in
{
  environment.systemPackages = [
    pkgs.emacs-pgtk.override { withTreeSitter = true; }
  ];

  home-manager.users.${username} = {
    home.stateVersion = "26.05";

    programs.emacs = {
      enable  = true;
      package = pkgs.emacs-pgtk.override { withTreeSitter = true; };

      extraPackages = epkgs: with epkgs; [
        #(epkgs.manualPackages.treesit-grammars.override { withAllGrammars = true; })
        rust-mode
        rustic
        nix-mode
        hcl-mode
        nerd-icons
        doom-modeline
        diminish
        eldoc
        eldoc-box
        pulsar
        which-key
        avy
        consult
        vertico
        marginalia
        crux
        shell-pop
        nerd-icons-corfu
        corfu
        cape
        orderless
        yasnippet
        yasnippet-snippets
        rg
        exec-path-from-shell
        eat
        f
        gptel
        nixpkgs-fmt
        envrc
        catppuccin-theme
        magit
        expreg
        vundo
        puni
        sideline
        sideline-flymake
        sideline-eglot
      ];

      # Load your init.el via extraConfig
      extraConfig = builtins.readFile ./init.el;
    };

    home.sessionVariables = {
      EDITOR = "emacs";
      XDG_SCREENSHOTS_DIR = "~/screenshots";
    };
  };
}

generated/traveldroid/todo/apps/emacs/early-init.el

This helps set up the emacs terminal

;;; package --- early init -*- lexical-binding: t -*-
 ;;; Commentary:
 ;;; Prevents white flash and better Emacs defaults
 ;;; Code:
 (set-language-environment "UTF-8")
 (setq-default
default-frame-alist
'((background-color . "#1e1e2e")
  (bottom-divider-width . 1)    ; Thin horizontal window divider
  (foreground-color . "#bac2de")    ; Default foreground color
  (fullscreen . maximized)      ; Maximize the window by default
  (horizontal-scroll-bars . nil)    ; No horizontal scroll-bars
  (left-fringe . 8)       ; Thin left fringe
  (menu-bar-lines . 0)      ; No menu bar
  (right-divider-width . 1)     ; Thin vertical window divider
  (right-fringe . 8)        ; Thin right fringe
  (tool-bar-lines . 0)      ; No tool bar
  (undecorated . t)       ; Remove extraneous X decorations
  (vertical-scroll-bars . nil))   ; No vertical scroll-bars
user-full-name "Henrov henrov"      ; ME!
;; memory configuration
;; Higher garbage collection threshold, prevents frequent gc locks, reset later
gc-cons-threshold most-positive-fixnum
;; Ignore warnings for (obsolete) elisp compilations
byte-compile-warnings '(not obsolete)
;; And other log types completely
warning-suppress-log-types '((comp) (bytecomp))
;; Large files are okay in the new millenium.
large-file-warning-threshold 100000000
;; dont show garbage collection messages at startup, will reset later
garbage-collection-messages nil
;; native compilation
package-native-compile t
native-comp-warning-on-missing-source nil
native-comp-async-report-warnings-errors 'silent
;; Read more based on system pipe capacity
read-process-output-max (max (* 10240 10240) read-process-output-max)
;; scroll configuration
scroll-margin 0           ; Lets scroll to the end of the margin
scroll-conservatively 100000        ; Never recenter the window
scroll-preserve-screen-position 1     ; Scrolling back and forth
;; frame config
;; Improve emacs startup time by not resizing to adjust for custom settings
frame-inhibit-implied-resize t
;; Dont resize based on character height / width but to exact pixels
frame-resize-pixelwise t
;; backups & files
backup-directory-alist '(("." . "~/.backups/")) ; Don't clutter
backup-by-copying t           ; Don't clobber symlinks
create-lockfiles nil          ; Don't have temp files
delete-old-versions t         ; Cleanup automatically
kept-new-versions 6           ; Update every few times
kept-old-versions 2           ; And cleanup even more
version-control t           ; Version them backups
delete-by-moving-to-trash t       ; Dont delete, send to trash instead
;; startup
inhibit-startup-screen t        ; I have already done the tutorial. Twice
inhibit-startup-message t         ; I know I am ready
inhibit-startup-echo-area-message t     ; Yep, still know it
initial-scratch-message nil       ; I know it is the scratch buffer!
initial-buffer-choice nil
inhibit-startup-buffer-menu t
inhibit-x-resources t
initial-major-mode 'fundamental-mode
pgtk-wait-for-event-timeout 0.001     ; faster child frames
ad-redefinition-action 'accept      ; dont care about legacy things being redefined
inhibit-compacting-font-caches t
;; tabs
tab-width 4             ; Always tab 4 spaces.
indent-tabs-mode nil          ; Never use actual tabs.
;; rendering
cursor-in-non-selected-windows nil      ; dont render cursors other windows
;; packages
use-package-always-defer t
load-prefer-newer t
default-input-method nil
use-dialog-box nil
use-file-dialog nil
use-package-expand-minimally t
package-enable-at-startup nil
use-package-enable-imenu-support t
auto-mode-case-fold nil  ; No second pass of case-insensitive search over auto-mode-alist.
package-archives '(("melpa"    . "https://melpa.org/packages/")
        ("gnu"    . "https://elpa.gnu.org/packages/")
        ("nongnu"   . "https://elpa.nongnu.org/nongnu/")
        ("melpa-stable" . "https://stable.melpa.org/packages/"))
package-archive-priorities '(("gnu"  . 99)
            ("nongnu" . 80)
            ("melpa"  . 70)
            ("melpa-stable" . 50))
)
;;; early-init.el ends here

generated/traveldroid/todo/apps/emacs/init.el

This helps set up the emacs terminal

;;; package --- Summary - My minimal Emacs init file -*- lexical-binding: t -*-

;;; Commentary:
;;; Simple Emacs setup I carry everywhere

;;; Code:
(setq custom-file (locate-user-emacs-file "custom.el"))
(load custom-file 'noerror)    ;; no error on missing custom file

(require 'package)
(package-initialize)

(defun reset-custom-vars ()
"Resets the custom variables that were set to crazy numbers"
(setopt gc-cons-threshold (* 1024 1024 100))
(setopt garbage-collection-messages t))

(use-package emacs
:custom
(native-comp-async-query-on-exit t)
(read-answer-short t)
(use-short-answers t)
(enable-recursive-minibuffers t)
(which-func-update-delay 1.0)
(visible-bell nil)
(custom-buffer-done-kill t)
(whitespace-line-column nil)
(x-underline-at-descent-line t)
(imenu-auto-rescan t)
(uniquify-buffer-name-style 'forward)
(confirm-nonexistent-file-or-buffer nil)
(create-lockfiles nil)
(make-backup-files nil)
(kill-do-not-save-duplicates t)
(sentence-end-double-space nil)
(treesit-enabled-modes t)
:init
;; base visual
(menu-bar-mode -1)       ;; no menu bar
(toggle-scroll-bar -1)     ;; no scroll bar
(tool-bar-mode -1)       ;; no tool bar either
(blink-cursor-mode -1)     ;; stop blinking

;; font of the century
(set-frame-font "Aporetic Sans Mono 12" nil t)

:bind
(("C-<wheel-up>" . pixel-scroll-precision) ; dont zoom in please, just scroll
 ("C-<wheel-down>" . pixel-scroll-precision) ; dont zoom in either, just scroll
 ("C-x k"    . kill-current-buffer)) ; kill the buffer, dont ask
:hook
(text-mode . delete-trailing-whitespace-mode)
(prog-mode . delete-trailing-whitespace-mode)
(after-init . global-display-line-numbers-mode) ;; always show line numbers
(after-init . column-number-mode)     ;; column number in the mode line
(after-init . size-indication-mode)     ;; file size in the mode line
(after-init . pixel-scroll-precision-mode)  ;; smooth mouse scroll
(after-init . electric-pair-mode)     ;; i mean ... parens should auto create
(after-init . reset-custom-vars)
)

(use-package autorevert
:ensure nil
:custom
(auto-revert-interval 3)
(auto-revert-remote-files nil)
(auto-revert-use-notify t)
(auto-revert-avoid-polling nil)
(auto-revert-verbose t)
:hook
(after-init . global-auto-revert-mode))

(use-package recentf
:ensure nil
:commands (recentf-mode recentf-cleanup)
:hook
(after-init . recentf-mode)
:custom
(recentf-auto-cleanup 'never)
(recentf-exclude
 (list "\\.tar$" "\\.tbz2$" "\\.tbz$" "\\.tgz$" "\\.bz2$"
   "\\.bz$" "\\.gz$" "\\.gzip$" "\\.xz$" "\\.zip$"
   "\\.7z$" "\\.rar$"
   "COMMIT_EDITMSG\\'"
   "\\.\\(?:gz\\|gif\\|svg\\|png\\|jpe?g\\|bmp\\|xpm\\)$"
   "-autoloads\\.el$" "autoload\\.el$"))

:config
;; A cleanup depth of -90 ensures that `recentf-cleanup' runs before
;; `recentf-save-list', allowing stale entries to be removed before the list
;; is saved by `recentf-save-list', which is automatically added to
;; `kill-emacs-hook' by `recentf-mode'.
(add-hook 'kill-emacs-hook #'recentf-cleanup -90))

(use-package savehist
:ensure nil
:commands (savehist-mode savehist-save)
:hook
(after-init . savehist-mode)
:custom
(savehist-autosave-interval 600)
(savehist-additional-variables
 '(kill-ring        ; clipboard
 register-alist       ; macros
 mark-ring global-mark-ring   ; marks
 search-ring regexp-search-ring)))

(use-package hl-line
:ensure nil
:custom
(hl-line-sticky-flag nil)
(global-hl-line-sticky-flag nil)
:hook
(after-init . global-hl-line-mode))

(use-package saveplace
:ensure nil
:commands (save-place-mode save-place-local-mode)
:hook
(after-init . save-place-mode)
:custom
(save-place-limit 400))

(use-package nerd-icons
:custom
;; disable bright icon colors
(nerd-icons-color-icons nil))hells.nix

(use-package doom-modeline
:custom
(inhibit-compacting-font-caches t)  ;; speed
(doom-modeline-buffer-file-name-style 'relative-from-project)
(doom-modeline-major-mode-icon nil) ;; distracting icons, no thank you
(doom-modeline-buffer-encoding nil) ;; everything is utf-8 anyway
(doom-modeline-buffer-state-icon nil) ;; the filename already shows me
(doom-modeline-lsp nil)     ;; lsp state is too distracting, too often
:hook (after-init . doom-modeline-mode))

(load-theme 'catppuccin :no-confirm)

(use-package diminish :demand t)   ;; declutter the modeline
(use-package eldoc
:diminish eldoc-mode
:custom
(eldoc-echo-area-use-multiline-p nil)) ;; docs for everything

(use-package eldoc-box
:defer t
:config
(set-face-background 'eldoc-box-border (catppuccin-color 'green))
(set-face-background 'eldoc-box-body (catppuccin-color 'base))
:bind
(("M-h" . eldoc-box-help-at-point)))

(use-package pulsar
:commands pulsar-global-mode pulsar-recenter-top pulsar-reveal-entry
:init
(defface pulsar-catppuccin
`((default :extend t)
  (((class color) (min-colors 88) (background light))
 :background ,(catppuccin-color 'sapphire))
  (((class color) (min-colors 88) (background dark))
 :background ,(catppuccin-color 'sapphire))
  (t :inverse-video t))
"Alternative nord face for `pulsar-face'."
:group 'pulsar-faces)
:custom
(pulsar-face 'pulsar-catppuccin)
:hook
(after-init . pulsar-global-mode))

(use-package which-key
:commands which-key-mode
:diminish which-key-mode
:hook
(after-init . which-key-mode))

(use-package expreg
:bind ("M-m" . expreg-expand))

(use-package vundo) ;; undo tree

;; better structured editing
(use-package puni
:commands puni-global-mode
:hook
(after-init . puni-global-mode))

(use-package avy
:bind
("M-i" . avy-goto-char-2)
:custom
(avy-background t))

(use-package consult
:bind
("C-x b" . consult-buffer)   ;; orig. switch-to-buffer
("M-y"   . consult-yank-pop) ;; orig. yank-pop
("M-g M-g" . consult-goto-line)  ;; orig. goto-line
("M-g i" . consult-imenu)  ;; consult version is interactive
("M-g r" . consult-ripgrep)  ;; find in project also works
:custom
(consult-narrow-key "<"))

(use-package vertico
:commands vertico-mode
:custom
(read-file-name-completion-ignore-case t)
(read-buffer-completion-ignore-case t)
(completion-ignore-case t)
(enable-recursive-minibuffers t)
(minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt))
:init
(vertico-mode)
:hook
(minibuffer-setup-hook . cursor-intangible-mode))

(use-package marginalia
:commands marginalia-mode
:hook (after-init . marginalia-mode))

(use-package crux
:bind
("C-c M-e" . crux-find-user-init-file)
("C-c C-w" . crux-transpose-windows)
("C-c M-d" . crux-find-current-directory-dir-locals-file)
("C-a"   . crux-move-beginning-of-line))

(use-package magit
:bind (("C-M-g" . magit-status)))

(use-package nerd-icons-corfu
:commands nerd-icons-corfu-formatter
:defines corfu-margin-formatters)

(use-package corfu
:commands global-corfu-mode
:custom
(corfu-cycle t)
(corfu-auto t)
(corfu-auto-delay  1)
(corfu-auto-prefix 3)
(corfu-separator ?_)
:hook
(after-init . global-corfu-mode)
:config
(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))

(use-package cape)

(use-package orderless
:custom
(completion-styles '(orderless partial-completion basic))
(completion-category-defaults nil)
(completion-category-overrides nil))

(use-package yasnippet
:commands yas-global-mode
:diminish yas-minor-mode
:hook
(after-init . yas-global-mode))

(use-package yasnippet-snippets :after yasnippet)

(use-package exec-path-from-shell
:commands exec-path-from-shell-initialize
:custom
(exec-path-from-shell-arguments nil)
:hook
(after-init . exec-path-from-shell-initialize))

(use-package nixpkgs-fmt
:custom
(nixpkgs-fmt-command "nixfmt"))

(use-package eat
:bind
(("C-c e p" . eat-project)
 ("C-c e t" . eat)))

(use-package f :demand t)

(use-package envrc
:commands envrc-global-mode
:hook
(after-init . envrc-global-mode))

(use-package gptel
:commands gptel-make-anthropic f-read-text
:config
(gptel-make-anthropic "Claude"
:stream t :key (f-read-text "/run/secrets/claude_key")))

(use-package sideline-flymake)
(use-package sideline-eglot)
(use-package sideline
:custom
(sideline-backends-right '(sideline-flymake sideline-eglot))
:hook
(eglot-managed-mode . sideline-mode)
(flymake-mode . sideline-mode))

(use-package eglot
:custom
(eglot-extend-to-xref t)
(eglot-ignored-server-capabilities '(:inlayHintProvider))
(jsonrpc-event-hook nil)
:hook
(eglot-managed-mode . eldoc-box-hover-mode)
(before-save . eldoc-format-buffer)
:bind
(:map eglot-mode-map
  ("C-c l a" . eglot-code-actions)
  ("C-c l r" . eglot-rename)
  ("C-c l h" . eldoc)
  ("C-c l g" . xref-find-references)
  ("C-c l w" . eglot-reconnect)))

(use-package proced
:custom
(proced-auto-update-flag t)
(proced-auto-update-interval 3)
(proced-enable-color-flag t)
(proced-show-remote-processes t))

(use-package org
:ensure t
:defer t
:commands (org-mode org-capture org-agenda)
:init
(defvar org-journal-file "~/nextcloud/org/journal.org")
(defvar org-archive-file "~/nextcloud/org/archive.org")
(defvar org-notes-file "~/nextcloud/org/notes.org")
(defvar org-inbox-file "~/nextcloud/org/inbox.org")
(defvar org-work-file "~/nextcloud/org/work.org")
(defun my/org-capture-project-target-heading ()
"Determine Org target headings from the current file's project path.

This function assumes a directory structure like '~/projects/COMPANY/PROJECT/'.
It extracts 'COMPANY' and 'PROJECT' to use as nested headlines
for an Org capture template.

If the current buffer is not visi
ting a file within such a
project structure, it returns nil, causing capture to default to
the top of the file."
(when-let* ((path (buffer-file-name))) ; Ensure we are in a file-visiting buffer
  (let ((path-parts (split-string path "/" t " ")))
  (when-let* ((projects-pos (cl-position "projects" path-parts :test #'string=))
      (company  (nth (+ 1 projects-pos) path-parts))
      (project  (nth (+ 2 projects-pos) path-parts)))
  ;; Return a list of headlines for Org to find or create.
  (list company project)))))
:bind
(("C-c c" . org-capture)
 ("C-c i" . org-store-link)
 ("C-c a" . org-agenda)
 :map org-mode-map
 ("C-c t" . org-toggle-inline-images)
 ("C-c l" . org-toggle-link-display))
:custom
(org-agenda-files (list org-inbox-file org-journal-file))
(org-directory "~/nextcloud/org")
(org-default-notes-file org-inbox-file)
(org-archive-location (concat org-archive-file "::* From %s"))
(org-log-done 'time)
(org-log-into-drawer t)
(org-hide-emphasis-markers t)
(org-src-fontify-natively t)
(org-src-tab-acts-natively t)
(org-capture-templates '(("t" "todo" entry (file org-inbox-file)
        "* todo %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%a\n\n)")
         ("j" "Journal" entry (file+olp+datetree org-journal-file)
        "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%a\n\n")
         ("n" "Note" entry (file org-notes-file)
        "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%a\n\n")
         ("p" "Project Task" item
        (file+function org-work-file my/org-capture-project-target-heading)
        "* todo %? \n  CLOCK: %U"
        ))
       )
:config
;; Enable syntax highlighting in code blocks
(add-hook 'org-mode-hook 'turn-on-font-lock)
(add-hook 'org-mode-hook 'org-indent-mode))

;; extras
(use-package comp-run
:ensure nil
:config
(push "tramp-loaddefs.el.gz" native-comp-jit-compilation-deny-list)
(push "cl-loaddefs.el.gz" native-comp-jit-compilation-deny-list))

(use-package rustic
:custom
(rustic-lsp-client 'eglot))

(provide 'init)

;;; init.el ends here

generated/traveldroid/todo/apps/wofi.nix

This is top file of this level which contains just an import statement for all relevant files and/or the subfolder in this folder

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

let
  programName = "wofi";
  username = config.defaultUser or "henrov";
  assetPath = ../../../assets/system/conf/${programName};
in
{
  # Deploy assets to ~/.config/wofi via Home Manager
  home-manager.users.${username}.home.file =
    if builtins.pathExists assetPath then
      lib.genAttrs (builtins.attrNames (builtins.readDir assetPath)) (name: {
        source = "${assetPath}/${name}";
        target = ".config/${programName}/${name}";
      })
    else {};
}