1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{
  description = "Profpatsch's personal utilities and projects";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    vuizvui.url = "github:openlab-aux/vuizvui";
    vuizvui.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils, vuizvui }:
  let
    # Shared x86_64-linux depot evaluation, reused by both packages and nixosConfigurations
    x86 = "x86_64-linux";
    # The depot is built against this flake's `nixpkgs` input, so that the
    # whole repository evaluates exactly one nixpkgs.
    depotX86 = import ./. { localSystem = x86; nixpkgsSrc = nixpkgs; };
    homeRepo = depotX86.users.Profpatsch;

    nixosMachines =
      let
        unfreeAndNonDistributablePkgs = import nixpkgs {
          system = x86;
          config.allowUnfree = true;
          overlays = [ vuizvui.overlay ];
        };
        binify = depotX86.nix.binify;
        depot = depotX86;
        mkMachine = path: nixpkgs.lib.nixosSystem {
          system = x86;
          specialArgs = { inherit homeRepo unfreeAndNonDistributablePkgs binify depot; };
          modules = [
            { nixpkgs.overlays = [ vuizvui.overlay ]; }
            path
          ];
        };
      in {
        rolery = mkMachine ./machines/profpatsch/rolery.nix;
        haku   = mkMachine ./machines/profpatsch/haku.nix;
        legosi = mkMachine ./machines/profpatsch/legosi.nix;
        leguin = mkMachine ./machines/profpatsch/leguin.nix;
      };
  in
  {
    nixosConfigurations = nixosMachines;
  } //
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        # Configure nixpkgs-unstable to allow unfree packages
        pkgs-unstable = import nixpkgs-unstable {
          inherit system;
          config = {
            allowUnfreePredicate = pkg: builtins.elem (nixpkgs.lib.getName pkg) [
              "claude-code"
            ];
          };
        };
        depot = if system == x86 then depotX86 else import ./. { localSystem = system; nixpkgsSrc = nixpkgs; };
        profpatsch = depot.users.Profpatsch;
      in
      {
        # Packages are listed explicitly rather than derived from the package
        # tree. Deriving them (e.g. `lib.filterAttrs (_: lib.isDerivation)`)
        # forces *every* package in order to test the predicate, and the
        # `buildGo.external` packages perform import-from-derivation (see
        # //nix/buildGo/external, which builds a `-structure.json` and reads it
        # at evaluation time). `nix flake show` and friends evaluate with
        # `allow-import-from-derivation` disabled, so the whole package set
        # then fails to evaluate there. Naming them here keeps evaluation lazy.
        packages = {
          default = profpatsch.git-blimey;
          git-blimey = profpatsch.git-blimey;
          git-branchey = profpatsch.git-branchey;
          timetrack = profpatsch.timetrack;
          agent-last-position = profpatsch.agent-last-position;
          alloy-viz = profpatsch.alloy-viz;
          claude-usage = profpatsch.claude-usage;
          pty-prompt = profpatsch.pty-prompt;
          varlink-mcp-bridge = profpatsch.varlink-mcp-bridge;
          varlink-http-proxy = profpatsch.varlink-http-proxy;
          maildir-varlink = profpatsch.maildir-varlink;
          capability-token-service = profpatsch.capability-token-service;
          alacritty-change-color-scheme = profpatsch.alacritty-change-color-scheme;
          display-brightness-control = profpatsch.display-brightness-control;
          sqlite-apps = profpatsch.sqlite-apps;
          pw-sesh = profpatsch.pw-sesh;
          mailweb = profpatsch.mailweb;
          notenlesen = profpatsch.notenlesen;
          inventory = profpatsch.inventory;
          firefox-profiler = profpatsch.firefox-profiler;
          modular-flyer = profpatsch.modular-flyer;
          source-forge = profpatsch.source-forge;
          webchat = profpatsch.webchat;
          blocks = profpatsch.blocks;
          mastodon-alt-text = profpatsch.mastodon-alt-text;
          fedisearch-spike = profpatsch.fedisearch.spike;
          my-llm = pkgs-unstable.llm.withPlugins {
			llm-deepseek = true;
			llm-gemini = true;
          };
          claude = pkgs-unstable.claude-code;
          yt-dlp = pkgs-unstable.yt-dlp;
          gitu = pkgs-unstable.gitu;
        };

        apps = {
          alacritty-change-color-scheme = {
            type = "app";
            program = "${profpatsch.alacritty-change-color-scheme}/bin/alacritty-change-color-scheme";
          };
          git-blimey = {
            type = "app";
            program = "${profpatsch.git-blimey}/bin/git-blimey";
          };
          git-branchey = {
            type = "app";
            program = "${profpatsch.git-branchey}/bin/git-branchey";
          };
          timetrack = {
            type = "app";
            program = "${profpatsch.timetrack}/bin/timetrack";
          };
          agent-last-position = {
            type = "app";
            program = "${profpatsch.agent-last-position}/bin/agent-last-position";
          };
          alloy-viz = {
            type = "app";
            program = "${profpatsch.alloy-viz}/bin/alloy-viz";
          };
          claude-usage = {
            type = "app";
            program = "${profpatsch.claude-usage}/bin/claude-usage";
          };
          varlink-mcp-bridge = {
            type = "app";
            program = "${profpatsch.varlink-mcp-bridge}/bin/varlink-mcp-bridge";
          };
          varlink-http-proxy = {
            type = "app";
            program = "${profpatsch.varlink-http-proxy}/bin/varlink-http-proxy";
          };
        };

        # `nix flake check` runs these. NixOS VM tests boot a real machine under
        # qemu, so they only exist on Linux; on other systems the attribute set
        # is simply empty rather than an eval error.
        checks = nixpkgs.lib.optionalAttrs (nixpkgs.lib.hasSuffix "-linux" system) {
          # Covers hosty's system mode end to end: attaching a portable service,
          # the sandbox actually applying (DynamicUser, not root), the FUSE mount
          # being writable from inside it, app state surviving a stop/start cycle,
          # and teardown leaving no attached units or stray mounts behind.
          hosty-system = import ./users/Profpatsch/hosty/system-test.nix {
            inherit depot pkgs;
          };
        };

        # Both args are passed explicitly, because shell.nix otherwise falls
        # back to `import ./. { }`, which needs `builtins.currentSystem` and
        # thus breaks under the pure evaluation of `nix flake check`.
        # `pkgs` must be the depot nixpkgs (not the plain flake input), so the
        # devShell gets the depot overlays and matches `nix-shell`.
        devShells.default = import ./shell.nix {
          inherit depot;
          pkgs = depot.third_party.nixpkgs;
        };
      }
    );
}