diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,29 +1,37 @@
 # ChangeLog for time-manager
 
+## 0.3.1.1
+
+* Added `README.md` file and improved documentation of modules and functions.
+  [#1057](https://github.com/yesodweb/wai/pull/1057)
+
 ## 0.3.1
 
 BUGFIXES:
 
-* `resume` now acts as a `tickle` if the `Handle` isn't paused.
-  This is the same behaviour as before version `0.3.0`.
-* `registerKillThread` now throws the `TimeoutThread` in a separate
-  thread, so as to not block the GHC's System TimerManager.
-  This does mean that `TimeoutThread` exceptions could technically
-  be thrown "out of order", but they will be more prompt.
+* [#1055](https://github.com/yesodweb/wai/pull/1055)
+  * `resume` now acts as a `tickle` if the `Handle` isn't paused.
+    This is the same behaviour as before version `0.3.0`.
+  * `registerKillThread` now throws the `TimeoutThread` in a separate
+    thread, so as to not block the GHC's System TimerManager.
+    This does mean that `TimeoutThread` exceptions could technically
+    be thrown "out of order", but they will be more prompt.
 
+
 ## 0.3.0
 
-* New architecture. The backend is switched from the designated thread
-  to GHC's System TimerManager. From this version, this library is
-  just wrapper APIs of GHC's System TimerManager. Unlike v0.2 or
-  earlier, callbacks are executed at the exact time. System
-  TimerManager uses a PSQ (a tree) while v0.2 or earlier uses a list.
-  So, this version hopefully scales better.
-* Deprecated functions: `stopManager`, `killManager` and `withManager'`.
-* `tickle` sets the specified timeout from now.
-* `pause` is now identical to `cancel`.
-* `resume` is now re-registration of timeout.
-* The signature of `withHandle` is changed.
+* [#1048](https://github.com/yesodweb/wai/pull/1048)
+  * New architecture. The backend is switched from the designated thread
+    to GHC's System TimerManager. From this version, this library is
+    just wrapper APIs of GHC's System TimerManager. Unlike v0.2 or
+    earlier, callbacks are executed at the exact time. System
+    TimerManager uses a PSQ (a tree) while v0.2 or earlier uses a list.
+    So, this version hopefully scales better.
+  * Deprecated functions: `stopManager`, `killManager` and `withManager'`.
+  * `tickle` sets the specified timeout from now.
+  * `pause` is now identical to `cancel`.
+  * `resume` is now re-registration of timeout.
+  * The signature of `withHandle` is changed.
 
 ## 0.2.4
 
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+## time-manager
+
+This package provides module to let you run actions with resettable timeouts
+(i.e. `System.TimeManager`) and run actions that will make sure that all
+threads forked with the given `ThreadManager` will be killed when the action
+finishes.
+
+## WARNINGS
+
+Since version `0.3.0`, **the timeout manager relies on GHC internals**.
+This change also means that using **this package only works with the threaded**
+**runtime**. The moment a timeout is registered on a non-threaded runtime, an
+exception will be thrown.
diff --git a/System/ThreadManager.hs b/System/ThreadManager.hs
--- a/System/ThreadManager.hs
+++ b/System/ThreadManager.hs
@@ -4,6 +4,17 @@
 
 -- | A thread manager including a time manager.
 --   The manager has responsibility to kill managed threads.
+--
+-- Because this is based on the accompanying "System.TimeManager" module,
+-- the same caveats apply:
+--
+--   * Only works for GHC.
+--   * Only works with a threaded runtime.
+--   * Users of older versions should check the current semantics.
+--   * Using 32-bit systems means the max timeout is @'maxBound' :: Int@
+--     (2147483647) microseconds, which is less than 36 minutes.
+--   * Using the same 'Handle' in different threads might cause issues in some
+--     edge cases. (i.e. using cancel/pause in one thread, and resume in another)
 module System.ThreadManager (
     ThreadManager,
     newThreadManager,
@@ -36,7 +47,7 @@
 import qualified Control.Exception as E
 import Control.Monad (unless, void)
 import Data.Foldable (forM_)
-import Data.IORef
+import Data.IORef (IORef, atomicModifyIORef', newIORef)
 import Data.Map.Strict (Map)
 import qualified Data.Map.Strict as Map
 import Data.Word (Word64)
@@ -65,10 +76,12 @@
 
 ----------------------------------------------------------------
 
--- | Starting a thread manager.
---   Its action is initially set to 'return ()' and should be set
---   by 'setAction'. This allows that the action can include
---   the manager itself.
+-- | Create a thread manager.
+--
+-- To create a 'ThreadManager', you will first have to create a
+-- 'T.Manager' from the "System.TimeManager" module.
+--
+-- You can use either 'System.TimeManager.initialize' or 'System.TimeManager.withManager'.
 newThreadManager :: T.Manager -> IO ThreadManager
 newThreadManager timmgr = ThreadManager timmgr <$> newTVarIO Map.empty
 
@@ -84,6 +97,10 @@
 
 -- | Stopping the manager.
 --
+-- @
+-- stopAfter threadManager action cleanup
+-- @
+--
 -- The action is run in the scope of an exception handler that catches all
 -- exceptions (including asynchronous ones); this allows the cleanup handler
 -- to cleanup in all circumstances. If an exception is caught, it is rethrown
@@ -123,14 +140,25 @@
 
 -- | Like 'forkManaged', but run action with exceptions masked
 forkManagedUnmask
-    :: ThreadManager -> String -> ((forall x. IO x -> IO x) -> IO ()) -> IO ()
+    :: ThreadManager
+    -> String
+    -- ^ Thread name
+    -> ((forall x. IO x -> IO x) -> IO ())
+    -- ^ Action with unmask argument
+    -> IO ()
 forkManagedUnmask (ThreadManager _timmgr var) label io =
     void $ E.mask_ $ forkIOWithUnmask $ \unmask -> E.handle ignore $ do
         labelMe label
         E.bracket (setup var) (clear var) $ \_ -> io unmask
 
 -- | Fork a managed thread with a handle created by a timeout manager.
-forkManagedTimeout :: ThreadManager -> String -> (T.Handle -> IO ()) -> IO ()
+forkManagedTimeout
+    :: ThreadManager
+    -> String
+    -- ^ Thread name
+    -> (T.Handle -> IO ())
+    -- ^ Action with timeout handle
+    -> IO ()
 forkManagedTimeout (ThreadManager timmgr var) label io =
     void $ forkIO $ do
         labelMe label
@@ -140,26 +168,37 @@
     ex = KilledByThreadManager Nothing
 
 -- | Fork a managed thread with a cleanup function.
-forkManagedFinally :: ThreadManager -> String -> IO () -> IO () -> IO ()
-forkManagedFinally mgr label io final = E.mask $ \restore ->
-    forkManaged
-        mgr
-        label
-        (E.try (restore io) >>= \(_ :: Either E.SomeException ()) -> final)
+forkManagedFinally
+    :: ThreadManager
+    -> String
+    -- ^ Thread name
+    -> IO ()
+    -- ^ Action
+    -> IO ()
+    -- ^ Cleanup function
+    -> IO ()
+forkManagedFinally mgr label io final =
+    forkManagedUnmask mgr label $ \restore ->
+        E.try (restore io) >>= \(_ :: Either E.SomeException ()) -> final
 
 -- | Fork a managed thread with a handle created by a timeout manager
 -- and with a cleanup function.
 forkManagedTimeoutFinally
-    :: ThreadManager -> String -> (T.Handle -> IO ()) -> IO () -> IO ()
+    :: ThreadManager
+    -> String
+    -- ^ Thread name
+    -> (T.Handle -> IO ())
+    -- ^ Action with timeout handle
+    -> IO ()
+    -- ^ Cleanup function
+    -> IO ()
 forkManagedTimeoutFinally mgr label io final = E.mask $ \restore ->
-    forkManagedTimeout
-        mgr
-        label
-        (\th -> E.try (restore $ io th) >>= \(_ :: Either E.SomeException ()) -> final)
+    forkManagedTimeout mgr label $ \th ->
+        E.try (restore $ io th) >>= \(_ :: Either E.SomeException ()) -> final
 
 setup :: TVar (Map Key ManagedThread) -> IO (Key, Weak ThreadId, IORef Bool)
 setup var = do
-    (wtid, n) <- myWeakThradId
+    (wtid, n) <- myWeakThreadId
     ref <- newIORef False
     let ent = ManagedThread wtid ref
     -- asking to throw KilledByThreadManager to me
@@ -184,21 +223,21 @@
 ignore :: KilledByThreadManager -> IO ()
 ignore (KilledByThreadManager _) = return ()
 
--- | Wait until all managed thread are finished.
+-- | Wait until all managed threads are finished.
 waitUntilAllGone :: ThreadManager -> IO ()
-waitUntilAllGone (ThreadManager _timmgr var) = atomically $ do
-    m <- readTVar var
-    check (Map.size m == 0)
+waitUntilAllGone tm =
+    atomically $
+        isAllGone tm >>= check
 
+-- | STM action that checks if all managed threads are finished.
 isAllGone :: ThreadManager -> STM Bool
-isAllGone (ThreadManager _timmgr var) = do
-    m <- readTVar var
-    return (Map.size m == 0)
+isAllGone (ThreadManager _timmgr var) =
+    Map.null <$> readTVar var
 
 ----------------------------------------------------------------
 
-myWeakThradId :: IO (Weak ThreadId, Key)
-myWeakThradId = do
+myWeakThreadId :: IO (Weak ThreadId, Key)
+myWeakThreadId = do
     tid <- myThreadId
     wtid <- mkWeakThreadId tid
     let n = fromThreadId tid
@@ -209,6 +248,8 @@
     tid <- myThreadId
     labelThread tid l
 
+-- | Registering a 'T.TimeoutAction' and unregister its 'T.Handle'
+--   when the body action is finished.
 withHandle
     :: ThreadManager -> T.TimeoutAction -> (T.Handle -> IO a) -> IO a
 withHandle (ThreadManager timmgr _) = T.withHandle timmgr
diff --git a/System/TimeManager.hs b/System/TimeManager.hs
--- a/System/TimeManager.hs
+++ b/System/TimeManager.hs
@@ -5,6 +5,7 @@
 -- GHC System TimerManager.
 --
 -- Some caveats of using this package:
+--
 --   * Only works for GHC
 --   * Only works with a threaded runtime
 --   * Users of older versions should check the current semantics.
diff --git a/time-manager.cabal b/time-manager.cabal
--- a/time-manager.cabal
+++ b/time-manager.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               time-manager
-version:            0.3.1
+version:            0.3.1.1
 license:            MIT
 license-file:       LICENSE
 maintainer:         kazu@iij.ad.jp
@@ -16,6 +16,7 @@
 category:           System
 build-type:         Simple
 extra-source-files: ChangeLog.md
+                    README.md
 
 library
     exposed-modules:
