diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,25 @@
+# Unreleased
+
+# 0.5.1.0
+
+* Add `untilJust`, a combinator that repeatedly executes an action until it returns `Just`, sleeping in between.
+
+# 0.5.0.0
+* Change the behaviour of `interceptTimeConstantState` so that sleeping polls the current time until it has been
+  adjusted further than the sleep duration.
+* Add `since`, a convenience combinator that diffs the current time against a reference instant.
+
+# 0.1.4.0
+* Add `secondsFrac`, a combinator that converts a unit into a fractional number of seconds.
+* Add combinators for repeatedly running an action with a sleep interval
+* Add interpreters that remain at a fixed instant
+
+# 0.1.3.0
+* Added `measure`, a combinator that returns the time span an action takes.
+
+# 0.1.1.0
+* Added `Time.Adjust`, an action that takes a time unit and adds it to the custom start time, if available.
+* Added `Fractional` instances for sub-second time units that treat literals as seconds.
+
+# 0.1.0.0
+* initial release
diff --git a/lib/Polysemy/Time.hs b/lib/Polysemy/Time.hs
--- a/lib/Polysemy/Time.hs
+++ b/lib/Polysemy/Time.hs
@@ -28,6 +28,7 @@
   -- * Combinators
   measure,
   while,
+  untilJust,
   loop,
   loop_,
   diff,
@@ -67,7 +68,7 @@
   interpretTimeGhcConstant,
   interpretTimeGhcConstantNow,
   )
-import Polysemy.Time.Loop (loop, loop_, while)
+import Polysemy.Time.Loop (loop, loop_, while, untilJust)
 import Polysemy.Time.Measure (measure)
 import Polysemy.Time.Orphans ()
 
diff --git a/lib/Polysemy/Time/At.hs b/lib/Polysemy/Time/At.hs
--- a/lib/Polysemy/Time/At.hs
+++ b/lib/Polysemy/Time/At.hs
@@ -1,3 +1,5 @@
+{-# options_haddock prune #-}
+
 -- |Interceptors for fixing a specific time, Internal
 module Polysemy.Time.At where
 
diff --git a/lib/Polysemy/Time/Effect/Time.hs b/lib/Polysemy/Time/Effect/Time.hs
--- a/lib/Polysemy/Time/Effect/Time.hs
+++ b/lib/Polysemy/Time/Effect/Time.hs
@@ -16,7 +16,7 @@
   -- |Set the current time, if the interpreter supports it.
   SetTime :: t -> Time t d m ()
   -- |Adjust the current time relatively, if the interpreter supports it.
-  Adjust :: AddTimeUnit t u1 u2 => u1 -> Time t d m ()
+  Adjust :: TimeUnit u1 => u1 -> Time t d m ()
   -- |Set the current date, if the interpreter supports it.
   SetDate :: d -> Time t d m ()
 
diff --git a/lib/Polysemy/Time/Loop.hs b/lib/Polysemy/Time/Loop.hs
--- a/lib/Polysemy/Time/Loop.hs
+++ b/lib/Polysemy/Time/Loop.hs
@@ -1,9 +1,26 @@
 -- |Combinators for looping with a sleep interval, Internal
 module Polysemy.Time.Loop where
 
+import Polysemy.Time.Data.TimeUnit (TimeUnit)
 import qualified Polysemy.Time.Effect.Time as Time
 import Polysemy.Time.Effect.Time (Time)
-import Polysemy.Time.Data.TimeUnit (TimeUnit)
+
+-- |Repeatedly run the @action@, sleeping for @interval@ between executions.
+-- Stops when @action@ returns @Just a@, returning the contained @a@.
+untilJust ::
+  ∀ t d u r a .
+  Member (Time t d) r =>
+  TimeUnit u =>
+  u ->
+  Sem r (Maybe a) ->
+  Sem r a
+untilJust interval action =
+  spin
+  where
+    spin =
+      action >>= \case
+        Just a -> pure a
+        Nothing -> Time.sleep @t @d interval *> spin
 
 -- |Repeatedly run the @action@, sleeping for @interval@ between executions.
 -- Stops when @action@ returns @False@.
diff --git a/polysemy-time.cabal b/polysemy-time.cabal
--- a/polysemy-time.cabal
+++ b/polysemy-time.cabal
@@ -1,11 +1,11 @@
 cabal-version: 2.2
 
--- This file has been generated from package.yaml by hpack version 0.34.6.
+-- This file has been generated from package.yaml by hpack version 0.34.7.
 --
 -- see: https://github.com/sol/hpack
 
 name:           polysemy-time
-version:        0.5.0.0
+version:        0.5.1.0
 synopsis:       Polysemy effects for time
 description:    See https://hackage.haskell.org/package/polysemy-time/docs/Polysemy-Time.html
 category:       Time
@@ -17,6 +17,9 @@
 license:        BSD-2-Clause-Patent
 license-file:   LICENSE
 build-type:     Simple
+extra-source-files:
+    changelog.md
+    readme.md
 
 source-repository head
   type: git
@@ -60,6 +63,7 @@
       DisambiguateRecordFields
       DoAndIfThenElse
       DuplicateRecordFields
+      EmptyCase
       EmptyDataDecls
       ExistentialQuantification
       FlexibleContexts
@@ -74,8 +78,9 @@
       MultiParamTypeClasses
       MultiWayIf
       NamedFieldPuns
-      OverloadedStrings
+      OverloadedLabels
       OverloadedLists
+      OverloadedStrings
       PackageImports
       PartialTypeSignatures
       PatternGuards
@@ -144,6 +149,7 @@
       DisambiguateRecordFields
       DoAndIfThenElse
       DuplicateRecordFields
+      EmptyCase
       EmptyDataDecls
       ExistentialQuantification
       FlexibleContexts
@@ -158,8 +164,9 @@
       MultiParamTypeClasses
       MultiWayIf
       NamedFieldPuns
-      OverloadedStrings
+      OverloadedLabels
       OverloadedLists
+      OverloadedStrings
       PackageImports
       PartialTypeSignatures
       PatternGuards
diff --git a/readme.md b/readme.md
new file mode 100644
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,89 @@
+# About
+
+This Haskell library provides a [Polysemy] effect for accessing the current time and date, and interpreters using
+[time].
+
+# Example
+
+```haskell
+import Data.Time (UTCTime)
+import Polysemy (Members, runM)
+import qualified Polysemy.Time as Time
+import Polysemy.Time (MilliSeconds(MilliSeconds), Seconds(Seconds), Time, interpretTimeGhcAt, mkDatetime, year)
+
+prog ::
+  Ord t =>
+  Members [Time t d, Embed IO] r =>
+  Sem r ()
+prog = do
+  time1 <- Time.now
+  Time.sleep (MilliSeconds 10)
+  time2 <- Time.now
+  print (time1 < time2)
+  -- True
+
+testTime :: UTCTime
+testTime =
+  mkDatetime 1845 12 31 23 59 59
+
+main :: IO ()
+main =
+  runM do
+    interpretTimeGhcAt testTime do
+      Time.sleep (Seconds 1)
+      time <- Time.now
+      print (year time)
+      -- Years { unYear = 1846 }
+```
+
+# Effect
+
+The only effect contained in **polysemy-time** is:
+
+```haskell
+data Time (time :: Type) (date :: Type) :: Effect where
+  Now :: Time t d m t
+  Today :: Time t d m d
+  Sleep :: TimeUnit u => u -> Time t d m ()
+  SetTime :: t -> Time t d m ()
+  SetDate :: d -> Time t d m ()
+```
+
+Interpreters are provided for the [time library](time) bundled with GHC.
+The project [polysemy-chronos] contains an alternative implementation for [chronos].
+
+The type parameters correspond to the representations in the implementation,
+like `Data.Time.UTCTime`/`Chronos.Time` and `Data.Time.Day`/`Chronos.Date`.
+
+`SetTime` and `SetDate` only have meaning when you're running in a testing context.
+
+A special interpreter variant suffixed with `At` exists for both
+implementations, with which the current time is overridden to be relative to
+the supplied override fixed at the start of interpretation.
+This is useful for testing.
+
+# Utilities
+
+A set of newtypes representing timespans are provided for convenience.
+Internally, the interpreters operate on `NanoSecond`s.
+
+The class `TimeUnit` ties those types, and the types `Chronos.Timespan` and
+`Data.Time.DiffTime`, together to allow you to convert between them with the
+function `convert`:
+
+```haskell
+>>> convert (picosecondsToDiffTime 50000000) :: MicroSeconds
+MicroSeconds {unMicroSeconds = 50}
+
+>>> convert (Days 5) :: Timespan
+Timespan {getTimespan = 432000000000000}
+```
+
+The class `Calendar` allows you to construct `UTCTime` and `Chronos.Datetime`
+from integers with the function `mkDatetime`, as demonstrated in the first
+example.
+
+[Polysemy]: https://hackage.haskell.org/package/polysemy
+[time]: https://hackage.haskell.org/package/time
+[chronos]: https://hackage.haskell.org/package/chronos
+[polysemy-chronos]: https://hackage.haskell.org/package/polysemy-chronos
