diff --git a/CONTRIBUTING b/CONTRIBUTING
deleted file mode 100644
index 587c37bc5cf8bd3580a6c65dfa1d63220760d2f2..0000000000000000000000000000000000000000
--- a/CONTRIBUTING
+++ /dev/null
@@ -1,23 +0,0 @@
-Contributing to ZKAPAuthorizer
-==============================
-
-Contributions are accepted in many forms.
-
-Examples of contributions include:
-
-* Bug reports and patch reviews
-* Documentation improvements
-* Code patches
-
-File a ticket at:
-
-https://github.com/PrivateStorageio/ZKAPAuthorizer/issues/new
-
-ZKAPAuthorizer uses GitHub keep track of bugs, feature requests, and associated patches.
-
-Contributions are managed using GitHub's Pull Requests.
-For a PR to be accepted it needs to have:
-
-* an associated issue
-* all CI tests passing
-* patch coverage of 100% as reported by codecov.io
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000000000000000000000000000000000000..362658dd97f01f11c6b235055831b8154e2b31f4
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,69 @@
+Contributing to ZKAPAuthorizer
+==============================
+
+Contributions are accepted in many forms.
+
+Examples of contributions include:
+
+* Bug reports and patch reviews
+* Documentation improvements
+* Code patches
+
+File a ticket at:
+
+https://github.com/PrivateStorageio/ZKAPAuthorizer/issues/new
+
+ZKAPAuthorizer uses GitHub keep track of bugs, feature requests, and associated patches.
+
+Contributions are managed using GitHub's Pull Requests.
+For a PR to be accepted it needs to have:
+
+* an associated issue
+* all CI tests passing
+* patch coverage of 100% as reported by codecov.io
+
+Updating Dependencies
+---------------------
+
+We use `niv <https://github.com/nmattia/niv>`_ to manage several of our dependencies.
+
+Python Dependencies
+...................
+
+We use `mach-nix <https://github.com/DavHau/mach-nix/>`_ to build python packages.
+It uses a snapshot of pypi to expose python dependencies to nix,
+thus our python depedencies (on nix) are automatically pinned.
+To update the pypy snapshot (and thus our python dependencies), run
+
+.. code:: shell
+
+   nix-shell --run 'niv update pypi-deps-db'
+
+tahoe-lafs
+..........
+
+We depend on pinned commit of tahoe-lafs.
+To update to the latest commit, run
+
+.. code:: shell
+
+   nix-shell --run 'niv update tahoe-lafs --branch master'
+
+It is also possible to pass ``pull/<pr-number>/head`` to test against a specific PR.
+
+If you want to test multiple versions, you can add an additional source, pointing at other version
+
+.. code:: shell
+
+   nix-shell --run 'niv add -n tahoe-lafs-next tahoe-lafs/tahoe-lafs --rev "<rev>"'
+   nix-build tests.nix --argstr tahoe-lafs-source tahoe-lafs-next
+
+``--argstr tahoe-lafs-source <...>`` can also be passed to ``nix-shell`` and ``nix-build default.nix``.
+
+nixpkgs
+.......
+
+We pin to a nixos channel release, which isn't directly supported by niv (`issue <https://github.com/nmattia/niv/issues/225>`_).
+Thus, the pin needs to be update manually.
+To do this, copy the ``url`` and ``sha256`` values from PrivateStorageio's `nixpkgs-2105.json <https://whetstone.privatestorage.io/privatestorage/PrivateStorageio/-/blob/develop/nixpkgs-2105.json>`_ into the ``release2015`` entry in ``nix/sources.json``.
+When this is deployed as part of Privatestorageio, we use the value pinned there, rather than the pin in this repository.
diff --git a/default.nix b/default.nix
index 5e1a78ff9418c3c74f72284daf69cd786c29f702..688bf8dfcf55e3a14fd4e6abd4d1fa98672f678a 100644
--- a/default.nix
+++ b/default.nix
@@ -4,7 +4,8 @@ in
 { pkgs ? import sources.release2015 {}
 , pypiData ? sources.pypi-deps-db
 , mach-nix ? import sources.mach-nix { inherit pkgs pypiData; }
-, tahoe-lafs-repo ? sources.tahoe-lafs
+, tahoe-lafs-source ? "tahoe-lafs"
+, tahoe-lafs-repo ? sources.${tahoe-lafs-source}
 }:
   let
     lib = pkgs.lib;
diff --git a/docs/source/CONTRIBUTING.rst b/docs/source/CONTRIBUTING.rst
index fe245d9d5560297d0d8fb5c6d53e0fa674c822c8..ac7b6bcf35e98139c791cb5c4b94f08849972d65 100644
--- a/docs/source/CONTRIBUTING.rst
+++ b/docs/source/CONTRIBUTING.rst
@@ -1 +1 @@
-.. include:: ../../CONTRIBUTING
+.. include:: ../../CONTRIBUTING.rst
diff --git a/shell.nix b/shell.nix
index a8d98586540d6feedc13fa9b8d131d05de0e6760..f34fcf949ca84d7b092cf06761aae4f03db8df51 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,9 +1,13 @@
 let
   sources = import nix/sources.nix;
 in
-{ pkgs ? import sources.release2015 {} }:
+{ pkgs ? import sources.release2015 {}
+, tahoe-lafs-source ? "tahoe-lafs"
+}:
   let
-    tests = pkgs.callPackage ./tests.nix {};
+    tests = pkgs.callPackage ./tests.nix {
+      inherit tahoe-lafs-source;
+    };
   in
     pkgs.mkShell {
       packages = [
diff --git a/tests.nix b/tests.nix
index 1bbeb1c57266fcfa77c979b377714d34f566107f..961d29d3399ff0bec7f9e0af63fae3cef12a86c8 100644
--- a/tests.nix
+++ b/tests.nix
@@ -4,7 +4,12 @@ in
 { pkgs ? import sources.release2015 {}
 , pypiData ? sources.pypi-deps-db
 , mach-nix ? import sources.mach-nix { inherit pkgs pypiData; }
-, zkapauthorizer ? (import ./. { inherit pkgs pypiData mach-nix; }).zkapauthorizer
+, tahoe-lafs-source ? "tahoe-lafs"
+, tahoe-lafs-repo ? sources.${tahoe-lafs-source}
+, privatestorage ? import ./. {
+    inherit pkgs pypiData mach-nix;
+    inherit tahoe-lafs-repo;
+  }
 , hypothesisProfile ? null
 , collectCoverage ? false
 , testSuite ? null
@@ -12,7 +17,8 @@ in
 ,
 }:
   let
-    lib = pkgs.lib;
+    inherit (pkgs) lib;
+    inherit (privatestorage) zkapauthorizer;
     hypothesisProfile' = if hypothesisProfile == null then "default" else hypothesisProfile;
     defaultTrialArgs = [ "--rterrors" ] ++ (lib.optional (! collectCoverage) "--jobs=$NIX_BUILD_CORES");
     trialArgs' = if trialArgs == null then defaultTrialArgs else trialArgs;