diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+## 0.1.0.0
+
+* Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2017 FP Complete
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# unliftio-core
+
+Provides the core `MonadUnliftIO` typeclass, instances for `base` and
+`transformers`, and basic utility functions. Typically, you'll want to use the
+[unliftio](https://www.stackage.org/package/unliftio) library, which provides
+more functionality (and a much better description).
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Control/Monad/IO/Unlift.hs b/src/Control/Monad/IO/Unlift.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/IO/Unlift.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE RankNTypes #-}
+-- | Please see the README.md file for information on using this
+-- package.
+module Control.Monad.IO.Unlift
+  ( MonadUnliftIO (..)
+  , UnliftIO (..)
+  , askRunInIO
+  , withUnliftIO
+  , withRunInIO
+  , toIO
+  , MonadIO (..)
+  ) where
+
+import Control.Monad (liftM)
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Reader (ReaderT (..))
+import Control.Monad.Trans.Identity (IdentityT (..))
+
+-- | The ability to run any monadic action @m a@ as @IO a@.
+--
+-- This is more precisely a natural transformation. We need to new
+-- datatype (instead of simply using a @forall@) due to lack of
+-- support in GHC for impredicative types.
+--
+-- @since 0.1.0.0
+newtype UnliftIO m = UnliftIO { unliftIO :: forall a. m a -> IO a }
+
+-- | Monads which allow their actions to be run in 'IO'.
+--
+-- While 'MonadIO' allows an 'IO' action to be lifted into another
+-- monad, this class captures the opposite concept: allowing you to
+-- capture the monadic context. Note that, in order to meet the laws
+-- given below, the intuition is that a monad must have no monadic
+-- state, but may have monadic context. This essentially limits
+-- 'MonadUnliftIO' to 'ReaderT' and 'IdentityT' transformers on top of
+-- 'IO'.
+--
+-- Laws. For any value @u@ returned by 'askUnliftIO', it must meet the
+-- monad transformer laws as reformulated for @MonadUnliftIO@:
+--
+-- * @unliftIO u . return = return@
+--
+-- * @unliftIO u (m >>= f) = unliftIO u m >>= unliftIO u . f@
+--
+-- The third is a currently nameless law which ensures that the
+-- current context is preserved.
+--
+-- * @askUnliftIO >>= (\u -> liftIO (unliftIO u m)) = m@
+--
+-- If you have a name for this, please submit it in a pull request for
+-- great glory.
+--
+-- @since 0.1.0.0
+class MonadIO m => MonadUnliftIO m where
+  -- | Capture the current monadic context, providing the ability to
+  -- run monadic actions in 'IO'.
+  --
+  -- See 'UnliftIO' for an explanation of why we need a helper
+  -- datatype here.
+  -- @since 0.1.0.0
+  askUnliftIO :: m (UnliftIO m)
+  -- Would be better, but GHC hates us
+  -- askUnliftIO :: m (forall a. m a -> IO a)
+instance MonadUnliftIO IO where
+  askUnliftIO = return (UnliftIO id)
+instance MonadUnliftIO m => MonadUnliftIO (ReaderT r m) where
+  askUnliftIO = ReaderT $ \r ->
+                withUnliftIO $ \u ->
+                return (UnliftIO (unliftIO u . flip runReaderT r))
+instance MonadUnliftIO m => MonadUnliftIO (IdentityT m) where
+  askUnliftIO = IdentityT $
+                withUnliftIO $ \u ->
+                return (UnliftIO (unliftIO u . runIdentityT))
+
+-- | Same ask 'askUnliftIO', but returns a monomorphic function
+-- instead of a polymorphic newtype wrapper. If you only need to apply
+-- the transformation on one concrete type, this function can be more
+-- convenient.
+--
+-- @since 0.1.0.0
+askRunInIO :: MonadUnliftIO m => m (m a -> IO a)
+askRunInIO = liftM unliftIO askUnliftIO
+
+-- | Convenience function for capturing the monadic context and running
+-- an 'IO' action.
+--
+-- @since 0.1.0.0
+withUnliftIO :: MonadUnliftIO m => (UnliftIO m -> IO a) -> m a
+withUnliftIO inner = askUnliftIO >>= liftIO . inner
+
+-- | Same as 'withUnliftIO', but uses a monomorphic function like
+-- 'askRunInIO'.
+--
+-- @since 0.1.0.0
+withRunInIO :: MonadUnliftIO m => ((m a -> IO a) -> IO b) -> m b
+withRunInIO inner = askRunInIO >>= liftIO . inner
+
+-- | Convert an action in @m@ to an action in @IO@.
+--
+-- @since 0.1.0.0
+toIO :: MonadUnliftIO m => m a -> m (IO a)
+toIO m = withRunInIO $ \run -> return $ run m
diff --git a/unliftio-core.cabal b/unliftio-core.cabal
new file mode 100644
--- /dev/null
+++ b/unliftio-core.cabal
@@ -0,0 +1,33 @@
+-- This file has been generated from package.yaml by hpack version 0.17.0.
+--
+-- see: https://github.com/sol/hpack
+
+name:           unliftio-core
+version:        0.1.0.0
+synopsis:       The MonadUnliftIO typeclass for unlifting monads to IO
+description:    Please see the README.md file for details
+category:       Control
+homepage:       https://github.com/fpco/monad-unlift/tree/master/unliftio-core#readme
+author:         Michael Snoyman, Francesco Mazzoli
+maintainer:     michael@snoyman.com
+copyright:      2017 FP Complete
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+library
+  hs-source-dirs:
+      src
+  build-depends:
+      base >= 4.5 && < 4.11
+    , transformers >= 0.2 && < 0.6
+  exposed-modules:
+      Control.Monad.IO.Unlift
+  other-modules:
+      Paths_unliftio_core
+  default-language: Haskell2010
