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 HEADb2831d33132967b4c4fb69e6068b2b05fff8fdffchanges onlyflake.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.