diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,9 @@
+0.2.0.1 (2023-02-09)
+----------------------------------------------------------------
+
+Corrections and improvements to `readme.md`
+
+
 0.2.0.0 (2023-02-08)
 ----------------------------------------------------------------
 
diff --git a/hash-addressed.cabal b/hash-addressed.cabal
--- a/hash-addressed.cabal
+++ b/hash-addressed.cabal
@@ -1,7 +1,7 @@
 cabal-version: 3.0
 
 name: hash-addressed
-version: 0.2.0.0
+version: 0.2.0.1
 synopsis: Hash-addressed file storage
 category: Hash, Filesystem
 
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -2,52 +2,90 @@
 file's name is a hash of its content.
 
 ```haskell
-import qualified HashAddressed.Directory    as Dir
-import qualified HashAddressed.HashFunction as Hash
-import qualified Data.ByteString.Lazy       as Lazy
-import qualified Data.ByteString            as Strict
+import HashAddressed.Directory
+import HashAddressed.HashFunction
 ```
 
-First define a `ContentAddressedDirectory` value by specifying which hash
-function to use and the path of the directory in which the files shall be kept.
-The directory does not need to already exist.
-
 ```haskell
-Dir.init :: Hash.HashFunction -> FilePath
-    -> Dir.ContentAddressedDirectory
+import qualified Data.ByteString.Lazy as Lazy
+import qualified Data.ByteString as Strict
+import qualified Pipes
 ```
 
-Presently the only supported hash function is `Hash.SHA_256`.
+### `Directory`
 
-You can then write files into the directory using one of the two *write*
-functions:
+First define a `Directory` value by specifying which hash function to use and
+the path of the directory in which the files shall be kept.
 
 ```haskell
-Dir.writeLazy :: Dir.ContentAddressedDirectory
-    -> Lazy.ByteString -> IO Dir.WriteResult
+data Directory = Directory { directoryPath :: FilePath,
+                             hashFunction :: HashFunction }
 ```
 
+Presently the only supported hash function is `sha256`.
+
+Ensure that `directoryPath` is the path of an existing directory. You can then
+write files into the directory using one of three *write* functions:
+`writeLazy`, `writeStream`, and `writeExcept`.
+
+### `writeLazy`
+
+`writeLazy` is the simplest to use; just give it a lazy `ByteString`.
+
 ```haskell
-Dir.writeStreaming :: Dir.ContentAddressedDirectory
-    -> (forall m. MonadIO m => (Strict.ByteString -> m ()) -> m ())
-    -> IO Dir.WriteResult
+writeLazy :: forall m. MonadIO m =>
+    Directory -> Lazy.ByteString -> m WriteResult
 ```
 
-The `IO` action returns a `WriteResult`, which gives you the path of the file in
-the store, including the path of the store itself. The `WriteType` value
-indicates whether the file was actually written by this action or was present in
-the store already.
-
 ```haskell
-data WriteResult = WriteResult{ contentAddressedFile :: FilePath,
-                                writeType :: Dir.WriteType }
+data WriteResult = WriteResult{ hashAddressedFile :: FilePath,
+                                writeType :: WriteType }
 ```
 
 ```haskell
 data WriteType = AlreadyPresent | NewContent
 ```
 
-All operations that write into a hash-addressed directory are performed by first
-writing the content somewhere within the system temporary directory and then
-moving the file to its target location. This ensures that the store never makes
-visible the results of a partial write.
+`WriteResult` gives you the path of the file in the store, including the path of
+the store itself. Because a hash-addressed store can never contain duplicate
+files, writing a file has no effect if the content is already present; the
+`WriteType` value indicates whether the file was actually written by this action
+or was present in the store already.
+
+### `writeStream`
+
+The limitation of `writeLazy` is that it doesn't allow streaming. Thus enters
+`writeStream`, which uses a pipes `Producer` to represent the content. The
+producer can perform `IO` while generating stream content (for example, perhaps
+it reads byte strings from a network socket). The producer can also return a
+value (the `commit` type parameter) that will be returned alongside the
+`WriteResult`.
+
+```haskell
+writeStream :: forall commit m. MonadIO m =>
+    Directory
+    -> Pipes.Producer Strict.ByteString IO commit
+    -> m (commit, WriteResult)
+```
+
+All operations that write into a hash-addressed `Directory` are performed by
+first writing the content somewhere within the system temporary directory and
+then moving the file to its target location. This ensures that the store never
+makes visible the results of a partial write. If the producer throws an
+exception, everything written so far will be deleted and no content will be
+written to the `Directory`.
+
+### `writeExcept`
+
+If there is some interesting way in which your stream can fail, you may wish to
+use `writeExcept` instead. In this variant, the producer returns an
+`Either abort commit` indicating whether the result should be committed to the
+store. Return a `Left` result to signal that an error has occurred. The
+`writeExcept` action will then throw the `abort` value into a `MonadError`
+context.
+
+```haskell
+writeExcept :: forall abort commit m. (MonadIO m, MonadError abort m) =>
+    Directory -> Pipes.Producer Strict.ByteString IO (Either abort commit)
+    -> m (commit, WriteResult)
+```
