let
  sources = import ./npins;
  metadata = import ./meta;

  lib = import (sources.nix-lib + "/src/trivial.nix");

  mkNode = node: { name, nodes, ... }: {
    # Import the base configuration for each node
    imports = builtins.map (lib.mkRel ./machines/${node}) [
      "_configuration.nix"
      "_hardware-configuration.nix"
    ];

    # Include default secrets
    dgn-secrets.sources = [ ./machines/${node}/secrets ];

    # Deployment config is specified in meta.nodes.${node}.deployment
    inherit (metadata.nodes.${node}) deployment;

    # Set NIX_PATH to the patched version of nixpkgs
    nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ];

    # Allow unfree packages
    nixpkgs.config.allowUnfree = true;

    # Use the stateVersion declared in the metadata
    system = { inherit (metadata.nodes.${node}) stateVersion; };
  };

  mkNixpkgs = node:
    let
      version = "nixos-${metadata.nodes.${node}.nixpkgs}";
      pkgs = import sources.${version} { };
    in pkgs.applyPatches {
      name = "${version}-patched";
      src = sources.${version};
      patches = (import sources.nix-patches {
        inherit pkgs;
        patchFile = ./patches;
      }).mkPatches version;
    };

  mkNixpkgs' = node: import (mkNixpkgs node) { };

  mkArgs = node: {
    dgn-lib = import sources.nix-lib { inherit ((mkNixpkgs' node)) lib; keysRoot = ./keys; metaRoot = ./meta; };
  };

  nodes = builtins.attrNames metadata.nodes;
in

{
  meta = {
    nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes;

    specialArgs = { inherit sources; meta = metadata; };

    nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes;
  };

  defaults = { ... }: {
    # Import the default modules
    imports = [ ./modules ];
  };
} // (lib.mapSingleFuse mkNode nodes)