diff --git a/antiope-core.cabal b/antiope-core.cabal
--- a/antiope-core.cabal
+++ b/antiope-core.cabal
@@ -1,23 +1,22 @@
--- This file has been generated from package.yaml by hpack version 0.20.0.
+-- This file has been generated from package.yaml by hpack version 0.28.2.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 53c4a0dfa1e3b0dff9ab29a31e4deb8d999ce4e32446d1ad56bac161798af9f8
+-- hash: 2840a668018391cb759e39eea78a0678bcb43acd7bc8f81e5205f552753ac7f2
 
 name:           antiope-core
-version:        1.0.0
+version:        3.1.0
 description:    Please see the README on Github at <https://github.com/arbor/antiope#readme>
 category:       Services
 homepage:       https://github.com/arbor/antiope#readme
 bug-reports:    https://github.com/arbor/antiope/issues
-author:         Tyler Durden
+author:         Arbor Networks
 maintainer:     mayhem@arbor.net
 copyright:      Arbor Networks
 license:        MIT
 license-file:   LICENSE
 build-type:     Simple
 cabal-version:  >= 1.10
-
 extra-source-files:
     ChangeLog.md
     README.md
@@ -35,10 +34,13 @@
     , amazonka-core
     , base >=4.7 && <5
     , bytestring
+    , generic-lens
     , http-client
     , lens
+    , mtl
     , resourcet
     , transformers
+    , unliftio-core
   exposed-modules:
       Antiope.Core
       Antiope.Env
@@ -58,10 +60,13 @@
     , antiope-core
     , base >=4.7 && <5
     , bytestring
+    , generic-lens
     , http-client
     , lens
+    , mtl
     , resourcet
     , transformers
+    , unliftio-core
   other-modules:
       Paths_antiope_core
   default-language: Haskell2010
diff --git a/src/Antiope/Core.hs b/src/Antiope/Core.hs
--- a/src/Antiope/Core.hs
+++ b/src/Antiope/Core.hs
@@ -1,29 +1,94 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE DataKinds           #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE RankNTypes          #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
+
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module Antiope.Core
-( module Network.AWS.Data.Text
-, AWS.Env
-, AWS.HasEnv(..)
-, AWS.MonadAWS
-, AWS.runAWS
-, AWS.send
-, AWS.runResourceT
-, AWS.liftAWS
-, AWS.sinkMD5, AWS.sinkSHA256
-, AWS.AWS
-, AWS.catching
-, AWS.Error(..)
-, AWS.ErrorCode(..), AWS.errorCode
-, AWS.Region(..)
-, AWS.LogLevel(..)
-)
-where
+  ( module Network.AWS.Data.Text
+  , AWS.Env
+  , AWS.HasEnv(..)
+  , AWS.runAWS
+  , AWS.send
+  , AWS.runResourceT
+  , AWS.liftAWS
+  , AWS.sinkMD5, AWS.sinkSHA256
+  , AWS.AWS
+  , AWS.catching
+  , AWS.Error(..)
+  , AWS.ErrorCode(..), AWS.errorCode
+  , AWS.Region(..)
+  , AWS.LogLevel(..)
+  , runAws
+  , runAwsThe
+  , runAwsTyped
+  , runResAws
+  , runResAwsThe
+  , runResAwsTyped
+  ) where
 
+import Control.Lens                 (view)
+import Control.Monad.Reader         (MonadReader)
+import Control.Monad.Trans.AWS
 import Control.Monad.Trans.Class    (lift)
-import Control.Monad.Trans.Resource (ResourceT)
+import Control.Monad.Trans.Resource (MonadResource, MonadUnliftIO, ResourceT)
+import Data.Generics.Product.Any
+import Data.Generics.Product.Typed
 import Network.AWS.Data.Text        (FromText (..), Text, ToText (..), fromText, toText)
 
-import qualified Network.AWS as AWS
+import qualified Control.Monad.Trans.AWS as AWS hiding (send)
+import qualified Network.AWS             as AWS
 
 instance AWS.MonadAWS m => AWS.MonadAWS (ResourceT m) where
   liftAWS = lift . AWS.liftAWS
+
+runAws :: (MonadResource m, AWS.HasEnv r) => r -> AWS.AWS a -> m a
+runAws = AWS.runAWS
+
+runResAws :: (MonadUnliftIO m, AWS.HasEnv r) => r -> AWS.AWS a -> m a
+runResAws r = AWS.runResourceT . AWS.runAWS r
+
+runAwsThe :: forall m r e s a.
+  ( MonadUnliftIO m
+  , MonadReader r m
+  , HasAny s r r e e
+  , HasEnv e)
+  => AWS.AWS a
+  -> m a
+runAwsThe f = do
+  e <- view $ the @s
+  AWS.runResourceT $ AWS.runAWS e f
+
+runResAwsThe :: forall m r e s a.
+  ( MonadResource m
+  , MonadReader r m
+  , HasAny s r r e e
+  , HasEnv e)
+  => AWS.AWS a
+  -> m a
+runResAwsThe f = do
+  e <- view $ the @s
+  AWS.runAWS e f
+
+runAwsTyped :: forall m r a.
+  ( MonadUnliftIO m
+  , MonadReader r m
+  , HasType AWS.Env r)
+  => AWS.AWS a
+  -> m a
+runAwsTyped f = do
+  e <- view $ typed @AWS.Env
+  AWS.runResourceT $ AWS.runAWS e f
+
+runResAwsTyped :: forall m r a.
+  ( MonadResource m
+  , MonadReader r m
+  , HasType AWS.Env r)
+  => AWS.AWS a
+  -> m a
+runResAwsTyped f = do
+  e <- view $ typed @AWS.Env
+  AWS.runAWS e f
diff --git a/src/Antiope/Env.hs b/src/Antiope/Env.hs
--- a/src/Antiope/Env.hs
+++ b/src/Antiope/Env.hs
@@ -1,22 +1,21 @@
 module Antiope.Env
-( mkEnv
-, AWS.Env
-, AWS.HasEnv(..)
-, AWS.LogLevel(..)
-, AWS.Region(..)
-)
-where
+  ( mkEnv
+  , AWS.Env
+  , AWS.HasEnv(..)
+  , AWS.LogLevel(..)
+  , AWS.Region(..)
+  ) where
 
-import           Control.Lens
-import           Control.Monad.Trans.AWS       hiding (LogLevel)
+import Control.Lens
+import Control.Monad.Trans.AWS hiding (LogLevel)
+import Data.ByteString.Builder
+import Network.HTTP.Client     (HttpException (..), HttpExceptionContent (..))
+
 import qualified Data.ByteString               as BS
-import           Data.ByteString.Builder
 import qualified Data.ByteString.Char8         as C8
 import qualified Data.ByteString.Lazy          as L
 import qualified Data.ByteString.Lazy.Internal as LBS
-
-import qualified Network.AWS         as AWS
-import           Network.HTTP.Client (HttpException (..), HttpExceptionContent (..))
+import qualified Network.AWS                   as AWS
 
 mkEnv :: Region -> (AWS.LogLevel -> LBS.ByteString -> IO ()) -> IO AWS.Env
 mkEnv region lg = do
