diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for nix-thunk
 
+## 0.7.3.0
+
+* Add `runMonadNixThunk` to make it easier to run the actions defined in the library.
+
 ## 0.7.2.2
 
 * Support GHC 9.12
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -19,9 +19,44 @@
 
 ## Installation
 
+`nix-thunk` is available from nixpkgs as `haskellPackages.nix-thunk`:
+
 ```bash
+nix-env -f '<nixpkgs>' -iA haskellPackages.nix-thunk
+```
+
+To install the latest version from this repository instead:
+
+```bash
 nix-env -f https://github.com/obsidiansystems/nix-thunk/archive/master.tar.gz -iA command
 ```
+
+Builds from this repository are available from the Reflex binary cache. On
+single-user Nix, or when running as a trusted user, it can be enabled for just
+this installation:
+
+```bash
+nix-env -f https://github.com/obsidiansystems/nix-thunk/archive/master.tar.gz \
+  -iA command \
+  --option extra-substituters https://nixcache.reflex-frp.org \
+  --option extra-trusted-public-keys \
+    'ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI='
+```
+
+Multi-user Nix restricts those options to trusted users. To make the cache
+available persistently on NixOS, add the following values to any existing
+substituter and public-key lists in `/etc/nixos/configuration.nix`:
+
+```nix
+nix.settings.substituters = [ "https://nixcache.reflex-frp.org" ];
+nix.settings.trusted-public-keys = [
+  "ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI="
+];
+```
+
+Run `sudo nixos-rebuild switch` after changing the configuration. The cache is
+most useful when installing from this repository; nixpkgs installations can
+normally use the standard nixpkgs binary cache.
 
 **WARNING**: It is _not_ possible to compile `nix-thunk` without Nix.
 To ensure that packed thunks are buildable even in environments where diamond paths are unavailable (specifically `<nixpkgs>`), `nix-thunk` _must_ be built with knowledge of a known-good nixpkgs, _and_ for `nix-thunk` to be able to manipulate these thunks, it must _always_ be the same version of nixpkgs.
diff --git a/nix-thunk.cabal b/nix-thunk.cabal
--- a/nix-thunk.cabal
+++ b/nix-thunk.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               nix-thunk
-version:            0.7.2.2
+version:            0.7.3.0
 license:            BSD3
 license-file:       LICENSE
 copyright:          Obsidian Systems LLC 2020-2022
@@ -75,4 +75,4 @@
 
 source-repository head
   type:     git
-  location: git://github.com/obsidiansystems/nix-thunk.git
+  location: https://github.com/obsidiansystems/nix-thunk.git
diff --git a/src/Nix/Thunk.hs b/src/Nix/Thunk.hs
--- a/src/Nix/Thunk.hs
+++ b/src/Nix/Thunk.hs
@@ -1,5 +1,6 @@
 module Nix.Thunk
-  ( ThunkSource (..)
+  ( runMonadNixThunk
+  , ThunkSource (..)
   , GitHubSource (..)
   , ThunkRev (..)
   , getLatestRev
diff --git a/src/Nix/Thunk/Command.hs b/src/Nix/Thunk/Command.hs
--- a/src/Nix/Thunk/Command.hs
+++ b/src/Nix/Thunk/Command.hs
@@ -5,7 +5,6 @@
 import Cli.Extras (HasCliConfig, Output)
 import Control.Monad.Catch (MonadMask)
 import Control.Monad.Error.Class (MonadError)
-import Control.Monad.Fail (MonadFail)
 import Control.Monad.IO.Class (MonadIO)
 import Control.Monad.Log (MonadLog)
 import Data.List.NonEmpty (NonEmpty(..))
diff --git a/src/Nix/Thunk/Internal.hs b/src/Nix/Thunk/Internal.hs
--- a/src/Nix/Thunk/Internal.hs
+++ b/src/Nix/Thunk/Internal.hs
@@ -8,6 +8,7 @@
 {-# LANGUAGE MultiWayIf #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TemplateHaskell #-}
@@ -35,7 +36,6 @@
 import Control.Monad.Catch (MonadCatch, MonadMask, handle)
 import Control.Monad.Except
 import Control.Monad.Extra (findM)
-import Control.Monad.Fail (MonadFail)
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Control.Monad.Log (MonadLog)
 import Crypto.Hash (Digest, HashAlgorithm, SHA1, digestFromByteString)
@@ -70,7 +70,6 @@
 import qualified Data.Text.IO as T
 import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
 import Data.Traversable
-import Data.Typeable (Typeable)
 import Data.Yaml (parseMaybe)
 import GitHub
 import GitHub.Data.Name
@@ -99,6 +98,12 @@
   , MonadFail m
   )
 
+-- | Runs a 'MonadNixThunk' action without interactive terminal output.
+runMonadNixThunk :: forall a. (forall m. MonadNixThunk m => m a) -> IO (Either NixThunkError a)
+runMonadNixThunk x = do
+  cliConf <- newCliConfig Error True True (\e -> (prettyNixThunkError e, ExitFailure 1))
+  runCli cliConf $ catchError (Right <$> x) (pure . Left)
+
 data NixThunkError
    = NixThunkError_ProcessFailure ProcessFailure
    | NixThunkError_Unstructured Text
@@ -432,7 +437,7 @@
   => NonEmpty (NonEmpty ThunkSpec) -> FilePath -> m (Either ReadThunkError ThunkData)
 readThunkWith specTypes dir = do
   dirFiles <- Set.fromList <$> liftIO (listDirectory dir)
-  let specs = concatMap toList $ toList $ NonEmpty.transpose specTypes -- Interleave spec types so we try each one in a "fair" ordering
+  let specs = concatMap toList (NonEmpty.transpose specTypes) -- Interleave spec types so we try each one in a "fair" ordering
   flip fix specs $ \loop -> \case
     [] -> pure $ Left ReadThunkError_UnrecognizedThunk
     spec:rest -> runExceptT (matchThunkSpecToDir spec dir dirFiles) >>= \case
@@ -1658,12 +1663,12 @@
 
 -- | Represent a git reference (SHA1)
 newtype Ref hash = Ref { unRef :: Digest hash }
-  deriving (Eq, Ord, Typeable)
+  deriving (Eq, Ord)
 
 -- | Invalid Reference exception raised when
 -- using something that is not a ref as a ref.
 newtype RefInvalid = RefInvalid { unRefInvalid :: ByteString }
-  deriving (Show, Eq, Data, Typeable)
+  deriving (Show, Eq, Data)
 
 instance Exception RefInvalid
 
