Skip to content

Add second enabling mode #2362

Description

@trueNAHO

This issue was converted from discussion #2112 with the following messages:

  • On Sun Dec 28, 2025 at 6:18 PM CET, @danth wrote:

    Methods could include things like:

    • Code patches
    • Runtime/asset patches
      • Change data loaded by the application at runtime.
      • Not supported by upstream developers.
      • Examples: GTK, Discord, Firefox GNOME Theme
    • Configuration files
      • Set the theme using provided functionality.
      • Supported by upstream developers.
      • Examples: Rofi, VSCode, various shells
    • Manual setup
      • Requires additional effort from the end user to get working: maybe changing their Nix code, or clicking a theme in a menu.
      • Examples: i3 bars, Blender

    Having this metadata would allow users to select modules that fit their criteria, without turning off autoEnable entirely.

    For example, some users would like to disable code patches because they don't have the resources to compile things locally. Some might want to use only officially supported methods, because these have the least chance to break things.

  • On Mon Jan 5, 2026 at 2:22 AM CET, @trueNAHO wrote:

    Add metadata about implementation methods

    Methods could include things like:

    After pondering again on how to generally implement the "second enabling mode" in Home Manager that has been discussed in-depth for the vivid module in bug: vivid: home.sessionVariables and yaml vs scientific notation home-manager#7994, vivid: replace theme content from yaml with json home-manager#7996, and vivid: init #1938, I came up with an upstream solution that coincidentally also reliably solves all modules are enabled by default, and they don't just style my configuration #543.

    Since the conclusion is very related to this proposal, let me elaborate.

    Essentially, all modules are enabled by default, and they don't just style my configuration #543 boils down to upstream inconsistently guarding config with something like config = lib.mkIf cfg.enable. Understandably, since Home Manager currently has over 500 modules, it is easy to eventually miss this during review.

    Fortunately, Stylix happens to generally solve this with its custom module system (/stylix/mk-target.nix) by automatically wrapping modules with lib.mkIf (config.stylix.enable && cfg.enable). Although the custom module system arguably increases code complexity with a small DSL, its indisputable benefit for Stylix is the automatic safeguarding of individual declarations based on options external to the specific module, which would be nearly impossible to consistently and correctly implement manually.

    Considering the sheer amount of Home Manager modules, even Home Manager would benefit from a simple custom module system that merely wraps modules with config = lib.mkIf cfg.enable, thus reliably solving all modules are enabled by default, and they don't just style my configuration #543.

    Extending and generalizing all modules are enabled by default, and they don't just style my configuration #543 and the "second enabling mode" implies the need to distinguish between installing binaries and everything else. Based on the previously mentioned vivid discussions, it is also beneficial to treat environment variable declarations specially. Based on vicinae: move from programs to services home-manager#8313 (comment), it is also beneficial to treat programs and services differently due to performance and security. This would lead to the following feature set (with names subject to change), where services implies arbitrary run time execution, and everything not handled by any previously explained feature falls under etc: packages, files, variables, services, and etc. This could be translated into the following custom module system interface, where features can be globally toggled with a features.${feature}.enable (namespace and name subject to change) option:

    {
      config = {
        packages = /* ... */;
        files = /* ... */;
        variables = /* ... */;
        services = /* ... */;
        etc = /* ... */;
      };
    }

    For reference and context, features.packages corresponds to Home Manager's current home.packages option, files to home.files (and its implicit dependants, like xdg.cacheFile and xdg.configFile), variables to home.sessionVariables, services to something like services or home.activation, and etc to everything previously unmatched.

    Specifically, all modules are enabled by default, and they don't just style my configuration #543 implicitly requests not enabling features.packages.enable, while the "second enabling mode" for the vivid module would be solved by only enabling the programs.vivid.features.variables.enable feature. Beyond that, Stylix would generally benefit from not enabling features.packages.enable.

    Some time during the review cycle of stylix/mk-target: polish, simplify, and extend interface #1721, I rewrote my NixOS configuration to leverage a custom and highly ergonomic module system that has more features than the Stylix module system and has an astonishingly simple, although very involved, implementation. Before upstreaming my work and findings to Stylix and Home Manager, I would like to experiment whether it is possible to refactor the core logic of my custom module system into a library to share between my NixOS and Home Manager repositories. If this ends up being impossible, it might be safe to assume that custom module systems are always project-specific and need to be implemented from scratch every time. For reference, I will probably only have time to look into this in at least a month.


    Based on the previously proposed Home Manager feature set (packages, files, variables, services, and etc), this proposal could map to that feature set and extend it. Maybe somewhere like stylix.features.${feature}.enable?

    Specifying module feature sets inside /modules/<MODULE>/meta.nix is too vague because /modules/<MODULE>/nixos.nix and /modules/<MODULE>/hm.nix may have different feature sets, meaning it should be defined in /modules/<MODULE>/<PLATFORM>.nix.

    For clarity, the stylix.features.${feature}.enable Stylix feature set can already be implemented by extending the existing Stylix module system without waiting on my module system refactor exploration or the proposed features.${feature}.enable Home Manager implementation.

    Would this not correspond to a stylix.features.overlays.enable feature? Following commits eb19696 ("stylix: add overlay module (stylix: add overlay module #1048)") and 581fa67 ("stylix: guard entire overlay declarations (stylix: ensure overlays aren't set when disabled #1088)"), would this not be a stylix.overlays.enable alias? Note that mapping to platform-specific Stylix options likely requires resolving stylix: Make platform-specific options available on all platforms (no-op on unsupported systems) #2078.

    • Runtime/asset patches
      • Change data loaded by the application at runtime.
      • Not supported by upstream developers.
      • Examples: GTK, Discord, Firefox GNOME Theme

    What about calling this feature something like stylix.features.extensions.enable?

    • Configuration files
      • Set the theme using provided functionality.
      • Supported by upstream developers.
      • Examples: Rofi, VSCode, various shells

    I suppose this corresponds to the previously proposed Home Manager feature set and would merely re-expose it under stylix.features.${feature}.enable.

    • Manual setup
      • Requires additional effort from the end user to get working: maybe changing their Nix code, or clicking a theme in a menu.
      • Examples: i3 bars, Blender

    What about calling this feature something like stylix.features.manual.enable?

    Having this metadata would allow users to select modules that fit their criteria, without turning off autoEnable entirely.

    For example, some users would like to disable code patches because they don't have the resources to compile things locally. Some might want to use only officially supported methods, because these have the least chance to break things.

    This proposal is great! Should we elevate this discussion to an issue?

    On a side note, I am using a "feature" concept in my NixOS configuration for flat (no DAG or tree compositions) module composition where host configurations may contain the following:

    # The 'os' namespace is my NixOS namespace, analogous to the 'stylix' namespace.
    os.features = {
      base.enable = true;
      server.enable = true;
    };
  • On Tue Jun 2, 2026 at 6:52 PM CEST, @0xda157 wrote:

    Based on the previously proposed Home Manager feature set (packages, files, variables, services, and etc), this proposal could map to that feature set and extend it. Maybe somewhere like stylix.features.${feature}.enable?

    I would prefer instead changing the type of autoEnable to a list of enum. Keeping the autoEnable option as a boolean doesn't really make much more sense in this case, and would seemingly conflict with stylix.features.*.enable under your proposal.

    Should we elevate this discussion to an issue?

    I think we should.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions