1 56 SpecialArgs and Home Manager Argument Flow
Nimmo edited this page 2026-09-13 13:07:16 +01:00

specialArgs and Home Manager Argument Flow

  • Type: Tutorial
  • Status: Current
  • Scope: How the shared flake builder passes inputs and host context into NixOS and Home Manager modules
  • Canonical sources: flake.nix; hosts/vega/default.nix; modules/services/redview.nix; modules/profiles/ai-agents.nix; home/users/nimmo/default.nix; Home Manager NixOS module manual
  • Last verified: Source commit 556df88494686003b1c4f20c8e0b99b5afc16a6e (2026-09-12); source HEAD b2831d33132967b4c4fb69e6068b2b05fff8fdff changes only flake.lock. Argument definitions and consumers checked 2026-09-13; no module changed.
  • Review triggers: makeNixosSystem, specialArgs, home-manager.extraSpecialArgs, primary-user path, host role metadata, or Home Manager module composition

Learning goal and prerequisites

Trace an external flake input and host-derived values to the module function that uses them, without confusing the NixOS and Home Manager argument scopes. Read Flakes and Inputs and NixOS Modules and Option Merging first. The Home Manager manual is the upstream reference for its NixOS-module integration.

The NixOS path

flake.nix captures all inputs as inputs in the outputs function. The shared makeNixosSystem builder passes them into NixOS evaluation with:

specialArgs = { inherit inputs; };

inherit inputs; means inputs = inputs;. Any NixOS module function that needs a root input can accept it, for example { config, inputs, lib, pkgs, ... }: in modules/services/redview.nix. That module imports inputs.redview.nixosModules.default and selects its package for the host platform. Other modules need not list inputs.

specialArgs adds a function argument; it does not automatically enable the module, place its package on every host, or decrypt any secret. A host must import the relevant module and satisfy any enable gate. The package output shape is specific to that input, as Adding Packages and Flake Inputs explains.

The Home Manager path

The same makeNixosSystem builder imports the matching Home Manager NixOS module and sets:

home-manager.users.${config.nixosConfig.primaryUser} =
  import ./home/users/${config.nixosConfig.primaryUser};

This creates the per-user Home Manager module from the configured primary user's directory. The builder sets home-manager.useGlobalPkgs = true, so Home Manager uses the host package set. It also contributes Plasma Manager through home-manager.sharedModules and passes the following arguments to Home Manager modules through home-manager.extraSpecialArgs: inputs, isServer, flakeRepo, primaryUser, userEmail, and hostName. Here isServer is derived from config.nixosConfig.host.role == "server"; it is not an extra flake-output parameter or a guess from the hostname.

home/users/nimmo/default.nix accepts isServer and primaryUser. It adds ./plasma.nix only when !isServer, and uses primaryUser for home.username and home.homeDirectory. Changing the primary user therefore requires a matching home/users/<name>/ entry point, not just a new name in host metadata. The module's home.stateVersion is its own persistent compatibility setting, separate from system.stateVersion.

The NixOS and Home Manager scopes are connected but not identical. The NixOS specialArgs does not, by itself, feed nested Home Manager modules; the explicit extraSpecialArgs does that. A NixOS module such as modules/profiles/ai-agents.nix may accept NixOS inputs and set home-manager.users options, while a file under home/users/nimmo/ is evaluated as a Home Manager module and receives its own argument set. Do not copy code between those locations assuming the same config, options, or arguments.

Guided check

Follow inputs.redview from flake.nix to the NixOS Redview module and Lyra's host import. Separately, follow isServer from the Lyra host role through home-manager.extraSpecialArgs to the conditional Plasma import in home/users/nimmo/default.nix. Explain why neither trace depends on the other. Then find a home/users/nimmo/ module that accepts inputs and identify which extra-argument declaration makes that possible.

If an argument is undefined, inspect the function header and the appropriate builder argument path first. If a Home Manager module is missing, inspect the selected primary-user directory and imports list, then use Repository Structure and Import Chain. Do not fix a missing argument by placing a second, divergent flake input inside a user module.