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.js tweaks 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.css that 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.spicetify option.
  • Custom Apps: Includes lyrics-plus, new-releases, and more.
  • Extensions: Hardened with adblock and shuffle improvements.
  • 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:

  1. Real Home (~): The source of truth for the human. This contains your projects, toolkits, and primary documents. It is the environment your terminal and editors (like Emacs/Vim) operate in.
  2. 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:

  1. 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.
  2. initXDG Activation: 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 because ZDOTDIR depends on XDG_CONFIG_HOME to locate Zsh’s configuration (.zshenv). If XDG variables are deferred to Home Manager’s hm-session-vars.sh, they won’t be available when Zsh starts, breaking the shell.
  • Why literal $HOME? If we set XDG_CONFIG_HOME = cfg.configDir (which evaluates to /home/alienzj/.config at build time), environment.sessionVariables will hardcode this path globally. This breaks root and dms-greeter (which runs as a restricted system user), causing them to write/read from the primary user’s directory and crash due to Permission Denied errors. By using XDG_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:

  1. Simple Apps (wrapFakeHome): For straightforward applications, we use a lightweight wrapper built on mkWrapper that targets the exact binary:

    wrapFakeHome = pkg: binName: mkWrapper pkg ''
      wrapProgram "$out/bin/${binName}" --run 'export HOME="$XDG_FAKE_HOME"'
    '';
  2. 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 raw mkWrapper or symlinkJoin in the module configuration. This “clean-room” approach guarantees predictability, allowing explicit postBuild scripts without risking Nix store link-of-link permission errors.

  3. 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 in modules/sandbox.nix, each app gets a shared baseline (gui-base, network, common modules) plus app-specific socket, bind mount, and env configuration. A wrapper script ensures HOME=~/.local/user before the nixpak launcher runs, so the entire .var tree 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.zshrc before compinit is 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 60ms timeout 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 remove username and hostname for 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 zi for 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:

  1. Integrated terminal — Open VS Code terminal and run distrobox enter bioarchlinux
  2. 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.