{
  description = "Pinned OpenWrt package feed hashes";

  inputs = {
    nixpkgs.url = "nixpkgs/nixos-unstable";
    openwrt-imagebuilder.url = "github:astro/nix-openwrt-imagebuilder";
    openwrt-imagebuilder.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, openwrt-imagebuilder }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};

      # What `update` regenerates. Each entry becomes a `cache/<release>` tree holding the
      # ImageBuilder hash and the expanded package feeds for that target's architecture.
      pins = [
        { release = "snapshot"; target = "realtek/rtl930x"; }
        { release = "25.12.5"; target = "realtek/rtl930x"; }
      ];

      update = pkgs.writeShellApplication {
        name = "update-openwrt-feeds";
        runtimeInputs = [ openwrt-imagebuilder.packages.${system}.release2nix ];
        text = ''
          root="''${1:-$PWD}"
          if [ ! -e "$root/flake.nix" ]; then
            echo "update-openwrt-feeds: $root is not the repository root" >&2
            exit 1
          fi
          cd "$root"

          ${builtins.concatStringsSep "\n" (map
            ({ release, target }: "release2nix '${release}' '${target}'")
            pins)}
        '';
      };
    in
    {
      # Paths to pass as `nix-openwrt-imagebuilder`'s `cachePath`. A flake's source is copied to
      # the store, so these resolve to importable store paths in a consumer.
      cachePaths = builtins.listToAttrs (map
        ({ release, ... }: {
          name = release;
          value = ./cache + "/${release}";
        })
        pins);

      packages.${system}.update = update;
      apps.${system} =
        let
          app = { type = "app"; program = "${update}/bin/update-openwrt-feeds"; };
        in
        { update = app; default = app; };
    };
}
