Software
Software Customization & Privacy
High-performance, privacy-hardened application stack with deep declarative customization.
🦊 LibreWolf (Hardened Browser)
LibreWolf is our primary browser, configured as a “Prisoner of the System” via Hybrid Fake HOME jailing.
🛡️ Privacy & Performance
We utilize two powerful upstream projects to harden LibreWolf:
- Betterfox: Implements advanced
user.jstweaks for speed (Smoothfox) and privacy (Peskyfox). It is managed declaratively and concatenated at build time. - Enterprise Policies: We use native Mozilla policies to enforce security:
DisablePocket: Removes all Pocket integration.DontCheckDefaultBrowser: Prevents nag screens.SearchEngines: Declaratively injects Kagi, NixOS Options, and GitHub while removing tracking-heavy defaults like Google.
🎨 UI Customization
The visual experience is governed by the active theme:
- Vertical Tabs: A minimalist
userChrome.cssthat hides the native tab bar and sidebar headers, optimized for vertical tab extensions like Sidebery. - Sidebery: Declaratively installed and pre-configured for a clean, layout-efficient browsing experience.
🎵 Spotify (Spicetify)
The Spotify client is enhanced via spicetify-nix.
Features
- Theming: Automatically pulls themes from the
modules.theme.apps.spicetifyoption. - Custom Apps: Includes
lyrics-plus,new-releases, and more. - Extensions: Hardened with
adblockandshuffleimprovements. - Reactive Design: If you change the system theme (e.g., from Alucard to Catppuccin), Spicetify automatically rebuilds with the matching color scheme.
🏠 Hybrid Fake HOME (Jailing)
Stubborn or sandboxed applications (Steam, LibreWolf, Flatpak) often pollute the user’s home directory. We use a Sovereign Isolation model centered around ~/.local/user.
🏗️ The Two-Home Architecture
We maintain two parallel home environments to ensure your primary $HOME remains clean and your data stays isolated:
- Real Home (
~): The source of truth for the human. This contains yourprojects,toolkits, and primarydocuments. It is the environment your terminal and editors (like Emacs/Vim) operate in. - Fake Home (
~/.local/user): The execution jail for software. Jailed applications see this as their$HOME. It isolates app-specific sprawl, caches, and telemetry.
🔗 The Configuration Bridge
To ensure jailed apps still feel integrated (sharing fonts, themes, and credentials), the Fake Home contains symlinks pointing back to the Real Home for core XDG base directories:
~/.local/user/.config->~/.config~/.local/user/.cache->~/.cache~/.local/user/.local->~/.local~/.local/user/.ssh->~/.ssh
🛡️ Data Isolation (Independent Folders)
Unlike configurations, user data directories are strictly independent. We do not link them. This results in “Two Worlds”:
- Human World:
~/documents,~/downloads,~/pictures. - Software World:
~/.local/user/documents,~/.local/user/downloads, etc.
This means a file downloaded in LibreWolf stays in the jail’s Downloads folder, never touching your primary workspace. Both worlds are independently persisted via modules/persist.nix.
⚙️ XDG & Activation
This model is enforced through two mechanisms:
user-dirs.dirs: Configured to point to the Fake Home paths (e.g.,XDG_DOWNLOAD_DIR="~/.local/user/downloads"). Jailed apps follow these variables into their isolation.initXDGActivation: A NixOS activation script (system.userActivationScripts) that ensures folders exist in both homes and the configuration bridge is linked correctly on every boot.
🚦 XDG Variable Initialization & User Scope
The initialization of XDG variables (XDG_CONFIG_HOME, XDG_FAKE_HOME, etc.) must be done carefully to ensure it supports all users (root, alienzj, dms-greeter) without permission errors or broken shell configurations.
We configure these variables in NixOS’s environment.sessionVariables using the literal $HOME string, rather than evaluating the Nix config.home.dir path or using Home Manager’s home.sessionVariables.
- Why
environment.sessionVariables? This ensures the variables are evaluated early by PAM (Pluggable Authentication Modules) at login. This is critical becauseZDOTDIRdepends onXDG_CONFIG_HOMEto locate Zsh’s configuration (.zshenv). If XDG variables are deferred to Home Manager’shm-session-vars.sh, they won’t be available when Zsh starts, breaking the shell. - Why literal
$HOME? If we setXDG_CONFIG_HOME = cfg.configDir(which evaluates to/home/alienzj/.configat build time),environment.sessionVariableswill hardcode this path globally. This breaksrootanddms-greeter(which runs as a restricted system user), causing them to write/read from the primary user’s directory and crash due toPermission Deniederrors. By usingXDG_CONFIG_HOME = "$HOME/.config", the path is evaluated dynamically at runtime based on the executing user’s$HOME.
Wrapper Logic
To ensure the jail is always active without manual environment variable management, applications are wrapped. We employ a three-tier strategy based on the app’s risk profile:
-
Simple Apps (
wrapFakeHome): For straightforward applications, we use a lightweight wrapper built onmkWrapperthat targets the exact binary:wrapFakeHome = pkg: binName: mkWrapper pkg '' wrapProgram "$out/bin/${binName}" --run 'export HOME="$XDG_FAKE_HOME"' ''; -
Complex Apps (
mkWrapper/symlinkJoin): For apps requiring multiple binaries (e.g., Steam), explicit icon paths (e.g., VSCode, Cursor), or complex environment scrubbing (e.g., Java, Kotlin), we use rawmkWrapperorsymlinkJoinin the module configuration. This “clean-room” approach guarantees predictability, allowing explicitpostBuildscripts without risking Nix store link-of-link permission errors. -
Untrusted Apps (Nixpak): For proprietary/high-risk GUI apps (Discord, Zoom, WeMeet, Telegram), we use nixpak — a Flatpak-inspired sandboxing framework that wraps bubblewrap with per-app DBus filtering, GPU passthrough, and Flatpak-compatible data isolation (
~/.var/app/<appId>/). Defined inmodules/sandbox.nix, each app gets a shared baseline (gui-base,network,commonmodules) plus app-specific socket, bind mount, and env configuration. A wrapper script ensuresHOME=~/.local/userbefore the nixpak launcher runs, so the entire.vartree stays inside the fake home. Desktop files are patched automatically to point to the sandbox wrapper.
🐚 Shell Stack (Zsh & Starship)
Our shell environment is designed for maximum speed, informative feedback, and aesthetic consistency.
1. Zsh (The Orchestrator)
Configured via modules/shell/zsh.nix, our Zsh setup focuses on a “Static & Fast” philosophy.
- Modular Prompts: Choose your prompt style via
modules.theme.apps.zsh.prompt.starship: (Default) Modern, informative, and cross-shell.matrix: Simple, distraction-free green prompt.p10k: Powerlevel10k integration (requires local.p10k.zsh).
- Predictable Startup: Automatic plugin updates (
zgenom autoupdate) are disabled to ensure every shell opens instantly without unexpected network lag. - Ordered Initialization: To ensure tool-generated completions (like Starship and Zoxide) are correctly captured, they are initialized in
extra.zshrcbeforecompinitis called. - FZF-Tab: Standard Zsh completion is enhanced with
fzf-tab, providing an interactive, searchable menu with live file and directory previews.
2. Tmux (Multiplexer)
Tmux theming is decoupled from the active system theme to allow for functional overrides.
- Theme Selection: Managed via
modules.theme.apps.tmux.theme.catppuccin: (Default) Feature-rich, highly configurable status line.matrix/gemini: Minimalist, color-focused themes.
- Catppuccin Granularity: All Catppuccin settings are exposed under
modules.shell.tmux.catppuccin. - Transparency: The status bar can be made transparent via
modules.theme.apps.tmux.transparent = true.
3. Starship (The Modern Prompt)
Managed via modules/shell/starship.nix, Starship is our universal cross-shell prompt.
- Performance: Optimized with an aggressive
60mstimeout and minimal logic to keep the shell snappy even in massive Git repositories. - Clean Aesthetic: Configuration is mirrored from
oddlama/nix-config, but surgically cleaned to removeusernameandhostnamefor a minimalist look. - Git-Native: Provides rich, color-coded Git status indicators (conflicted, stashed, staged, etc.) directly in the prompt.
3. Zoxide (Smart Navigation)
Fully integrated as the replacement for cd.
- Usage: Use
z <dir>to jump to frequently visited directories. - Interactive: Use
zifor a fuzzy selection of your most used paths.
4. Fuzzy Workflow (FZF)
Centralized in config/zsh/fzf.zsh, FZF is woven into the shell experience:
- Alt-f: Fuzzy find and select files.
- Alt-c: Fuzzy jump to subdirectories.
- Alt-h / Ctrl-r: Fuzzy search command history.
- Tmux Integration: Automatically detects if you are in Tmux and uses specialized popups for a non-disruptive workflow.
Our setup supports VS Code Remote Development (SSH) while maintaining our isolation and security standards.
🛡️ Declarative Jailing
To prevent the VS Code server from polluting your home directory, we declaratively instruct it to install itself in the “Fake Home” directory. This is managed in modules/editors/default.nix via the remote.SSH.serverInstallPath setting:
"remote.SSH.serverInstallPath": {
"id3-eniac": "~/.local/user/.vscode-server",
"id3-yoga": "~/.local/user/.vscode-server"
}
This ensures that extensions and server state are isolated and persisted via our standard /persist mechanism.
🔌 Remote Development Setup
VS Code runs inside the “Fake Home” jail (HOME=~/.local/user). While ~/.local/user/.ssh symlinks to ~/.ssh, the Remote SSH extension may not resolve it reliably. The remote.SSH.configFile setting is set to the absolute path /home/alienzj/.ssh/config to bypass any $HOME resolution issues.
Connecting to Distrobox containers: Distrobox containers (e.g. bioarchlinux) are general-purpose Linux environments — they are NOT Dev Containers. The ms-vscode-remote.remote-containers extension expects containers with .devcontainer/devcontainer.json and won’t see Distrobox instances. To connect VS Code to a Distrobox container:
- Integrated terminal — Open VS Code terminal and run
distrobox enter bioarchlinux - Remote SSH — Set up sshd inside the distrobox, then connect via Remote SSH as you would to any other host
Connecting to NixOS remote hosts: The remote host must have programs.nix-ld.enable = true (or use nixos-vscode-server) so the prebuilt Node.js binary VS Code uploads can resolve its dynamic libraries. All hosts in this flake (id3-eniac, id3-yoga, lab-matrix, etc.) already have this enabled via modules/security.nix.
🧩 NixOS Compatibility (nix-ld)
NixOS’s non-standard FHS (Filesystem Hierarchy Standard) often breaks pre-compiled binaries like the VS Code Node.js server. We resolve this using nix-ld, which provides a “Compatibility Layer” for dynamic linking.
- Implementation: Enabled in
modules/security.nix. - Function: Automatically redirects requests for standard dynamic loaders to the Nix store and provides a comprehensive set of shared libraries (glibc, libstdc++, etc.) to unpatched binaries.