diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+# CHANGELOG
+
+## v0.1.0.0
+* Initial release
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,31 @@
+Copyright (c) 2022, Tristan de Cacqueray
+Copyright (c) 2013, Ozgun Ataman
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Ozgun Ataman nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# retry-effectful
+
+Adaptation of the [retry][retry] library for the [effectful][effectful] ecosystem.
+
+[retry]: https://hackage.haskell.org/package/retry
+[effectful]: https://github.com/haskell-effectful/effectful
diff --git a/retry-effectful.cabal b/retry-effectful.cabal
new file mode 100644
--- /dev/null
+++ b/retry-effectful.cabal
@@ -0,0 +1,58 @@
+cabal-version:      3.0
+name:               retry-effectful
+version:            0.1.0.0
+category:           Control
+stability:          experimental
+synopsis:           Adaptation of the retry library for the effectful ecosystem.
+description:
+  Adaptation of the @<https://hackage.haskell.org/package/retry retry>@ library for the @<https://hackage.haskell.org/package/effectful effectful>@ ecosystem.
+
+bug-reports:        https://github.com/change-metrics/retry-effectful/issues
+homepage:           https://github.com/change-metrics/retry-effectful#readme
+author:             Tristan de Cacqueray
+maintainer:         tdecacqu@redhat.com
+copyright:          2022 Red Hat
+license:            BSD-3-Clause
+license-file:       LICENSE.md
+build-type:         Simple
+extra-source-files:
+  CHANGELOG.md
+  README.md
+
+source-repository head
+  type:     git
+  location: https://github.com/change-metrics/retry-effectful
+
+common common
+  ghc-options:
+    -Weverything -Wno-redundant-constraints -Wno-implicit-prelude
+    -Wno-missing-import-lists -Wno-safe -Wno-unsafe
+    -Wno-missing-safe-haskell-mode -Wno-missing-local-signatures
+
+  if impl(ghc >=9.2)
+    ghc-options: -Wno-missing-kind-signatures
+
+  default-language: Haskell2010
+
+library
+  import:          common
+  hs-source-dirs:  src
+  exposed-modules: Effectful.Retry
+  build-depends:
+    , base            <5
+    , effectful-core  >=1.0 && <3.0
+    , exceptions
+    , retry           >=0.9.3
+
+test-suite retry-effectful-test
+  import:         common
+  ghc-options:    -rtsopts -threaded -with-rtsopts=-N
+  type:           exitcode-stdio-1.0
+  main-is:        Main.hs
+  hs-source-dirs: test
+  build-depends:
+    , base            <5
+    , effectful-core  >=1.0 && <3.0
+    , retry-effectful
+    , tasty           ^>=1.4.2
+    , tasty-hunit     ^>=0.10
diff --git a/src/Effectful/Retry.hs b/src/Effectful/Retry.hs
new file mode 100644
--- /dev/null
+++ b/src/Effectful/Retry.hs
@@ -0,0 +1,245 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+
+{- | This module provides a Retry effect to adapt
+ the @<https://hackage.haskell.org/package/retry retry>@ library for
+ the @<https://hackage.haskell.org/package/effectful effectful>@ ecosystem.
+-}
+module Effectful.Retry (
+    -- * Effect
+    Retry,
+    runRetry,
+
+    -- * Types and Operations
+    Control.Retry.RetryPolicyM (..),
+    Control.Retry.retryPolicy,
+    Control.Retry.retryPolicyDefault,
+    Control.Retry.RetryAction (..),
+    Control.Retry.toRetryAction,
+    Control.Retry.RetryStatus (..),
+    Control.Retry.defaultRetryStatus,
+    Effectful.Retry.applyPolicy,
+    Effectful.Retry.applyAndDelay,
+
+    -- * Applying Retry Policies
+    Effectful.Retry.retrying,
+    Effectful.Retry.retryingDynamic,
+    Effectful.Retry.recovering,
+    Effectful.Retry.recoveringDynamic,
+    Effectful.Retry.stepping,
+    Effectful.Retry.recoverAll,
+    Effectful.Retry.skipAsyncExceptions,
+    Effectful.Retry.logRetries,
+    Control.Retry.defaultLogMsg,
+    -- Effectful.Retry.retryOnError,
+
+    -- * Resumable variants
+    Effectful.Retry.resumeRetrying,
+    Effectful.Retry.resumeRetryingDynamic,
+    Effectful.Retry.resumeRecovering,
+    Effectful.Retry.resumeRecoveringDynamic,
+    Effectful.Retry.resumeRecoverAll,
+
+    -- * Retry Policies
+    Control.Retry.constantDelay,
+    Control.Retry.exponentialBackoff,
+    Control.Retry.fullJitterBackoff,
+    Control.Retry.fibonacciBackoff,
+    Control.Retry.limitRetries,
+
+    -- * Policy Transformers
+    Control.Retry.limitRetriesByDelay,
+    Control.Retry.limitRetriesByCumulativeDelay,
+    Control.Retry.capDelay,
+
+    -- * Development Helpers
+    Control.Retry.simulatePolicy,
+    Control.Retry.simulatePolicyPP,
+) where
+
+import Effectful
+import Effectful.Dispatch.Static
+import Effectful.Internal.Env (Env)
+
+import Control.Exception (AsyncException, SomeAsyncException)
+import Control.Monad.Catch
+import Control.Retry
+
+-- | An empty effect to provide the retry requirements, e.g. MonadIO and MonadMask
+data Retry :: Effect
+
+type instance DispatchOf Retry = 'Static 'WithSideEffects
+data instance StaticRep Retry = Retry
+
+-- | Peel the 'Retry' effect.
+runRetry :: IOE :> es => Eff (Retry : es) a -> Eff es a
+runRetry = evalStaticRep Retry
+
+-- effect helper
+policyIO :: Env es -> RetryPolicyM (Eff es) -> RetryPolicyM IO
+policyIO env (RetryPolicyM policy) = RetryPolicyM $ \s -> unEff (policy s) env
+
+-- effect helper
+handlerIO :: Env es -> Handler (Eff es) a -> Handler IO a
+handlerIO env (Handler handler) = Handler $ \e -> unEff (handler e) env
+
+-- wrappers
+applyPolicy :: Retry :> es => RetryPolicyM (Eff es) -> RetryStatus -> Eff es (Maybe RetryStatus)
+applyPolicy policy status = unsafeEff $ \env -> Control.Retry.applyPolicy (policyIO env policy) status
+
+applyAndDelay :: Retry :> es => RetryPolicyM (Eff es) -> RetryStatus -> Eff es (Maybe RetryStatus)
+applyAndDelay policy status = unsafeEff $ \env -> Control.Retry.applyAndDelay (policyIO env policy) status
+
+retrying ::
+    Retry :> es =>
+    RetryPolicyM (Eff es) ->
+    (RetryStatus -> b -> Eff es Bool) ->
+    (RetryStatus -> Eff es b) ->
+    Eff es b
+retrying = Effectful.Retry.resumeRetrying defaultRetryStatus
+
+retryingDynamic ::
+    Retry :> es =>
+    RetryPolicyM (Eff es) ->
+    (RetryStatus -> b -> Eff es RetryAction) ->
+    (RetryStatus -> Eff es b) ->
+    Eff es b
+retryingDynamic = Effectful.Retry.resumeRetryingDynamic defaultRetryStatus
+
+resumeRetrying ::
+    Retry :> es =>
+    RetryStatus ->
+    RetryPolicyM (Eff es) ->
+    (RetryStatus -> b -> Eff es Bool) ->
+    (RetryStatus -> Eff es b) ->
+    Eff es b
+resumeRetrying retryStatus policy chk =
+    Effectful.Retry.resumeRetryingDynamic
+        retryStatus
+        policy
+        (\rs -> fmap toRetryAction . chk rs)
+
+resumeRetryingDynamic ::
+    Retry :> es =>
+    RetryStatus ->
+    RetryPolicyM (Eff es) ->
+    (RetryStatus -> b -> Eff es RetryAction) ->
+    (RetryStatus -> Eff es b) ->
+    Eff es b
+resumeRetryingDynamic retryStatus policy chk f =
+    unsafeEff $ \env ->
+        Control.Retry.resumeRetryingDynamic
+            retryStatus
+            (policyIO env policy)
+            (\rs b -> unEff (chk rs b) env)
+            (\rs -> unEff (f rs) env)
+
+recovering ::
+    Retry :> es =>
+    RetryPolicyM (Eff es) ->
+    [RetryStatus -> Handler (Eff es) Bool] ->
+    (RetryStatus -> Eff es a) ->
+    Eff es a
+recovering = Effectful.Retry.resumeRecovering defaultRetryStatus
+
+resumeRecovering ::
+    Retry :> es =>
+    RetryStatus ->
+    RetryPolicyM (Eff es) ->
+    [RetryStatus -> Handler (Eff es) Bool] ->
+    (RetryStatus -> Eff es a) ->
+    Eff es a
+resumeRecovering retryStatus policy hs =
+    Effectful.Retry.resumeRecoveringDynamic retryStatus policy hs'
+  where
+    hs' = map (fmap toRetryAction .) hs
+
+recoveringDynamic ::
+    Retry :> es =>
+    RetryPolicyM (Eff es) ->
+    [RetryStatus -> Handler (Eff es) RetryAction] ->
+    (RetryStatus -> Eff es a) ->
+    Eff es a
+recoveringDynamic = Effectful.Retry.resumeRecoveringDynamic defaultRetryStatus
+
+resumeRecoveringDynamic ::
+    Retry :> es =>
+    RetryStatus ->
+    RetryPolicyM (Eff es) ->
+    [RetryStatus -> Handler (Eff es) RetryAction] ->
+    (RetryStatus -> Eff es a) ->
+    Eff es a
+resumeRecoveringDynamic retryStatus policy hs f =
+    unsafeEff $ \env ->
+        Control.Retry.resumeRecoveringDynamic
+            retryStatus
+            (policyIO env policy)
+            (fmap (handlerIO env) <$> hs)
+            (\rs -> unEff (f rs) env)
+
+stepping ::
+    Retry :> es =>
+    RetryPolicyM (Eff es) ->
+    [RetryStatus -> Handler (Eff es) Bool] ->
+    (RetryStatus -> Eff es ()) ->
+    (RetryStatus -> Eff es a) ->
+    RetryStatus ->
+    Eff es (Maybe a)
+stepping policy hs schedule f s =
+    unsafeEff $ \env ->
+        Control.Retry.stepping
+            (policyIO env policy)
+            (fmap (handlerIO env) <$> hs)
+            (\rs -> unEff (schedule rs) env)
+            (\rs -> unEff (f rs) env)
+            s
+
+recoverAll ::
+    Retry :> es =>
+    RetryPolicyM (Eff es) ->
+    (RetryStatus -> Eff es a) ->
+    Eff es a
+recoverAll = Effectful.Retry.resumeRecoverAll defaultRetryStatus
+
+resumeRecoverAll :: Retry :> es => RetryStatus -> RetryPolicyM (Eff es) -> (RetryStatus -> Eff es a) -> Eff es a
+resumeRecoverAll retryStatus policy f =
+    unsafeEff $ \env ->
+        Control.Retry.resumeRecoverAll
+            retryStatus
+            (policyIO env policy)
+            (\rs -> unEff (f rs) env)
+
+skipAsyncExceptions ::
+    Retry :> es =>
+    [RetryStatus -> Handler (Eff es) Bool]
+skipAsyncExceptions = [asyncH, someAsyncH]
+  where
+    asyncH _ = Handler $ \(_ :: AsyncException) -> return False
+    someAsyncH _ = Handler $ \(_ :: SomeAsyncException) -> return False
+
+logRetries ::
+    (Retry :> es, Exception e) =>
+    (e -> Eff es Bool) ->
+    (Bool -> e -> RetryStatus -> Eff es ()) ->
+    RetryStatus ->
+    Handler (Eff es) Bool
+logRetries test reporter status = Handler $ \err -> do
+    result <- test err
+    reporter result err status
+    return result
+
+{- TODO
+retryOnError
+    :: (Error e :> es, Retry :> es)
+    => RetryPolicyM (Eff es)
+    -> (RetryStatus -> e -> Eff es Bool)
+    -> (RetryStatus -> Eff es a)
+    -> Eff es a
+retryOnError policy chk f = go defaultRetryStatus
+  where
+    go stat = do
+-}
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeOperators #-}
+
+module Main (main) where
+
+import Effectful
+import Effectful.Retry
+import Test.Tasty
+import Test.Tasty.HUnit
+
+main :: IO ()
+main =
+    defaultMain $
+        testGroup
+            "retry-effectful"
+            [ testCase "`retrying` works" $ do
+                res <- runRetryEff testRetrying
+                assertEqual "match" res 42
+            ]
+
+runRetryEff :: Eff '[Retry, IOE] a -> IO a
+runRetryEff = runEff . runRetry
+
+testRetrying :: '[Retry] :>> es => Eff es Int
+testRetrying = do
+    retrying (constantDelay 100) chk (const $ pure 42)
+  where
+    chk _ 42 = pure False
+    chk _ _ = pure True
