docs: condense comments across the repo
Comments had drifted into multi-paragraph narrative (git commit lineage, debugging stories, restated code) in several hot spots (scripts/deploy, hermes-agent.nix, flake.nix, gitea.nix, headscale.nix). Trim every comment to its load-bearing "why" — gotchas, safety warnings, and non-obvious rationale survive verbatim in substance, just tightened to 1-2 sentences; historical narrative and anything already covered in CLAUDE.md is cut. No code/logic changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UJqEmY1y3AYX3JoX4Y6b21
This commit is contained in:
@@ -44,17 +44,9 @@ in
|
||||
# https://nix.dev/permalink/stub-ld ----
|
||||
programs.nix-ld.enable = true;
|
||||
|
||||
# The default set above is deliberately minimal and carries no X11,
|
||||
# freetype, wayland or xkbcommon, so a prebuilt *graphical* binary dies
|
||||
# before it draws anything. JetBrains IDEs installed through Toolbox are the
|
||||
# case that surfaced this: their bundled JBR aborts with `libX11.so.6:
|
||||
# cannot open shared object file` unless the Toolbox GUI — itself an FHS
|
||||
# wrapper — is what launches them, which makes them unusable from a terminal
|
||||
# or from a per-repo devShell. These are the libraries `ldd` reports missing
|
||||
# across a JBR's own .so files, plus the three it resolves by dlopen rather
|
||||
# than DT_NEEDED: fontconfig for font discovery, libGL, and libsecret for
|
||||
# the credential store. Definitions merge, so this adds to the module's base
|
||||
# list rather than replacing it (zlib is already there).
|
||||
# JetBrains IDEs installed via Toolbox bundle a JBR that aborts with
|
||||
# `libX11.so.6: cannot open shared object file` under the default (X11-less)
|
||||
# nix-ld set. Additive — merges with the module's own base list (zlib etc).
|
||||
programs.nix-ld.libraries = with pkgs; [
|
||||
freetype
|
||||
fontconfig
|
||||
@@ -72,28 +64,19 @@ in
|
||||
libxinerama
|
||||
libxcb
|
||||
|
||||
# CLion Nova's C++ backend (the clion-radler plugin) is a .NET 10
|
||||
# application bundling its own runtime, and .NET refuses to start
|
||||
# without ICU: libSystem.Globalization.Native.so dlopens libicuuc.so
|
||||
# and libicui18n.so, and failing that the IDE reports "Couldn't find a
|
||||
# valid ICU package installed on the system" and comes up degraded.
|
||||
# CLion Nova's C++ backend is a .NET 10 app that needs ICU or reports
|
||||
# "Couldn't find a valid ICU package installed on the system".
|
||||
icu
|
||||
];
|
||||
|
||||
# ---- envfs: serves /bin and /usr/bin from the calling process's PATH ----
|
||||
# NixOS ships only /bin/sh, but plenty of third-party tooling writes scripts
|
||||
# with a hardcoded interpreter. JetBrains Toolbox is the standing example:
|
||||
# it generates ~/.local/share/JetBrains/Toolbox/scripts/{clion,rider,...}
|
||||
# with `#!/bin/bash`, so every one of those shims fails with `bad
|
||||
# interpreter` in any shell. envfs resolves such shebangs against PATH,
|
||||
# which fixes them all at once instead of per-IDE wrappers.
|
||||
# NixOS only ships /bin/sh; envfs serves /bin and /usr/bin from PATH so
|
||||
# third-party scripts hardcoding `#!/bin/bash` (e.g. JetBrains Toolbox's
|
||||
# generated launchers) still resolve.
|
||||
services.envfs.enable = true;
|
||||
|
||||
# ---- home-manager (user-level config for darman) ----
|
||||
# Base settings (useGlobalPkgs/useUserPackages/backupFileExtension) and the
|
||||
# shared zsh baseline now live in common.nix + home/common.nix, applied to
|
||||
# every host. This just layers terra's desktop/dev-specific profile on top
|
||||
# — home-manager.users.darman.imports merges additively across modules.
|
||||
# Base settings + shared zsh baseline live in common.nix + home/common.nix
|
||||
# (every host); this layers terra's desktop profile on top (imports merge).
|
||||
home-manager.extraSpecialArgs = { inherit unstable inputs; };
|
||||
home-manager.users.darman.imports = [ ./home.nix ];
|
||||
|
||||
@@ -102,71 +85,47 @@ in
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
hardware.cpu.amd.updateMicrocode = true;
|
||||
|
||||
# mercury (aarch64) is built/flashed from here. Without this, `nix build`
|
||||
# for it dies with "platform mismatch" — no qemu binfmt handler registered
|
||||
# and aarch64-linux missing from nix.settings.extra-platforms. This module
|
||||
# sets up both (see CLAUDE.md's aarch64 gotcha).
|
||||
# Lets `nix build` target mercury (aarch64) from here — see CLAUDE.md's
|
||||
# aarch64 gotcha.
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
|
||||
# ---- GPU (Radeon RX 6800 XT / Navi 21) ----
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
boot.initrd.kernelModules = [ "amdgpu" ];
|
||||
|
||||
# /dev/dri/renderD128 is root:render 0660, so rootless podman containers can
|
||||
# only reach the GPU if the *host* user is in render. Needed by the Vulkan
|
||||
# whisper.cpp/llama.cpp containers in ~/Data/Dev/repos/content-trigger-scanner.
|
||||
# /dev/dri/renderD128 is root:render 0660 — host user needs render group for
|
||||
# rootless podman GPU containers (Vulkan whisper.cpp/llama.cpp).
|
||||
users.users.darman.extraGroups = [ "render" "video" ];
|
||||
|
||||
# ---- ollama (local LLM server, ROCm on the 6800 XT) ----
|
||||
# Navi 21 is gfx1030 — officially supported by ROCm, so no
|
||||
# rocmOverrideGfx/HSA_OVERRIDE_GFX_VERSION needed (that's for gpus ROCm
|
||||
# doesn't recognize, e.g. RDNA1/gfx101x). The upstream module runs the
|
||||
# service under DynamicUser with SupplementaryGroups=["render"] and
|
||||
# DeviceAllow for char-kfd/char-drm/char-fb already, so unlike jellyfin's
|
||||
# static user it needs no extraGroups wiring here.
|
||||
# Navi 21 (gfx1030) is officially ROCm-supported, so no
|
||||
# HSA_OVERRIDE_GFX_VERSION needed. Upstream module already runs under
|
||||
# DynamicUser with render/kfd/drm access wired, unlike jellyfin's static user.
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
package = pkgs.ollama-rocm;
|
||||
# keep in sync with services/desktop/librechat.nix's endpoints.custom
|
||||
# default model — LibreChat's config schema needs a non-empty default
|
||||
# even though fetch=true replaces it with whatever's actually pulled.
|
||||
# gemma4:12b: general chat/coding daily driver, fits fully in 16G VRAM —
|
||||
# also doubles as the memory-extraction agent (see librechat.nix): a
|
||||
# 3b model (llama3.2:3b, dropped) couldn't reliably tell the user's
|
||||
# stated facts apart from its own boilerplate, e.g. saving "I am an AI
|
||||
# assistant with tool calling capabilities" as the user's personal_info
|
||||
# after "Hi I'm Erik Simon". Reusing gemma4:12b for both roles also means
|
||||
# no second model needs to swap into VRAM while it's already the active
|
||||
# chat model.
|
||||
# qwen3.6:35b-a3b: MoE (3B active/36B total), ~24GB Q4_K_M — doesn't fit
|
||||
# in VRAM alone, so ollama offloads the inactive experts to CPU RAM.
|
||||
# Sparse activation makes that far less painful than it'd be for a dense
|
||||
# model this size, but still expect it to run slower than the two above.
|
||||
# VladimirGav/qwen3.8-27B-14GB-IQ4: dense 27B at IQ4, ~14GB of weights —
|
||||
# nominally fits the 6800 XT's 16G, but that leaves only ~2G for the KV
|
||||
# cache and the compositor, so expect partial CPU offload as context grows
|
||||
# (OLLAMA_CONTEXT_LENGTH below applies to every model on this server).
|
||||
# keep default model in sync with services/desktop/librechat.nix's
|
||||
# endpoints.custom default (its schema needs a non-empty value even
|
||||
# though fetch=true overrides it).
|
||||
# gemma4:12b: daily-driver chat/coding model, fits fully in 16G VRAM; also
|
||||
# doubles as LibreChat's memory-extraction agent (librechat.nix) since a
|
||||
# smaller model confused the user's stated facts with its own boilerplate.
|
||||
# qwen3.6:35b-a3b: MoE (3B active/36B total, ~24GB Q4_K_M) — doesn't fit
|
||||
# in VRAM alone, so ollama offloads inactive experts to CPU RAM; sparsity
|
||||
# makes that less painful than for a dense model this size, but still slower.
|
||||
# VladimirGav/qwen3.8-27B-14GB-IQ4: dense 27B at IQ4 (~14GB) — nominally
|
||||
# fits the 16G card but leaves little headroom, so expect partial CPU
|
||||
# offload as context grows.
|
||||
loadModels = [
|
||||
"gemma4:12b"
|
||||
"qwen3.6:35b-a3b"
|
||||
"VladimirGav/qwen3.8-27B-14GB-IQ4"
|
||||
];
|
||||
# Ollama truncates context far below the model's real window unless
|
||||
# told otherwise (the OpenAI-compat /v1 route it's reached through has
|
||||
# no way to set this per-request). 131072 chosen as the practical
|
||||
# ceiling after load-testing with real prompts, not just idle
|
||||
# `ollama ps` checks:
|
||||
# 32768 (31.6k-token prompt) and 65536 (40.8k-token prompt) both stayed
|
||||
# 100% GPU with VRAM barely moving (~10.1G / ~10.67G of 16G) — KV cache
|
||||
# cost barely grows with context, likely sliding-window/local attention
|
||||
# on most of gemma4:12b's layers. At 131072 that stopped being true: a
|
||||
# ~108k-token prompt pushed VRAM to ~11.4G/16G (still 100% GPU, no CPU
|
||||
# spillover, negligible GTT) but with visibly shrinking headroom, and
|
||||
# prefill throughput measurably dropped (~490 -> ~460 tok/s) over just
|
||||
# the last 13k tokens — filling the full window would take minutes of
|
||||
# pure prompt processing. Stopped here rather than push further: next
|
||||
# doubling would risk CPU spillover under any concurrent GPU load
|
||||
# (desktop compositor, jellyfin transcode) for diminishing benefit.
|
||||
# Ollama truncates context far below a model's real window unless told
|
||||
# otherwise. 131072 is the practical ceiling from load-testing: VRAM stays
|
||||
# 100% GPU with no CPU spillover up to here, but headroom and prefill
|
||||
# throughput both degrade near the top — going higher risks CPU spillover
|
||||
# under concurrent GPU load (compositor, jellyfin transcode) for little gain.
|
||||
environmentVariables.OLLAMA_CONTEXT_LENGTH = "131072";
|
||||
};
|
||||
|
||||
|
||||
@@ -5,27 +5,14 @@
|
||||
# `fileSystems.*` entries, so hardware-configuration.nix must NOT define
|
||||
# fileSystems for "/" or "/boot".
|
||||
#
|
||||
# ⚠️ disko's `mkfs` create step SKIPS formatting when `blkid` still detects a
|
||||
# filesystem signature on the freshly-cut partition:
|
||||
#
|
||||
# if ! (blkid "$device" -o export | grep -q '^TYPE='); then
|
||||
# mkfs.btrfs "$device" -f # ← -f only runs WHEN this line runs
|
||||
# fi
|
||||
#
|
||||
# The disk previously held a CachyOS btrfs root. The whole-disk `wipefs`
|
||||
# disko runs before partitioning clears the signature at the OLD layout's
|
||||
# offsets, but `sgdisk --clear --align-end` then re-cuts the partitions, so
|
||||
# a stale btrfs superblock survives at the NEW root partition's own 64 KiB
|
||||
# offset. `blkid` sees TYPE=btrfs, `mkfs` is skipped entirely, and the
|
||||
# later `mount` fails on the leftover bytes ("wrong fs type / bad
|
||||
# superblock"). Switching ext4→btrfs did NOT fix this: `mkfs.btrfs -f` is
|
||||
# never reached, because the guard is on whether `mkfs` runs at all, not on
|
||||
# its flags. The ESP hits the same trap (its `mkfs.vfat` gets skipped too).
|
||||
#
|
||||
# Fix: `preCreateHook = wipefs --all --force "$device"` on each partition's
|
||||
# content. The hook runs AFTER sgdisk re-cuts the partition but BEFORE the
|
||||
# `blkid` guard, so it erases the stale signature at the FINAL offset;
|
||||
# `blkid` then comes back empty and `mkfs` actually runs.
|
||||
# ⚠️ disko's `mkfs` step skips formatting if `blkid` still detects a
|
||||
# filesystem signature on the partition. Repartitioning doesn't erase
|
||||
# signatures at the new offsets, so this disk's old CachyOS btrfs
|
||||
# superblock survived, causing mkfs (and the ESP's mkfs.vfat) to be
|
||||
# skipped and the later mount to fail on the stale superblock.
|
||||
# Fix: `preCreateHook = wipefs --all --force "$device"` on each
|
||||
# partition — it runs after sgdisk re-cuts the partition but before the
|
||||
# `blkid` guard, so the guard sees no signature and `mkfs` actually runs.
|
||||
#
|
||||
# ⚠️ This disk is WIPED on install. This is the Kingston SA400 SSD that
|
||||
# currently holds CachyOS (btrfs root+subvols on sdb2, ESP on sdb1).
|
||||
@@ -58,8 +45,7 @@
|
||||
type = "btrfs";
|
||||
extraArgs = [ "-f" ];
|
||||
mountpoint = "/";
|
||||
# erase the stale CachyOS btrfs superblock before disko's blkid
|
||||
# format-guard, otherwise mkfs.btrfs is skipped (see header comment)
|
||||
# same wipefs fix as the ESP above (see header comment)
|
||||
preCreateHook = ''wipefs --all --force "$device"'';
|
||||
};
|
||||
};
|
||||
|
||||
+12
-20
@@ -2,23 +2,17 @@
|
||||
let
|
||||
tome = pkgs.callPackage ../../pkgs/tome.nix { src = inputs.tome; };
|
||||
|
||||
# SUDO_ASKPASS helper: renders sudo's password prompt in the quickshell
|
||||
# shell (HyprChrome/Widgets/Askpass) instead of on the terminal.
|
||||
# SUDO_ASKPASS helper: shows sudo's password prompt in quickshell
|
||||
# (HyprChrome/Widgets/Askpass) instead of the terminal. sudo doesn't speak
|
||||
# polkit (setuid + PAM reading the tty), so this reuses the polkit dialog's
|
||||
# look via the askpass mechanism instead — `run0` is the actual polkit-native
|
||||
# alternative.
|
||||
#
|
||||
# sudo does NOT speak polkit — it is setuid + PAM reading the tty, and no
|
||||
# sudoers option bridges the two — so this is the askpass mechanism, a
|
||||
# separate path that happens to reuse the polkit dialog's look. `run0` is the
|
||||
# polkit-native alternative if you want the agent itself.
|
||||
# Must be a package, not a dotfiles file: SUDO_ASKPASS needs an executable,
|
||||
# and xdg.configFile copies keep store-copy permissions.
|
||||
#
|
||||
# A package rather than a file in dotfiles/quickshell because SUDO_ASKPASS
|
||||
# must point at something EXECUTABLE, and xdg.configFile copies keep their
|
||||
# store mode — which is why open_launcher.sh has to be invoked as
|
||||
# `bash <path>` rather than run directly.
|
||||
#
|
||||
# The secret comes back over a 0600 fifo, never in argv or the environment,
|
||||
# so it is not visible in /proc to anything. Cancelling closes the fifo
|
||||
# without writing: `cat` reads nothing, this exits non-zero, and sudo aborts
|
||||
# instead of burning a retry on an empty password.
|
||||
# The secret returns over a 0600 fifo (never argv/env, so not visible in
|
||||
# /proc); cancelling closes the fifo unwritten so sudo aborts cleanly.
|
||||
qs-askpass = pkgs.writeShellApplication {
|
||||
name = "qs-askpass";
|
||||
runtimeInputs = [ pkgs.quickshell pkgs.coreutils ];
|
||||
@@ -74,11 +68,9 @@ in
|
||||
nix-direnv.enable = true;
|
||||
};
|
||||
|
||||
# Rootless podman: containers run as darman, not root. services/containers.nix
|
||||
# gives us the `docker` CLI shim (dockerCompat), but compose v2 is a separate
|
||||
# binary and talks to a socket rather than the CLI — the NixOS podman module
|
||||
# enables the *user* socket (systemd.user.sockets.podman), so point compose at
|
||||
# it instead of the root /var/run/docker.sock.
|
||||
# Rootless podman runs containers as darman; compose v2 talks to a socket
|
||||
# rather than the docker CLI shim, so point it at the user podman socket
|
||||
# instead of the root one.
|
||||
home.sessionVariables.DOCKER_HOST = "unix:///run/user/1000/podman/podman.sock";
|
||||
|
||||
# Only sets WHICH helper sudo uses; it still only calls it when asked with
|
||||
|
||||
@@ -1,32 +1,16 @@
|
||||
{ lib, pkgs, config, inputs, ... }:
|
||||
|
||||
# Hyprland config migrated from github.com/darman96/hyprland-dotfiles (the
|
||||
# hyprlang `hypr/*.conf` files) into the home-manager lua-style `settings`
|
||||
# (configType defaults to "lua" on stateVersion 26.05). Each top-level
|
||||
# `settings` attr becomes an `hl.<name>(...)` call in ~/.config/hypr/hyprland.lua;
|
||||
# `_args` lists become multi-arg calls, `_var` locals become `local x = ...`, and
|
||||
# `lib.generators.mkLuaInline` values render as raw Lua expressions.
|
||||
# Hyprland config migrated from github.com/darman96/hyprland-dotfiles into
|
||||
# home-manager's lua-style `settings` (each attr becomes an `hl.<name>(...)`
|
||||
# call in hyprland.lua). Imported by home.nix; system-level enable lives in
|
||||
# ../../services/desktop/desktop-hyprland.nix.
|
||||
#
|
||||
# Imported by home.nix. System-level Hyprland enable (session entry, portals)
|
||||
# lives in ../../services/desktop/desktop-hyprland.nix; this manages the user's
|
||||
# own hyprland.lua.
|
||||
#
|
||||
# Deliberately NOT migrated:
|
||||
# - hyprbars.conf: config for the third-party `hyprbevelbars` plugin, which
|
||||
# isn't packaged in nixpkgs. Load it via
|
||||
# `wayland.windowManager.hyprland.plugins` and re-add its config once
|
||||
# available. (hyprredsquare.conf's plugin was renamed hypr-chrome and
|
||||
# rewritten since - it's wired in below via the `hypr-chrome` flake
|
||||
# input instead, with its own `plugin.hyprchrome` config.)
|
||||
# - hyprqt6engine.conf + `QT_QPA_PLATFORMTHEME=hyprqt6engine`: terra themes Qt
|
||||
# through qtct/Dracula in home.nix, so that env var is left off to avoid a conflict.
|
||||
# - hyprlock.conf: a separate program (use `programs.hyprlock` if wanted).
|
||||
# - the duplicate pamixer/amixer + `.wob` volume binds: kept only the clean
|
||||
# pipewire `wpctl`/`playerctl` set (no wob overlay is configured here).
|
||||
# - `XDG_MENU_PREFIX=arch-` and `VCPKG_ROOT`: Arch-/user-specific.
|
||||
# Many binds reference apps/scripts not packaged on terra yet (vivaldi-stable,
|
||||
# dolphin, vicinae, grimblast, waypaper, discord, gitkraken, qbz,
|
||||
# ~/.config/scripts/start-communications.sh); add them separately.
|
||||
# Not migrated: hyprbars (unpackaged plugin; its successor hypr-chrome is
|
||||
# wired in below instead), hyprqt6engine (conflicts with home.nix's qtct/
|
||||
# Dracula Qt theming), hyprlock (use programs.hyprlock), the old wob volume
|
||||
# overlay (kept only wpctl/playerctl), and Arch-specific env vars. Several
|
||||
# binds reference apps not yet packaged here (vivaldi-stable, dolphin,
|
||||
# vicinae, grimblast, waypaper, discord, gitkraken, qbz).
|
||||
|
||||
let
|
||||
lua = lib.generators.mkLuaInline;
|
||||
@@ -37,11 +21,9 @@ let
|
||||
cursorName = config.home.pointerCursor.name;
|
||||
cursorSize = toString config.home.pointerCursor.size;
|
||||
|
||||
# Wallpaper images aren't checked into this repo (binary blobs) — pulled
|
||||
# from the existing Wallhaven library on /mnt/hdd_01 instead. Picked once
|
||||
# here rather than at runtime, since hyprpaper has no built-in "random"
|
||||
# mode; re-pick and rebuild (or swap in real per-monitor selection) when
|
||||
# this stops being a placeholder.
|
||||
# Wallpapers aren't checked into this repo (binaries) — pulled from the
|
||||
# Wallhaven library on /mnt/hdd_01. Picked once here since hyprpaper has
|
||||
# no built-in "random" mode.
|
||||
# wallpaper = "/mnt/hdd_01/data/Pictures/Wallhaven/wallhaven-ym81rl.png";
|
||||
wallpaper = "/mnt/hdd_01/data/Pictures/Wallhaven/wallhaven-mlwz78.png";
|
||||
|
||||
@@ -317,11 +299,8 @@ in
|
||||
"hyprland.start"
|
||||
(lua ''
|
||||
function()
|
||||
-- No polkit agent is started here: quickshell registers one
|
||||
-- itself (HyprChrome/Widgets/Polkit), and a session admits only
|
||||
-- one. The hyprpolkitagent line this replaces had been dead for
|
||||
-- a while anyway — the unit was never installed, so the start
|
||||
-- failed silently and the session ran with no agent at all.
|
||||
-- No polkit agent started here: quickshell registers its own
|
||||
-- (HyprChrome/Widgets/Polkit), and a session admits only one.
|
||||
hl.exec_cmd("cosmic-settings-daemon")
|
||||
hl.exec_cmd("quickshell")
|
||||
hl.exec_cmd("alacritty", { workspace = "special:terminal silent" })
|
||||
|
||||
@@ -23,14 +23,11 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
# The cursor theme. XCURSOR_THEME alone is not enough for Steam: the client
|
||||
# UI (steamwebhelper) runs inside a pressure-vessel container that rebuilds
|
||||
# /etc, so the /etc/profiles/per-user/darman/share/icons entry of
|
||||
# XCURSOR_PATH does not exist in there and libXcursor finds no theme by
|
||||
# that name — it falls back to the built-in core X11 cursor. $HOME and
|
||||
# /nix are bind-mounted into the container, so the ~/.icons symlink that
|
||||
# `dotIcons` (on by default) drops does resolve. Same class of problem as
|
||||
# the ~/.themes/~/.icons flatpak workaround above.
|
||||
# XCURSOR_THEME alone isn't enough for Steam: steamwebhelper runs inside a
|
||||
# pressure-vessel container with its own /etc, so XCURSOR_PATH doesn't
|
||||
# resolve there and it falls back to the core X11 cursor. $HOME and /nix are
|
||||
# bind-mounted in though, so the ~/.icons symlink `dotIcons` drops still
|
||||
# resolves — same fix as the flatpak workaround below.
|
||||
home.pointerCursor = {
|
||||
name = "Bibata-Modern-Classic";
|
||||
package = pkgs.bibata-cursors;
|
||||
@@ -39,11 +36,9 @@ in
|
||||
hyprcursor.enable = true;
|
||||
};
|
||||
|
||||
# Flatpak apps are sandboxed and can't see XDG_DATA_DIRS/nix-store theme
|
||||
# paths, so the portal-reported GTK theme / icon theme names resolve to
|
||||
# nothing inside the sandbox and they fall back to Adwaita. Flatpak
|
||||
# auto-exposes ~/.themes and ~/.icons read-only to every sandboxed app
|
||||
# specifically for this case.
|
||||
# Flatpak apps can't see XDG_DATA_DIRS/nix-store theme paths, so the
|
||||
# portal-reported theme names resolve to nothing and fall back to Adwaita;
|
||||
# Flatpak auto-exposes ~/.themes and ~/.icons read-only as the workaround.
|
||||
home.file.".themes/Dracula".source =
|
||||
"${pkgs.dracula-theme}/share/themes/Dracula";
|
||||
home.file.".icons/${iconTheme}".source = iconThemeFolder;
|
||||
|
||||
Reference in New Issue
Block a user