Interactive non-login Bash shells now apply the current session
variables file before bashrcExtra and initExtra. New terminals pick up
values changed by home-manager switch.
Login shells skip the refresh because .profile already applied it.
Non-interactive shells skip it because sshd can read .bashrc for remote
commands, where startup output can corrupt protocols such as scp and
rsync.
Apply programs.bash.sessionVariables after generic values to preserve
its precedence. Expansions run on every interactive non-login shell, so
warn when direct self-references can change repeatedly. Declarative
search paths remain stable across repeated sourcing.
A profileExtra assignment that collides with a Home Manager-managed
variable is now overwritten in non-login shells. Move such overrides to
initExtra, which runs after the refresh.
targets.genericLinux no longer needs its separate initExtra source.
Move the once-per-session guard to the final extra-code section. Plain
and search variables can then refresh without rerunning arbitrary code.
Keep the extra body top-level so shell parse behavior stays unchanged.
Use an exported generation token for Zsh. Changes to generic or
Zsh-specific values reapply both layers, while unchanged nested shells
keep Zsh precedence and do not repeat self-references.
Plain values are re-evaluated each time the file is applied. Command
substitutions run again, and some self-references can change repeatedly.
Removing a variable still requires a new session.
Closes#3999Closes#4559
Warn when session-variable definitions may change if applied more than
once. Apply the check to home and Zsh session variables without changing
their generated output.
Detect direct references after caller-specific rendering while excluding
stable whole-value expansions. Attribute each warning to the surviving
per-attribute definitions, including their module priorities and wrappers.
This gives users advance notice before later work allows the session
configuration to be applied in new shells. Recommend search-variable
options for path-like values and complete assignments for other values.
Tests cover detector boundaries, Zsh escaping, source attribution, and
both module call sites.
Build TERMINFO_DIRS from home.sessionSearchVariables and
home.sessionSearchVariablesAppend instead of a self-referential
home.sessionVariables value.
On the first merge, place Home Manager's directory first and the
system fallback last. Later merges preserve configured entries already
present in TERMINFO_DIRS. Do not add duplicate configured entries.
Add targets.darwin.terminfo.enable as the explicit opt-out. The prior
home.sessionVariables.TERMINFO_DIRS override now composes with the
module's paths instead of disabling them, so document the new opt-out in
news.
Run zsh test commands with -f because zsh reads .zshenv for -c commands.
This prevents host session markers from bypassing test merges.
Add entries after a PATH-like variable's runtime-inherited value.
`home.sessionSearchVariables` still places entries before that value.
`lib.mkAfter` cannot express this. It orders configured entries relative
to each other, but cannot place an entry after a value inherited at
runtime.
On the first merge in a process tree, configured entries are repositioned
according to prepend or append mode. Later merges preserve existing
positions so intervening environment changes are not reordered. An entry
listed in both options therefore takes append position on the first merge
and retains its inherited position later.
Neither option has an `environment.d` counterpart, so neither reaches
systemd user services. Modules that need that set
`systemd.user.sessionVariables` separately.
Switches `home.sessionPath` and `home.sessionSearchVariables` from
concatenation to the merge helper added in the previous commit. The
first merge preserves configured-first search order while removing
duplicate entries. Later merge blocks preserve inherited positions.
Entries that expand to an empty string are ignored. Statically empty
entries also produce an evaluation warning so an accidental
current-directory entry does not disappear silently.
Fish gets a native merge helper because babelfish rejects the POSIX
helper's quoted pattern removal, and Fish stores names ending in PATH as
lists. Candidate assignments and merge calls are translated together so
references to earlier search variables observe the same values as the
POSIX file. The native helper also preserves newline-bearing values
through Fish command substitutions.
A shared behavioral fixture sources both generated files for first and
later merges. It covers expansion and escaping, cross-variable
references, unset and empty values, duplicates, separator-bearing
entries, empty fields, Fish list shape, helper cleanup, and leading,
embedded, and trailing newlines.
Removes `prependToVar`, which has no consumers left and produced the
self-referential form this replaces. It was public through
`lib.hm.shell`, so the release notes include migration guidance.
Adds a POSIX `__hm_merge` helper and one `mergeSearchVariables`
generator. The generator owns helper setup, prepend and append calls,
marker export, and cleanup so callers cannot misorder those stages.
Nothing consumes it yet; `prependToVar` is untouched.
Adding an entry that is already present never duplicates it. Whether an
already-present entry may be moved depends on where the merge runs:
- First merge in a process tree, detected by
`__HM_SESS_VARS_MERGED` being unset: configured entries take their
configured precedence and existing occurrences are repositioned.
- Any later merge: existing entries keep their position, so re-sourcing
cannot reorder a path a development shell, direnv, or a wrapper put in
front.
The complete generator exports the marker after the last merge, then
removes its helper and scratch variables. The marker is deliberately
separate from `__HM_SESS_VARS_SOURCED`, whose position relative to the
merges is not fixed.
Entries expand in a double-quoted shell context. Raw double quotes
remain shell syntax so quoted command substitutions keep working; `\"`
produces a literal quote.
The helper lives in `session-search-merge.sh` rather than a Nix string.
It contains no interpolation, so keeping it as shell source avoids three
layers of escaping and lets shellcheck read it.
Removal is join-based rather than token-splitting. Splitting on the
separator is not idempotent for entries that contain the separator:
merging `a:b` into `x:a:b:y` would grow on every source.
Verified in bash, dash, and zsh across substring entries and globs.
Coverage also includes separator-bearing values, marker transitions,
prepend and append ordering, cleanup, and repeated sourcing.
`XDG_CONFIG_DIRS` and `XDG_DATA_DIRS` were self-referential
`home.sessionVariables` values. Declare the shell side through
`home.sessionSearchVariables`, which expands to the same search path.
Order the module entries after existing plain search-variable
contributions. This preserves the previous user, module, then inherited
lookup order. `systemd.user.sessionVariables` is unchanged, so the
`environment.d` output is byte-identical.
Add a news entry covering these two names and `NIX_PATH`. A user value
set through `home.sessionVariables` now becomes the trailing value
instead of colliding with the module definition. The entry also
documents list merging, `lib.mkForce`, and the separate `environment.d`
behavior.
`nix.nixPath` with `keepOldNixPath` produced a self-referential
`home.sessionVariables.NIX_PATH`. Declare it through
`home.sessionSearchVariables` instead. The generated value keeps the
same search path without depending on the variable it defines.
Order the module entries with `lib.mkAfter` so existing plain
`home.sessionSearchVariables.NIX_PATH` entries retain their precedence.
Read inherited search-variable values through `${VAR-}` so generated
files remain safe when sourced under `set -u`.
Preserve ordinary unset, empty, and inherited values. Add runtime
coverage and update the affected search-variable expectations.
nixpkgs#558216 switched the worktrunk package to the installAgentSkills
hook, moving the bundled skills from $out/skills/ to
$out/share/skills/worktrunk/.
Assisted-by: Claude-Code:GLM-5.3
Co-authored-by: Austin Horstman <khaneliman12@gmail.com>
Add programs.astroid.settings for native JSON configuration and
generate the configuration file from it.
The extraConfig and externalEditor options become deprecated aliases
into settings. Home Manager no longer writes its bundled template;
Astroid's built-in defaults match it except editor.markdown_processor.
Astroid accounts still supply account settings, the notmuch path, and
the GPG path as per-key defaults. Empty settings write no file.
externalEditor now merges at ordinary priority instead of replacing
the editor keys, and priorities on extraConfig sections apply to the
section as a unit. The release notes describe both changes.
Add programs.notmuch.settings for native INI configuration with list
values, and generate the configuration file from it.
The new.ignore, new.tags, maildir.synchronizeFlags, search.excludeTags,
and extraConfig options become deprecated aliases into settings.
Settings carry no static defaults: new.tags, new.ignore, and
maildir.synchronize_flags fall back to notmuch's identical defaults.
State versions before 26.11 keep search.exclude_tags = deleted;spam and
write database.path even without email accounts. Enabled email
accounts supply database.path, and notmuch-enabled accounts the user
identity. Null values and empty sections are omitted so a derived
value can be removed.
extraConfig no longer overwrites modeled values unconditionally: forced
definitions win and ordinary collisions fail. The release notes
describe the migration.
Mbsync, lieer, and mujmap now write settings.new.ignore directly, so
they do not trigger deprecation warnings.
Add programs.borgmatic.backups.<name>.settings for native borgmatic
YAML and generate each backup file from it.
The location, storage, retention, and consistency options and the
section extraConfig options become deprecated aliases into settings.
Warnings name the affected backup. Legacy configurations without
overlapping keys produce the same YAML, and Home Manager symlink
exclusions still append to exclude_from.
Drop the assertions that rejected backups setting both or neither of
sourceDirectories and patterns, so native source patterns and
database-only backups work.
Consistency checks without a frequency were written as
`frequency: null`, which borgmatic rejects during configuration
validation. Omit null check fields so borgmatic applies its own
default.
The user-service drop-in invoked activate without a driver version, so
the script defaulted to driver 0 and always managed the per-user
home-manager profile, ignoring enableLegacyProfileManagement. Use the
same version as the system service and assert both generated
user-service commands.
pwd-file was typed as a path, but ExecStart renders settings through
lib.cli.toCommandLine, whose default value formatter has no case for
paths, so a path literal such as ./mpd-password aborted evaluation with
"generators.mkValueStringDefault: this value is not supported".
Accept a string or a path, and render path-like values with toString,
which gives a path literal's location without copying the file into the
Nix store. Strings and derivations render as before. Add a test for a
path literal.
The network, host, and port migrations from services.mpd-mpris.mpd to
services.mpd-mpris.settings share the same prefixes and option names,
so lib.hm.deprecations.mkSettingsRenamedOptionModules expresses them
without repeating each option path. It expands to the same
mkRenamedOptionModule calls.
Add a test that sets the old options and checks the rename warnings and
the generated unit, which no existing test covered.
Fixes#8000
The `mpd-mpris` module used different names for the options than
`mpd-mpris` itself, causing some confusion.
Additionally, this makes some more improvements in the module, largely
based on the upstream module [^1], which includes:
- Removing the `services.mpd-mpris.mpd` namespace, it did not serve any
purpose. This also got rid of the `services.mpd-mpris.mpd.useLocal`
option, just don't configure `host` to connect to the local instance.
- Removing the `password` option, it should have never gotten into this
module because it will write the password to the world readable nix
store. A new `password-file` option was added to replace it.
- Moving the settings to a new freeform submodule under the key
`services.mpd-mpris.settings`.
- Replacing the `renderCmd` function with a use of `lib.cli.toCommandLine`.
While I diverged quite a bit from the upstream module, much credit for
these changes goes to @natsukagami!
[^1] 90c4264e58/nix/module.nix
Forward converted values to the complete settings path so the standard
changed-option warning identifies the destination key. Preserve legacy
reads, priorities, defaults, and shadowed conversions.
Point mpdris2 at Library.music_dir directly and cover nested paths,
literal dotted keys, and the affected callers in warning tests. The
contributor guidelines now describe `to` as the settings path that
contains `key` instead of the settings root.
Fixes an issue introduced in [1] where gtk4 apps would print the
following warning:
> Error setting gtk-interface-color-scheme in
> /home/mithic/.config/gtk-4.0/settings.ini: Key file contains key
> “gtk-interface-color-scheme” which has a value that cannot be
> interpreted.
The value should be set to the nickname ("light" or "dark" in this
case), rather than the actual numerical value of the enum. This lookup
happens at [2].
These nicknames appear to be undocumented and automatically generated at
compile time, but in general they appear to follow the pattern where an
enum value FOO_BAR_BAZ_QUUX of the enum FOO_BAR has nickname "baz-quux".
Regardless, they can be looked up in the generated file
gtktypebuiltins.c (it unfortunately appears that nix only keeps
gtktypebuiltins.h, which does not contain the nicknames).
[1] https://github.com/nix-community/home-manager/pull/7763
[2] https://gitlab.gnome.org/GNOME/gtk/-/blob/4.22.4/gtk/gtksettings.c#L1863
Allow native POP3 retrievers without an IMAP mailbox list. Preserve
explicit mailbox defaults and cover the omitted setting in the account
configuration test.
Expose native filter, retriever, and destination configuration while
retaining account defaults and legacy boolean aliases. Preserve tuple
rendering and allow complete native retriever configuration without an
IMAP account block.
Generate managed JSON from canonical settings while preserving legacy editor and sync conversions. Use the shared overlay helper for extraConfig priorities and effective-key detection.
Keep activation-time merging into the writable application file, including unmanaged settings and historical null and empty-string filtering.
Adds programs.yopass for managing the yopass CLI configuration file
(~/.config/yopass/defaults.yml), with an NMT test verifying the
generated settings.
Assisted-by: Claude Fable 5
Expose cover matching and notification settings without duplicating the
upstream schema. Preserve legacy options and MPD integration through
per-key migration helpers and retain path-valued music directories.
Generate grobi.conf from unrestricted JSON settings so root fields such as on_failure and nested rule values are configurable.
Migrate rules and executeAfter through the ordered settings rename helper, retaining historical empty defaults, alias reads, priorities, and list ordering.
Leave native defaults to Rofi instead of injecting location and offset
values. Preserve explicit legacy settings and theme selection, and omit
configuration files when no effective settings or theme are supplied.
Generate the Rasi configuration block from merged native settings. Preserve legacy option conversions, overlay precedence, numeric defaults, and theme ordering.
Use the shared settings overlay helper for extraConfig forwarding and key detection. Keep package integration and the existing serializer unchanged.
The old cloud-only mappings cannot express root-level cache and client
settings. Expose complete YAML documents while preserving existing
configurations through standard rename aliases.
With `waitForNixStore = false` an agent is started through a launcher
script so that macOS lists it under its own name in System Settings >
Login Items & Extensions. Two properties of that launcher were fixed and
unreachable from configuration: its base name (the agent's attribute name)
and its interpreter (`/bin/sh`).
Both matter on macOS. The name is what "Allow in the Background" shows, so
a fleet-wide prefix such as `nix-` makes every Home Manager agent
recognisable next to third-party items. The interpreter is the binary the
system attributes the agent's process to; a store-resident shell attributes
it to the launcher itself rather than to Apple's `/bin/sh`, which changes
how the privacy prompts for folders like `~/Downloads` apply. Users who
need either property today have to vendor this module.
`launcher.name` (default: the attribute name, as before) and
`launcher.shell` (default: `/bin/sh`, as before) make both configurable
without changing any existing agent.
Share raw overlay forwarding and effective-key detection for default-empty
legacy options. Keep application defaults and conversions in consumers.
Delegate aliases and diagnostics to doRename without rewrapping prepared
priorities. Cover ordering, composition, empty values, and source filenames
in the existing evaluations.
Add opt-in ordered forwarding to the settings rename helper so legacy and canonical list definitions retain priorities and mkBefore/mkAfter ordering.
Keep the default helper path unchanged and cover evaluation in module scopes without a warnings option.
Build on the existing programs.worktrunk module:
- add bash/zsh/fish/nushell shell integrations, enabled by default via
the corresponding home.shell.enable<SHELL>Integration options,
- add an opt-in programs.worktrunk.claudeCodeIntegration, which wires
worktrunk into programs.claude-code: a statusLine, WorktreeCreate/
WorktreeRemove hooks (so agent isolation routes through wt), activity
state-marker hooks (🤖/💬 in wt list), and skills. Of the skills,
/wt-switch-create is on by default while /worktrunk is off by default,
since settings already manages the config it would help edit.
Both integrations need the wt binary, so they are inert when package is
set to null.
Follow-up to #9226, recreating the integration part of #9788.
Assisted-by: Claude-Code:GLM-5.3