diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+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/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/retry.cabal b/retry.cabal
new file mode 100644
--- /dev/null
+++ b/retry.cabal
@@ -0,0 +1,38 @@
+name:                retry
+
+description: 
+
+        This package exposes combinators that can wrap arbitrary
+        monadic actions. They run the action and potentially retry
+        running it with some configurable delay for a configurable
+        number of times.
+
+        The purpose is to make it easier to work with IO and
+        especially network IO actions that often experience temporary
+        failure and warrant retrying of the original action. For
+        example, a database query may time out for a while, in which
+        case we should hang back for a bit and retry the query instead
+        of simply raising an exception.
+
+version:             0.1.0.0
+synopsis:            Retry combinators for monadic actions that may fail
+license:             BSD3
+license-file:        LICENSE
+author:              Ozgun Ataman
+maintainer:          ozgun.ataman@soostone.com
+copyright:           Ozgun Ataman, Soostone Inc
+category:            Control
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Control.Retry
+  build-depends:       
+    base ==4.*, 
+    MonadCatchIO-transformers >= 0.3,
+    mtl >= 0.2,
+    data-default,
+    syb >= 0.3
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+
diff --git a/src/Control/Retry.hs b/src/Control/Retry.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Retry.hs
@@ -0,0 +1,215 @@
+{-# LANGUAGE BangPatterns        #-}
+{-# LANGUAGE DeriveDataTypeable  #-}
+{-# LANGUAGE RankNTypes          #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Retry
+-- Copyright   :  Ozgun Ataman <ozgun.ataman@soostone.com>
+-- License     :  BSD3
+--
+-- Maintainer  :  Ozgun Ataman
+-- Stability   :  provisional
+--
+-- This module exposes combinators that can wrap arbitrary monadic
+-- actions. They run the action and potentially retry running it with
+-- some configurable delay for a configurable number of times.
+--
+-- The express purpose of this library is to make it easier to work
+-- with IO and especially network IO actions that often experience
+-- temporary failure that warrant retrying of the original action. For
+-- example, a database query may time out for a while, in which case
+-- we should delay a bit and retry the query.
+----------------------------------------------------------------------------
+
+
+module Control.Retry
+    (
+      -- * High Level Operation
+      RetrySettings (..)
+    , retrying
+    , recovering
+    , recoverAll
+
+    -- * Utilities
+    , delay
+    , flatDelay
+    , backoffDelay
+    ) where
+
+-------------------------------------------------------------------------------
+import           Control.Concurrent
+import           Control.Exception     (SomeException)
+import           Control.Monad.CatchIO
+import           Control.Monad.Trans
+import           Data.Default
+import           Data.Generics
+import           Prelude               hiding (catch)
+-------------------------------------------------------------------------------
+
+
+-- | Settings for retry behavior. Simply using 'def' for default
+-- values should work in most cases.
+data RetrySettings = RetrySettings {
+      numRetries :: Int
+    -- ^ Number of retries. Defaults to 5.
+    , backoff    :: Bool
+    -- ^ Whether to implement exponential backoff in retries. Defaults
+    -- to True.
+    , baseDelay  :: Int
+    -- ^ The base delay in miliseconds. Defaults to 50. Without
+    -- 'backoff', this is the delay. With 'backoff', this base delay
+    -- will grow by a factor of 2 on each subsequent retry.
+    }
+
+
+instance Default RetrySettings where
+    def = RetrySettings 5 True 50
+
+
+-- | Delay thread using backoff delay for the nth retry.
+backoffDelay :: (Integral b, MonadIO m) => RetrySettings -> b -> m ()
+backoffDelay set@RetrySettings{..} !n = liftIO (threadDelay (2^n * delay set))
+
+-- | Delay thread using flat delay
+flatDelay :: MonadIO m => RetrySettings -> t -> m ()
+flatDelay set@RetrySettings{..} !n = liftIO (threadDelay $ delay set)
+
+-- | Delay in micro seconds
+delay :: RetrySettings -> Int
+delay RetrySettings{..} = baseDelay * 1000
+
+
+-- | Retry combinator for actions that don't raise exceptions, but
+-- signal in their type the outcome has failed. Examples are the
+-- 'Maybe', 'Either' and 'EitherT' monads.
+--
+-- Let's write a function that always fails and watch this combinator
+-- retry it 5 additional times following the initial run:
+--
+-- >>> import Data.Maybe
+-- >>> let f = putStrLn "Running action" >> return Nothing
+-- >>> retrying def isNothing f
+-- Running action
+-- Running action
+-- Running action
+-- Running action
+-- Running action
+-- Running action
+-- Nothing
+--
+-- Note how the latest failing result is returned after all retries
+-- have been exhausted.
+retrying :: MonadIO m
+         => RetrySettings
+         -> (b -> Bool)
+         -- ^ A function to check whether the result should be
+         -- retried. If True, we delay and retry the operation.
+         -> m b
+         -- ^ Action to run
+         -> m b
+retrying set@RetrySettings{..} chk f = go 0
+    where
+      go n = do
+          res <- f
+          case chk res of
+            True ->
+              case n >= numRetries of
+                True -> return res
+                False -> do
+                    if backoff
+                      then backoffDelay set n
+                      else flatDelay set n
+                    go $! n+1
+            False -> return res
+
+
+
+-- | Retry ALL exceptions that may be raised. To be used with caution;
+-- this matches the exception on 'SomeException'.
+--
+-- See how the action below is run once and retried 5 more times
+-- before finally failing for good:
+--
+-- >>> let f = putStrLn "Running action" >> error "this is an error"
+-- >>> recoverAll def f
+-- Running action
+-- Running action
+-- Running action
+-- Running action
+-- Running action
+-- Running action
+-- *** Exception: this is an error
+recoverAll :: MonadCatchIO m
+         => RetrySettings
+         -> m a
+         -> m a
+recoverAll set f = recovering set [h] f
+    where
+      h = Handler $ \ (e :: SomeException) -> return True
+
+
+-- | Run an action and recover from a raised exception by potentially
+-- retrying the action a number of times.
+recovering :: forall m a. MonadCatchIO m
+           => RetrySettings
+           -- ^ Just use 'def' faor default settings
+           -> [Handler m Bool]
+           -- ^ Should a given exception be retried? Action will be
+           -- retried if this returns True.
+           -> m a
+           -- ^ Action to perform
+           -> m a
+recovering set@RetrySettings{..} hs f = go 0
+    where
+      -- | Convert a (e -> m Bool) handler into (e -> m a) so it can
+      -- be wired into the 'catches' combinator.
+      transHandler :: Int -> Handler m Bool -> Handler m a
+      transHandler n (Handler h) = Handler $ \ e -> do
+          chk <- h e
+          case chk of
+            True ->
+              case n >= numRetries of
+                True -> throw e
+                False -> do
+                    if backoff
+                      then backoffDelay set n
+                      else flatDelay set n
+                    go $! n+1
+            False -> throw e
+
+      -- handle :: forall e. Exception e => Handler m Bool -> Int -> e -> m a
+      -- handle (Handler h) n e = do
+      --     chk <- h e
+      --     case chk of
+      --       True ->
+      --         case n >= numRetries of
+      --           True -> throw e
+      --           False -> if backoff then backoffRetry n else flatRetry n
+      --       False -> throw e
+
+      go n = f `catches` map (transHandler n) hs
+
+
+
+                              ------------------
+                              -- Simple Tests --
+                              ------------------
+
+
+
+-- data TestException = TestException deriving (Show, Typeable)
+-- data AnotherException = AnotherException deriving (Show, Typeable)
+
+-- instance Exception TestException
+-- instance Exception AnotherException
+
+
+-- test = retrying def [h1,h2] f
+--     where
+--       f = putStrLn "Running action" >> throw AnotherException
+--       h1 = Handler $ \ (e :: TestException) -> return False
+--       h2 = Handler $ \ (e :: AnotherException) -> return True
+
+
