Table of contents
Adding Packages and Flake Inputs
- Type: Runbook
- Status: Current
- Scope: Adding or changing packages and root flake inputs in
nixos-config- Canonical sources:
AGENTS.md;flake.nix;lib/auto-update-policy.nix;modules/common/system.nix;modules/desktop/apps.nix;modules/profiles/gaming.nix;modules/profiles/ai-agents.nix;modules/services/redview.nix;modules/services/navidrome-mcp.nix;modules/services/jellyfin.nix;home/users/nimmo/default.nix;home/users/nimmo/browser.nix;home/users/nimmo/desktop.nix;justfiles/deploy.just; Configuration Ownership Boundaries- Last verified: Source commit
556df88494686003b1c4f20c8e0b99b5afc16a6e(2026-09-12); source HEADb2831d33132967b4c4fb69e6068b2b05fff8fdffchanges onlyflake.lock. Paths, outputs, update policy, and local command syntax checked 2026-09-13; no lock or package change was made.- Review triggers: Changes to flake inputs/outputs, package placement, Home Manager composition, auto-update policy, package pins, CI checks, or deployment recipes
Purpose
Add software at the right scope (which hosts and users receive it) and from the right source (the selected Nixpkgs input, an existing external flake, a local derivation, or a separately maintained wrapper). These are independent decisions. Configuration Ownership Boundaries owns the general placement rules; this page gives the package and input procedure.
Prerequisites and safety boundary
- Identify the actual consumers, their Nixpkgs branch, architecture, and whether the software needs system service, device, firewall, or account integration. Electra, Lena, Vega, and Lyra use the unstable input; Cosmos and Chaos use stable NixOS/Home Manager 26.05. A package available on one branch or architecture is not thereby available to every host.
- Check for an appropriate NixOS or Home Manager
programs.*/services.*option before adding a bare executable. An option may configure more than the binary, including units, policies, or companion files; inspect its actual module behavior rather than assuming an option and a package are interchangeable. For instance, the current gaming profile enables Steam and GameMode options and adds selected user packages separately. - Decide whether this is a bounded package edit or a new root input or
service. Root-input, cross-host, service, security, or CI changes use the
issue/branch/merge-request lifecycle in
AGENTS.md. A package addition that affects a live service needs an appropriate canary and rollback plan. - Do not add secret values to package derivations, flake URLs, Nix strings, build arguments, or Git. Service credentials must be delivered at runtime through the relevant SOPS integration.
1. Choose the installed scope
| Desired scope | Current insertion point | Example and check |
|---|---|---|
| System tool on every registered host | modules/common/system.nix via environment.systemPackages |
This file is reached by both desktop and server compositions. Confirm the tool builds on unstable and stable hosts before broadening it. |
| System app on desktop/laptop hosts | modules/desktop/apps.nix or a narrower desktop capability module |
trilium-next desktop comes from an external flake here; this module is selected by the GUI profile. |
| Personal package or setting for the primary user | A focused home/users/nimmo/ module, via home.packages or programs.* |
desktop.nix gates desktop-only packages with isServer; browser.nix configures Firefox and NUR add-ons. |
| Package coupled to a selected workload | The relevant modules/profiles/ or modules/services/ module |
gaming.nix adds user packages only where that profile is imported; redview.nix chooses the service package where Redview is enabled. |
| One host only | hosts/<host>/default.nix for a simple choice, or a reusable module selected by that host |
Keep hardware facts and host-specific values in the host even when implementation is reusable. |
| Fleet-local build definition | packages/ plus the consuming module/flake output |
Keep a derivation separate from service integration; use an independent repository only when its build and release lifecycle justify one. |
The same package may be reachable to a user through a system path, a
Home Manager profile, or both. Choose an owner deliberately; do not rely on
list merging to make duplicate entries desirable. If software needs a daemon
or system privilege, home.packages alone is not the service configuration.
If it is purely personal, users.users.<name>.packages is not this
repository's normal Home Manager path.
2. Prefer an existing source before a new input
Start with the target host's pkgs and an existing NixOS/Home Manager option.
The current root nixpkgs is unstable, while nixpkgs-stable is used for
Cosmos/Chaos. A module can make a narrow, explicit cross-input choice when
needed: modules/services/jellyfin.nix currently selects Jellyfin from
inputs.nixpkgs-stable.legacyPackages on its consuming host. Do not silently
switch an entire host or mix package sets in a generic profile to fix one
package; assess runtime compatibility and build cost for that particular
override.
If an input already exists, use its real output shape. These current examples are deliberately different:
inputs.redview.packages.${pkgs.stdenv.hostPlatform.system}.redview-nvidia
inputs.navidrome-mcp.packages.${pkgs.stdenv.hostPlatform.system}.default
inputs.nur.legacyPackages.${pkgs.stdenv.hostPlatform.system}.repos.rycee.firefox-addons
packages, legacyPackages, and nixosModules are distinct outputs; do not
guess default. flake.nix passes inputs to NixOS modules through
specialArgs and to Home Manager through extraSpecialArgs. The raw-source
inputs bash-it and pi-ollama use flake = false; they are source trees,
not flakes with a packages output. Check the consumer before copying a
package expression.
When nixpkgs or an existing input is insufficient, decide whether a local
derivation under packages/, a source-only input, or an independent wrapper
flake is warranted. ADR-002 owns the
native-versus-container choice; Wrapper-Repository
Packaging covers the independent build
boundary.
3. Add and classify a root flake input
In the feature branch, add a named input to flake.nix. Pin its exact
revision in flake.lock; a URL in flake.nix alone does not prove what will
build. Set inputs.<name>.inputs.nixpkgs.follows = "nixpkgs" only if that
upstream flake supports and should share the consumer package set. The
current Navidrome MCP input follows root Nixpkgs; Redview does not. For a
non-flake source, declare flake = false and consume it as a path/source,
not as packages.<system>.
In the same commit, add the root input to
lib/auto-update-policy.nix: normally one input group with the hosts that
actually consume it, or an explicitly pinned entry with a reason. Count
transitive consumers through profiles, shared flake modules, and checks; do
not list only the host where you happened to test it. The exported policy's
rootInputs list is generated from the actual flake.nix input set. The
guarded producer rejects unclassified or stale input policy and builds the
affected hosts; the wrapper's upstream update workflow is a separate layer.
Do not edit the obsolete source-repo path
scripts/nixos-update-common.sh: the controller is supplied by the pinned
nixos-auto-update flake.
Update only the intended input and inspect the lock and policy diff:
nix flake update <input-name>
git diff -- flake.nix flake.lock lib/auto-update-policy.nix
Replace <input-name> with the new input name. nix flake update without a
name updates all eligible inputs and is not a scoped package-addition step.
The initial lock update may add transitive nodes; inspect them as well as the
root entry. Do not use a routine package edit to silently change a
deployment-critical pinned input.
4. Validate and review before activation
Stage newly created .nix files before flake evaluation; Git-backed flakes
cannot see untracked files. Then, from the source checkout, run:
just check
nix build .#nixosConfigurations.<host>.config.system.build.toplevel --no-link
Replace <host> with each actual consumer. just check runs nix flake check; a host build proves the selected closure evaluates and builds, not
that the deployed application starts. For a new root input, review the
Forgejo producer/update-policy check as well as ordinary MR checks. The
just test-auto-update recipe runs remediation regressions; it is not the
input-inventory gate.
Inspect the package and service diff, then follow Safe Testing and Deployment for a canary and genuine client checks when activation is warranted. On a remote host, create an auto-update hold before a test deployment. Keep the issue open until any required live deployment and no-op follow-up evidence exists. Documentation-only package guidance does not authorize an update or deployment.
Success checks and rollback
- The desired package or option is owned at the intended system/user/host scope; no other hosts inherit it accidentally.
- A new input resolves to the output and architecture actually consumed, is
pinned in
flake.lock, and has correct update-policy classification. - The relevant flake checks, consumer host builds, MR gates, and canary pass; the actual command, service, or desktop client works after activation.
- For a failed package update, stop promotion and return to the last validated lock/package or NixOS generation through the normal reviewed path. If a service has already migrated writable state, a package rollback is not a data rollback; use its service-specific recovery plan.
Troubleshooting
- If an input has no
packages.<system>.<name>, inspect its actual flake outputs; it may exportlegacyPackages, anixosModulesmodule, a different package name, or only a raw source path. - If evaluation succeeds on one host but another fails, check its selected Nixpkgs branch, target system, profile imports, and package availability before broadening an override to the fleet.
- If the update producer rejects a new input, compare the root input name,
lib/auto-update-policy.nixgroup/pin, and real transitive consumers. Do not bypass that gate merely to publish a lock change. - If the built service fails after deployment, collect service and client evidence using Monitoring and Service Investigation. Check runtime credentials, assets, devices, mounts, and data compatibility separately from package build success.
Canonical source map
| Concern | Source |
|---|---|
| Ownership decision | Configuration Ownership Boundaries |
| Root inputs, host channels, and input forwarding | flake.nix |
| Input-to-host update policy | lib/auto-update-policy.nix |
| System, desktop, and user package examples | modules/common/system.nix, modules/desktop/apps.nix, home/users/nimmo/ |
| External output examples | modules/services/redview.nix, modules/services/navidrome-mcp.nix, home/users/nimmo/browser.nix |
| Validation and deployment | justfiles/deploy.just, Safe Testing and Deployment |