diff --git a/home/base/cli-tools/default.nix b/home/base/cli-tools/default.nix
new file mode 100644
index 0000000..0a4dd8f
--- /dev/null
+++ b/home/base/cli-tools/default.nix
@@ -0,0 +1,9 @@
+# CLI tools aggregator — imports all base command-line utilities.
+{...}: {
+ imports = [
+ ./fzf.nix
+ ./nitch.nix
+ ./television.nix
+ ./zellij.nix
+ ];
+}
diff --git a/home/base/cli-tools/fzf.nix b/home/base/cli-tools/fzf.nix
new file mode 100644
index 0000000..8939199
--- /dev/null
+++ b/home/base/cli-tools/fzf.nix
@@ -0,0 +1,41 @@
+# Fuzzy finder with nix-colors palette and Wayland clipboard integration.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.base.cliTools.fzf;
+in {
+ options.base.cliTools.fzf.enable = mkEnableOption "enable fuzzy finder";
+
+ config = mkIf cfg.enable {
+ programs.fzf = {
+ enable = true;
+ enableFishIntegration = true;
+ colors = {
+ "fg" = "#${config.colorScheme.palette.base05}";
+ "bg" = "#${config.colorScheme.palette.base00}";
+ "hl" = "#${config.colorScheme.palette.base0E}";
+ "fg+" = "#${config.colorScheme.palette.base05}";
+ "bg+" = "#${config.colorScheme.palette.base02}";
+ "hl+" = "#${config.colorScheme.palette.base0E}";
+ "info" = "#${config.colorScheme.palette.base09}";
+ "prompt" = "#${config.colorScheme.palette.base0B}";
+ "pointer" = "#${config.colorScheme.palette.base08}";
+ "marker" = "#${config.colorScheme.palette.base08}";
+ "spinner" = "#${config.colorScheme.palette.base09}";
+ "header" = "#${config.colorScheme.palette.base03}";
+ };
+ defaultOptions = [
+ "--preview='bat --color=always -n {}'"
+ "--bind 'ctrl-/:toggle-preview'"
+ "--header 'Press CTRL-Y to copy command into clipboard'"
+ "--bind 'ctrl-/:toggle-preview'"
+ "--bind 'ctrl-y:execute-silent(echo -n {2..} | wl-copy)+abort'"
+ ];
+ defaultCommand = "fd --type f --exclude .git --follow --hidden";
+ changeDirWidgetCommand = "fd --type d --exclude .git --follow --hidden";
+ };
+ };
+}
diff --git a/home/base/cli-tools/nitch.nix b/home/base/cli-tools/nitch.nix
new file mode 100644
index 0000000..dc2147d
--- /dev/null
+++ b/home/base/cli-tools/nitch.nix
@@ -0,0 +1,16 @@
+# Nitch — minimal system information display tool.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.base.cliTools.nitch;
+in {
+ options.base.cliTools.nitch.enable = mkEnableOption "enable nitch";
+
+ config = mkIf cfg.enable {
+ home.packages = [pkgs.nitch];
+ };
+}
diff --git a/home/base/cli-tools/television.nix b/home/base/cli-tools/television.nix
new file mode 100644
index 0000000..3c6aa67
--- /dev/null
+++ b/home/base/cli-tools/television.nix
@@ -0,0 +1,59 @@
+# Television — fuzzy finder with custom channels for tldr, git-diff, and git-log.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.base.cliTools.television;
+in {
+ options.base.cliTools.television.enable = mkEnableOption "enable television";
+
+ config = mkIf cfg.enable {
+ programs.television = {
+ enable = true;
+ channels = {
+ tldr = {
+ metadata = {
+ description = "Browse TLDR pages";
+ name = "tldr";
+ requirements = ["tldr"];
+ };
+ preview = {
+ command = "tldr '{}'";
+ };
+ source = {
+ command = "tldr --list";
+ };
+ };
+ git-diff = {
+ metadata = {
+ description = "A channel to select files from git diff commands";
+ name = "git-diff";
+ requirements = ["git"];
+ };
+ preview = {
+ command = "git diff HEAD --color=always -- '{}'";
+ };
+ source = {
+ command = "git diff --name-only HEAD";
+ };
+ };
+ git-log = {
+ metadata = {
+ description = "A channel to select from git log entries";
+ name = "git-log";
+ requirements = ["git"];
+ };
+ preview = {
+ command = "git show -p --stat --pretty=fuller --color=always '{0}'";
+ };
+ source = {
+ command = "git log --oneline --date=short --pretty=\"format:%h %s %an %cd\" \"$@\"";
+ output = "{split: :0}";
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/home/base/cli-tools/zellij.nix b/home/base/cli-tools/zellij.nix
new file mode 100644
index 0000000..38e5c40
--- /dev/null
+++ b/home/base/cli-tools/zellij.nix
@@ -0,0 +1,33 @@
+# Zellij terminal multiplexer with nix-colors theming.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.base.cliTools.zellij;
+in {
+ options.base.cliTools.zellij.enable = mkEnableOption "enable zellij multiplexer";
+
+ config = mkIf cfg.enable {
+ programs.zellij = {
+ enable = true;
+ settings = {
+ theme = "universal";
+ themes.universal = {
+ bg = "#${config.colorScheme.palette.base00}";
+ fg = "#${config.colorScheme.palette.base05}";
+ black = "#${config.colorScheme.palette.base01}";
+ red = "#${config.colorScheme.palette.base08}";
+ green = "#${config.colorScheme.palette.base0B}";
+ yellow = "#${config.colorScheme.palette.base0A}";
+ blue = "#${config.colorScheme.palette.base0D}";
+ magenta = "#${config.colorScheme.palette.base0E}";
+ cyan = "#${config.colorScheme.palette.base0C}";
+ white = "#${config.colorScheme.palette.base07}";
+ orange = "#${config.colorScheme.palette.base09}";
+ };
+ };
+ };
+ };
+}
diff --git a/home/base/default.nix b/home/base/default.nix
new file mode 100644
index 0000000..daa5afb
--- /dev/null
+++ b/home/base/default.nix
@@ -0,0 +1,9 @@
+# Base home-manager configuration — always loaded on every host.
+# Includes shell, CLI tools, and secrets modules.
+{...}: {
+ imports = [
+ ./shell
+ ./cli-tools
+ ./secrets/secrets.nix
+ ];
+}
diff --git a/home/base/secrets/secrets.nix b/home/base/secrets/secrets.nix
new file mode 100644
index 0000000..7a72827
--- /dev/null
+++ b/home/base/secrets/secrets.nix
@@ -0,0 +1,23 @@
+# Password store and secrets management via pass-wayland with OTP and import extensions.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.base.secrets;
+in {
+ options.base.secrets.enable = mkEnableOption "enable secrets management";
+
+ config = mkIf cfg.enable {
+ programs.password-store = {
+ enable = true;
+ package =
+ pkgs.pass-wayland.withExtensions
+ (exts: [exts.pass-otp exts.pass-import]);
+ settings = {PASSWORD_STORE_DIR = "$XDG_DATA_HOME/password-store";};
+ };
+ home.packages = [pkgs.pinentry-gnome3];
+ };
+}
diff --git a/home/base/shell/default.nix b/home/base/shell/default.nix
new file mode 100644
index 0000000..b5b0c37
--- /dev/null
+++ b/home/base/shell/default.nix
@@ -0,0 +1,7 @@
+# Shell aggregator — imports Nushell (primary) and Starship prompt.
+{...}: {
+ imports = [
+ ./nushell.nix
+ ./starship.nix
+ ];
+}
diff --git a/home/base/shell/nushell.nix b/home/base/shell/nushell.nix
new file mode 100644
index 0000000..9616531
--- /dev/null
+++ b/home/base/shell/nushell.nix
@@ -0,0 +1,85 @@
+# Primary shell configuration — Nushell with environment, aliases, and integrations.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.base.shell.nushell;
+in {
+ options.base.shell.nushell.enable = mkEnableOption "enable nushell";
+
+ config = mkIf cfg.enable {
+ programs.nushell = {
+ enable = true;
+ envFile.text = ''
+ $env.config.show_banner = false
+ $env.NIX_PATH = "nixpkgs=channel:nixos-unstable"
+ $env.NIX_LOG = "iunfo"
+ $env.WEBKIT_DISABLE_COMPOSITING_MODE = "1"
+ $env.TERMINAL = "ghostty"
+ $env.EDITOR = "nvim"
+ $env.VISUAL = "zeditor"
+ $env.FZF_DEFAULT_COMMAND = "fd --type f --exclude .git --follow --hidden"
+ $env.FZF_DEFAULT_OPTS = "--preview='bat --color=always -n {}' --bind 'ctrl-/:toggle-preview' --header 'Press CTRL-Y to copy command into clipboard' --bind 'ctrl-/:toggle-preview' --bind 'ctrl-y:execute-silent(echo -n {2..} | wl-copy)+abort' --color bg:#282a36,bg+:#44475a,fg:#f8f8f2,fg+:#f8f8f2,header:#6272a4,hl:#bd93f9,hl+:#bd93f9,info:#ffb86c,marker:#ff79c6,pointer:#ff79c6,prompt:#50fa7b,spinner:#ffb86c"
+ $env.XDG_DATA_HOME = $"($env.HOME)/.local/share"
+ $env.SSH_AUTH_SOCK = "/run/user/1000/gnupg/S.gpg-agent.ssh"
+ $env.PATH = ($env.PATH | split row (char esep) | append $"($env.HOME)/.cache/.bun/bin" | append $"($env.HOME)/.npm-global/bin" | uniq)
+ $env.NPM_CONFIG_PREFIX = $"($env.HOME)/.npm-global"
+ $env.FLAKE = $"($env.HOME)/p/NIX/nixos-config"
+
+ # Load kestractl-env from agenix
+ if ("/run/agenix/kestractl-env" | path exists) {
+ open /run/agenix/kestractl-env
+ | lines
+ | where {($in | str trim | str length) > 0}
+ | parse "{key}={value}"
+ | update value {str trim -c '"'}
+ | transpose -r -d
+ | load-env
+ }
+ '';
+
+ configFile.text = ''
+ # Aliases
+ alias .. = cd ..
+ alias ... = cd ...
+ alias h = cd $env.HOME
+ alias b = yazi
+ alias lt = eza --tree --level=2 --long --icons --git
+ alias grep = rg
+ alias just = just --unstable
+
+ alias node = bun
+ alias npx = bunx
+
+ alias n = nix
+ alias nd = nix develop -c $nu.current-shell
+ alias ns = nix shell
+ alias nsn = nix shell nixpkgs#
+ alias nb = nix build
+ alias nbn = nix build nixpkgs#
+ alias nf = nix flake
+
+ alias nr = sudo nixos-rebuild --flake .
+ alias nrs = sudo nixos-rebuild switch --flake .#(sys host | get hostname)
+ alias snr = sudo nixos-rebuild --flake .
+ alias snrs = sudo nixos-rebuild --flake . switch
+ alias hm = home-manager --flake .
+ alias hms = home-manager --flake . switch
+ alias hmr = do { cd ~/projects/nix-configurations; nix flake lock --update-input dotfiles; home-manager --flake .#(whoami)@(hostname) switch }
+
+ alias tsu = sudo tailscale up
+ alias tsd = sudo tailscale down
+
+ alias vi = nvim
+ alias vim = nvim
+
+ if (which tv | is-not-empty) {
+ mkdir ($nu.data-dir | path join "vendor/autoload")
+ tv init nu | save -f ($nu.data-dir | path join "vendor/autoload/tv.nu")
+ }
+ '';
+ };
+ };
+}
diff --git a/home/base/shell/starship.nix b/home/base/shell/starship.nix
new file mode 100644
index 0000000..3fb6c10
--- /dev/null
+++ b/home/base/shell/starship.nix
@@ -0,0 +1,69 @@
+# Starship cross-shell prompt with nix-colors theming.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.base.shell.starship;
+in {
+ options.base.shell.starship.enable = mkEnableOption "enable starship prompt";
+
+ config = mkIf cfg.enable {
+ programs.starship = {
+ enable = true;
+ enableFishIntegration = true;
+ enableNushellIntegration = true;
+ settings = {
+ format = "$all$character";
+ palette = "universal";
+
+ palettes.universal = {
+ background = "#${config.colorScheme.palette.base00}";
+ surface = "#${config.colorScheme.palette.base01}";
+ muted = "#${config.colorScheme.palette.base03}";
+ text = "#${config.colorScheme.palette.base05}";
+ bright = "#${config.colorScheme.palette.base07}";
+ accent1 = "#${config.colorScheme.palette.base08}";
+ accent2 = "#${config.colorScheme.palette.base09}";
+ accent3 = "#${config.colorScheme.palette.base0A}";
+ accent4 = "#${config.colorScheme.palette.base0B}";
+ accent5 = "#${config.colorScheme.palette.base0C}";
+ accent6 = "#${config.colorScheme.palette.base0D}";
+ accent7 = "#${config.colorScheme.palette.base0E}";
+ };
+
+ character = {
+ success_symbol = "[❯](accent7)";
+ error_symbol = "[❯](accent1)";
+ };
+
+ directory = {
+ style = "accent6";
+ truncation_length = 3;
+ truncate_to_repo = false;
+ };
+
+ git_branch = {
+ style = "accent7";
+ };
+
+ git_status = {
+ style = "accent5";
+ };
+
+ cmd_duration = {
+ style = "accent3";
+ };
+
+ hostname = {
+ style = "accent4";
+ };
+
+ username = {
+ style_user = "accent2";
+ };
+ };
+ };
+ };
+}
diff --git a/home/coding/agents/agents.nix b/home/coding/agents/agents.nix
new file mode 100644
index 0000000..ca014a7
--- /dev/null
+++ b/home/coding/agents/agents.nix
@@ -0,0 +1,103 @@
+# AI agent system — OpenCode, Pi, and MCP server configuration.
+# References inputs.m3ta-nixpkgs.homeManagerModules.coding.agents for the base module.
+{
+ config,
+ inputs,
+ lib,
+ pkgs,
+ videoDrivers,
+ ...
+}:
+with lib; let
+ npmGlobalPrefix = "${config.home.homeDirectory}/.npm-global";
+in {
+ home.file.".npmrc".text = ''
+ prefix=${npmGlobalPrefix}
+ '';
+ home.sessionVariables.NPM_CONFIG_PREFIX = npmGlobalPrefix;
+
+ imports = [
+ # OpenCode and Pi agent configurations
+ ../../features/coding/opencode.nix
+ ../../features/coding/pi.nix
+ ];
+
+ coding.agents.skills = {
+ agentsInput = inputs.agents;
+ externalSkills = [
+ {
+ src = inputs.skills-anthropic;
+ selectSkills = ["pdf" "docx" "frontend-design"];
+ }
+ {src = inputs.skills-vercel;}
+ {src = inputs.skills-basecamp;}
+ {src = inputs.skills-kestra;}
+ ];
+ };
+
+ programs.mcp = {
+ enable = true;
+ servers = {
+ DeepWiki = {
+ url = "https://mcp.deepwiki.com/mcp";
+ };
+ Ref = {
+ command = "bash";
+ args = ["-c" "REF_API_KEY=$(cat /run/agenix/ref-key) exec bunx ref-tools-mcp@latest"];
+ };
+ Exa = {
+ command = "bash";
+ args = ["-c" "EXA_API_KEY=$(cat /run/agenix/exa-key) exec bunx exa-mcp-server@latest tools=web_search_exa"];
+ };
+ Outline = {
+ url = "https://wiki.az-gruppe.com/mcp";
+ };
+ ContextMode = {
+ command = "bash";
+ args = ["-c" "exec bunx context-mode@latest"];
+ };
+ Honcho = {
+ command = "bash";
+ args = [
+ "-c"
+ ''exec bunx mcp-remote@latest https://mcp.honcho.dev --header "Authorization:Bearer $(cat /run/agenix/honcho-key)" --header "X-Honcho-User-Name:m3tam3re"''
+ ];
+ };
+ };
+ };
+
+ home.packages = with pkgs; [
+ agenix-cli
+ agent-browser
+ alejandra
+ bc
+ bun
+ devpod
+ gnumake
+ cmake
+ (python3.withPackages (ps:
+ with ps; [
+ pip
+ uv
+ numba
+ numpy
+ torch
+ srt
+ ]))
+ pyrefly
+ nixd
+ nix-update
+ nodejs
+ (qmd.override {
+ vulkanSupport = videoDrivers == ["amdgpu"];
+ cudaSupport = videoDrivers == ["nvidia"];
+ })
+ openshell
+ openspec
+ pi-coding-agent
+ sidecar
+ tailwindcss
+ tailwindcss-language-server
+ td
+ ];
+}
diff --git a/home/coding/default.nix b/home/coding/default.nix
new file mode 100644
index 0000000..11c433c
--- /dev/null
+++ b/home/coding/default.nix
@@ -0,0 +1,10 @@
+# Coding environment aggregator — profile-independent development tooling.
+# Imports editors, LSP servers, git configuration, and the agent system.
+{...}: {
+ imports = [
+ ./editor
+ ./lsp
+ ./git/git.nix
+ ./agents/agents.nix
+ ];
+}
diff --git a/home/coding/editor/default.nix b/home/coding/editor/default.nix
new file mode 100644
index 0000000..6c02d36
--- /dev/null
+++ b/home/coding/editor/default.nix
@@ -0,0 +1,6 @@
+# Editor aggregator — delegates to m3ta-nixpkgs editors module for NeoVim and Zed.
+{...}: {
+ imports = [
+ ./neovim.nix
+ ];
+}
diff --git a/home/coding/editor/neovim.nix b/home/coding/editor/neovim.nix
new file mode 100644
index 0000000..9c555c4
--- /dev/null
+++ b/home/coding/editor/neovim.nix
@@ -0,0 +1,17 @@
+# NeoVim base configuration via m3ta-nixpkgs coding.editors module.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.coding.editors.neovim;
+in {
+ # coding.editors.neovim is provided by inputs.m3ta-nixpkgs.homeManagerModules.default
+ options.coding.editors.neovim.enable = mkEnableOption "enable NeoVim editor";
+
+ config = mkIf cfg.enable {
+ # NeoVim configuration is managed by the m3ta-nixpkgs coding.editors module.
+ # Additional host-specific overrides can be added here.
+ };
+}
diff --git a/home/coding/git/git.nix b/home/coding/git/git.nix
new file mode 100644
index 0000000..4d91287
--- /dev/null
+++ b/home/coding/git/git.nix
@@ -0,0 +1,41 @@
+# Git configuration with signing, aliases, and global ignore.
+# Identity and host-specific SSH keys are set per-host in home/m3tam3re/.
+{
+ lib,
+ pkgs,
+ ...
+}:
+with lib; {
+ programs.git = {
+ enable = true;
+ signing.format = null;
+ settings = {
+ user = {
+ name = lib.mkDefault "m3tam3re";
+ email = lib.mkDefault "p@m3ta.dev";
+ };
+ core.excludesfile = "~/.gitignore_global";
+ init.defaultBranch = "master";
+ alias = {
+ st = "status";
+ logd = "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
+ };
+ };
+ };
+
+ programs.difftastic.enable = true;
+
+ programs.jujutsu = {
+ enable = true;
+ settings = {
+ user = {
+ email = "m@m3tam3re.com";
+ name = "Sascha Koenig";
+ };
+ };
+ };
+
+ home.packages = with pkgs; [
+ lazygit
+ ];
+}
diff --git a/home/coding/lsp/default.nix b/home/coding/lsp/default.nix
new file mode 100644
index 0000000..c8e11b0
--- /dev/null
+++ b/home/coding/lsp/default.nix
@@ -0,0 +1,6 @@
+# LSP aggregator — language server protocol tooling.
+{...}: {
+ imports = [
+ ./servers.nix
+ ];
+}
diff --git a/home/coding/lsp/servers.nix b/home/coding/lsp/servers.nix
new file mode 100644
index 0000000..935855e
--- /dev/null
+++ b/home/coding/lsp/servers.nix
@@ -0,0 +1,22 @@
+# LSP server configuration — language servers for the development environment.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.coding.lsp;
+in {
+ options.coding.lsp.enable = mkEnableOption "enable LSP servers";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ # Nix
+ nixd
+ # General
+ nodePackages.typescript-language-server
+ tailwindcss-language-server
+ ];
+ };
+}
diff --git a/home/desktop/apps/crypto.nix b/home/desktop/apps/crypto.nix
new file mode 100644
index 0000000..56b0ad8
--- /dev/null
+++ b/home/desktop/apps/crypto.nix
@@ -0,0 +1,16 @@
+# Cryptocurrency applications — Bisq, Monero GUI, and Trezor Suite.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.apps.crypto;
+in {
+ options.desktop.apps.crypto.enable = mkEnableOption "enable crypto applications";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [bisq2 monero-gui trezor-suite];
+ };
+}
diff --git a/home/desktop/apps/default.nix b/home/desktop/apps/default.nix
new file mode 100644
index 0000000..05fb046
--- /dev/null
+++ b/home/desktop/apps/default.nix
@@ -0,0 +1,9 @@
+# Desktop apps aggregator — Obsidian, Office, web apps, and crypto tools.
+{...}: {
+ imports = [
+ ./obsidian.nix
+ ./office.nix
+ ./webapps.nix
+ ./crypto.nix
+ ];
+}
diff --git a/home/desktop/apps/obsidian.nix b/home/desktop/apps/obsidian.nix
new file mode 100644
index 0000000..588cb98
--- /dev/null
+++ b/home/desktop/apps/obsidian.nix
@@ -0,0 +1,25 @@
+# Obsidian knowledge base with markdown MIME association.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.apps.obsidian;
+in {
+ options.desktop.apps.obsidian.enable = mkEnableOption "enable Obsidian knowledge base";
+
+ config = mkIf cfg.enable {
+ programs.obsidian.enable = true;
+
+ xdg.mimeApps = {
+ enable = true;
+ associations.added = {
+ "text/markdown" = ["obsidian.desktop"];
+ };
+ defaultApplications = {
+ "text/markdown" = ["obsidian.desktop"];
+ };
+ };
+ };
+}
diff --git a/home/desktop/apps/office.nix b/home/desktop/apps/office.nix
new file mode 100644
index 0000000..3d9c062
--- /dev/null
+++ b/home/desktop/apps/office.nix
@@ -0,0 +1,16 @@
+# Office and productivity applications — LibreOffice and document tools.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.apps.office;
+in {
+ options.desktop.apps.office.enable = mkEnableOption "install office and paperwork apps";
+
+ config = mkIf cfg.enable {
+ home.packages = [pkgs.libreoffice-fresh];
+ };
+}
diff --git a/home/desktop/apps/webapps.nix b/home/desktop/apps/webapps.nix
new file mode 100644
index 0000000..d731fb9
--- /dev/null
+++ b/home/desktop/apps/webapps.nix
@@ -0,0 +1,56 @@
+# Web application desktop entries — Teams, Outlook, Basecamp, and OpenCode launchers.
+{
+ pkgs,
+ lib,
+ ...
+}: let
+ icons = {
+ teams = pkgs.fetchurl {
+ url = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/microsoft-teams.svg";
+ sha256 = "sha256-Pr9QS8nnXJq97r4/G3c6JXi34zxHl0ps9gcyI8cN/s8=";
+ };
+ outlook = pkgs.fetchurl {
+ url = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/microsoft-outlook.svg";
+ sha256 = "sha256-3u8t5QNHFZvrAegxBiGicO4PjtMWhEaQSCv7MSSfLLc=";
+ };
+ opencode = pkgs.fetchurl {
+ url = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/opencode-dark.svg";
+ sha256 = "1lms4f8habamvdh2qqqz9psx4py9wx23mmlkkds44pvrbq3bkj3n";
+ };
+ };
+in {
+ xdg.desktopEntries = {
+ teams = {
+ name = "Microsoft Teams";
+ exec = "launch-webapp https://teams.microsoft.com";
+ comment = "Open Microsoft Teams as a Desktop App";
+ categories = ["Application" "Network" "Chat"];
+ terminal = false;
+ icon = icons.teams;
+ };
+ outlook = {
+ name = "Microsoft Outlook";
+ exec = "launch-webapp https://outlook.office.com/mail/";
+ comment = "Open Microsoft Outlook as a Desktop App";
+ categories = ["Application" "Network"];
+ terminal = false;
+ icon = icons.outlook;
+ };
+ basecamp = {
+ name = "Basecamp";
+ exec = "launch-webapp https://3.basecamp.com/5996442/";
+ comment = "Open Basecamp as a Desktop App";
+ categories = ["Application" "Network"];
+ terminal = false;
+ icon = "/home/sascha.koenig/.local/share/icons/basecamp-logo.png";
+ };
+ opencode = {
+ name = "Opencode";
+ exec = "rofi-project-opener";
+ comment = "Open Opencode Terminal App";
+ categories = ["Application" "Development"];
+ terminal = false;
+ icon = icons.opencode;
+ };
+ };
+}
diff --git a/home/desktop/default.nix b/home/desktop/default.nix
new file mode 100644
index 0000000..ac73f43
--- /dev/null
+++ b/home/desktop/default.nix
@@ -0,0 +1,125 @@
+# Desktop environment aggregator — only loaded when context=desktop.
+# Includes window manager, applications, theming, and desktop session config.
+{
+ config,
+ pkgs,
+ ...
+}: {
+ imports = [
+ ./wm
+ ./apps
+ ./theme
+ ];
+
+ xdg = {
+ enable = true;
+ configFile."mimeapps.list".force = true;
+ mimeApps = {
+ enable = true;
+ associations.added = {
+ "application/zip" = ["org.gnome.FileRoller.desktop"];
+ "application/csv" = ["calc.desktop"];
+ "application/pdf" = ["okularApplication_pdf.desktop"];
+ };
+ defaultApplications = {
+ "application/zip" = ["org.gnome.FileRoller.desktop"];
+ "application/csv" = ["calc.desktop"];
+ "application/pdf" = ["okularApplication_pdf.desktop"];
+ "application/md" = ["nvim.desktop"];
+ "application/text" = ["nvim.desktop"];
+ "x-scheme-handler/http" = ["io.github.zen_browser.zen"];
+ "x-scheme-handler/https" = ["io.github.zen_browser.zen"];
+ };
+ };
+ userDirs = {
+ enable = true;
+ createDirectories = true;
+ setSessionVariables = true;
+ };
+ };
+
+ home.sessionVariables = {
+ WEBKIT_DISABLE_COMPOSITING_MODE = "1";
+ NIXOS_OZONE_WL = "1";
+ TERMINAL = "ghostty";
+ QT_QPA_PLATFORM = "wayland";
+ XDG_CURRENT_DESKTOP = "Hyprland";
+ XDG_SESSION_TYPE = "wayland";
+ XDG_SESSION_DESKTOP = "Hyprland";
+ };
+
+ home.sessionPath = [
+ "\${XDG_BIN_HOME}"
+ "\${HOME}/.cargo/bin"
+ "$HOME/.npm-global/bin"
+ "$HOME/.cache/.bun/bin"
+ ];
+
+ fonts.fontconfig.enable = true;
+
+ programs.ghostty = {
+ enable = true;
+ enableFishIntegration = true;
+ enableBashIntegration = true;
+ settings = {
+ font-family = "Fira Code";
+ copy-on-select = true;
+ foreground = "#${config.colorScheme.palette.base05}";
+ background = "#${config.colorScheme.palette.base00}";
+ selection-foreground = "#${config.colorScheme.palette.base07}";
+ selection-background = "#${config.colorScheme.palette.base02}";
+ cursor-color = "#${config.colorScheme.palette.base05}";
+ palette = [
+ "0=#${config.colorScheme.palette.base01}"
+ "1=#${config.colorScheme.palette.base08}"
+ "2=#${config.colorScheme.palette.base0B}"
+ "3=#${config.colorScheme.palette.base0A}"
+ "4=#${config.colorScheme.palette.base0D}"
+ "5=#${config.colorScheme.palette.base0E}"
+ "6=#${config.colorScheme.palette.base0C}"
+ "7=#${config.colorScheme.palette.base05}"
+ "8=#${config.colorScheme.palette.base03}"
+ "9=#${config.colorScheme.palette.base08}"
+ "10=#${config.colorScheme.palette.base0B}"
+ "11=#${config.colorScheme.palette.base0A}"
+ "12=#${config.colorScheme.palette.base0D}"
+ "13=#${config.colorScheme.palette.base0E}"
+ "14=#${config.colorScheme.palette.base0C}"
+ "15=#${config.colorScheme.palette.base07}"
+ ];
+ };
+ };
+
+ home.pointerCursor = {
+ gtk.enable = true;
+ package = pkgs.bibata-cursors;
+ name = "Bibata-Modern-Ice";
+ size = 20;
+ };
+
+ home.packages = with pkgs; [
+ appimage-run
+ bemoji
+ brave
+ distrobox
+ eigent
+ (element-desktop.override {
+ commandLineArgs = "--password-store=gnome-libsecret";
+ })
+ launch-webapp
+ file-roller
+ hyprpanel
+ seahorse
+ sushi
+ ksnip
+ msty-studio
+ nwg-look
+ rose-pine-hyprcursor
+ remmina
+ slack
+ telegram-desktop
+ vivaldi
+ vivaldi-ffmpeg-codecs
+ vibetyper
+ ];
+}
diff --git a/home/desktop/theme/default.nix b/home/desktop/theme/default.nix
new file mode 100644
index 0000000..8445fe5
--- /dev/null
+++ b/home/desktop/theme/default.nix
@@ -0,0 +1,8 @@
+# Theme aggregator — fonts, GTK/Qt theming, and wallpapers.
+{...}: {
+ imports = [
+ ./fonts.nix
+ ./theme.nix
+ ./wallpapers.nix
+ ];
+}
diff --git a/home/desktop/theme/fonts.nix b/home/desktop/theme/fonts.nix
new file mode 100644
index 0000000..95eb69c
--- /dev/null
+++ b/home/desktop/theme/fonts.nix
@@ -0,0 +1,24 @@
+# Font packages — Fira Code, JetBrains Mono Nerd Font, and supporting icon fonts.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.theme.fonts;
+in {
+ options.desktop.theme.fonts.enable = mkEnableOption "install desktop fonts";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ fira-code
+ fira-code-symbols
+ nerd-fonts.fira-code
+ nerd-fonts.jetbrains-mono
+ font-manager
+ font-awesome_5
+ noto-fonts
+ ];
+ };
+}
diff --git a/home/desktop/theme/theme.nix b/home/desktop/theme/theme.nix
new file mode 100644
index 0000000..c78c598
--- /dev/null
+++ b/home/desktop/theme/theme.nix
@@ -0,0 +1,24 @@
+# GTK and Qt theming — Dracula theme with matching icons and cursor.
+{
+ pkgs,
+ config,
+ ...
+}: {
+ qt = {
+ enable = true;
+ platformTheme.name = "gtk";
+ };
+
+ gtk = {
+ enable = true;
+ theme = {
+ name = "Dracula";
+ package = pkgs.dracula-theme;
+ };
+ iconTheme = {
+ name = "Dracula";
+ package = pkgs.dracula-icon-theme;
+ };
+ gtk4.theme = config.gtk.theme;
+ };
+}
diff --git a/home/desktop/theme/wallpapers.nix b/home/desktop/theme/wallpapers.nix
new file mode 100644
index 0000000..24fd90c
--- /dev/null
+++ b/home/desktop/theme/wallpapers.nix
@@ -0,0 +1,19 @@
+# Wallpaper collection — copies wallpapers to Hyprland config directory.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.theme.wallpapers;
+in {
+ options.desktop.theme.wallpapers = mkEnableOption "wallpapers for Hyprland";
+
+ config = mkIf cfg {
+ xdg.configFile."hypr/wallpapers" = {
+ # Wallpapers are stored relative to the home/m3tam3re directory.
+ source = ../../../m3tam3re/wallpapers;
+ recursive = true;
+ };
+ };
+}
diff --git a/home/desktop/wm/default.nix b/home/desktop/wm/default.nix
new file mode 100644
index 0000000..796b018
--- /dev/null
+++ b/home/desktop/wm/default.nix
@@ -0,0 +1,8 @@
+# Window manager aggregator — Hyprland, Wayland tools, and Rofi launcher.
+{...}: {
+ imports = [
+ ./hyprland.nix
+ ./wayland.nix
+ ./rofi.nix
+ ];
+}
diff --git a/home/desktop/wm/hyprland.nix b/home/desktop/wm/hyprland.nix
new file mode 100644
index 0000000..75e3cd8
--- /dev/null
+++ b/home/desktop/wm/hyprland.nix
@@ -0,0 +1,318 @@
+# Hyprland window manager with keybindings, window rules, idle/lock, and hyprpaper.
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.wm.hyprland;
+in {
+ options.desktop.wm.hyprland.enable = mkEnableOption "Hyprland window manager";
+
+ config = mkIf cfg.enable {
+ wayland.windowManager.hyprland = {
+ settings = {
+ xwayland = {
+ force_zero_scaling = true;
+ };
+
+ exec-once = [
+ "hyprpanel"
+ "while ! hyprpaper-random; do sleep 0.5; done"
+ "wl-paste --type text --watch cliphist store"
+ "wl-paste --type image --watch cliphist store"
+ "vibetyper"
+ ];
+
+ env = [
+ "XCURSOR_SIZE,32"
+ "HYPRCURSOR_THEME,Bibata-Modern-Ice"
+ "WLR_NO_HARDWARE_CURSORS,1"
+ "GTK_THEME,Dracula"
+ "XDG_CURRENT_DESKTOP,Hyprland"
+ "XDG_SESSION_TYPE,wayland"
+ "XDG_SESSION_DESKTOP,Hyprland"
+ "XKB_DEFAULT_LAYOUT,de"
+ "NIXOS_OZONE_WL,1"
+ ];
+
+ input = {
+ kb_layout = "de,us";
+ kb_variant = "";
+ kb_model = "";
+ kb_rules = "";
+ kb_options = "ctrl:nocaps";
+ follow_mouse = 1;
+ };
+
+ general = {
+ gaps_in = 5;
+ gaps_out = 5;
+ border_size = 1;
+ "col.active_border" = "rgba(9742b5ee) rgba(9742b5ee) 45deg";
+ "col.inactive_border" = "rgba(${config.colorScheme.palette.base03}aa)";
+ layout = "dwindle";
+ };
+
+ decoration = {
+ shadow = {
+ enabled = true;
+ range = 60;
+ render_power = 3;
+ color = "rgba(${config.colorScheme.palette.base00}66)";
+ offset = "1 2";
+ scale = 0.97;
+ };
+ rounding = 8;
+ blur = {
+ enabled = true;
+ size = 3;
+ passes = 3;
+ };
+ active_opacity = 0.9;
+ inactive_opacity = 0.5;
+ };
+
+ animations = {
+ enabled = true;
+ bezier = "myBezier, 0.05, 0.9, 0.1, 1.05";
+ animation = [
+ "windows, 1, 7, myBezier"
+ "windowsOut, 1, 7, default, popin 80%"
+ "border, 1, 10, default"
+ "borderangle, 1, 8, default"
+ "fade, 1, 7, default"
+ "workspaces, 1, 6, default"
+ ];
+ };
+
+ dwindle = {
+ pseudotile = true;
+ preserve_split = true;
+ };
+
+ master = {
+ new_status = "master";
+ };
+
+ device = [
+ {
+ name = "epic-mouse-v1";
+ sensitivity = -0.5;
+ }
+ {
+ name = "zsa-technology-labs-moonlander-mark-i";
+ kb_layout = "us";
+ }
+ {
+ name = "keychron-keychron-k7";
+ kb_layout = "us";
+ }
+ ];
+
+ windowrule = [
+ "match:class file_progress, float on"
+ "match:class confirm, float on"
+ "match:class dialog, float on"
+ "match:class download, float on"
+ "match:class notification, float on"
+ "match:class error, float on"
+ "match:class splash, float on"
+ "match:class confirmreset, float on"
+ "match:title Open File, float on"
+ "match:title branchdialog, float on"
+ "match:class pavucontrol-qt, float on"
+ "match:class pavucontrol, float on"
+ "match:class class:^(espanso)$, float on"
+ "match:class wlogout, fullscreen on"
+ "match:title wlogout, float on"
+ "match:title wlogout, fullscreen on"
+ "match:class mpv, float on"
+ "match:class mpv, idle_inhibit focus"
+ "match:class mpv, opacity 1.0 override"
+ "match:title ^(Media viewer)$, float on"
+ "match:title ^(Volume Control)$, float on"
+ "match:title ^(Picture-in-Picture)$, float on"
+ "match:title ^(floating-pomodoro)$, float on"
+ "match:title ^(floating-pomodoro)$, size 250 50"
+ "match:title ^(floating-pomodoro)$, move 12 (monitor_h-150)"
+ "match:title ^(floating-pomodoro)$, pin on"
+ "match:initial_title .*streamlabs.com.*, float on"
+ "match:initial_title .*streamlabs.com.*, pin on"
+ "match:initial_title .*streamlabs.com.*, size 800 400"
+ "match:initial_title .*alert-box.*, move 100%-820 102"
+ "match:initial_title .*chat-box.*, move 100%-820 512"
+ "match:initial_title .*streamlabs.com.*, opacity 0.5 override"
+ "match:initial_title .*streamlabs.com.*, idle_inhibit focus"
+ "match:initial_title .*streamlabs.com.*, no_anim on"
+ "match:initial_title .*streamlabs.com.*, decorate off"
+ "match:initial_title .*streamlabs.com.*, no_shadow on"
+ "match:initial_title .*streamlabs.com.*, no_blur on"
+ "match:class ^vibe-typer$, match:title ^Recording Indicator$, no_blur on"
+ "border_color rgb(ffffff), match:xwayland 1"
+ ];
+
+ "$mainMod" = "SUPER";
+ "$terminal" = "ghostty";
+
+ bind = [
+ "$mainMod, return, exec, $terminal nu -c zellij-ps"
+ "$mainMod, t, exec, $terminal -e nu -c 'nitch; exec nu'"
+ "$mainMod SHIFT, t, exec, launch-timer"
+ "$mainMod, n, exec, $terminal -e nvim"
+ "$mainMod, z, exec, uwsm app -- zeditor"
+ "$mainMod, o, exec, hyprctl dispatch setprop activewindow opaque toggle"
+ "$mainMod, r, exec, hyprctl dispatch focuswindow \"initialtitle:.*alert-box.*\" && hyprctl dispatch moveactive exact 4300 102 && hyprctl dispatch focuswindow \"initialtitle:.*chat-box.*\" && hyprctl dispatch moveactive exact 4300 512"
+ "$mainMod, b, exec, uwsm app -- thunar"
+ "$mainMod SHIFT, B, exec, uwsm app -- vivaldi"
+ "$mainMod, Escape, exec, uwsm app -- wlogout -p layer-shell"
+ "$mainMod, Space, togglefloating"
+ "$mainMod, q, killactive"
+ "$mainMod, M, exit"
+ "$mainMod, F, fullscreen"
+ "$mainMod SHIFT, V, togglefloating"
+ "$mainMod, D, exec, uwsm app -- rofi -show drun -run-command \"uwsm app -- {cmd}\""
+ "$mainMod, V, exec, uwsm app -- cliphist list | rofi -dmenu | cliphist decode | wl-copy"
+ "$mainMod, C, exec, bash -c 'FILE=/tmp/screenshot_$(date +%s).png; grim -g \"$(slurp)\" \"$FILE\" && ksnip \"$FILE\"'"
+ "$mainMod SHIFT, S, exec, uwsm app -- rofi -show emoji"
+ "$mainMod, P, exec, uwsm app -- rofi-pass"
+ "$mainMod SHIFT, P, pseudo"
+ "$mainMod, R, exec, stt-ptt start"
+ "$mainMod, S, exec, stt-ptt start"
+ "$mainMod, J, togglesplit"
+ "$mainMod, h, movefocus, l"
+ "$mainMod, l, movefocus, r"
+ "$mainMod, k, movefocus, u"
+ "$mainMod, j, movefocus, d"
+ "$mainMod, 1, workspace, 1"
+ "$mainMod, 2, workspace, 2"
+ "$mainMod, 3, workspace, 3"
+ "$mainMod, 4, workspace, 4"
+ "$mainMod, 5, workspace, 5"
+ "$mainMod, 6, workspace, 6"
+ "$mainMod, 7, workspace, 7"
+ "$mainMod, 8, workspace, 8"
+ "$mainMod, 9, workspace, 9"
+ "$mainMod, 0, workspace, 10"
+ "$mainMod SHIFT, 1, movetoworkspace, 1"
+ "$mainMod SHIFT, 2, movetoworkspace, 2"
+ "$mainMod SHIFT, 3, movetoworkspace, 3"
+ "$mainMod SHIFT, 4, movetoworkspace, 4"
+ "$mainMod SHIFT, 5, movetoworkspace, 5"
+ "$mainMod SHIFT, 6, movetoworkspace, 6"
+ "$mainMod SHIFT, 7, movetoworkspace, 7"
+ "$mainMod SHIFT, 8, movetoworkspace, 8"
+ "$mainMod SHIFT, 9, movetoworkspace, 9"
+ "$mainMod SHIFT, 0, movetoworkspace, 10"
+ "$mainMod, mouse_down, workspace, e+1"
+ "$mainMod, mouse_up, workspace, e-1"
+ ];
+
+ bindr = [
+ "$mainMod, R, exec, stt-ptt stop"
+ "$mainMod, S, exec, stt-ptt format-stop"
+ ];
+
+ bindm = [
+ "$mainMod, mouse:272, movewindow"
+ "$mainMod, mouse:273, resizewindow"
+ ];
+ };
+ };
+
+ services.hypridle = {
+ enable = true;
+ settings = {
+ general = {
+ before_sleep_cmd = "hyprlock";
+ after_sleep_cmd = "hyprctl dispatch dpms on";
+ inhibit_sleep = 3;
+ };
+ listener = [
+ {
+ timeout = 300;
+ on-timeout = "hyprlock";
+ }
+ {
+ timeout = 420;
+ on-timeout = "hyprctl dispatch dpms off";
+ on-resume = "hyprctl dispatch dpms on";
+ }
+ ];
+ };
+ };
+
+ services.hyprpaper.enable = true;
+
+ programs.hyprlock = {
+ enable = true;
+ settings = {
+ "$font" = "JetBrainsMono Nerd Font";
+ "$base" = "rgb(${config.colorScheme.palette.base00})";
+ "$text" = "rgb(${config.colorScheme.palette.base05})";
+ "$textAlpha" = "${config.colorScheme.palette.base05}";
+ "$accentAlpha" = "${config.colorScheme.palette.base0D}";
+ "$red" = "rgb(${config.colorScheme.palette.base08})";
+ "$yellow" = "rgb(${config.colorScheme.palette.base0A})";
+
+ general = {
+ hide_cursor = true;
+ };
+
+ background = {
+ monitor = "";
+ path = "${config.home.homeDirectory}/.config/hypr/wallpapers/wallhaven-lmmo8r.jpg";
+ blur_passes = 0;
+ color = "rgb(${config.colorScheme.palette.base00})";
+ };
+
+ label = [
+ {
+ monitor = "";
+ text = "$TIME";
+ color = "$text";
+ font_size = 90;
+ font_family = "$font";
+ position = "30, 0";
+ halign = "left";
+ valign = "top";
+ }
+ {
+ monitor = "";
+ text = ''cmd[update:43200000] echo "$(date +"%A, %d %B %Y")"'';
+ color = "$text";
+ font_size = 25;
+ font_family = "$font";
+ position = "30, -150";
+ halign = "left";
+ valign = "top";
+ }
+ ];
+
+ input-field = [
+ {
+ monitor = "";
+ size = "300, 60";
+ outline_thickness = 4;
+ dots_size = 0.2;
+ dots_spacing = 0.2;
+ dots_center = true;
+ outer_color = "rgb(${config.colorScheme.palette.base0D})";
+ inner_color = "rgb(${config.colorScheme.palette.base00})";
+ font_color = "rgb(${config.colorScheme.palette.base05})";
+ fade_on_empty = false;
+ placeholder_text = '' Logged in as $USER'';
+ hide_input = false;
+ check_color = "rgb(${config.colorScheme.palette.base0D})";
+ fail_color = "rgb(${config.colorScheme.palette.base08})";
+ fail_text = ''$FAIL ($ATTEMPTS)'';
+ capslock_color = "rgb(${config.colorScheme.palette.base0A})";
+ position = "0, -35";
+ halign = "center";
+ valign = "center";
+ }
+ ];
+ };
+ };
+ };
+}
diff --git a/home/desktop/wm/rofi.nix b/home/desktop/wm/rofi.nix
new file mode 100644
index 0000000..d3c3a76
--- /dev/null
+++ b/home/desktop/wm/rofi.nix
@@ -0,0 +1,207 @@
+# Rofi application launcher with nix-colors theme, pass integration, and project opener.
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.wm.rofi;
+in {
+ options.desktop.wm.rofi.enable = mkEnableOption "enable rofi";
+
+ config = mkIf cfg.enable {
+ programs.rofi = {
+ enable = true;
+ package = pkgs.rofi.override {
+ plugins = [
+ pkgs.rofi-calc
+ pkgs.rofi-emoji
+ pkgs.stable.rofi-file-browser
+ ];
+ };
+ pass = {
+ enable = true;
+ package = pkgs.rofi-pass-wayland;
+ };
+ terminal = "${pkgs.ghostty}/bin/ghostty";
+ font = "Fira Code";
+ extraConfig = {
+ show-icons = true;
+ disable-history = false;
+ modi = "drun,calc,emoji,filebrowser";
+ kb-primary-paste = "Control+V,Shift+Insert";
+ kb-secondary-paste = "Control+v,Insert";
+ };
+ theme = let
+ inherit (config.colorScheme) palette;
+ in
+ builtins.toString (pkgs.writeText "rofi-universal-theme.rasi" ''
+ * {
+ /* Universal theme colors from nix-colors */
+ background: #${palette.base00};
+ surface: #${palette.base01};
+ overlay: #${palette.base02};
+ muted: #${palette.base03};
+ subtle: #${palette.base04};
+ text: #${palette.base05};
+ bright-text: #${palette.base06};
+ highlight: #${palette.base07};
+ accent1: #${palette.base08};
+ accent2: #${palette.base09};
+ accent3: #${palette.base0A};
+ accent4: #${palette.base0B};
+ accent5: #${palette.base0C};
+ accent6: #${palette.base0D};
+ accent7: #${palette.base0E};
+ accent8: #${palette.base0F};
+
+ /* Global properties */
+ background-color: @background;
+ text-color: @text;
+ font: "Fira Code 12";
+ border: 0;
+ margin: 0;
+ padding: 0;
+ spacing: 0;
+ }
+
+ window {
+ background-color: @background;
+ border: 1px;
+ border-color: @accent7;
+ border-radius: 6px;
+ width: 40%;
+ padding: 16px;
+ }
+
+ inputbar {
+ children: [ prompt, entry ];
+ spacing: 12px;
+ padding: 8px;
+ border-radius: 4px;
+ background-color: @surface;
+ }
+
+ prompt {
+ text-color: @accent7;
+ background-color: transparent;
+ }
+
+ entry {
+ placeholder: "Search...";
+ placeholder-color: @subtle;
+ text-color: @text;
+ background-color: transparent;
+ cursor-color: @accent7;
+ }
+
+ message {
+ background-color: @surface;
+ border-radius: 4px;
+ padding: 8px;
+ margin: 8px 0;
+ }
+
+ textbox {
+ text-color: @text;
+ background-color: transparent;
+ }
+
+ listview {
+ background-color: transparent;
+ margin: 8px 0 0;
+ lines: 10;
+ columns: 1;
+ fixed-height: true;
+ scrollbar: false;
+ }
+
+ element {
+ background-color: transparent;
+ text-color: @text;
+ padding: 8px;
+ border-radius: 4px;
+ spacing: 8px;
+ }
+
+ element normal.normal {
+ background-color: transparent;
+ text-color: @text;
+ }
+
+ element selected.normal {
+ background-color: @accent7;
+ text-color: @background;
+ }
+
+ element alternate.normal {
+ background-color: transparent;
+ text-color: @text;
+ }
+
+ element-icon {
+ background-color: transparent;
+ size: 24px;
+ }
+
+ element-text {
+ background-color: transparent;
+ text-color: inherit;
+ vertical-align: 0.5;
+ }
+
+ mode-switcher {
+ spacing: 0;
+ background-color: @surface;
+ border-radius: 4px;
+ margin: 8px 0 0;
+ }
+
+ button {
+ padding: 8px 16px;
+ background-color: transparent;
+ text-color: @text;
+ border-radius: 4px;
+ }
+
+ button selected {
+ background-color: @accent7;
+ text-color: @background;
+ }
+
+ scrollbar {
+ width: 4px;
+ border: 0;
+ handle-color: @accent7;
+ handle-width: 4px;
+ padding: 0;
+ }
+ '');
+ };
+
+ cli.rofi-project-opener = {
+ enable = true;
+ projectDirs = {
+ AI = {
+ path = "~/p/AI";
+ args = "";
+ };
+ CHAT = {
+ path = "~/p/CHAT";
+ args = "--agent chiron";
+ };
+ MISC = {
+ path = "~/p/MISC";
+ args = "--agent chiron-forge";
+ };
+ NIX = {
+ path = "~/p/NIX";
+ args = "";
+ };
+ };
+ terminal = pkgs.ghostty;
+ terminalCommand = "opencode %a";
+ };
+ };
+}
diff --git a/home/desktop/wm/wayland.nix b/home/desktop/wm/wayland.nix
new file mode 100644
index 0000000..1429d35
--- /dev/null
+++ b/home/desktop/wm/wayland.nix
@@ -0,0 +1,30 @@
+# Wayland extra tooling — screenshot, clipboard, cursor, and display utilities.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.desktop.wm.wayland;
+in {
+ options.desktop.wm.wayland.enable = mkEnableOption "wayland extra tools and config";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ grim
+ hyprcursor
+ hyprlock
+ hyprpaper
+ qt6.qtwayland
+ slurp
+ waypipe
+ wl-clipboard
+ wf-recorder
+ wl-mirror
+ wlogout
+ wtype
+ ydotool
+ ];
+ };
+}
diff --git a/home/profiles/gaming/default.nix b/home/profiles/gaming/default.nix
new file mode 100644
index 0000000..e1d0e47
--- /dev/null
+++ b/home/profiles/gaming/default.nix
@@ -0,0 +1,7 @@
+# Gaming profile aggregator — Steam platform and Gamescope session support.
+{...}: {
+ imports = [
+ ./steam.nix
+ ./gamescope.nix
+ ];
+}
diff --git a/home/profiles/gaming/gamescope.nix b/home/profiles/gaming/gamescope.nix
new file mode 100644
index 0000000..6f975cd
--- /dev/null
+++ b/home/profiles/gaming/gamescope.nix
@@ -0,0 +1,16 @@
+# Gamescope — Valve's micro-compositor for Steam gaming sessions.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.gaming.gamescope;
+in {
+ options.profiles.gaming.gamescope.enable = mkEnableOption "enable Gamescope session";
+
+ config = mkIf cfg.enable {
+ home.packages = [pkgs.gamescope];
+ };
+}
diff --git a/home/profiles/gaming/steam.nix b/home/profiles/gaming/steam.nix
new file mode 100644
index 0000000..92a24c1
--- /dev/null
+++ b/home/profiles/gaming/steam.nix
@@ -0,0 +1,21 @@
+# Steam gaming platform with Steam Deck compatibility tools and gaming utilities.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.gaming.steam;
+in {
+ options.profiles.gaming.steam.enable = mkEnableOption "enable Steam gaming";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ gamemode
+ goverlay
+ mangohud
+ protonplus
+ ];
+ };
+}
diff --git a/home/profiles/media/default.nix b/home/profiles/media/default.nix
new file mode 100644
index 0000000..0f453a5
--- /dev/null
+++ b/home/profiles/media/default.nix
@@ -0,0 +1,10 @@
+# Media profile aggregator — OBS, FFmpeg, yt-dlp, Kdenlive, and HandBrake.
+{...}: {
+ imports = [
+ ./obs.nix
+ ./ffmpeg.nix
+ ./yt-dlp.nix
+ ./kdenlive.nix
+ ./handbrake.nix
+ ];
+}
diff --git a/home/profiles/media/ffmpeg.nix b/home/profiles/media/ffmpeg.nix
new file mode 100644
index 0000000..287e32c
--- /dev/null
+++ b/home/profiles/media/ffmpeg.nix
@@ -0,0 +1,24 @@
+# FFmpeg — full-featured multimedia processing toolchain.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.media.ffmpeg;
+in {
+ options.profiles.media.ffmpeg.enable = mkEnableOption "enable FFmpeg tools";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ amf
+ ffmpeg_6-full
+ gst_all_1.gstreamer
+ gst_all_1.gst-vaapi
+ pamixer
+ pavucontrol
+ qpwgraph
+ ];
+ };
+}
diff --git a/home/profiles/media/handbrake.nix b/home/profiles/media/handbrake.nix
new file mode 100644
index 0000000..f14ff5d
--- /dev/null
+++ b/home/profiles/media/handbrake.nix
@@ -0,0 +1,21 @@
+# HandBrake — open-source video transcoder.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.media.handbrake;
+in {
+ options.profiles.media.handbrake.enable = mkEnableOption "enable HandBrake transcoder";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ handbrake
+ gimp
+ inkscape
+ libation
+ ];
+ };
+}
diff --git a/home/profiles/media/kdenlive.nix b/home/profiles/media/kdenlive.nix
new file mode 100644
index 0000000..f3a4dbd
--- /dev/null
+++ b/home/profiles/media/kdenlive.nix
@@ -0,0 +1,16 @@
+# Kdenlive — KDE non-linear video editor.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.media.kdenlive;
+in {
+ options.profiles.media.kdenlive.enable = mkEnableOption "enable Kdenlive video editor";
+
+ config = mkIf cfg.enable {
+ home.packages = [pkgs.kdePackages.kdenlive];
+ };
+}
diff --git a/home/profiles/media/obs.nix b/home/profiles/media/obs.nix
new file mode 100644
index 0000000..2a6f22c
--- /dev/null
+++ b/home/profiles/media/obs.nix
@@ -0,0 +1,21 @@
+# OBS Studio — open broadcaster software for streaming and recording.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.media.obs;
+in {
+ options.profiles.media.obs.enable = mkEnableOption "enable OBS Studio";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ v4l-utils
+ ];
+
+ # OBS is managed via NixOS programs.obs-studio at the system level.
+ # Home-manager only installs supporting tools.
+ };
+}
diff --git a/home/profiles/media/yt-dlp.nix b/home/profiles/media/yt-dlp.nix
new file mode 100644
index 0000000..982f585
--- /dev/null
+++ b/home/profiles/media/yt-dlp.nix
@@ -0,0 +1,31 @@
+# yt-dlp and media playback — YouTube downloader with MPV integration.
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.profiles.media.ytDlp;
+in {
+ options.profiles.media.ytDlp.enable = mkEnableOption "enable yt-dlp and media playback";
+
+ config = mkIf cfg.enable {
+ home.packages = with pkgs; [
+ plexamp
+ webcord
+ ];
+
+ programs.mpv = {
+ enable = true;
+ bindings = {
+ WHEEL_UP = "seek 10";
+ WHEEL_DOWN = "seek -10";
+ };
+ config = {
+ profile = "gpu-hq";
+ ytdl-format = "bestvideo+bestaudio";
+ };
+ };
+ };
+}
diff --git a/home/server/default.nix b/home/server/default.nix
new file mode 100644
index 0000000..2c6d8ea
--- /dev/null
+++ b/home/server/default.nix
@@ -0,0 +1,6 @@
+# Server context home-manager configuration — minimal headless setup.
+# Loaded on server hosts: m3-atlas, m3-helios, m3-aether.
+{...}: {
+ # Server hosts use the base and coding modules directly.
+ # No desktop environment or GUI applications.
+}