diff --git a/src/Quasar/Async.hs b/src/Quasar/Async.hs
index 0608eeb23a5b38b9f685b9471103e4b72da38718..98f09c6ff54f269bf1e4e2523eb54ae287aebb24 100644
--- a/src/Quasar/Async.hs
+++ b/src/Quasar/Async.hs
@@ -1,16 +1,9 @@
 module Quasar.Async (
   -- * Async/await
-  MonadAsync(..),
   async,
   async_,
   asyncWithUnmask,
   asyncWithUnmask_,
-  runUnlimitedAsync,
-
-  -- ** Async context
-  IsAsyncContext(..),
-  AsyncContext,
-  unlimitedAsyncContext,
 ) where
 
 import Control.Monad.Reader
@@ -20,83 +13,28 @@ import Quasar.ResourceManager
 import Quasar.Utils.Concurrent
 
 
-
-class IsAsyncContext a where
-  asyncOnContextWithUnmask :: MonadResourceManager m => a -> (forall f. MonadAsync f => (forall b. f b -> f b) -> f r) -> m (Awaitable r)
-  asyncOnContextWithUnmask self = asyncOnContextWithUnmask (toAsyncContext self)
-
-  toAsyncContext :: a -> AsyncContext
-  toAsyncContext = AsyncContext
-
-  {-# MINIMAL toAsyncContext | asyncOnContextWithUnmask #-}
-
-data AsyncContext = forall a. IsAsyncContext a => AsyncContext a
-
-instance IsAsyncContext AsyncContext where
-  asyncOnContextWithUnmask (AsyncContext ctx) = asyncOnContextWithUnmask ctx
-  toAsyncContext = id
-
-data UnlimitedAsyncContext = UnlimitedAsyncContext
-
-unlimitedAsyncContext :: AsyncContext
-unlimitedAsyncContext = toAsyncContext UnlimitedAsyncContext
-
-
-instance IsAsyncContext UnlimitedAsyncContext where
-  asyncOnContextWithUnmask UnlimitedAsyncContext action = do
-    resourceManager <- askResourceManager
-    let asyncContext = unlimitedAsyncContext
-    toAwaitable <$> registerNewResource do
-      unmanagedForkWithUnmask (\unmask -> runReaderT (runReaderT (action (liftUnmask unmask)) asyncContext) resourceManager)
-    where
-      liftUnmask :: (forall b. IO b -> IO b) -> ReaderT AsyncContext (ReaderT ResourceManager IO) a -> ReaderT AsyncContext (ReaderT ResourceManager IO) a
-      liftUnmask unmask innerAction = do
-        resourceManager <- askResourceManager
-        asyncContext <- askAsyncContext
-        liftIO $ unmask $ runReaderT (runReaderT innerAction asyncContext) resourceManager
-
-
-class MonadResourceManager m => MonadAsync m where
-  askAsyncContext :: m AsyncContext
-
-  localAsyncContext :: IsAsyncContext a => a -> m r -> m r
-
-
-instance MonadResourceManager m => MonadAsync (ReaderT AsyncContext m) where
-  askAsyncContext = ask
-  localAsyncContext = local . const . toAsyncContext
-
-instance {-# OVERLAPPABLE #-} MonadAsync m => MonadAsync (ReaderT r m) where
-  askAsyncContext = lift askAsyncContext
-  localAsyncContext asyncContext action = do
-    x <- ask
-    lift $ localAsyncContext asyncContext $ runReaderT action x
-
-
 -- | TODO: Documentation
 --
 -- The action will be run with asynchronous exceptions unmasked.
-async :: MonadAsync m => (forall f. MonadAsync f => f a) -> m (Awaitable a)
+async :: MonadResourceManager m => (ResourceManagerIO a) -> m (Awaitable a)
 async action = asyncWithUnmask \unmask -> unmask action
 
 -- | TODO: Documentation
 --
 -- The action will be run with asynchronous exceptions masked and will be passed an action that can be used to unmask.
-asyncWithUnmask :: MonadAsync m => (forall f. MonadAsync f => (forall a. f a -> f a) -> f r) -> m (Awaitable r)
+asyncWithUnmask :: MonadResourceManager m => ((ResourceManagerIO a -> ResourceManagerIO a) -> ResourceManagerIO r) -> m (Awaitable r)
 asyncWithUnmask action = do
-  asyncContext <- askAsyncContext
-  asyncOnContextWithUnmask asyncContext action
-
-async_ :: MonadAsync m => (forall f. MonadAsync f => f ()) -> m ()
+  resourceManager <- askResourceManager
+  toAwaitable <$> registerNewResource do
+    unmanagedForkWithUnmask (\unmask -> runReaderT (action (liftUnmask unmask)) resourceManager)
+  where
+    liftUnmask :: (forall b. IO b -> IO b) -> ResourceManagerIO a -> ResourceManagerIO a
+    liftUnmask unmask innerAction = do
+      resourceManager <- askResourceManager
+      liftIO $ unmask $ runReaderT innerAction resourceManager
+
+async_ :: MonadResourceManager m => (ResourceManagerIO ()) -> m ()
 async_ action = void $ async action
 
-asyncWithUnmask_ :: MonadAsync m => (forall f. MonadAsync f => (forall a. f a -> f a) -> f ()) -> m ()
+asyncWithUnmask_ :: MonadResourceManager m => ((ResourceManagerIO a -> ResourceManagerIO a) -> ResourceManagerIO ()) -> m ()
 asyncWithUnmask_ action = void $ asyncWithUnmask action
-
-
-
--- | Run a computation in `MonadAsync` where `async` is implemented without any thread limits (i.e. every `async` will
--- fork a new (RTS) thread).
-runUnlimitedAsync :: ReaderT AsyncContext m a -> m a
-runUnlimitedAsync action = do
-  runReaderT action unlimitedAsyncContext
diff --git a/test/Quasar/AsyncSpec.hs b/test/Quasar/AsyncSpec.hs
index 870be2c40e77b72cbc2bd29787dc94e631f9f461..fd5a614befc770ed0485f1351f2b6a485466f5a9 100644
--- a/test/Quasar/AsyncSpec.hs
+++ b/test/Quasar/AsyncSpec.hs
@@ -14,10 +14,10 @@ spec :: Spec
 spec = parallel $ do
   describe "async" $ do
     it "can pass a value through async and await" $ do
-      withRootResourceManager (runUnlimitedAsync (await =<< async (pure 42))) `shouldReturn` (42 :: Int)
+      withRootResourceManager (await =<< async (pure 42)) `shouldReturn` (42 :: Int)
 
     it "can pass a value through async and await" $ do
-      withRootResourceManager (runUnlimitedAsync (await =<< async (liftIO (threadDelay 100000) >> pure 42))) `shouldReturn` (42 :: Int)
+      withRootResourceManager (await =<< async (liftIO (threadDelay 100000) >> pure 42)) `shouldReturn` (42 :: Int)
 
   describe "await" $ do
     it "can await the result of an async that is completed later" $ do