{
  inputs ? import ./inputs.nix {},
  selfPath ? ./.
}:

let

lib = (import "${inputs.nixpkgs}/lib").extend (import ./lib/overlays/version-info-fixup.nix { inherit inputs; });

self = {
  inherit inputs lib self;
  __toString = _: selfPath;
  modifiedNixpkgs     = import ./pkgs/top-level/impure.nix;
  modifiedNixpkgsPure = import ./pkgs/top-level/default.nix;
  overlays = {
    selfExpr = import ./pkgs/overlays/selfExpr.nix { nixpkgsPath = inputs.nixpkgs; };
    unstable = import ./pkgs/overlays/unstable.nix;
    versionInfoFixup = import ./pkgs/overlays/version-info-fixup.nix { inherit inputs; };
  };
  nixosConfigurations = let
    # list nix file paths in ./hosts to attributes in nixosConfigurations
    filePaths = lib.pipe ./hosts [
      builtins.readDir
      ( lib.filterAttrs (name: type:
        ( # regular .nix files
          (type == "regular" && lib.hasSuffix ".nix" name)
          || # directories that contain a default.nix file
          (type == "directory" && builtins.pathExists "${./hosts}/${name}/default.nix")
        )
        # filter out files that start with .
        && !lib.hasPrefix "." name
      ))
    ];
    nixosSystem = import "${inputs.nixpkgs}/nixos/lib/eval-config.nix";
  in
    # mapped list of nix file paths to attrSet with initialized NixOS configurations,
    # whose names are derived from file names
    lib.pipe filePaths [
      (builtins.mapAttrs (name: type: {
        name = if type == "directory" then name else builtins.substring 0 (builtins.stringLength name - 4) name;
        value = nixosSystem {
          inherit lib;
          modules = [
            ./hosts/${name}
            {
              config.nixpkgs.overlays = [
                ( import ./pkgs/overlays/selfExpr.nix { nixpkgsPath = "${self}/pkgs/top-level/impure.nix"; } )
                ( import ./pkgs/top-level/by-name-overlay.nix "${self}/pkgs/by-name" )
                self.overlays.versionInfoFixup
              ];
            }
          ];
          specialArgs = { inherit self inputs; };
        };
      }))
      builtins.attrValues
      builtins.listToAttrs
    ];
};

in self