let
  sources = import ./npins;

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

  patch = import sources.nix-patches { patchFile = ./patches; };

  nodes' = import ./meta/nodes.nix;
  nodes = builtins.attrNames nodes';

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

  mkNixpkgs =
    node:
    patch.mkNixpkgsSrc rec {
      src = sources.${version};
      version = "nixos-${nodes'.${node}.nixpkgs or (import ./meta/nixpkgs.nix)}";
    };

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

  ###
  # Function to create arguments based on the node
  #
  mkArgs = node: rec {
    lib = import sources.nix-lib {
      inherit (mkNixpkgs' node) lib;

      keysRoot = ./keys;
    };

    meta = (import ./meta) lib;
  };
in
# nodes = builtins.attrNames metadata.nodes;
{
  meta = {
    nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes;

    specialArgs = {
      inherit sources;
    };

    nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes;
  };

  defaults =
    { meta, name, ... }:
    {
      # Import the default modules
      imports = [ ./modules ];

      # Include default secrets
      age-secrets.sources = [ (./machines + "/${name}/secrets") ];

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

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

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

      # Use the stateVersion declared in the metadata
      system = {
        inherit (meta.nodes.${name}) stateVersion;
      };
    };
}
// (lib.mapSingleFuse mkNode nodes)