Files
nixos/docs/superpowers/specs/2026-07-24-dank-material-shell-design.md
T

9.2 KiB

DankMaterialShell (niri) Profile — Design

Date: 2026-07-24 Branch: feat/dank-material-shell Status: Approved (brainstorming)

Summary

Add a my.profiles.dank NixOS profile that provides a complete DankMaterialShell (DMS) desktop running on the niri Wayland compositor, selectable at the SDDM login screen alongside the existing KDE session on mibook (user finn).

DMS's keybind, spawn, and declarative-settings integration is delivered only through home-manager modules, so this work also introduces home-manager into the flake — as its own opt-in profile (my.profiles.home-manager) that the dank profile enables as a dependency. Everything stays declarative inside the flake; there is no separate home-manager entrypoint.

Background / Research

DMS is a Quickshell-based Wayland desktop shell (bar, launcher, control center, lock screen, notifications) — not a compositor. Its repository (github:AvengeMedia/DankMaterialShell) ships a flake with:

  • nixosModules.dank-material-shell — system side: installs the dms-shell package + quickshell, a dms systemd user service, dgop (system monitoring), matugen (dynamic theming), and enables polkit / power-profiles-daemon / accounts-daemon / geoclue2. Configured via programs.dank-material-shell.*.
  • homeModules.dank-material-shell — home side: declarative ~/.config/DankMaterialShell/settings.json, the dms user service, plugin management, and the programs.quickshell HM program.
  • homeModules.niri — niri-specific integration: generates niri keybinds wired to dms ipc (launcher, clipboard, notifications, media/brightness keys, power menu, lock) and spawn-at-startup for dms run.

homeModules.niri builds on niri-flake's home-manager API (programs.niri.settings, config.lib.niri.actions); DMS does not bundle niri-flake, so it must be added as its own input. quickshell ≥ 0.3.0 is recommended and is available in nixos-unstable → use pkgs.unstable.quickshell.

Key repo facts

  • This repo is flake-parts based, pins nixpkgs/nixos-26.05, and exposes pkgs.unstable via an overlay in machines/configuration.nix.
  • inputs and self are already threaded into every NixOS module via _module.args (set in machines/configuration.nix), so modules/ files may take inputs / self as arguments and imports = [ inputs.<x>... ].
  • The repo currently uses no home-manager; compositor profiles (e.g. hyprland) install packages via users.users.finn.packages.
  • mibook currently runs the KDE desktop (my.profiles.kde-desktop).

Scope

  • In: mibook only; niri+DMS as a session parallel to KDE; home-manager scoped to user finn; a reusable my.profiles.home-manager module.
  • Out: enabling on jupiter (headless server); Dank Greeter as the login manager (SDDM stays); declarative DMS settings.json content (DMS is configured through its own GUI at runtime; the HM settings option remains available for later use but is left empty); any change to configuration.nix.

Design

1. New flake inputs (flake.nix)

home-manager = {
  url = "github:nix-community/home-manager";
  inputs.nixpkgs.follows = "nixpkgs";
};
niri.url = "github:sodiboo/niri-flake";
dank.url = "github:AvengeMedia/DankMaterialShell";

Notes:

  • dank tracks nixos-unstable internally (its own nixpkgs), which is expected for the DMS package build.
  • niri-flake provides both the compositor session (nixosModule) and the HM programs.niri.settings API that DMS's niri module extends.
  • home-manager follows the repo nixpkgs (nixos-26.05).

machines/configuration.nix is not modified — the existing _module.args.inputs = self.inputs line already makes these inputs reachable from any module.

2. Home-manager profile (modules/environments/home-manager/default.nix)

A new opt-in my.profiles.home-manager profile. Because module imports cannot be gated on an option value, the home-manager NixOS module is imported unconditionally (harmless — it only adds options and does nothing until home-manager.users.* is populated); only the global settings are guarded by mkIf cfg.enable:

{ config, lib, inputs, self, ... }:
let
  cfg = config.my.profiles.home-manager;
in
{
  imports = [ inputs.home-manager.nixosModules.home-manager ];

  options.my.profiles.home-manager.enable =
    lib.mkEnableOption "home-manager integration";

  config = lib.mkIf cfg.enable {
    home-manager.useGlobalPkgs = true;      # HM shares the system pkgs (+ unstable overlay)
    home-manager.useUserPackages = true;
    home-manager.extraSpecialArgs = { inherit inputs self; };
  };
}

Registered by adding ./environments/home-manager to modules/environments/default.nix.

Placement note: the profile lives under modules/environments/ (where my.profiles.* modules live) to match the namespace, even though its function is infrastructural.

3. Dank profile (modules/environments/dank/default.nix)

Standard profile pattern; enables the home-manager profile as a dependency and splits configuration between the system module (session + daemons) and the home-manager module (keybinds / spawn / settings):

{ config, lib, pkgs, inputs, ... }:
let
  cfg = config.my.profiles.dank;
in
{
  imports = [ inputs.dank.nixosModules.dank-material-shell ];

  options.my.profiles.dank.enable = lib.mkEnableOption "DankMaterialShell on niri";

  config = lib.mkIf cfg.enable {
    # dependency: pull in home-manager integration
    my.profiles.home-manager.enable = true;

    # --- system side: niri session + DMS daemons/packages ---
    programs.niri.enable = true;                     # niri-flake nixosModule → Wayland session in SDDM

    programs.dank-material-shell = {
      enable = true;
      systemd.enable = true;
      quickshell.package = pkgs.unstable.quickshell;  # >= 0.3.0 from unstable
      # enableSystemMonitoring / enableVPN / enableDynamicTheming / enableAudioWavelength
      # / enableCalendarEvents all default true — left on.
    };

    # --- home side: DMS + niri keybinds for finn ---
    home-manager.users.finn = {
      imports = [
        inputs.niri.homeModules.niri
        inputs.dank.homeModules.dank-material-shell
        inputs.dank.homeModules.niri
      ];

      programs.dank-material-shell = {
        enable = true;
        systemd.enable = true;
        quickshell.package = pkgs.unstable.quickshell;
        niri.enableKeybinds = true;    # Mod+Space launcher, Mod+V clipboard, media/brightness, power, lock…
        niri.enableSpawn = true;       # spawn `dms run` at niri startup
      };

      home.stateVersion = "26.05";     # match nixpkgs release; required by HM
    };
  };
}

Registered by adding ./environments/dank to modules/environments/default.nix.

Open validation point (resolve during implementation, not a blocker):

  • Confirm the exact HM output name for the niri integration (homeModules.niri vs homeModules.dankMaterialShell.niri) and that programs.niri.enable is the correct niri-flake nixosModule option; adjust to match the pinned input revisions.
  • Confirm whether programs.dank-material-shell.quickshell.package needs to be set on both the system and HM sides or only one; set consistently.

4. Enable on mibook (machines/mibook/environments.nix)

Add to the my.profiles block:

dank.enable = true;

KDE (kde-desktop.enable = true) stays; both sessions are offered by SDDM.

5. Documentation

No homepage dashboard entry (DMS is not a web service). CLAUDE.md is left unchanged unless, after implementation, the home-manager pattern warrants a short note — decided at the end, not up front (YAGNI).

Data / control flow

  1. nixos-rebuild builds the mibook toplevel; niri-flake registers a niri Wayland session, DMS nixosModule installs packages + the dms user service template, home-manager renders finn's niri config (with DMS keybinds) and DMS config.
  2. At login, SDDM lists KDE and niri. Selecting niri starts the compositor; spawn-at-startup launches dms run, bringing up the DMS shell.
  3. Keybinds invoke dms ipc … (launcher, clipboard, notifications, media, brightness, power, lock). DMS is further configured via its own GUI, persisted under ~/.config/DankMaterialShell/.

Risks / open questions

  • unstable/stable skew: the repo pins nixos-26.05 while dank and niri-flake track nixos-unstable, and quickshell comes from pkgs.unstable. Qt6/quickshell version mismatch between the DMS package and the stable base is the most likely failure. Mitigation: validate with a full toplevel build and, if it fails, align quickshell/qt sourcing (e.g. take the DMS package's own quickshell) before switching.
  • HM output/option names may differ from the researched revision — pin the inputs first, then read the resolved module options and adjust (see §3 open validation point).
  • First HM activation for finn: ensure home.stateVersion is set so the build doesn't error.

Verification

  1. nix flake check succeeds.
  2. nix build '.#nixosConfigurations.mibook.config.system.build.toplevel' succeeds.
  3. sudo nixos-rebuild test --flake '.#mibook', then log into the niri session: DMS bar appears, Mod+Space opens the launcher, KDE session still works.