diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
index 0000000000000000000000000000000000000000..a33680922e6f60ffb562fa9f1bb2289aded0a21f
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# ChangeLog for horion-platform
+
+## unstable-2023-02-20
+
+* Initial unstable tag. Handwritten policy added.
diff --git a/README.md b/README.md
index 752dd94b7ac2407049fcc75173518325164c01da..d67217bbe3875a9906c32188886ef357f6dd9e84 100644
--- a/README.md
+++ b/README.md
@@ -32,3 +32,50 @@ delete the packages folder.
 If you need to do additional manual overrides to the nix code, such as
 `addPkgconfigDepends`, edit the `configuration.nix` overlay, which is applied
 afterwards.
+
+## Package Set Policy
+
+This package set has the following policy.
+
+* GHC will advance as often as possible
+* Nonversioned locations (git, unversioned tarballs) are permitted to allow
+  GHC to advance.
+* The following packages must always build:
+  * aeson
+  * beam-postgres
+  * composite-base
+  * dhall
+  * haskell-language-server
+  * hedgehog
+  * pandoc
+  * persistent-postgresql
+  * polysemy
+  * servant
+  * sydtest
+  * tasty
+  * xmonad-contrib
+  * xmonad
+  * wai-app-static
+  * warp
+* Tags will be of the form `unstable-<yyyy>-<mm>-<dd>-r<N>` where any
+  unversioned source is used.
+* Tags will be of the form `stable-<yyyy>-<mm>-<dd>-r<N>` where all
+stable sources are used.
+
+## Commit Policy
+
+* All commits should evaluate with `nix flake show`.
+* All commits should pass all checks with `nix flake check`.
+* All derivations in `packages` should build.
+* Where possible, commits should be atomic, of the form
+  * foo: init at <version>
+  * foo: <old-version> -> <new-version>
+* If multiple packages need to be maintained in lockstep,
+  the commit message should contain all changes.
+
+## ChangeLog Policy
+
+* ChangeLogs should clearly show source stability changes between versions,
+  of the form:
+  * stabilized source: aeson, lens
+  * destabilized source: pandoc
diff --git a/flake.lock b/flake.lock
index 4db7b5c8f98e406d4c418049ba1669f0d032c721..261c2f6ec03616d138a5a385a4511e267ab23a7d 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,20 +1,24 @@
 {
   "nodes": {
-    "flake-utils": {
+    "flake-parts": {
+      "inputs": {
+        "nixpkgs-lib": "nixpkgs-lib"
+      },
       "locked": {
-        "lastModified": 1659877975,
-        "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
+        "lastModified": 1675933616,
+        "narHash": "sha256-/rczJkJHtx16IFxMmAWu5nNYcSXNg1YYXTHoGjLrLUA=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "47478a4a003e745402acf63be7f9a092d51b83d7",
         "type": "github"
       },
       "original": {
-        "id": "flake-utils",
-        "type": "indirect"
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
       }
     },
-    "flake-utils_2": {
+    "flake-utils": {
       "locked": {
         "lastModified": 1667077288,
         "narHash": "sha256-bdC8sFNDpT0HK74u9fUkpbf1MEzVYJ+ka7NXCdgBoaA=",
@@ -29,7 +33,7 @@
         "type": "github"
       }
     },
-    "flake-utils_3": {
+    "flake-utils_2": {
       "locked": {
         "lastModified": 1659877975,
         "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
@@ -43,7 +47,7 @@
         "type": "indirect"
       }
     },
-    "flake-utils_4": {
+    "flake-utils_3": {
       "locked": {
         "lastModified": 1644229661,
         "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
@@ -58,7 +62,7 @@
         "type": "github"
       }
     },
-    "flake-utils_5": {
+    "flake-utils_4": {
       "locked": {
         "lastModified": 1644229661,
         "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
@@ -73,7 +77,7 @@
         "type": "github"
       }
     },
-    "flake-utils_6": {
+    "flake-utils_5": {
       "locked": {
         "lastModified": 1644229661,
         "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
@@ -151,7 +155,7 @@
     },
     "horizon-gen-nix-flake": {
       "inputs": {
-        "flake-utils": "flake-utils_2",
+        "flake-utils": "flake-utils",
         "get-flake": "get-flake_2",
         "horizon-gen-nix": "horizon-gen-nix",
         "horizon-platform": "horizon-platform",
@@ -190,7 +194,7 @@
     },
     "horizon-platform": {
       "inputs": {
-        "flake-utils": "flake-utils_3",
+        "flake-utils": "flake-utils_2",
         "get-flake": "get-flake_3",
         "horizon-gen-nix": "horizon-gen-nix_2",
         "lint-utils": "lint-utils",
@@ -228,7 +232,7 @@
     },
     "lint-utils": {
       "inputs": {
-        "flake-utils": "flake-utils_4",
+        "flake-utils": "flake-utils_3",
         "nixpkgs": "nixpkgs"
       },
       "locked": {
@@ -247,7 +251,7 @@
     },
     "lint-utils_2": {
       "inputs": {
-        "flake-utils": "flake-utils_5",
+        "flake-utils": "flake-utils_4",
         "nixpkgs": [
           "horizon-gen-nix-flake",
           "nixpkgs"
@@ -269,7 +273,7 @@
     },
     "lint-utils_3": {
       "inputs": {
-        "flake-utils": "flake-utils_6",
+        "flake-utils": "flake-utils_5",
         "nixpkgs": "nixpkgs_4"
       },
       "locked": {
@@ -302,6 +306,24 @@
         "type": "github"
       }
     },
+    "nixpkgs-lib": {
+      "locked": {
+        "dir": "lib",
+        "lastModified": 1675183161,
+        "narHash": "sha256-Zq8sNgAxDckpn7tJo7V1afRSk2eoVbu3OjI1QklGLNg=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "e1e1b192c1a5aab2960bf0a0bd53a2e8124fa18e",
+        "type": "github"
+      },
+      "original": {
+        "dir": "lib",
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "nixpkgs_2": {
       "locked": {
         "lastModified": 1665830552,
@@ -368,7 +390,7 @@
     },
     "root": {
       "inputs": {
-        "flake-utils": "flake-utils",
+        "flake-parts": "flake-parts",
         "get-flake": "get-flake",
         "horizon-gen-nix-flake": "horizon-gen-nix-flake",
         "horizon-platform": "horizon-platform_2",
diff --git a/flake.nix b/flake.nix
index 68096875e46b0bd65b2e3f723c68dad98382533e..710c463622897cbc0d2b2486558aac05a59a50f1 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,117 +1,123 @@
 {
+
+  description = "Haskell Horizon Platform";
+
   inputs = {
     get-flake.url = "github:ursi/get-flake";
+    flake-parts.url = "github:hercules-ci/flake-parts";
+    horizon-gen-nix-flake.url = "git+https://gitlab.homotopic.tech/horizon/horizon-gen-nix";
     horizon-platform = {
       url = "git+https://gitlab.homotopic.tech/horizon/horizon-platform";
       flake = false;
     };
     lint-utils.url = "git+https://gitlab.homotopic.tech/nix/lint-utils";
     nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
-    horizon-gen-nix-flake.url = "git+https://gitlab.homotopic.tech/horizon/horizon-gen-nix";
   };
 
   outputs =
     inputs@
     { self
     , get-flake
-    , flake-utils
+    , flake-parts
     , horizon-platform
     , horizon-gen-nix-flake
     , lint-utils
     , nixpkgs
     , ...
     }:
-    flake-utils.lib.eachSystem [ "x86_64-linux" ]
-      (system:
-      let
-        pkgs = nixpkgs.legacyPackages.${system};
-      in
-      with pkgs.lib;
-      with pkgs.writers;
-      with lint-utils.writers.${system};
-      let
-
-        horizon-platform-prev = get-flake horizon-platform;
-
-        horizon-gen-nix = pkgs.writeShellApplication {
-          name = "horizon-gen-nix";
-          runtimeInputs = with pkgs; [ ghc cabal-install ];
-          text = ''
-            cabal update
-            ${horizon-gen-nix-flake.legacyPackages.${system}.horizon-gen-nix}/bin/horizon-gen-nix;
-            ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt pkgs/*
-            ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt initial-packages.nix
-          '';
-        };
+    flake-parts.lib.mkFlake { inherit inputs; } {
+      systems = [ "x86_64-linux" ];
+      perSystem = { config, system, ... }:
+        let
+          pkgs = nixpkgs.legacyPackages.${system};
+        in
+        with pkgs.lib;
+        with pkgs.writers;
+        with lint-utils.writers.${system};
+        let
+
+          horizon-platform-prev = get-flake horizon-platform;
+
+          horizon-gen-nix = pkgs.writeShellApplication {
+            name = "horizon-gen-nix";
+            runtimeInputs = with pkgs; [ ghc cabal-install ];
+            text = ''
+              cabal update
+              ${horizon-gen-nix-flake.legacyPackages.${system}.horizon-gen-nix}/bin/horizon-gen-nix;
+              ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt pkgs/*
+              ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt initial-packages.nix
+            '';
+          };
 
-        haskellLib = pkgs.haskell.lib.compose;
-
-        legacyPackages = pkgs.callPackage (nixpkgs + /pkgs/development/haskell-modules) {
-          buildHaskellPackages = pkgs.haskell.packages.ghc944;
-          compilerConfig = pkgs.callPackage ./configuration-ghc.nix { inherit haskellLib; };
-          configurationArm = { pkgs, haskellLib }: self: super: { };
-          configurationCommon = import ./configuration.nix;
-          configurationDarwin = { pkgs, haskellLib }: self: super: { };
-          configurationNix = { pkgs, haskellLib }: self: super: { };
-          ghc = pkgs.haskell.compiler.ghc944;
-          inherit haskellLib;
-          initialPackages = import ./initial-packages.nix;
-          nonHackagePackages = self: super: { };
-        };
+          haskellLib = pkgs.haskell.lib.compose;
+
+          legacyPackages = pkgs.callPackage (nixpkgs + /pkgs/development/haskell-modules) {
+            buildHaskellPackages = pkgs.haskell.packages.ghc944;
+            compilerConfig = pkgs.callPackage ./configuration-ghc.nix { inherit haskellLib; };
+            configurationArm = { pkgs, haskellLib }: self: super: { };
+            configurationCommon = import ./configuration.nix;
+            configurationDarwin = { pkgs, haskellLib }: self: super: { };
+            configurationNix = { pkgs, haskellLib }: self: super: { };
+            ghc = pkgs.haskell.compiler.ghc944;
+            inherit haskellLib;
+            initialPackages = import ./initial-packages.nix;
+            nonHackagePackages = self: super: { };
+          };
 
-        packages = filterAttrs
-          (n: v: v != null
-            && builtins.typeOf v == "set"
-            && pkgs.lib.hasAttr "type" v
-            && v.type == "derivation"
-            && v.meta.broken == false)
-          legacyPackages;
-
-        run-impure-tests = writePorcelainOrDieBin {
-          name = "run-impure-tests";
-          src = ./.;
-          command = ''
-            export PATH=$PATH:${pkgs.nix-prefetch-git}/bin:${pkgs.cabal-install}/bin
-            cabal update
-            rm pkgs -rf && nix run .#horizon-gen-nix;
-            nixpkgs-fmt pkgs/*
-          '';
-          advice = "Try removing the offending packages from pkgs/ and running nix run .#horizon-gen-nix";
-        };
+          packages = filterAttrs
+            (n: v: v != null
+              && builtins.typeOf v == "set"
+              && pkgs.lib.hasAttr "type" v
+              && v.type == "derivation"
+              && v.meta.broken == false)
+            legacyPackages;
+
+          run-impure-tests = writePorcelainOrDieBin {
+            name = "run-impure-tests";
+            src = ./.;
+            command = ''
+              export PATH=$PATH:${pkgs.nix-prefetch-git}/bin:${pkgs.cabal-install}/bin
+              cabal update
+              rm pkgs -rf && nix run .#horizon-gen-nix;
+              nixpkgs-fmt pkgs/*
+            '';
+            advice = "Try removing the offending packages from pkgs/ and running nix run .#horizon-gen-nix";
+          };
 
-        run-impure-tests-app = {
-          type = "app";
-          program = "${run-impure-tests}/bin/run-impure-tests";
-        };
+          run-impure-tests-app = {
+            type = "app";
+            program = "${run-impure-tests}/bin/run-impure-tests";
+          };
 
-        procex = import ./shell/default.nix { haskellPackages = horizon-platform-prev.legacyPackages.${system}; inherit (pkgs) runCommand writeShellScriptBin; };
-      in
-      {
+          procex = import ./shell/default.nix { haskellPackages = horizon-platform-prev.legacyPackages.${system}; inherit (pkgs) runCommand writeShellScriptBin; };
+        in
+        {
 
-        apps = {
+          apps = {
 
-          horizon-gen-nix = {
-            type = "app";
-            program = "${horizon-gen-nix}/bin/horizon-gen-nix";
-          };
+            horizon-gen-nix = {
+              type = "app";
+              program = "${horizon-gen-nix}/bin/horizon-gen-nix";
+            };
 
-          procex = {
-            type = "app";
-            program = "${procex}/bin/procex-shell";
-          };
+            procex = {
+              type = "app";
+              program = "${procex}/bin/procex-shell";
+            };
 
-          run-impure-tests = run-impure-tests-app;
-        };
+            run-impure-tests = run-impure-tests-app;
+          };
 
-        checks = with lint-utils.linters.${system}; {
-          dhall-format = dhall-format { src = self; };
-          nixpkgs-fmt = nixpkgs-fmt { src = self; };
-          stylish-haskell = stylish-haskell { src = self; };
-        };
+          checks = with lint-utils.linters.${system}; {
+            dhall-format = dhall-format { src = self; };
+            nixpkgs-fmt = nixpkgs-fmt { src = self; };
+            stylish-haskell = stylish-haskell { src = self; };
+          };
 
-        inherit legacyPackages;
+          inherit legacyPackages;
 
-        inherit packages;
+          inherit packages;
 
-      });
+        };
+    };
 }
diff --git a/horizon.dhall b/horizon.dhall
index 848f81e35c5019d5813620fd54d56e57c41d7292..bbe95398de96a1026ba41b3956bad8ea538852eb 100644
--- a/horizon.dhall
+++ b/horizon.dhall
@@ -181,11 +181,7 @@ let packages =
       , cabal-doctest = H.callHackage "cabal-doctest" "1.0.9"
       , cabal-install = H.callHackage "cabal-install" "3.8.1.0"
       , cabal-install-solver = H.callHackage "cabal-install-solver" "3.8.1.0"
-      , cabal2nix =
-          H.callGit
-            "https://github.com/NixOS/cabal2nix"
-            "8e97f51e4bd4e5b9ff79391aa599ed8547771954"
-            (Some "cabal2nix")
+      , cabal2nix = H.callHackage "cabal2nix" "2.19.1"
       , cache = H.callHackage "cache" "0.1.3.0"
       , call-stack = H.callHackage "call-stack" "0.4.0"
       , canonical-json = H.callHackage "canonical-json" "0.6.0.1"
@@ -327,11 +323,7 @@ let packages =
       , doctest-parallel = H.callHackage "doctest-parallel" "0.2.5"
       , dom-lt = H.callHackage "dom-lt" "0.2.3"
       , dotgen = H.callHackage "dotgen" "0.4.3"
-      , double-conversion =
-          H.callGit
-            "https://github.com/haskell/double-conversion"
-            "5d092e0664442eaac8ae1d101dba57ce9b1c9b03"
-            (None Text)
+      , double-conversion = H.callHackage "double-conversion" "2.0.4.2"
       , dual-tree = H.callHackage "dual-tree" "0.2.3.1"
       , easy-file = H.callHackage "easy-file" "0.2.2"
       , echo = H.callHackage "echo" "0.1.4"
@@ -1057,20 +1049,12 @@ let packages =
             "https://github.com/locallycompact/tar"
             "107c0b78524acfd0e77e767b83073492008bea0c"
             (None Text)
-      , tasty =
-          H.callGit
-            "https://github.com/UnkindPartition/tasty"
-            "207d3453a64b414593512c1e968171d64a8dbe61"
-            (Some "core")
+      , tasty = H.callHackage "tasty" "1.4.3"
       , tasty-bench = H.callHackage "tasty-bench" "0.3.2"
       , tasty-discover = H.callHackage "tasty-discover" "5.0.0"
       , tasty-expected-failure = H.callHackage "tasty-expected-failure" "0.12.3"
       , tasty-golden = H.callHackage "tasty-golden" "2.3.5"
-      , tasty-hedgehog =
-          H.callGit
-            "https://github.com/locallycompact/tasty-hedgehog"
-            "4a3477578ed21aa82e5b74f387d08e5d750635d6"
-            (None Text)
+      , tasty-hedgehog = H.callHackage "tasty-hedgehog" "1.4.0.0"
       , tasty-hslua = H.callHackage "tasty-hslua" "1.0.2"
       , tasty-hspec = H.callHackage "tasty-hspec" "1.2.0.1"
       , tasty-hunit =
diff --git a/pkgs/cabal2nix.nix b/pkgs/cabal2nix.nix
index 1293490a03364bf17ea60737d1d0b0ca3811cac4..940ceaf50fbeb750f83479935c17edf99628933d 100644
--- a/pkgs/cabal2nix.nix
+++ b/pkgs/cabal2nix.nix
@@ -8,7 +8,6 @@
 , deepseq
 , directory
 , distribution-nixpkgs
-, fetchgit
 , filepath
 , hackage-db
 , hopenssl
@@ -33,13 +32,7 @@
 mkDerivation {
   pname = "cabal2nix";
   version = "2.19.1";
-  src = fetchgit {
-    url = "https://github.com/NixOS/cabal2nix";
-    sha256 = "1n4jy4xsrzywqvzicsca6kaw4bp0xdz5qfkvj7bkh4np9p3hnj08";
-    rev = "8e97f51e4bd4e5b9ff79391aa599ed8547771954";
-    fetchSubmodules = true;
-  };
-  postUnpack = "sourceRoot+=/cabal2nix/; echo source root reset to $sourceRoot";
+  sha256 = "e0dba35dba0917f4663ba3aee131341dcbf2241112227e07e4d4cfbe37f667b2";
   isLibrary = true;
   isExecutable = true;
   enableSeparateDataOutput = false;
diff --git a/pkgs/double-conversion.nix b/pkgs/double-conversion.nix
index 7c9d8739a8e03b2f71ae7ecba38f5d3fc3e8f824..ce76fefdef46860a2bbc088a97e2335e71825666 100644
--- a/pkgs/double-conversion.nix
+++ b/pkgs/double-conversion.nix
@@ -2,7 +2,6 @@
 , HUnit
 , base
 , bytestring
-, fetchgit
 , ghc-prim
 , lib
 , system-cxx-std-lib
@@ -13,13 +12,10 @@
 }:
 mkDerivation {
   pname = "double-conversion";
-  version = "2.0.4.1";
-  src = fetchgit {
-    url = "https://github.com/haskell/double-conversion";
-    sha256 = "0z27zd1nyydz6hirbbdyhqmd4nbxcn7vcfx6jvlygrm4jwmhkr9b";
-    rev = "5d092e0664442eaac8ae1d101dba57ce9b1c9b03";
-    fetchSubmodules = true;
-  };
+  version = "2.0.4.2";
+  sha256 = "9ab8bc1f0fa7de356c07b23d7d684b6c3ddfa542fd56ea422fb5fd17000aec64";
+  revision = "2";
+  editedCabalFile = "1mpnx4m2pg5crfz9k8wamh5mgsha0np3ynnllrmglmwh54gvfjj3";
   isLibrary = true;
   isExecutable = false;
   enableSeparateDataOutput = false;
diff --git a/pkgs/tasty-hedgehog.nix b/pkgs/tasty-hedgehog.nix
index 1e90fd97c5893972171d0d05c8e58a0b0474beb5..c22de81d8a934c996d176553c7c2b0e6078c1441 100644
--- a/pkgs/tasty-hedgehog.nix
+++ b/pkgs/tasty-hedgehog.nix
@@ -1,6 +1,5 @@
 { mkDerivation
 , base
-, fetchgit
 , hedgehog
 , lib
 , tagged
@@ -9,13 +8,8 @@
 }:
 mkDerivation {
   pname = "tasty-hedgehog";
-  version = "1.2.0.0";
-  src = fetchgit {
-    url = "https://github.com/locallycompact/tasty-hedgehog";
-    sha256 = "1ql4wsah4zz2dizakgh3lfgbbq9c3c6nmypcp6fl3i96pbdj2bh5";
-    rev = "4a3477578ed21aa82e5b74f387d08e5d750635d6";
-    fetchSubmodules = true;
-  };
+  version = "1.4.0.0";
+  sha256 = "93e4009389a7c14a37e9195ff8a96b739438543e2d408d089eebec6e715c9cbd";
   isLibrary = true;
   isExecutable = false;
   enableSeparateDataOutput = false;
diff --git a/pkgs/tasty.nix b/pkgs/tasty.nix
index 4141ce4a6206a2d67c641f4fc722d449852bad92..1d38a80a9c762b458c6d2257d928786dfe05e3a5 100644
--- a/pkgs/tasty.nix
+++ b/pkgs/tasty.nix
@@ -2,7 +2,6 @@
 , ansi-terminal
 , base
 , containers
-, fetchgit
 , lib
 , optparse-applicative
 , stm
@@ -12,14 +11,8 @@
 }:
 mkDerivation {
   pname = "tasty";
-  version = "1.4.2.3";
-  src = fetchgit {
-    url = "https://github.com/UnkindPartition/tasty";
-    sha256 = "0mbzw9plh5gffpdzbnw6749b45dpal29wdak2y04qlmjs42wxcv1";
-    rev = "207d3453a64b414593512c1e968171d64a8dbe61";
-    fetchSubmodules = true;
-  };
-  postUnpack = "sourceRoot+=/core/; echo source root reset to $sourceRoot";
+  version = "1.4.3";
+  sha256 = "f420da9560267271dce8a0007a1cb77c06987f0d129eb0f613110ce61f71cb00";
   isLibrary = true;
   isExecutable = false;
   enableSeparateDataOutput = false;