{
  description = "Minne application flake";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    crane.url = "github:ipetkov/crane";
    fenix.url = "github:nix-community/fenix";
    fenix.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = {
    self,
    nixpkgs,
    flake-utils,
    crane,
    fenix,
  }: let
    inherit (nixpkgs.legacyPackages.x86_64-linux) lib;
    ortVersion = "1.23.2";
  in
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};
      lib = pkgs.lib;
      craneLib = crane.mkLib pkgs;
      libExt =
        if pkgs.stdenv.isDarwin
        then "dylib"
        else "so";
      minneVersion = "1.0.4";
      mozjsRelease = "mozjs-sys-v140.10.1-0";

      mozjsTarget =
        {
          "x86_64-linux" = "x86_64-unknown-linux-gnu";
          "aarch64-linux" = "aarch64-unknown-linux-gnu";
          "aarch64-darwin" = "aarch64-apple-darwin";
          "x86_64-darwin" = "x86_64-apple-darwin";
        }
        .${system}
        or (throw "mozjs prebuilt archive not configured for system ${system}");

      mozjsHashes = {
        "x86_64-unknown-linux-gnu" = "sha256-e5kW8HTg6Hrd3sGgU9bqFNTTf7wJCChFOwKE3xyYT4Q=";
        "aarch64-unknown-linux-gnu" = "sha256-VXrcktvjSH+14tO9Kzx+n9f/9ZQGAzfEsniiT+xKT6Q=";
        "aarch64-apple-darwin" = "sha256-T3y73nVic6R60keUpmVRFe110Eh7AcE/VwZQWXRU9A0=";
        "x86_64-apple-darwin" = "sha256-4v6f6c1OwYdg1FKnFfdLEsrRdyghcxup4gF7ioTZzm4=";
      };

      # Pre-download mozjs binary archive for mozjs_sys (servo dep).
      # When updating mozjs_sys version in Cargo.lock, update mozjsRelease + hashes.
      mozjsArchive = pkgs.fetchurl {
        url = "https://github.com/servo/mozjs/releases/download/${mozjsRelease}/libmozjs-${mozjsTarget}.tar.gz";
        hash = mozjsHashes.${mozjsTarget} or (throw "missing mozjs hash for ${mozjsTarget}");
      };

      # Extra paths (common/db, html-router/templates, html-router/assets) are
      # embedded at compile time via include_dir! / minijinja_embed.
      commonArgs = {
        version = minneVersion;
        src = lib.cleanSourceWith {
          src = ./.;
          filter = path: type:
            craneLib.filterCargoSources path type
            || lib.any (x: lib.hasPrefix (toString x) (toString path)) [
              (toString ./Cargo.lock)
              (toString ./common/db)
              (toString ./html-router/templates)
              (toString ./html-router/assets)
            ];
        };
        strictDeps = true;

        buildInputs = [
          pkgs.openssl
          pkgs.libglvnd
          pkgs.onnxruntime
          pkgs.fontconfig # .pc for yeslogic-fontconfig-sys (servo dep)
          pkgs.libclang.lib # libclang.so for bindgen (servo dep)
        ];

        nativeBuildInputs = [
          pkgs.pkg-config
          pkgs.rustfmt
          pkgs.makeWrapper
          pkgs.python3 # needed by servo's stylo crate build.rs
          pkgs.llvmPackages.llvm # llvm-objdump for mozjs_sys (servo dep)
          pkgs.rustPlatform.bindgenHook # configures bindgen (servo deps)
        ];

        # Provide pre-downloaded mozjs archive so it doesn't need network
        MOZJS_ARCHIVE = "${mozjsArchive}";
      };

      # Build *just* the cargo dependencies using a dummy source so that source
      # code changes don't invalidate the cached dependency layer.
      cargoArtifacts = craneLib.buildDepsOnly (commonArgs
        // {
          pname = "minne";
          cargoExtraArgs = "--workspace";
          doCheck = false;
        });

      minne-pkg =
        if pkgs.onnxruntime.version == ortVersion
        then
          craneLib.buildPackage (commonArgs
            // {
              pname = "minne";
              version = minneVersion;
              inherit cargoArtifacts;
              doCheck = false; # checks are in separate derivations
              doInstallCargoArtifacts = true; # for reuse by check derivations

              postInstall =
                lib.optionalString pkgs.stdenv.isLinux ''
                  wrapProgram $out/bin/main \
                    --prefix LD_LIBRARY_PATH : ${pkgs.libglvnd}/lib \
                    --set ORT_DYLIB_PATH ${pkgs.onnxruntime}/lib/libonnxruntime.${libExt}
                  for b in worker server; do
                    if [ -x "$out/bin/$b" ]; then
                      wrapProgram $out/bin/$b \
                        --prefix LD_LIBRARY_PATH : ${pkgs.libglvnd}/lib \
                        --set ORT_DYLIB_PATH ${pkgs.onnxruntime}/lib/libonnxruntime.${libExt}
                    fi
                  done
                ''
                + lib.optionalString pkgs.stdenv.isDarwin ''
                  for b in main worker server; do
                    if [ -x "$out/bin/$b" ]; then
                      wrapProgram $out/bin/$b \
                        --set ORT_DYLIB_PATH ${pkgs.onnxruntime}/lib/libonnxruntime.${libExt}
                    fi
                  done
                '';
            })
        else throw "pkgs.onnxruntime.version (${pkgs.onnxruntime.version}) must match ortVersion in flake.nix (${ortVersion})";

      targetTriple = pkgs.stdenv.hostPlatform.config;

      releaseCommonArgs = {
        inherit minneVersion targetTriple;
        bzip2 = pkgs.bzip2.out;
        brotli = pkgs.brotli.lib;
        srcRoot = ./.;
      };

      minne-release =
        if pkgs.stdenv.isLinux
        then
          pkgs.callPackage ./nix/minne-release.nix (releaseCommonArgs // {
            platform = "linux";
            inherit minne-pkg;
          })
        else if pkgs.stdenv.isDarwin
        then
          pkgs.callPackage ./nix/minne-release.nix (releaseCommonArgs // {
            platform = "darwin";
            inherit minne-pkg;
          })
        else null;

      windowsTarget = "x86_64-pc-windows-msvc";

      windowsRustToolchain =
        if system == "x86_64-linux"
        then
          let
            fenixPkgs = fenix.packages.${system};
          in
          fenixPkgs.combine [
            fenixPkgs.stable.defaultToolchain
            fenixPkgs.targets.${windowsTarget}.stable.rust-std
          ]
        else null;

      windowsCraneLib =
        if system == "x86_64-linux"
        then craneLib.overrideToolchain (_: windowsRustToolchain)
        else craneLib;

      mozjsArchiveWindows = pkgs.fetchurl {
        url = "https://github.com/servo/mozjs/releases/download/${mozjsRelease}/libmozjs-${windowsTarget}.tar.gz";
        hash = "sha256-nEX55a4vZJGxlDMCea9TEee60HiNe/yQzXtUqMlaM3c=";
      };

      ortArchiveWindows = pkgs.fetchurl {
        url = "https://github.com/microsoft/onnxruntime/releases/download/v${ortVersion}/onnxruntime-win-x64-${ortVersion}.zip";
        hash = "sha256-CzjfmvIYNOQec9YC2Q21ywbb0cphiUi48dZtYHrJ880=";
      };

      windowsCross = pkgs.callPackage ./nix/windows-cross.nix {};

      inherit (windowsCross) clangClWrapper xwinCargoCache;

      # blake3's build.rs only enables MSVC asm when CC_x86_64_pc_windows_msvc is exactly
      # "cl" or "cl.exe" (not a store path). Route through the clang-cl wrapper.
      # cc-rs invokes ml64.exe for MSVC asm; llvm-ml64 is ml64-compatible.
      msvcShim = pkgs.symlinkJoin {
        name = "minne-msvc-shim";
        paths = [
          (pkgs.writeShellScriptBin "cl.exe" ''
            exec ${clangClWrapper} "$@"
          '')
          (pkgs.writeShellScriptBin "ml64.exe" ''
            exec ${pkgs.llvmPackages.llvm}/bin/llvm-ml64 "$@"
          '')
        ];
      };

      # Offline MSVC env (nixpkgs cargo-xwin lacks `cache` and tries to download CRT in sandbox).
      xwinSetup = pkgs.writeShellScript "minne-xwin-setup" ''
        set -eo pipefail

        cache=${xwinCargoCache}
        crt="$cache/xwin/crt"
        sdk="$cache/xwin/sdk"

        export PATH="${msvcShim}/bin:${pkgs.llvmPackages.clang-unwrapped}/bin:${pkgs.llvmPackages.lld}/bin:${pkgs.llvmPackages.llvm}/bin:$PATH"

        # Host build scripts (webrender, etc.) run on Linux and need libstdc++ at runtime.
        export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

        export AR_x86_64_pc_windows_msvc=${pkgs.llvmPackages.llvm}/bin/llvm-lib
        export BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_msvc="-I$crt/include -I$sdk/include/ucrt -I$sdk/include/um -I$sdk/include/shared -I$sdk/include/winrt"
        export CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER=${pkgs.llvmPackages.lld}/bin/lld-link
        export CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-C linker-flavor=lld-link -Lnative=$crt/lib/x86_64 -Lnative=$sdk/lib/um/x86_64 -Lnative=$sdk/lib/ucrt/x86_64"
        export CC_x86_64_pc_windows_msvc=cl.exe
        export CXX_x86_64_pc_windows_msvc=cl.exe
        export REAL_CLANG_CL=${pkgs.llvmPackages.clang-unwrapped}/bin/clang-cl
        export REAL_LLD_LINK=${pkgs.llvmPackages.lld}/bin/lld-link

        _imsvc="--target=x86_64-pc-windows-msvc -Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc $crt/include /imsvc $sdk/include/ucrt /imsvc $sdk/include/um /imsvc $sdk/include/shared /imsvc $sdk/include/winrt"
        export CFLAGS_x86_64_pc_windows_msvc="$_imsvc"
        export CXXFLAGS_x86_64_pc_windows_msvc="$_imsvc /EHsc"
        export CL_FLAGS="--target=x86_64-pc-windows-msvc -Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc $crt/include /imsvc $sdk/include/ucrt /imsvc $sdk/include/um /imsvc $sdk/include/shared /imsvc $sdk/include/winrt"

        export CMAKE_GENERATOR=Ninja
        export CMAKE_SYSTEM_NAME=Windows
        export CMAKE_TOOLCHAIN_FILE_x86_64_pc_windows_msvc="$cache/cmake/clang-cl/x86_64-pc-windows-msvc-toolchain.cmake"

        export LIB="$crt/lib/x86_64;$sdk/lib/um/x86_64;$sdk/lib/ucrt/x86_64"
        export RCFLAGS="-I$crt/include -I$sdk/include/ucrt -I$sdk/include/um -I$sdk/include/shared -I$sdk/include/winrt"
        export TARGET_AR=${pkgs.llvmPackages.llvm}/bin/llvm-lib
        export TARGET_CC=${pkgs.llvmPackages.clang-unwrapped}/bin/clang-cl
        export TARGET_CXX=${pkgs.llvmPackages.clang-unwrapped}/bin/clang-cl
        export WINEDEBUG=-all
      '';

      windowsCommonArgs =
        commonArgs
        // {
          MOZJS_ARCHIVE = "${mozjsArchiveWindows}";
          CARGO_BUILD_TARGET = windowsTarget;
          doIncludeCrossToolchainEnv = false;
          env.CARGO_PROFILE = "dist";
          buildInputs = [
            pkgs.openssl
            pkgs.fontconfig
            pkgs.libclang.lib
          ];
          nativeBuildInputs =
            commonArgs.nativeBuildInputs
            ++ [
              pkgs.llvmPackages.llvm
              pkgs.llvmPackages.clang-unwrapped
              pkgs.llvmPackages.lld
              pkgs.stdenv.cc.cc.lib # host build scripts (e.g. webrender) link libstdc++
            ];
        };

      windowsCargoArtifacts =
        if system == "x86_64-linux"
        then
          windowsCraneLib.buildDepsOnly (windowsCommonArgs
            // {
              pname = "minne";
              cargoExtraArgs = "--workspace";
              doCheck = false;
              preBuild = "source ${xwinSetup}";
            })
        else null;

      minne-pkg-windows =
        if system == "x86_64-linux"
        then
          windowsCraneLib.buildPackage (windowsCommonArgs
            // {
              pname = "minne-windows";
              version = minneVersion;
              cargoArtifacts = windowsCargoArtifacts;
              cargoExtraArgs = "--target ${windowsTarget} -p main --bin main --bin server --bin worker";
              doCheck = false;
              doInstallCargoArtifacts = false;
              preBuild = "source ${xwinSetup}";
              installPhaseCommand = ''
                mkdir -p "$out/bin"
                for b in main server worker; do
                  install -m 755 "target/${windowsTarget}/dist/$b.exe" "$out/bin/$b.exe"
                done
              '';
            })
        else null;

      minne-release-windows =
        if system == "x86_64-linux"
        then
          pkgs.callPackage ./nix/minne-release.nix (releaseCommonArgs // {
            platform = "windows";
            inherit minne-pkg-windows ortArchiveWindows;
            targetTriple = windowsTarget;
          })
        else null;

      dockerImage = pkgs.dockerTools.buildLayeredImage {
        name = "minne";
        tag = minneVersion;
        created = "now";

        contents = [
          minne-pkg
          pkgs.cacert
          pkgs.bashInteractive
          pkgs.libglvnd
          pkgs.fontconfig.lib
          pkgs.freetype
          pkgs.stdenv.cc.cc.lib # libgomp (OpenMP) for ONNX Runtime
        ];

        maxLayers = 25;

        config = {
          Cmd = ["${minne-pkg}/bin/main"];
          Env = [
            "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-certificates.crt"
            "ORT_DYLIB_PATH=${pkgs.onnxruntime}/lib/libonnxruntime.${libExt}"
          ];
          ExposedPorts = {"3000/tcp" = {};};
          User = "appuser";
        };
      };
    in {
      packages = {
        inherit minne-pkg dockerImage;
        default = minne-pkg;
      }
      // lib.optionalAttrs (minne-release != null) {
        minne-release = minne-release;
      }
      // lib.optionalAttrs (minne-release-windows != null) {
        inherit xwinCargoCache;
        minne-release-windows = minne-release-windows;
      };

      apps = {
        main = {
          type = "app";
          program = "${minne-pkg}/bin/main";
          meta.description = "Minne main server — API, web UI, and background worker";
        };
        worker = {
          type = "app";
          program = "${minne-pkg}/bin/worker";
          meta.description = "Minne standalone background worker (ingestion, indexing, maintenance)";
        };
        server = {
          type = "app";
          program = "${minne-pkg}/bin/server";
          meta.description = "Minne API-only server (no background worker)";
        };
        default = {
          type = "app";
          program = "${minne-pkg}/bin/main";
          meta.description = "Minne main server — API, web UI, and background worker";
        };
      };

      checks = {
        ortVersion = pkgs.runCommand "ort-version-check" {} ''
          if [ "${pkgs.onnxruntime.version}" != "${ortVersion}" ]; then
            echo "pkgs.onnxruntime.version is ${pkgs.onnxruntime.version}, but flake pins ${ortVersion}" >&2
            echo "Update ortVersion in flake.nix or wait for nixpkgs to catch up." >&2
            exit 1
          fi
          touch $out
        '';

        minne-clippy = craneLib.cargoClippy (commonArgs
          // {
            cargoArtifacts = minne-pkg;
            pname = "minne";
            cargoClippyExtraArgs = "--all-targets -- --deny warnings";
          });

        minne-test = craneLib.cargoTest (commonArgs
          // {
            cargoArtifacts = minne-pkg;
            pname = "minne";
            buildInputs = commonArgs.buildInputs ++ [pkgs.cacert];
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-certificates.crt";
            cargoTestExtraArgs = "--lib --bins";
          });

        minne-fmt = craneLib.cargoFmt {
          pname = "minne-fmt";
          version = minneVersion;
          src = craneLib.cleanCargoSource ./.;
        };
      };
    })
    // {
      lib = {
        inherit ortVersion;
      };
    };
}
