<nixpkgs/nixos> is an expert system database

This isn’t a question, or answer, or announcement, just a public note that should actually be a blog post.

I’ve been always looking at NixOS modules codebase and it made me worry - “I see some pattern here, but I don’t understand which one”. But now I understand: NixOS modules is one of the largest world expert systems, with knowledge acquired from dozens of sysadmins and devops. How come?

Expert system

Expert system is a database of rules, made in IF…THEN… format. Then, given a set of “facts”, inference engine uses that database or rules to make some conclusions. What distinguish expert system from algorithm, is that rules are separated from each other, and rules are evaluated in a way to minimize infinite recursion problems.

In NixOS module system we specify facts by making option declarations in configuration.nix:

networking.hostname = "my-computer";

Now networking.hostname is a fact. configuration.nix is user-supplied fact database.

In NixOS module system, we have if and mkIf, which allow us to specify rules which operate on facts. In expert system the condition in mkIf is called LHS (left-hand side) and return value is called RHS (right-hand side). RHS in NixOS’s mkIf can add new facts:

systemd.services.my-service = mkIf config.services.my-service.enable {
   after = [ "network-setup.target" ];

Here systemd.services.my-service.after fact can be added to fact database after mkIf config.services.my-service.enable rule fired. Note that there are 1000+ mkIf calls in NixOS modules codebase, this corresponds to 1000+ rules defined.

On the differences with expert system, NixOS has conflict resolution strategy on fact level, not rule level. NixOS module system also have facts merge semantics. If two modules specify networking.nameservers = [ "" ]; and networking.nameservers = [ "" ];, this won’t make conflicts. Resolution would be combined list of strings. By using mkOrder, mkForce, mkDefault, mkOverride and other we set conflict strategy for facts. When all fact conflicts are resolved, module system fires all possible rules, to generate all possible facts. That is also an insight why it is impossible to remove facts in NixOS rule RHS.

So next time you do nixos-rebuild switch, recall that you’re evaluating expert system, one of the successful applications of AI to real-world domain.


Very interesting!

Now that we know that NixOS can be seen as an expert system, what can NixOS learn from other expert systems?


Now that we know that NixOS can be seen as an expert system, what can NixOS learn from other expert systems?

Not that NixOS can learn, but existence of Module System, and it’s practical application (NixOS) should drive researchers. I’m quite surprised that Nix maternity company, given it’s background in Datalog, doesn’t sponsor research for NixOS (or doesn’t do it in public). Probably there still isn’t enough critical mass.

I see there are efforts to push Nix into HPC (and LHC) world. Also, I believe NixOS (or it’s variant) will get some certifications in future, which will allow it to become most wanted distribution for scientific machines (that would require lots of breaking refactors for NixOS though).


I feel like a lot of the specific points mentioned are arbitrary (such as “Expert system is a database of rules, made in IF…THEN… format.”), but there is something important in the basic idea here.

When looking at some PRs and wondering if the addition of a server as a package should also have an associated NixOS module, I began to think of the cost-benefits. Just for discussion:

Sometimes a dedicated service module allows the Nix community to encode expert knowledge. For example, nginx has some settings like recommendedGzipSettings and enableACME. Other modules have the most common default use case ready to go.

Then there is the other style, where the module does little more than thread some options through, where it might be simpler to just have the writer accomplish their task by writing a systemd.services.<name> expression. In this case, the module is still helpful to prioritize common settings and discovery. If someone has decided that a setting should be expressed and not in the extraConfig bucket, it probably means I should learn it. Or looking at the structure of the configuration file can describe how some software should be normally used. Seeing the options in NixOS Search - Loading... is great for discovery.

Something missing is a way to tell how good a particular section is. To know how recent it is, or how many users, how many eyeballs on that part of the system. Perhaps we add a marker or indication in the results that indicate how many different contributors committed to the “Declared in”, section and how long ago. This would also provide easy discovery of what sections of the system need work. I’m not necessarily convinced this is a good idea, but it’s a thought.

1 Like

I don’t think the number of contributors or age is a good indicator for the quality of a module.

The user can see if one can achieve what one wants to do. If not, create an issue on GitHub and someone might improve it or tell them how to do it. We might want to document unclear cases. So we can put more expert knowledge into our system.

My intuition is that there are different levels of integrations for the services.* subtree. In my mental model, the scale goes roughly like this:

  1. Trivial
    Only an “enable” option, possibly a “configFile” option if applicable, otherwise rely on whatever is in /etc/xxx/config)
  2. Minimal
    Some basic options, at least one of extraConfig, or configFile)
  3. Mixed
    Several config options covering “most” use cases, the remaining in extraConfig
  4. Complete
    The service can be fully configured in Nix options, without relying on an extraConfig argument, think bluethooth)
  5. Advanced
    The service is fully configurable in nix, and options are type-checked, and tested with config testers. Currently bluetooth does not prevent the insertion of mis-typed keys. Think knot-config-checked where the check is done with the right version of the package as configured in nixos.

Note that all of these support levels are valid. It just describes how tightly the service is integrated in nixos config system. Often, two styles can coexist. At the moment, bluetooth still supports extraConfig, even if is deprecated.

Beyond that, a usage count would be really interesting, just as it would be for nixpkgs packages, but that seems more difficult to achieve.

Hosted by Flying Circus.