diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.0.1.0
+
+* Add `Bluefin.Writer`
+
 ## 0.0.0.0
 
 * Initial version
diff --git a/bluefin.cabal b/bluefin.cabal
--- a/bluefin.cabal
+++ b/bluefin.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               bluefin
-version:            0.0.0.0
+version:            0.0.1.0
 license:            MIT
 license-file:       LICENSE
 author:             Tom Ellis
@@ -28,7 +28,8 @@
       Bluefin.IO,
       Bluefin.State,
       Bluefin.Stream,
+      Bluefin.Writer,
     build-depends:
-      bluefin-internal < 0.1
+      bluefin-internal >= 0.0.1 && < 0.1
     hs-source-dirs:   src
     default-language: Haskell2010
diff --git a/src/Bluefin.hs b/src/Bluefin.hs
--- a/src/Bluefin.hs
+++ b/src/Bluefin.hs
@@ -124,26 +124,26 @@
     --
     -- It would be great to share code between the two projects!  But
     -- there are two Bluefin features that I don't know to implement
-    -- in terms of effectful: 'Bluefin.Bluefin.Coroutine's and
-    -- 'Bluefin.Bluefin.Compound' effects.
+    -- in terms of effectful: "Bluefin.Coroutine"s and
+    -- "Bluefin.Compound" effects.
 
     -- * Implementation
 
     -- | Bluefin has a similar implementation style to effectful.
-    -- 'Bluefin.Eff.Eff' is an opaque wrapper around 'IO',
-    -- 'Bluefin.State.State' is an opaque wrapper around
+    -- t'Bluefin.Eff.Eff' is an opaque wrapper around 'IO',
+    -- t'Bluefin.State.State' is an opaque wrapper around
     -- 'Data.IORef.IORef', and 'Bluefin.Exception.throw' throws an
-    -- actual @IO@ exception.  'Bluefin.Coroutine.Coroutine', which
+    -- actual @IO@ exception.  t'Bluefin.Coroutine.Coroutine', which
     -- doesn't exist in effectful, is implemented simply as a
     -- function.
     --
     -- @
-    -- newtype 'Bluefin.Eff.Eff' (es :: 'Bluefin.Eff.Effects') a = 'Bluefin.Internal.UnsafeMkEff' (IO a)
-    -- newtype 'Bluefin.State.State' s (st :: Effects) = 'Bluefin.Internal.UnsafeMkState' (IORef s)
-    -- newtype 'Bluefin.Coroutine.Coroutine' a b (s :: Effects) = 'Bluefin.Internal.UnsafeMkCoroutine' (a -> IO b)
+    -- newtype t'Bluefin.Eff.Eff' (es :: 'Bluefin.Eff.Effects') a = 'Bluefin.Internal.UnsafeMkEff' (IO a)
+    -- newtype t'Bluefin.State.State' s (st :: Effects) = 'Bluefin.Internal.UnsafeMkState' (IORef s)
+    -- newtype t'Bluefin.Coroutine.Coroutine' a b (s :: Effects) = 'Bluefin.Internal.UnsafeMkCoroutine' (a -> IO b)
     -- @
     --
-    -- The type parameters of kind 'Bluefin.Eff.Effects' are phantom
+    -- The type parameters of kind t'Bluefin.Eff.Effects' are phantom
     -- type parameters which track which effects can be used in an
     -- operation. Bluefin uses them to ensure that effects cannot
     -- escape the scope of their handler, in the same way that the
@@ -157,7 +157,8 @@
     -- * Tips
 
     -- | * Use @NoMonoLocalBinds@ and @NoMonomorphismRestriction@ for
-    -- better type inference.
+    -- better type inference.  (You can always change back to the
+    -- default after adding inferred type signatures.)
     --
     -- * Writing a handler often requires an explicit type signature.
 
diff --git a/src/Bluefin/Writer.hs b/src/Bluefin/Writer.hs
new file mode 100644
--- /dev/null
+++ b/src/Bluefin/Writer.hs
@@ -0,0 +1,17 @@
+module Bluefin.Writer
+  ( -- | In most cases you'll probably prefer t'Bluefin.Stream.Stream'
+    -- to @Writer@, but @Writer@ can still be useful in some cases,
+    -- for example with @Data.Monoid.'Data.Monoid.Any'@ to determine
+    -- whether an event ever occurred.
+
+    -- * Handle
+    Writer,
+    -- * Handlers
+    runWriter,
+    execWriter,
+    -- * Effectful operations
+    tell,
+  )
+where
+
+import Bluefin.Internal
