diff --git a/cabal.project b/cabal.project
deleted file mode 100644
index 760e76b1a10fb74602316214ee71292f53812a21..0000000000000000000000000000000000000000
--- a/cabal.project
+++ /dev/null
@@ -1,15 +0,0 @@
-packages: .
-          -- These aren't released on hackage yet so we have to grab them
-          -- straight from the vcs host.  Probably should do some releases
-          -- soon.
-          https://whetstone.private.storage/privatestorage/tahoe-ssk/-/archive/0.2.0.0/tahoe-ssk-0.2.0.0.tar.gz
-          https://whetstone.private.storage/privatestorage/tahoe-chk/-/archive/0.1.0.1/tahoe-chk-0.1.0.1.tar.gz
-          https://whetstone.private.storage/privatestorage/tahoe-great-black-swamp/-/archive/0.3.0.0/tahoe-great-black-swamp-0.3.0.0.tar.gz
-          ../tahoe-directory
-
-package zlib
-        -- Turn on discovery of the underlying zlib using pkg-config.  This
-        -- fixes build failures when the underlying zlib is not in the
-        -- traditional location but is discoverable with pkg-config.  It might
-        -- break non-pkg-config platforms.
-        flags: +pkg-config
diff --git a/flake.lock b/flake.lock
index 605b213984989df112e71a403a58bb0b04998a4b..fd61df1d75d973817a19262dd262a546159899f1 100644
--- a/flake.lock
+++ b/flake.lock
@@ -64,6 +64,54 @@
         "type": "github"
       }
     },
+    "flake-compat_5": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1673956053,
+        "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
+    "flake-compat_6": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1673956053,
+        "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
+    "flake-compat_7": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1673956053,
+        "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "edolstra",
+        "repo": "flake-compat",
+        "type": "github"
+      }
+    },
     "flake-utils": {
       "locked": {
         "lastModified": 1667395993,
@@ -79,7 +127,7 @@
         "type": "github"
       }
     },
-    "flake-utils_2": {
+    "flake-utils_10": {
       "locked": {
         "lastModified": 1676283394,
         "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
@@ -94,7 +142,7 @@
         "type": "github"
       }
     },
-    "flake-utils_3": {
+    "flake-utils_11": {
       "locked": {
         "lastModified": 1667395993,
         "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
@@ -109,7 +157,7 @@
         "type": "github"
       }
     },
-    "flake-utils_4": {
+    "flake-utils_12": {
       "locked": {
         "lastModified": 1676283394,
         "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
@@ -124,7 +172,7 @@
         "type": "github"
       }
     },
-    "flake-utils_5": {
+    "flake-utils_13": {
       "locked": {
         "lastModified": 1676283394,
         "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
@@ -139,7 +187,7 @@
         "type": "github"
       }
     },
-    "flake-utils_6": {
+    "flake-utils_14": {
       "locked": {
         "lastModified": 1676283394,
         "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
@@ -154,7 +202,22 @@
         "type": "github"
       }
     },
-    "flake-utils_7": {
+    "flake-utils_2": {
+      "locked": {
+        "lastModified": 1676283394,
+        "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_3": {
       "inputs": {
         "systems": "systems"
       },
@@ -172,6 +235,66 @@
         "type": "github"
       }
     },
+    "flake-utils_4": {
+      "locked": {
+        "lastModified": 1676283394,
+        "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_5": {
+      "locked": {
+        "lastModified": 1667395993,
+        "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_6": {
+      "locked": {
+        "lastModified": 1676283394,
+        "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_7": {
+      "locked": {
+        "lastModified": 1667395993,
+        "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
     "flake-utils_8": {
       "locked": {
         "lastModified": 1676283394,
@@ -187,6 +310,24 @@
         "type": "github"
       }
     },
+    "flake-utils_9": {
+      "inputs": {
+        "systems": "systems_2"
+      },
+      "locked": {
+        "lastModified": 1681202837,
+        "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
     "gitignore": {
       "inputs": {
         "nixpkgs": [
@@ -212,7 +353,7 @@
     "gitignore_2": {
       "inputs": {
         "nixpkgs": [
-          "tahoe-chk",
+          "tahoe-directory",
           "hs-flake-utils",
           "pre-commit-hooks",
           "nixpkgs"
@@ -235,7 +376,8 @@
     "gitignore_3": {
       "inputs": {
         "nixpkgs": [
-          "tahoe-great-black-swamp",
+          "tahoe-directory",
+          "tahoe-capabilities",
           "hs-flake-utils",
           "pre-commit-hooks",
           "nixpkgs"
@@ -258,7 +400,80 @@
     "gitignore_4": {
       "inputs": {
         "nixpkgs": [
+          "tahoe-directory",
+          "tahoe-chk",
+          "hs-flake-utils",
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1660459072,
+        "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_5": {
+      "inputs": {
+        "nixpkgs": [
+          "tahoe-directory",
+          "tahoe-ssk",
+          "hs-flake-utils",
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1660459072,
+        "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_6": {
+      "inputs": {
+        "nixpkgs": [
+          "tahoe-directory",
           "tahoe-ssk",
+          "tahoe-capabilities",
+          "hs-flake-utils",
+          "pre-commit-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1660459072,
+        "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_7": {
+      "inputs": {
+        "nixpkgs": [
+          "tahoe-great-black-swamp",
           "hs-flake-utils",
           "pre-commit-hooks",
           "nixpkgs"
@@ -285,11 +500,11 @@
         "pre-commit-hooks": "pre-commit-hooks"
       },
       "locked": {
-        "lastModified": 1681762240,
-        "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=",
+        "lastModified": 1686149618,
+        "narHash": "sha256-/IHWacNutk3tklouWOgClp7FnOH+Yk6If13kKJMSEi8=",
         "ref": "main",
-        "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3",
-        "revCount": 10,
+        "rev": "49696f704eb965f57d729871c6d450ac0aff2b68",
+        "revCount": 12,
         "type": "git",
         "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
       },
@@ -306,11 +521,11 @@
         "pre-commit-hooks": "pre-commit-hooks_2"
       },
       "locked": {
-        "lastModified": 1677773826,
-        "narHash": "sha256-xJmOtHugr4k2zNhP/AF6JdIUnIEyM+TEspLn2n5kloc=",
+        "lastModified": 1686149618,
+        "narHash": "sha256-/IHWacNutk3tklouWOgClp7FnOH+Yk6If13kKJMSEi8=",
         "ref": "main",
-        "rev": "d3a83fdd9563546ca41771186427638e685a2e2b",
-        "revCount": 9,
+        "rev": "49696f704eb965f57d729871c6d450ac0aff2b68",
+        "revCount": 12,
         "type": "git",
         "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
       },
@@ -343,9 +558,72 @@
     },
     "hs-flake-utils_4": {
       "inputs": {
-        "flake-utils": "flake-utils_8",
-        "nixpkgs": "nixpkgs_4",
-        "pre-commit-hooks": "pre-commit-hooks_4"
+        "flake-utils": "flake-utils_8",
+        "nixpkgs": "nixpkgs_4",
+        "pre-commit-hooks": "pre-commit-hooks_4"
+      },
+      "locked": {
+        "lastModified": 1677773826,
+        "narHash": "sha256-xJmOtHugr4k2zNhP/AF6JdIUnIEyM+TEspLn2n5kloc=",
+        "ref": "main",
+        "rev": "d3a83fdd9563546ca41771186427638e685a2e2b",
+        "revCount": 9,
+        "type": "git",
+        "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
+      },
+      "original": {
+        "ref": "main",
+        "type": "git",
+        "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
+      }
+    },
+    "hs-flake-utils_5": {
+      "inputs": {
+        "flake-utils": "flake-utils_10",
+        "nixpkgs": "nixpkgs_5",
+        "pre-commit-hooks": "pre-commit-hooks_5"
+      },
+      "locked": {
+        "lastModified": 1681762240,
+        "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=",
+        "ref": "main",
+        "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3",
+        "revCount": 10,
+        "type": "git",
+        "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
+      },
+      "original": {
+        "ref": "main",
+        "type": "git",
+        "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
+      }
+    },
+    "hs-flake-utils_6": {
+      "inputs": {
+        "flake-utils": "flake-utils_12",
+        "nixpkgs": "nixpkgs_6",
+        "pre-commit-hooks": "pre-commit-hooks_6"
+      },
+      "locked": {
+        "lastModified": 1681762240,
+        "narHash": "sha256-+PLx9xHBvV70dA7Gy/+YTH1w3PcSOrGV0z0rGxts8jU=",
+        "ref": "main",
+        "rev": "a51e591b7fdf8881ac0237452691df7b1aceecd3",
+        "revCount": 10,
+        "type": "git",
+        "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
+      },
+      "original": {
+        "ref": "main",
+        "type": "git",
+        "url": "https://whetstone.private.storage/jcalderone/hs-flake-utils.git"
+      }
+    },
+    "hs-flake-utils_7": {
+      "inputs": {
+        "flake-utils": "flake-utils_14",
+        "nixpkgs": "nixpkgs_7",
+        "pre-commit-hooks": "pre-commit-hooks_7"
       },
       "locked": {
         "lastModified": 1681762240,
@@ -442,6 +720,54 @@
         "type": "github"
       }
     },
+    "nixpkgs-stable_5": {
+      "locked": {
+        "lastModified": 1673800717,
+        "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs-stable_6": {
+      "locked": {
+        "lastModified": 1673800717,
+        "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs-stable_7": {
+      "locked": {
+        "lastModified": 1673800717,
+        "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "nixpkgs_2": {
       "locked": {
         "lastModified": 1677624842,
@@ -490,6 +816,54 @@
         "type": "github"
       }
     },
+    "nixpkgs_5": {
+      "locked": {
+        "lastModified": 1677624842,
+        "narHash": "sha256-4DF9DbDuK4/+KYx0L6XcPBeDHUFVCtzok2fWtwXtb5w=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "d70f5cd5c3bef45f7f52698f39e7cc7a89daa7f0",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_6": {
+      "locked": {
+        "lastModified": 1677624842,
+        "narHash": "sha256-4DF9DbDuK4/+KYx0L6XcPBeDHUFVCtzok2fWtwXtb5w=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "d70f5cd5c3bef45f7f52698f39e7cc7a89daa7f0",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_7": {
+      "locked": {
+        "lastModified": 1677624842,
+        "narHash": "sha256-4DF9DbDuK4/+KYx0L6XcPBeDHUFVCtzok2fWtwXtb5w=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "d70f5cd5c3bef45f7f52698f39e7cc7a89daa7f0",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
     "pre-commit-hooks": {
       "inputs": {
         "flake-compat": "flake-compat",
@@ -522,13 +896,13 @@
       "inputs": {
         "flake-compat": "flake-compat_2",
         "flake-utils": [
-          "tahoe-chk",
+          "tahoe-directory",
           "hs-flake-utils",
           "flake-utils"
         ],
         "gitignore": "gitignore_2",
         "nixpkgs": [
-          "tahoe-chk",
+          "tahoe-directory",
           "hs-flake-utils",
           "nixpkgs"
         ],
@@ -552,13 +926,15 @@
       "inputs": {
         "flake-compat": "flake-compat_3",
         "flake-utils": [
-          "tahoe-great-black-swamp",
+          "tahoe-directory",
+          "tahoe-capabilities",
           "hs-flake-utils",
           "flake-utils"
         ],
         "gitignore": "gitignore_3",
         "nixpkgs": [
-          "tahoe-great-black-swamp",
+          "tahoe-directory",
+          "tahoe-capabilities",
           "hs-flake-utils",
           "nixpkgs"
         ],
@@ -582,13 +958,15 @@
       "inputs": {
         "flake-compat": "flake-compat_4",
         "flake-utils": [
-          "tahoe-ssk",
+          "tahoe-directory",
+          "tahoe-chk",
           "hs-flake-utils",
           "flake-utils"
         ],
         "gitignore": "gitignore_4",
         "nixpkgs": [
-          "tahoe-ssk",
+          "tahoe-directory",
+          "tahoe-chk",
           "hs-flake-utils",
           "nixpkgs"
         ],
@@ -608,6 +986,102 @@
         "type": "github"
       }
     },
+    "pre-commit-hooks_5": {
+      "inputs": {
+        "flake-compat": "flake-compat_5",
+        "flake-utils": [
+          "tahoe-directory",
+          "tahoe-ssk",
+          "hs-flake-utils",
+          "flake-utils"
+        ],
+        "gitignore": "gitignore_5",
+        "nixpkgs": [
+          "tahoe-directory",
+          "tahoe-ssk",
+          "hs-flake-utils",
+          "nixpkgs"
+        ],
+        "nixpkgs-stable": "nixpkgs-stable_5"
+      },
+      "locked": {
+        "lastModified": 1677722096,
+        "narHash": "sha256-7mjVMvCs9InnrRybBfr5ohqcOz+pyEX8m22C1XsDilg=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "61a3511668891c68ebd19d40122150b98dc2fe3b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
+    "pre-commit-hooks_6": {
+      "inputs": {
+        "flake-compat": "flake-compat_6",
+        "flake-utils": [
+          "tahoe-directory",
+          "tahoe-ssk",
+          "tahoe-capabilities",
+          "hs-flake-utils",
+          "flake-utils"
+        ],
+        "gitignore": "gitignore_6",
+        "nixpkgs": [
+          "tahoe-directory",
+          "tahoe-ssk",
+          "tahoe-capabilities",
+          "hs-flake-utils",
+          "nixpkgs"
+        ],
+        "nixpkgs-stable": "nixpkgs-stable_6"
+      },
+      "locked": {
+        "lastModified": 1677722096,
+        "narHash": "sha256-7mjVMvCs9InnrRybBfr5ohqcOz+pyEX8m22C1XsDilg=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "61a3511668891c68ebd19d40122150b98dc2fe3b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
+    "pre-commit-hooks_7": {
+      "inputs": {
+        "flake-compat": "flake-compat_7",
+        "flake-utils": [
+          "tahoe-great-black-swamp",
+          "hs-flake-utils",
+          "flake-utils"
+        ],
+        "gitignore": "gitignore_7",
+        "nixpkgs": [
+          "tahoe-great-black-swamp",
+          "hs-flake-utils",
+          "nixpkgs"
+        ],
+        "nixpkgs-stable": "nixpkgs-stable_7"
+      },
+      "locked": {
+        "lastModified": 1677722096,
+        "narHash": "sha256-7mjVMvCs9InnrRybBfr5ohqcOz+pyEX8m22C1XsDilg=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "61a3511668891c68ebd19d40122150b98dc2fe3b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
     "root": {
       "inputs": {
         "flake-utils": "flake-utils",
@@ -616,9 +1090,20 @@
           "hs-flake-utils",
           "nixpkgs"
         ],
-        "tahoe-chk": "tahoe-chk",
+        "tahoe-capabilities": [
+          "tahoe-directory",
+          "tahoe-capabilities"
+        ],
+        "tahoe-chk": [
+          "tahoe-directory",
+          "tahoe-chk"
+        ],
+        "tahoe-directory": "tahoe-directory",
         "tahoe-great-black-swamp": "tahoe-great-black-swamp",
-        "tahoe-ssk": "tahoe-ssk"
+        "tahoe-ssk": [
+          "tahoe-directory",
+          "tahoe-ssk"
+        ]
       }
     },
     "systems": {
@@ -636,11 +1121,76 @@
         "type": "github"
       }
     },
+    "systems_2": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "tahoe-capabilities": {
+      "inputs": {
+        "flake-utils": "flake-utils_5",
+        "hs-flake-utils": "hs-flake-utils_3",
+        "nixpkgs": [
+          "tahoe-directory",
+          "hs-flake-utils",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1686164259,
+        "narHash": "sha256-T0U5B/DH+XDEXfBG7cHlTcMec4aUTDd+HH8Bsv0C71Y=",
+        "ref": "refs/heads/main",
+        "rev": "f0a11218007f6c2fe0f6b5e09e0993fe253f6e23",
+        "revCount": 9,
+        "type": "git",
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-capabilities"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-capabilities"
+      }
+    },
+    "tahoe-capabilities_2": {
+      "inputs": {
+        "flake-utils": "flake-utils_11",
+        "hs-flake-utils": "hs-flake-utils_6",
+        "nixpkgs": [
+          "tahoe-directory",
+          "tahoe-ssk",
+          "hs-flake-utils",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1686164259,
+        "narHash": "sha256-T0U5B/DH+XDEXfBG7cHlTcMec4aUTDd+HH8Bsv0C71Y=",
+        "ref": "refs/heads/main",
+        "rev": "f0a11218007f6c2fe0f6b5e09e0993fe253f6e23",
+        "revCount": 9,
+        "type": "git",
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-capabilities"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-capabilities"
+      }
+    },
     "tahoe-chk": {
       "inputs": {
-        "flake-utils": "flake-utils_3",
-        "hs-flake-utils": "hs-flake-utils_2",
+        "flake-utils": "flake-utils_7",
+        "hs-flake-utils": "hs-flake-utils_4",
         "nixpkgs": [
+          "tahoe-directory",
           "hs-flake-utils",
           "nixpkgs"
         ]
@@ -660,10 +1210,36 @@
         "url": "https://whetstone.private.storage/PrivateStorage/tahoe-chk"
       }
     },
+    "tahoe-directory": {
+      "inputs": {
+        "flake-utils": "flake-utils_3",
+        "hs-flake-utils": "hs-flake-utils_2",
+        "nixpkgs": [
+          "hs-flake-utils",
+          "nixpkgs"
+        ],
+        "tahoe-capabilities": "tahoe-capabilities",
+        "tahoe-chk": "tahoe-chk",
+        "tahoe-ssk": "tahoe-ssk"
+      },
+      "locked": {
+        "lastModified": 1686169487,
+        "narHash": "sha256-dXtryScMhtz9N3hu0U+kCIGtRo58BHdP2F8PFqHjmao=",
+        "ref": "refs/heads/main",
+        "rev": "87c750f2c16a290c0fcedef65d2dbebf6a877965",
+        "revCount": 14,
+        "type": "git",
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-directory.git"
+      },
+      "original": {
+        "type": "git",
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-directory.git"
+      }
+    },
     "tahoe-great-black-swamp": {
       "inputs": {
-        "flake-utils": "flake-utils_5",
-        "hs-flake-utils": "hs-flake-utils_3",
+        "flake-utils": "flake-utils_13",
+        "hs-flake-utils": "hs-flake-utils_7",
         "nixpkgs": [
           "hs-flake-utils",
           "nixpkgs"
@@ -689,29 +1265,31 @@
     },
     "tahoe-ssk": {
       "inputs": {
-        "flake-utils": "flake-utils_7",
-        "hs-flake-utils": "hs-flake-utils_4",
+        "flake-utils": "flake-utils_9",
+        "hs-flake-utils": "hs-flake-utils_5",
         "nixpkgs": [
+          "tahoe-directory",
           "hs-flake-utils",
           "nixpkgs"
         ],
+        "tahoe-capabilities": "tahoe-capabilities_2",
         "tahoe-chk": [
+          "tahoe-directory",
           "tahoe-chk"
         ]
       },
       "locked": {
-        "lastModified": 1685641443,
-        "narHash": "sha256-lgHcvFz6s07HXdGCz1C/dOSVLi0HiAtHiv0Na4QkQEg=",
-        "ref": "refs/tags/0.2.0.0",
-        "rev": "1afe634278c96d61b8acb994ec82a71a6394d032",
-        "revCount": 84,
+        "lastModified": 1686166709,
+        "narHash": "sha256-z+QzmnfmLuqqNFWvlYAVZoS7jBHEj54OZest/sKgDqk=",
+        "ref": "refs/heads/main",
+        "rev": "8f73a87054546c875c3b0284ee4d2f3e0483d963",
+        "revCount": 93,
         "type": "git",
-        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk"
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk.git"
       },
       "original": {
-        "ref": "refs/tags/0.2.0.0",
         "type": "git",
-        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk"
+        "url": "https://whetstone.private.storage/PrivateStorage/tahoe-ssk.git"
       }
     }
   },
diff --git a/flake.nix b/flake.nix
index d04dcad05bc4ae044d5beb0ccc2029fbc2b687ce..794d0ed80816433cedeb9d0b4034541352fcf06b 100644
--- a/flake.nix
+++ b/flake.nix
@@ -7,16 +7,14 @@
     flake-utils.url = github:numtide/flake-utils;
     hs-flake-utils.url = "git+https://whetstone.private.storage/jcalderone/hs-flake-utils.git?ref=main";
 
-    tahoe-chk = {
-      url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-chk?ref=refs/tags/0.1.0.1";
+    tahoe-directory = {
+      url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-directory.git";
       inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs";
     };
 
-    tahoe-ssk = {
-      url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-ssk?ref=refs/tags/0.2.0.0";
-      inputs.nixpkgs.follows = "hs-flake-utils/nixpkgs";
-      inputs.tahoe-chk.follows = "tahoe-chk";
-    };
+    tahoe-chk.follows = "tahoe-directory/tahoe-chk";
+    tahoe-ssk.follows = "tahoe-directory/tahoe-ssk";
+    tahoe-capabilities.follows = "tahoe-directory/tahoe-capabilities";
 
     tahoe-great-black-swamp = {
       url = "git+https://whetstone.private.storage/PrivateStorage/tahoe-great-black-swamp?ref=refs/tags/0.3.0.0";
@@ -32,6 +30,8 @@
     hs-flake-utils,
     tahoe-chk,
     tahoe-ssk,
+    tahoe-capabilities,
+    tahoe-directory,
     tahoe-great-black-swamp,
   }: let
     ulib = flake-utils.lib;
@@ -47,16 +47,24 @@
         src = ./.;
         compilerVersion = ghcVersion;
         packageName = "gbs-downloader";
-        hsPkgsOverrides = import ./nix/haskell-packages.nix {
+        hsPkgsOverrides = hfinal: hprev: {
           tahoe-chk = tahoe-chk.outputs.packages.${system}.default;
           tahoe-ssk = tahoe-ssk.outputs.packages.${system}.default;
+          tahoe-directory = tahoe-directory.outputs.packages.${system}.default;
+          tahoe-capabilities = tahoe-capabilities.outputs.packages.${system}.default;
           tahoe-great-black-swamp = tahoe-great-black-swamp.outputs.packages.${system}.default;
-          haskellLib = pkgs.haskell.lib;
+
+          # A broken dependency of a tahoe-great-black-swamp executable that
+          # we don't use.  Flip the broken bit so we can get a build.
+          language-ecmascript = pkgs.haskell.unmarkBroken hprev.language-ecmascript;
         };
       };
     in {
       checks = hslib.checks {};
       devShells = hslib.devShells {
+        shellHook = ''
+          nix run .#generate-cabal-project
+        '';
         extraBuildInputs = pkgs:
           with pkgs; [
             # We configure cabal to use zlib:pkg-config so we better supply
@@ -70,6 +78,51 @@
       };
       packages = hslib.packages {};
       apps.hlint = hslib.apps.hlint {};
+      apps.generate-cabal-project = {
+        type = "app";
+        program = "${
+          pkgs.writeShellApplication {
+            name = "generate-cabal-project";
+            text = ''
+              cat >cabal.project.local <<EOF
+              -- This file is auto-generated by the flake devShell's shellHook.  Do
+              -- not edit this file.  Make changes in flake.nix.
+              packages:
+                -- These aren't released on hackage yet so we have to get them
+                -- another way.  Here, we get them from the Nix store.
+                -- tahoe-chk
+                ${tahoe-chk}
+                -- tahoe-ssk
+                ${tahoe-ssk}
+                -- tahoe-capabilities
+                ${tahoe-capabilities}
+                -- tahoe-directory
+                ${tahoe-directory}
+                -- tahoe-great-black-swamp
+                ${tahoe-great-black-swamp}
+              EOF
+            '';
+          }
+        }/bin/generate-cabal-project";
+      };
+
+      apps.entr-test = {
+        type = "app";
+        program = "${
+          pkgs.writeShellApplication {
+            name = "entr-test";
+            runtimeInputs = with pkgs; [
+              entr
+              cabal-install
+              haskell.compiler.${ghcVersion}
+            ];
+
+            text = ''
+              find . -iname '*.hs' -or -iname '*.cabal' | entr bash -c "cabal run tests; if [ \$? != 0 ]; then printf '\e[31m%s\e[0m\n' \"FAILED: \$?\"; else printf '\e[32m%s\e[0m\n' 'SUCCESS'; fi"
+            '';
+          }
+        }/bin/entr-test";
+      };
 
       # Using the working directory of `nix run`, do a build with cabal and
       # then run the test suite.
@@ -88,6 +141,8 @@
             ];
 
             text = ''
+              nix run .#generate-cabal-project
+
               # Here we make zlib discoverable by pkg-config so cabal can find
               # headers and stuff.
               export PKG_CONFIG_PATH=${pkgs.lib.makeSearchPath "lib/pkgconfig" [pkgs.zlib.dev]}
@@ -96,9 +151,10 @@
               # solve our dependencies.
               cabal update hackage.haskell.org
 
-              # Configure with tests enable, build the tests (if necessary),
-              # and run the default test suite.
-              cabal run --enable-tests tests
+              # Run the default test suite.  The local cabal project file
+              # written above should have enabled tests so the build plan will
+              # support them.
+              cabal run tests
             '';
           }
         }/bin/cabal-build-and-test";
diff --git a/gbs-downloader.cabal b/gbs-downloader.cabal
index 5b79beb1da8cc4ba249423f856ab5a382f9efb8d..56b04e183a35076172e4937be5c25ac9b1e5d7d2 100644
--- a/gbs-downloader.cabal
+++ b/gbs-downloader.cabal
@@ -111,6 +111,7 @@ library
     , servant-client
     , servant-client-core
     , tahoe-chk
+    , tahoe-directory
     , tahoe-great-black-swamp  >=0.3 && <0.4
     , tahoe-ssk                >=0.2 && <0.3
     , text
@@ -122,7 +123,7 @@ library
   -- Base language which the package is written in.
   default-language: Haskell2010
 
-executable gbs-download-chk
+executable download-chk
   -- Import common warning flags.
   import:
     warnings
@@ -155,7 +156,7 @@ executable gbs-download-chk
   -- Base language which the package is written in.
   default-language: Haskell2010
 
-executable gbs-download-sdmf
+executable download-sdmf
   import:
     warnings
     , language
@@ -175,6 +176,28 @@ executable gbs-download-sdmf
   hs-source-dirs:   download-sdmf
   default-language: Haskell2010
 
+executable list-dircap
+  import:
+    warnings
+    , language
+
+  main-is:          Main.hs
+  build-depends:
+    , aeson
+    , base
+    , bytestring
+    , containers
+    , gbs-downloader
+    , megaparsec
+    , tahoe-chk
+    , tahoe-directory
+    , tahoe-ssk        >=0.2 && <0.3
+    , text
+    , yaml
+
+  hs-source-dirs:   list-dircap
+  default-language: Haskell2010
+
 test-suite gbs-downloader-test
   -- Import common warning flags.
   import:
diff --git a/list-dircap/Main.hs b/list-dircap/Main.hs
new file mode 100644
index 0000000000000000000000000000000000000000..c0adc747c73d34ba882233bf596f445a44d37074
--- /dev/null
+++ b/list-dircap/Main.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+module Main where
+
+import qualified Data.ByteString as B
+import qualified Data.Text as T
+import Data.Yaml (decodeEither')
+import System.Environment (getArgs)
+import Tahoe.Announcement (Announcements (..))
+import qualified Tahoe.Directory as TD
+import Text.Megaparsec (parse)
+
+import Tahoe.Download (announcementToImmutableStorageServer, announcementToMutableStorageServer, downloadDirectory)
+
+main :: IO ()
+main = do
+    [announcementPath, dirReadCap] <- getArgs
+    -- Load server announcements
+    announcementsBytes <- B.readFile announcementPath
+    let Right (Announcements announcements) = decodeEither' announcementsBytes
+
+    -- Accept & parse read capability
+    case parse TD.pReadSDMF "<argv>" (T.pack dirReadCap) of
+        Right r -> go announcements r announcementToMutableStorageServer
+        Left eSDMF -> case parse TD.pReadCHK "<argv>" (T.pack dirReadCap) of
+            Right r -> go announcements r announcementToImmutableStorageServer
+            Left eCHK -> do
+                print $ "Failed to parse cap: " <> show eSDMF
+                print $ "Failed to parse cap: " <> show eCHK
+  where
+    go announcements cap lookupServer = do
+        -- Download & decode the shares
+        result <- downloadDirectory announcements cap lookupServer
+
+        -- Show the result
+        putStrLn "Your result:"
+        either print print result
diff --git a/nix/haskell-packages.nix b/nix/haskell-packages.nix
deleted file mode 100644
index dbf474bdcd3a3ddcda31a2255387b72a9fe477a4..0000000000000000000000000000000000000000
--- a/nix/haskell-packages.nix
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  haskellLib,
-  tahoe-chk,
-  tahoe-ssk,
-  tahoe-great-black-swamp,
-}: hfinal: hprev: {
-  inherit tahoe-chk;
-  inherit tahoe-ssk;
-  inherit tahoe-great-black-swamp;
-
-  # A broken dependency of a tahoe-great-black-swamp executable that we don't
-  # use.  Flip the broken bit so we can get a build.
-  language-ecmascript = haskellLib.unmarkBroken hprev.language-ecmascript;
-}
diff --git a/src/Tahoe/Download.hs b/src/Tahoe/Download.hs
index 79f3bb66c90f84b8eb9ef57827f63df1277689b8..c5a64c489b48c40d25d91389e5b2c3666159e471 100644
--- a/src/Tahoe/Download.hs
+++ b/src/Tahoe/Download.hs
@@ -10,6 +10,7 @@ module Tahoe.Download (
     DiscoverError (..),
     discoverShares,
     download,
+    downloadDirectory,
     announcementToImmutableStorageServer,
     announcementToMutableStorageServer,
     getShareNumbers,
@@ -28,6 +29,8 @@ import qualified Data.Set as Set
 import Tahoe.Announcement (StorageServerAnnouncement)
 import Tahoe.CHK.Server (StorageServer (..), StorageServerID)
 import Tahoe.CHK.Types (ShareNum, StorageIndex)
+import Tahoe.Directory (Directory, DirectoryCapability (DirectoryCapability))
+import qualified Tahoe.Directory as Directory
 import Tahoe.Download.Internal.Capability
 import Tahoe.Download.Internal.Client
 import Tahoe.Download.Internal.Immutable
@@ -226,3 +229,29 @@ downloadShare storageIndex (shareNum, s) = do
     let massaged = first (ShareDownloadError . (displayException :: SomeException -> String)) shareBytes
     print' "Downloaded it"
     pure (shareNum, LB.fromStrict <$> massaged)
+
+{- | Download the data associated with a directory capability and interpret it
+ as a collection of entries.
+-}
+downloadDirectory ::
+    (MonadIO m, Readable readCap, Verifiable v, Verifier readCap ~ v) =>
+    -- | Information about the servers from which to consider downloading shares
+    -- representing the application data.
+    Map.Map StorageServerID StorageServerAnnouncement ->
+    -- | The read capability for the application data.
+    DirectoryCapability readCap ->
+    -- | Get functions for interacting with a server given its URL.
+    LookupServer m ->
+    -- | Either a description of how the recovery failed or the recovered
+    -- application data.
+    m (Either DirectoryDownloadError Directory)
+downloadDirectory anns (DirectoryCapability cap) lookupServer = do
+    bs <- download anns cap lookupServer
+    pure $ do
+        bs' <- first UnderlyingDownloadError bs
+        first (const DecodingError) $ Directory.parse (LB.toStrict bs')
+
+data DirectoryDownloadError
+    = UnderlyingDownloadError DownloadError
+    | DecodingError
+    deriving (Ord, Eq, Show)