diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Change log
 
+## 0.2.0.0
+
+* Updated for postgresql-tx-0.2.0.0.
+* Added `HasCallStack` constraints in transaction runners.
+* Added more transaction runners: `withTransactionMode`, `withTransactionModeRetry`, `withTransactionSerializable`.
+* Moved internals to an `Internal` module.
+
 ## 0.1.0.0
 
-Initial release
+* Initial release
diff --git a/package.yaml b/package.yaml
--- a/package.yaml
+++ b/package.yaml
@@ -1,6 +1,6 @@
 name:                postgresql-tx-simple
-version:             0.1.0.0
-github:              "simspace/postgresql-tx/simple"
+version:             0.2.0.0
+github:              "simspace/postgresql-tx"
 license:             BSD3
 license-file:        LICENSE.md
 author:              "Cary Robbins"
@@ -20,8 +20,9 @@
 
 dependencies:
 - base >= 4.7 && < 5
+- bytestring >= 0.10.10.0 && < 0.11
 - postgresql-simple >= 0.6.2 && < 0.7
-- postgresql-tx >= 0.1.0.0 && < 0.2
+- postgresql-tx >= 0.2.0.0 && < 0.3
 - transformers >= 0.5.6.2 && < 0.6
 
 library:
diff --git a/postgresql-tx-simple.cabal b/postgresql-tx-simple.cabal
--- a/postgresql-tx-simple.cabal
+++ b/postgresql-tx-simple.cabal
@@ -1,13 +1,13 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.33.0.
+-- This file has been generated from package.yaml by hpack version 0.31.2.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: c49c4584915e0a9050d6fb99053fd27a445d8a627a7797f743efae7b38b42d34
+-- hash: a28e2079196694ad2a65da28273d761629b586f6af9c436a58761fccd48ba274
 
 name:           postgresql-tx-simple
-version:        0.1.0.0
+version:        0.2.0.0
 synopsis:       postgresql-tx interfacing for use with postgresql-simple.
 description:    Please see the README on GitHub at <https://github.com/simspace/postgresql-tx#readme>
 category:       Database
@@ -27,11 +27,11 @@
 source-repository head
   type: git
   location: https://github.com/simspace/postgresql-tx
-  subdir: simple
 
 library
   exposed-modules:
       Database.PostgreSQL.Tx.Simple
+      Database.PostgreSQL.Tx.Simple.Internal
   other-modules:
       Paths_postgresql_tx_simple
   hs-source-dirs:
@@ -39,7 +39,8 @@
   ghc-options: -Wall
   build-depends:
       base >=4.7 && <5
+    , bytestring >=0.10.10.0 && <0.11
     , postgresql-simple >=0.6.2 && <0.7
-    , postgresql-tx >=0.1.0.0 && <0.2
+    , postgresql-tx >=0.2.0.0 && <0.3
     , transformers >=0.5.6.2 && <0.6
   default-language: Haskell2010
diff --git a/src/Database/PostgreSQL/Tx/Simple.hs b/src/Database/PostgreSQL/Tx/Simple.hs
--- a/src/Database/PostgreSQL/Tx/Simple.hs
+++ b/src/Database/PostgreSQL/Tx/Simple.hs
@@ -1,42 +1,90 @@
-{-# LANGUAGE BlockArguments #-}
-module Database.PostgreSQL.Tx.Simple where
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+module Database.PostgreSQL.Tx.Simple
+  ( PgSimpleEnv
+  , PgSimpleM
+  , module Database.PostgreSQL.Tx.Simple
+  ) where
 
-import Control.Monad.Trans.Reader (ReaderT)
+import Control.Exception (Exception)
 import Data.Int (Int64)
-import Database.PostgreSQL.Tx (TxM, unsafeRunTxM, unsafeReaderIOTx)
+import Database.PostgreSQL.Tx (TxM, shouldRetryTx)
+import Database.PostgreSQL.Tx.Simple.Internal
+import GHC.Stack (HasCallStack)
 import qualified Database.PostgreSQL.Simple as Simple
 import qualified Database.PostgreSQL.Simple.Transaction as Simple
 
-type PgSimpleM = ReaderT Simple.Connection TxM
+-- | Analogue of 'Simple.withTransaction'.
+--
+-- @since 0.1.0.0
+withTransaction
+  :: (PgSimpleEnv r, HasCallStack)
+  => r -> (HasCallStack => TxM r a) -> IO a
+withTransaction = unsafeRunTransaction Simple.withTransaction
 
-withTransaction :: Simple.Connection -> TxM a -> IO a
-withTransaction c x = Simple.withTransaction c (unsafeRunTxM x)
+-- | Analogue of 'Simple.withTransactionLevel'.
+--
+-- @since 0.1.0.0
+withTransactionLevel
+  :: (PgSimpleEnv r, HasCallStack)
+  => Simple.IsolationLevel -> r -> (HasCallStack => TxM r a) -> IO a
+withTransactionLevel = unsafeRunTransaction . Simple.withTransactionLevel
 
-withTransactionLevel :: Simple.IsolationLevel -> Simple.Connection -> TxM a -> IO a
-withTransactionLevel lvl c x = Simple.withTransactionLevel lvl c (unsafeRunTxM x)
+-- | Analogue of 'Simple.withTransactionMode'.
+--
+-- @since 0.2.0.0
+withTransactionMode
+  :: (PgSimpleEnv r, HasCallStack)
+  => Simple.TransactionMode -> r -> (HasCallStack => TxM r a) -> IO a
+withTransactionMode = unsafeRunTransaction . Simple.withTransactionMode
 
-unsafeFromPgSimple1
-  :: (Simple.Connection -> a1 -> IO r)
-  -> a1 -> PgSimpleM r
-unsafeFromPgSimple1 f a1 = unsafeReaderIOTx \c -> f c a1
+-- | Analogue of 'Simple.withTransactionSerializable'.
+-- Unlike @postgresql-simple@, uses 'shouldRetryTx' to also retry
+-- on @deadlock_detected@, not just @serialization_failure@.
+--
+-- Note that any 'IO' that occurs inside the 'TxM' may be executed multiple times.
+--
+-- @since 0.2.0.0
+withTransactionSerializable
+  :: (PgSimpleEnv r, HasCallStack)
+  => r -> (HasCallStack => TxM r a) -> IO a
+withTransactionSerializable =
+  withTransactionModeRetry mode shouldRetryTx
+  where
+  mode = Simple.TransactionMode Simple.Serializable Simple.ReadWrite
 
-unsafeFromPgSimple2
-  :: (Simple.Connection -> a1 -> a2 -> IO r)
-  -> a1 -> a2 -> PgSimpleM r
-unsafeFromPgSimple2 f a1 a2 = unsafeReaderIOTx \c -> f c a1 a2
+-- | Analogue of 'Simple.withTransactionModeRetry'.
+-- You should generally prefer 'withTransactionSerializable'.
+--
+-- Note that any 'IO' that occurs inside the 'TxM' may be executed multiple times.
+--
+-- @since 0.2.0.0
+withTransactionModeRetry
+  :: (Exception e, PgSimpleEnv r, HasCallStack)
+  => Simple.TransactionMode -> (e -> Bool) -> r -> (HasCallStack => TxM r a) -> IO a
+withTransactionModeRetry mode shouldRetry =
+  unsafeRunTransaction $ Simple.withTransactionModeRetry' mode shouldRetry
 
--- | Re-export of 'Simple.query'
-query :: (Simple.ToRow q, Simple.FromRow r) => Simple.Query -> q -> PgSimpleM [r]
+-- | Analogue of 'Simple.query'
+--
+-- @since 0.1.0.0
+query :: (Simple.ToRow q, Simple.FromRow x) => Simple.Query -> q -> PgSimpleM [x]
 query = unsafeFromPgSimple2 Simple.query
 
--- | Re-export of 'Simple.query_'
-query_ :: (Simple.FromRow r) => Simple.Query -> PgSimpleM [r]
+-- | Analogue of 'Simple.query_'.
+--
+-- @since 0.1.0.0
+query_ :: (Simple.FromRow x) => Simple.Query -> PgSimpleM [x]
 query_ = unsafeFromPgSimple1 Simple.query_
 
--- | Re-export of 'Simple.execute'
+-- | Analogue of 'Simple.execute'.
+--
+-- @since 0.1.0.0
 execute :: (Simple.ToRow q) => Simple.Query -> q -> PgSimpleM Int64
 execute = unsafeFromPgSimple2 Simple.execute
 
--- | Re-export of 'Simple.execute_'
+-- | Analogue of 'Simple.execute_'.
+--
+-- @since 0.1.0.0
 execute_ :: Simple.Query -> PgSimpleM Int64
 execute_ = unsafeFromPgSimple1 Simple.execute_
diff --git a/src/Database/PostgreSQL/Tx/Simple/Internal.hs b/src/Database/PostgreSQL/Tx/Simple/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/PostgreSQL/Tx/Simple/Internal.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TypeApplications #-}
+module Database.PostgreSQL.Tx.Simple.Internal
+  ( -- * Disclaimer
+    -- $disclaimer
+
+    -- ** Internals
+    module Database.PostgreSQL.Tx.Simple.Internal
+  ) where
+
+import Data.Kind (Constraint)
+import Database.PostgreSQL.Tx (TxEnv, TxException, TxM, askTxEnv, mapExceptionTx)
+import Database.PostgreSQL.Tx.Unsafe (unsafeMkTxException, unsafeMksTxM, unsafeRunIOInTxM, unsafeRunTxM)
+import qualified Data.ByteString.Char8 as Char8
+import qualified Database.PostgreSQL.Simple as Simple
+
+-- | Runtime environment needed to run @postgresql-simple@ via @postgresql-tx@.
+--
+-- @since 0.2.0.0
+type PgSimpleEnv r = (TxEnv Simple.Connection r) :: Constraint
+
+-- | Monad type alias for running @postgresql-simple@ via @postgresql-tx@.
+--
+-- @since 0.2.0.0
+type PgSimpleM a = forall r. (PgSimpleEnv r) => TxM r a
+
+unsafeRunTransaction
+  :: (PgSimpleEnv r)
+  => (Simple.Connection -> IO a -> IO a)
+  -> r -> TxM r a -> IO a
+unsafeRunTransaction f r x = do
+  unsafeRunTxM r do
+    conn <- askTxEnv
+    unsafeRunIOInTxM $ f conn (unsafeRunTxM r x)
+
+fromSqlError :: Simple.SqlError -> TxException
+fromSqlError = unsafeMkTxException (Just . Char8.unpack . Simple.sqlState)
+
+unsafeFromPgSimple
+  :: (Simple.Connection -> IO x)
+  -> PgSimpleM x
+unsafeFromPgSimple f =
+  mapExceptionTx (Just . fromSqlError) do
+    unsafeMksTxM f
+
+unsafeFromPgSimple1
+  :: (Simple.Connection -> a1 -> IO x)
+  -> a1 -> PgSimpleM x
+unsafeFromPgSimple1 f a1 = unsafeFromPgSimple \c -> f c a1
+
+unsafeFromPgSimple2
+  :: (Simple.Connection -> a1 -> a2 -> IO x)
+  -> a1 -> a2 -> PgSimpleM x
+unsafeFromPgSimple2 f a1 a2 = unsafeFromPgSimple \c -> f c a1 a2
+
+-- $disclaimer
+--
+-- Changes to this module will not be reflected in the library's version
+-- updates.
