diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,149 @@
+# 2.3.0
+
+* BREAKING CHANGE: `syncIO` now expects a `MonadIO` constraint instead of
+  `UnexceptionalIO`
+    * `syncIO` also changes how it detects asynchronous exceptions.  It now
+      decides based on whether or not an exception inherits from
+      `SomeAsyncException`
+    * See: https://github.com/Gabriel439/Haskell-Errors-Library/pull/53
+
+# 2.2.5
+
+* Increase upper bound on `exceptions`
+
+# 2.2.4
+
+* Increase upper bound on `exceptions`
+
+# 2.2.3
+
+* Increase upper bound on `transformers-compat`
+
+# 2.2.2
+
+* Support GHC 8.4 through compatibility with Semigroup/Monoid proposal
+
+# 2.2.1
+
+* Add precedence and fixity for `(?:)`
+
+# 2.2.0
+
+* BREAKING CHANGE: Use `Text` instead of `String`
+* Add `handleExceptT`
+
+# 2.1.3
+
+* Support older versions of `ghc`
+
+# 2.1.2
+
+* Increase upper bound on `transformers` dependency
+
+# 2.1.1
+
+* Increase upper bound on `transformers-compat`
+
+# 2.1.0
+
+* Change `syncio` to use `unexceptionalio` to prove that all synchronous
+  exceptions were caught and handled
+
+# 2.0.0
+
+* Switch from `EitherT` to `ExceptT`
+
+# 1.4.7
+
+* Increase upper bound on `transformers` from `0.4` to `0.5`
+
+# 1.4.6
+
+* Add `bool`
+* Add `(?:)`
+* Add `isJustT`
+* Add `isNothingT`
+* Add `isLeftT`
+* Add `isRightT`
+
+# 1.4.5
+
+* Increase upper bound on `either` from `4.1` to `5`
+
+# 1.4.4
+
+* Add `failWith`
+* Add `failWithM`
+
+# 1.4.3
+
+* Add `AllE`
+* Add `AnyE`
+* Increase upper bound on `either` from `3.5` to `4.1`
+
+# 1.4.2
+
+* Add `(??)`
+* Add `(!?)`
+* Add `syncIO`
+
+# 1.4.1
+
+* Re-export `EitherT`
+* Re-export `MaybeT`
+
+# 1.4.0
+
+* Add `maybeT`
+* Add `just`
+* Add `nothing`
+* Add upper bound to `either`
+* Add upper bound to `safe`
+* Add upper bound to `transformers`
+
+# 1.3.1
+
+* Increase lower bound on `transformers` from `0.2` to `0.3.0.0`
+
+# 1.3.0
+
+* Add `assertMay`
+* Add `rightMay`
+* Add `justErr`
+* Add `tryJust`
+* Add `tryRight`
+* Add `MonadPlus` functions to `Control.Error.Safe`
+* Add `isLeft`
+* Add `isRight`
+* Add `fmapR`
+* Add `fmapRT`
+* Add `err`
+* Add `errLn`
+* Add `flipE`
+* Add `flipET`
+* Rename `tryIO` to `scriptIO`
+* Remove `tryMaybe`
+* Remove `tryEither`
+* Rename `liftMaybe` to `hoistMaybe`
+* Rename `liftEither` to `hoistEither`
+
+# 1.2.1
+
+* Add lower bound to `either`
+
+# 1.2.0
+
+* Remove `right`
+* Remove `left`
+
+# 1.1.1
+
+* Cosmetic changes
+
+# 1.1.0
+
+* Add `left`
+
+# 1.0.0
+
+* Initial release
diff --git a/Control/Error.hs b/Control/Error.hs
--- a/Control/Error.hs
+++ b/Control/Error.hs
@@ -10,7 +10,7 @@
       'EitherT', and 'MonadPlus' variations on total functions
 
     * "Control.Error.Script": Support for simple scripts that catch all errors
-      and transform them to 'String's
+      and transform them to 'Text'
 
     * "Control.Error.Util": Utility functions and conversions between common
       error-handling types
diff --git a/Control/Error/Script.hs b/Control/Error/Script.hs
--- a/Control/Error/Script.hs
+++ b/Control/Error/Script.hs
@@ -1,5 +1,7 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 {-|
-    Use this module if you like to write simple scripts with 'String'-based
+    Use this module if you like to write simple scripts with 'Text'-based
     errors, but you prefer to use 'ExceptT' to handle errors rather than
     @Control.Exception@.
 
@@ -24,6 +26,8 @@
 import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT)
 import Control.Error.Util (errLn)
 import Data.EitherR (fmapL)
+import Data.Monoid ((<>))
+import Data.Text (Text)
 import System.Environment (getProgName)
 import System.Exit (exitFailure)
 
@@ -31,9 +35,11 @@
 import Control.Monad.Trans.Class (lift)
 import System.IO (stderr)
 
--- | An 'IO' action that can fail with a 'String' error message
-type Script = ExceptT String IO
+import qualified Data.Text
 
+-- | An 'IO' action that can fail with a 'Text' error message
+type Script = ExceptT Text IO
+
 {-| Runs the 'Script' monad
 
     Prints the first error to 'stderr' and exits with 'exitFailure'
@@ -43,17 +49,18 @@
     e <- runExceptT s
     case e of
         Left  e -> do
-            errLn =<< liftM (++ ": " ++ e) getProgName
+            let adapt str = Data.Text.pack str <> ": " <> e
+            errLn =<< liftM adapt getProgName
             exitFailure
         Right a -> return a
 
 {-| 'scriptIO' resembles 'lift', except it catches all exceptions and converts
-    them to 'String's.
+    them to 'Text'
 
     Note that 'scriptIO' is compatible with the 'Script' monad.
 -}
-scriptIO :: (MonadIO m) => IO a -> ExceptT String m a
+scriptIO :: (MonadIO m) => IO a -> ExceptT Text m a
 scriptIO = ExceptT
          . liftIO
-         . liftM (fmapL show)
+         . liftM (fmapL (Data.Text.pack . show))
          . (try :: IO a -> IO (Either SomeException a))
diff --git a/Control/Error/Util.hs b/Control/Error/Util.hs
--- a/Control/Error/Util.hs
+++ b/Control/Error/Util.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 -- | This module exports miscellaneous error-handling functions.
 
 module Control.Error.Util (
@@ -47,21 +49,28 @@
 
     -- * Exceptions
     tryIO,
+    handleExceptT,
     syncIO
     ) where
 
 import Control.Applicative (Applicative, pure, (<$>))
-import qualified Control.Exception as Ex
+import Control.Exception (IOException, SomeException, Exception)
 import Control.Monad (liftM)
+import Control.Monad.Catch (MonadCatch, try)
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT)
 import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
-import Data.Dynamic (Dynamic)
 import Data.Monoid (Monoid(mempty, mappend))
+#if MIN_VERSION_base(4,9,0)
+import Data.Semigroup
+#endif
 import Data.Maybe (fromMaybe)
-import System.Exit (ExitCode)
-import System.IO (hPutStr, hPutStrLn, stderr)
+import Data.Text (Text)
+import System.IO (stderr)
 
+import qualified Control.Exception as Exception
+import qualified Data.Text.IO
+
 -- | Fold an 'ExceptT' by providing one continuation for each constructor
 exceptT :: Monad m => (a -> m c) -> (b -> m c) -> ExceptT a m b -> m c
 exceptT f g (ExceptT m) = m >>= \z -> case z of
@@ -119,6 +128,8 @@
 maybeA ?: b = fromMaybe b maybeA
 {-# INLINABLE (?:) #-}
 
+infixr 0 ?:
+
 {-| Convert a 'Maybe' value into the 'ExceptT' monad
 
     Named version of ('??') with arguments flipped
@@ -187,12 +198,22 @@
 -}
 newtype AllE e r = AllE { runAllE :: Either e r }
 
+#if MIN_VERSION_base(4,9,0)
+instance (Semigroup e, Semigroup r) => Semigroup (AllE e r) where
+    AllE (Right x) <> AllE (Right y) = AllE (Right (x <> y))
+    AllE (Right _) <> AllE (Left  y) = AllE (Left y)
+    AllE (Left  x) <> AllE (Right _) = AllE (Left x)
+    AllE (Left  x) <> AllE (Left  y) = AllE (Left  (x <> y))
+#endif
+
 instance (Monoid e, Monoid r) => Monoid (AllE e r) where
     mempty = AllE (Right mempty)
+#if !(MIN_VERSION_base(4,11,0))
     mappend (AllE (Right x)) (AllE (Right y)) = AllE (Right (mappend x y))
     mappend (AllE (Right _)) (AllE (Left  y)) = AllE (Left y)
     mappend (AllE (Left  x)) (AllE (Right _)) = AllE (Left x)
     mappend (AllE (Left  x)) (AllE (Left  y)) = AllE (Left  (mappend x y))
+#endif
 
 {-| Run multiple 'Either' computations and succeed if any of them succeed
 
@@ -200,12 +221,22 @@
 -}
 newtype AnyE e r = AnyE { runAnyE :: Either e r }
 
+#if MIN_VERSION_base(4,9,0)
+instance (Semigroup e, Semigroup r) => Semigroup (AnyE e r) where
+    AnyE (Right x) <> AnyE (Right y) = AnyE (Right (x <> y))
+    AnyE (Right x) <> AnyE (Left  _) = AnyE (Right x)
+    AnyE (Left  _) <> AnyE (Right y) = AnyE (Right y)
+    AnyE (Left  x) <> AnyE (Left  y) = AnyE (Left  (x <> y))
+#endif
+
 instance (Monoid e, Monoid r) => Monoid (AnyE e r) where
     mempty = AnyE (Right mempty)
+#if !(MIN_VERSION_base(4,11,0))
     mappend (AnyE (Right x)) (AnyE (Right y)) = AnyE (Right (mappend x y))
     mappend (AnyE (Right x)) (AnyE (Left  _)) = AnyE (Right x)
     mappend (AnyE (Left  _)) (AnyE (Right y)) = AnyE (Right y)
     mappend (AnyE (Left  x)) (AnyE (Left  y)) = AnyE (Left  (mappend x y))
+#endif
 
 -- | Analogous to 'isLeft', but for 'ExceptT'
 isLeftT :: (Monad m) => ExceptT a m b -> m Bool
@@ -224,38 +255,30 @@
 fmapRT = liftM
 
 -- | Write a string to standard error
-err :: String -> IO ()
-err = hPutStr stderr
+err :: Text -> IO ()
+err = Data.Text.IO.hPutStr stderr
 
 -- | Write a string with a newline to standard error
-errLn :: String -> IO ()
-errLn = hPutStrLn stderr
+errLn :: Text -> IO ()
+errLn = Data.Text.IO.hPutStrLn stderr
 
--- | Catch 'Ex.IOException's and convert them to the 'ExceptT' monad
-tryIO :: (MonadIO m) => IO a -> ExceptT Ex.IOException m a
-tryIO = ExceptT . liftIO . Ex.try
+-- | Catch 'IOException's and convert them to the 'ExceptT' monad
+tryIO :: MonadIO m => IO a -> ExceptT IOException m a
+tryIO = ExceptT . liftIO . Exception.try
 
+-- | Run a monad action which may throw an exception in the `ExceptT` monad
+handleExceptT :: (Exception e, Functor m, MonadCatch m) => (e -> x) -> m a -> ExceptT x m a
+handleExceptT handler = bimapExceptT handler id . ExceptT . try
+
+
 {-| Catch all exceptions, except for asynchronous exceptions found in @base@
     and convert them to the 'ExceptT' monad
 -}
-syncIO :: MonadIO m => IO a -> ExceptT Ex.SomeException m a
-syncIO a = ExceptT . liftIO $ Ex.catches (Right <$> a)
-    [ Ex.Handler $ \e -> Ex.throw (e :: Ex.ArithException)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.ArrayException)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.AssertionFailed)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.AsyncException)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.BlockedIndefinitelyOnMVar)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.BlockedIndefinitelyOnSTM)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.Deadlock)
-    , Ex.Handler $ \e -> Ex.throw (e ::    Dynamic)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.ErrorCall)
-    , Ex.Handler $ \e -> Ex.throw (e ::    ExitCode)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.NestedAtomically)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.NoMethodError)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.NonTermination)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.PatternMatchFail)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.RecConError)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.RecSelError)
-    , Ex.Handler $ \e -> Ex.throw (e :: Ex.RecUpdError)
-    , Ex.Handler $ return . Left
-    ]
+syncIO :: MonadIO m => IO a -> ExceptT SomeException m a
+syncIO = ExceptT . liftIO . trySync
+
+trySync :: IO a -> IO (Either SomeException a)
+trySync io = (fmap Right io) `Exception.catch` \e ->
+  case Exception.fromException e of
+    Just (Exception.SomeAsyncException _) -> Exception.throwIO e
+    Nothing -> return (Left e)
diff --git a/Data/EitherR.hs b/Data/EitherR.hs
--- a/Data/EitherR.hs
+++ b/Data/EitherR.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 {-| This module provides 'throwEither' and 'catchEither' for 'Either'.  These two
     functions reside here because 'throwEither' and 'catchEither' correspond to 'return'
     and ('>>=') for the flipped 'Either' monad: 'EitherR'.  Additionally, this
@@ -64,6 +66,8 @@
 import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT, throwE, catchE)
 import Data.Monoid (Monoid(mempty, mappend))
 
+import qualified Control.Monad.Trans.Except
+
 {-| If \"@Either e r@\" is the error monad, then \"@EitherR r e@\" is the
     corresponding success monad, where:
 
@@ -169,13 +173,18 @@
 succeedT :: (Monad m) => r -> ExceptRT r m e
 succeedT r = ExceptRT (return r)
 
--- | 'catchT' with the arguments flipped
+-- | 'catchE' with the arguments flipped
 handleE :: (Monad m) => (a -> ExceptT b m r) -> ExceptT a m r -> ExceptT b m r
 handleE = flip catchE
 
 -- | Map a function over the 'Left' value of an 'ExceptT'
+#if MIN_VERSION_base(4,8,0)
+fmapLT :: Functor m => (a -> b) -> ExceptT a m r -> ExceptT b m r
+fmapLT = Control.Monad.Trans.Except.withExceptT
+#else
 fmapLT :: (Monad m) => (a -> b) -> ExceptT a m r -> ExceptT b m r
 fmapLT f = runExceptRT . fmap f . ExceptRT
+#endif
 
 -- | Flip the type variables of an 'ExceptT'
 flipET :: (Monad m) => ExceptT a m b -> ExceptT b m a
diff --git a/errors.cabal b/errors.cabal
--- a/errors.cabal
+++ b/errors.cabal
@@ -1,7 +1,8 @@
 Name: errors
-Version: 2.0.1
+Version: 2.3.0
 Cabal-Version: >=1.8.0.2
 Build-Type: Simple
+Tested-With: GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1
 License: BSD3
 License-File: LICENSE
 Copyright: 2012, 2013 Gabriel Gonzalez
@@ -16,20 +17,27 @@
     This library encourages an error-handling style that directly uses the type
     system, rather than out-of-band exceptions.
 Category: Control, Error Handling
+extra-source-files: CHANGELOG.md
 Source-Repository head
     Type: git
     Location: https://github.com/Gabriel439/Haskell-Errors-Library
 
 Library
     Build-Depends:
-        base                >= 4     && < 5  ,
-        safe                >= 0.3.3 && < 0.4,
-        transformers        >= 0.2   && < 0.5,
-        transformers-compat >= 0.4   && < 0.5
+        base                >= 4.7   && < 5   ,
+        exceptions          >= 0.6   && < 0.11,
+        text                            < 1.3 ,
+        transformers        >= 0.2   && < 0.6 ,
+        transformers-compat >= 0.4   && < 0.7
+    if impl(ghc <= 7.6.3)
+        Build-Depends:
+            safe            >= 0.3.3 && < 0.3.10
+    else
+        Build-Depends:
+            safe            >= 0.3.3 && < 0.4
     Exposed-Modules:
         Control.Error,
         Control.Error.Safe,
         Control.Error.Script,
         Control.Error.Util,
         Data.EitherR
-    GHC-Options: -O2
