diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog for unliftio
 
+## 0.2.13.1
+
+* Improve `UnliftIO.Exception` documentation
+
 ## 0.2.13
 
 * Add `UnliftIO.STM.orElse`
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # unliftio
 
-[![Build Status](https://dev.azure.com/fpco/unliftio/_apis/build/status/fpco.unliftio?branchName=master)](https://dev.azure.com/fpco/unliftio/_build/latest?definitionId=3&branchName=master)
+![Tests](https://github.com/fpco/unliftio/workflows/Tests/badge.svg)
 
 
 Provides the core `MonadUnliftIO` typeclass, a number of common
@@ -131,31 +131,33 @@
 pre-unlifted versions of functions (like
 `UnliftIO.Exception.catch`). But ultimately, you'll probably want to
 use the typeclass directly. The type class has only one method --
-`askUnliftIO`:
+`withRunInIO`:
 
 ```haskell
-newtype UnliftIO m = UnliftIO { unliftIO :: forall a. m a -> IO a }
-
 class MonadIO m => MonadUnliftIO m where
-  askUnliftIO :: m (UnliftIO m)
+  withRunInIO :: ((forall a. m a -> IO a) -> IO b) -> m b
 ```
 
-`askUnliftIO` gives us a function to run arbitrary computation in `m`
+`withRunInIO` provides a function to run arbitrary computations in `m`
 in `IO`. Thus the "unlift": it's like `liftIO`, but the other way around.
 
 Here are some sample typeclass instances:
 
 ```haskell
 instance MonadUnliftIO IO where
-  askUnliftIO = return (UnliftIO id)
-instance MonadUnliftIO m => MonadUnliftIO (IdentityT m) where
-  askUnliftIO = IdentityT $
-                withUnliftIO $ \u ->
-                return (UnliftIO (unliftIO u . runIdentityT))
+  withRunInIO inner = inner id
+
 instance MonadUnliftIO m => MonadUnliftIO (ReaderT r m) where
-  askUnliftIO = ReaderT $ \r ->
-                withUnliftIO $ \u ->
-                return (UnliftIO (unliftIO u . flip runReaderT r))
+  withRunInIO inner =
+    ReaderT $ \r ->
+    withRunInIO $ \run ->
+    inner (run . flip runReaderT r)
+
+instance MonadUnliftIO m => MonadUnliftIO (IdentityT m) where
+  withRunInIO inner =
+    IdentityT $
+    withRunInIO $ \run ->
+    inner (run . runIdentityT)
 ```
 
 Note that:
@@ -163,21 +165,12 @@
 * The `IO` instance does not actually do any lifting or unlifting, and
   therefore it can use `id`
 * `IdentityT` is essentially just wrapping/unwrapping its data
-  constructor, and then recursively calling `withUnliftIO` on the
+  constructor, and then recursively calling `withRunInIO` on the
   underlying monad.
 * `ReaderT` is just like `IdentityT`, but it captures the reader
   environment when starting.
 
-We can use `askUnliftIO` to unlift a function:
-
-```haskell
-timeout :: MonadUnliftIO m => Int -> m a -> m (Maybe a)
-timeout x y = do
-  (u :: UnliftIO m) <- askUnliftIO
-  liftIO $ System.Timeout.timeout x $ unliftIO u y
-```
-
-or more concisely using `withRunInIO`:
+We can use `withRunInIO` to unlift a function:
 
 ```haskell
 timeout :: MonadUnliftIO m => Int -> m a -> m (Maybe a)
diff --git a/src/UnliftIO/Exception.hs b/src/UnliftIO/Exception.hs
--- a/src/UnliftIO/Exception.hs
+++ b/src/UnliftIO/Exception.hs
@@ -9,7 +9,7 @@
 --
 -- This module works best when your cleanup functions adhere to certain
 -- expectations around exception safety and interruptible actions.
--- For more details, see [this exception safety tutorial](https://haskell.fpcomplete.com/tutorial/exceptions).
+-- For more details, see [this exception safety tutorial](https://www.fpcomplete.com/haskell/tutorial/exceptions/).
 module UnliftIO.Exception
   ( -- * Throwing
     throwIO
@@ -101,10 +101,17 @@
 import GHC.Stack.Types (HasCallStack, CallStack, getCallStack)
 #endif
 
--- | Unlifted 'EUnsafe.catch', but will not catch asynchronous exceptions.
+-- | Catch a synchronous (but not asynchronous) exception and recover from it.
 --
+-- This is parameterized on the exception type. To catch all synchronous exceptions,
+-- use 'catchAny'.
+--
 -- @since 0.1.0.0
-catch :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a
+catch
+  :: (MonadUnliftIO m, Exception e)
+  => m a -- ^ action
+  -> (e -> m a) -- ^ handler
+  -> m a
 catch f g = withRunInIO $ \run -> run f `EUnsafe.catch` \e ->
   if isSyncException e
     then run (g e)
@@ -118,7 +125,7 @@
 catchIO :: MonadUnliftIO m => m a -> (IOException -> m a) -> m a
 catchIO = catch
 
--- | 'catch' specialized to catch all synchronous exception.
+-- | 'catch' specialized to catch all synchronous exceptions.
 --
 -- @since 0.1.0.0
 catchAny :: MonadUnliftIO m => m a -> (SomeException -> m a) -> m a
@@ -182,8 +189,11 @@
 handleJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a
 handleJust f = flip (catchJust f)
 
--- | Unlifted 'EUnsafe.try', but will not catch asynchronous exceptions.
+-- | Run the given action and catch any synchronous exceptions as a 'Left' value.
 --
+-- This is parameterized on the exception type. To catch all synchronous exceptions,
+-- use 'tryAny'.
+--
 -- @since 0.1.0.0
 try :: (MonadUnliftIO m, Exception e) => m a -> m (Either e a)
 try f = catch (liftM Right f) (return . Left)
@@ -235,7 +245,7 @@
 pureTryDeep :: NFData a => a -> Either SomeException a
 pureTryDeep = unsafePerformIO . tryAnyDeep . return
 
--- | Generalized version of 'EUnsafe.Handler'.
+-- | A helper data type for usage with 'catches' and similar functions.
 --
 -- @since 0.1.0.0
 data Handler m a = forall e . Exception e => Handler (e -> m a)
@@ -248,9 +258,11 @@
                 Just e' -> handler e'
                 Nothing -> res
 
--- | Same as upstream 'EUnsafe.catches', but will not catch
--- asynchronous exceptions.
+-- | Similar to 'catch', but provides multiple different handler functions.
 --
+-- For more information on motivation, see @base@'s 'EUnsafe.catches'. Note that,
+-- unlike that function, this function will not catch asynchronous exceptions.
+--
 -- @since 0.1.0.0
 catches :: MonadUnliftIO m => m a -> [Handler m a] -> m a
 catches io handlers = io `catch` catchesHandler handlers
@@ -274,8 +286,21 @@
 evaluateDeep :: (MonadIO m, NFData a) => a -> m a
 evaluateDeep = (evaluate $!!)
 
--- | Async safe version of 'EUnsafe.bracket'.
+-- | Allocate and clean up a resource safely.
 --
+-- For more information on motivation and usage of this function, see @base@'s
+-- 'EUnsafe.bracket'. This function has two differences from the one in @base@.
+-- The first, and more obvious, is that it works on any @MonadUnliftIO@
+-- instance, not just @IO@.
+--
+-- The more subtle difference is that this function will use uninterruptible
+-- masking for its cleanup handler. This is a subtle distinction, but at a
+-- high level, means that resource cleanup has more guarantees to complete.
+-- This comes at the cost that an incorrectly written cleanup function
+-- cannot be interrupted.
+--
+-- For more information, please see <https://github.com/fpco/safe-exceptions/issues/3>.
+--
 -- @since 0.1.0.0
 bracket :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c
 bracket before after thing = withRunInIO $ \run -> EUnsafe.mask $ \restore -> do
@@ -295,13 +320,15 @@
       _ <- EUnsafe.uninterruptibleMask_ $ run $ after x
       return y
 
--- | Async safe version of 'EUnsafe.bracket_'.
+-- | Same as 'bracket', but does not pass the acquired resource to cleanup and use functions.
 --
+-- For more information, see @base@'s 'EUnsafe.bracket_'.
+--
 -- @since 0.1.0.0
 bracket_ :: MonadUnliftIO m => m a -> m b -> m c -> m c
 bracket_ before after thing = bracket before (const after) (const thing)
 
--- | Async safe version of 'EUnsafe.bracketOnError'.
+-- | Same as 'bracket', but only perform the cleanup if an exception is thrown.
 --
 -- @since 0.1.0.0
 bracketOnError :: MonadUnliftIO m => m a -> (a -> m b) -> (a -> m c) -> m c
@@ -323,10 +350,17 @@
 bracketOnError_ :: MonadUnliftIO m => m a -> m b -> m c -> m c
 bracketOnError_ before after thing = bracketOnError before (const after) (const thing)
 
--- | Async safe version of 'EUnsafe.finally'.
+-- | Perform @thing@, guaranteeing that @after@ will run after, even if an exception occurs.
 --
+-- Same interruptible vs uninterrupible points apply as with 'bracket'. See @base@'s
+-- 'EUnsafe.finally' for more information.
+--
 -- @since 0.1.0.0
-finally :: MonadUnliftIO m => m a -> m b -> m a
+finally
+  :: MonadUnliftIO m
+  => m a -- ^ thing
+  -> m b -- ^ after
+  -> m a
 finally thing after = withRunInIO $ \run -> EUnsafe.uninterruptibleMask $ \restore -> do
   res1 <- EUnsafe.try $ restore $ run thing
   case res1 of
@@ -353,13 +387,16 @@
             EUnsafe.throwIO e1
         Right x -> return x
 
--- | Async safe version of 'EUnsafe.onException'.
+-- | Like 'finally', but only call @after@ if an exception occurs.
 --
 -- @since 0.1.0.0
 onException :: MonadUnliftIO m => m a -> m b -> m a
 onException thing after = withException thing (\(_ :: SomeException) -> after)
 
 -- | Synchronously throw the given exception.
+--
+-- Note that, if you provide an exception value which is of an asynchronous
+-- type, it will be wrapped up in 'SyncExceptionWrapper'. See 'toSyncException'.
 --
 -- @since 0.1.0.0
 throwIO :: (MonadIO m, Exception e) => e -> m a
diff --git a/src/UnliftIO/Internals/Async.hs b/src/UnliftIO/Internals/Async.hs
--- a/src/UnliftIO/Internals/Async.hs
+++ b/src/UnliftIO/Internals/Async.hs
@@ -383,8 +383,8 @@
 
 -- | A more efficient alternative to 'Concurrently', which reduces the
 -- number of threads that need to be forked. For more information, see
--- @FIXME link to blog post@. This is provided as a separate type to
--- @Concurrently@ as it has a slightly different API.
+-- [this blog post](https://www.fpcomplete.com/blog/transformations-on-applicative-concurrent-computations/).
+-- This is provided as a separate type to @Concurrently@ as it has a slightly different API.
 --
 -- Use the 'conc' function to construct values of type 'Conc', and
 -- 'runConc' to execute the composed actions. You can use the
diff --git a/unliftio.cabal b/unliftio.cabal
--- a/unliftio.cabal
+++ b/unliftio.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: bc7612e266638a6d07a620579aafe7d2690c4bef6d120416a1a7a3fc8999b416
+-- hash: c11215b81aa0898968a1dbf5189319f0bd07fa70861b5812ac34043c9f118ebb
 
 name:           unliftio
-version:        0.2.13
+version:        0.2.13.1
 synopsis:       The MonadUnliftIO typeclass for unlifting monads to IO (batteries included)
 description:    Please see the documentation and README at <https://www.stackage.org/package/unliftio>
 category:       Control
