diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for freer-catching
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Co—Star Astrology, Ben Weitzman
+
+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,37 @@
+# freer-catching
+
+This is library for working with exceptions that are thrown during interpreation of free monad effects, at call time.
+
+## How to use
+
+This library exposes one effect:
+
+```haskell
+catching :: forall e f a r
+          . (Exception e, Member (Catching f e) r)
+         => Eff '[f] a
+         -> Eff r (Either e a)
+```
+
+We take an effectful function over one effect `f` and we turn it into an effectful computation of a new effect which denotes that we have an obligation to catch exceptions when we interpret this effect.
+
+We can then discharge this obligation by interpretting the effect `f` and and any `Catching` effects built on `f` by interpretting them both at the same time: 
+
+```haskell
+runCatching :: forall e r v f
+             . (Member IO r, Member IO (f ': r))
+            => (forall a q . Member IO q => Eff (f ': q) a -> Eff q a)
+            -> Eff (Catching f e : f : r) v
+            -> Eff r v
+``` 
+
+We can also interpret a `Catching f e` effect by way of another effect `g`:
+
+```haskell
+runCatching2 :: forall e r v f g
+             . (Member IO r, Member IO (f : r), Member IO (f : g : r))
+            => (forall a q. Member g q => Eff (f : q) a -> Eff q a)
+            -> (forall a q. Member IO q => Eff (g : q) a -> Eff q a)
+            -> Eff (Catching f e : f : g : r) v
+            -> Eff r v
+```            
diff --git a/freer-simple-catching.cabal b/freer-simple-catching.cabal
new file mode 100644
--- /dev/null
+++ b/freer-simple-catching.cabal
@@ -0,0 +1,55 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 0772a1bfb6665ce76c6a2873fff53b7df0d4c8140c85d8e2345f189a0cae3ade
+
+name:           freer-simple-catching
+version:        0.1.0.0
+synopsis:       Checked runtime exceptions with freer-simple
+description:    Please see the README on Gitlab at <https://gitlab.com/costar-astrology/freer-simple-contrib/tree/master/freer-simple-catching>
+category:       Control
+author:         Ben Weitzman
+maintainer:     ben@costarastrology.com
+copyright:      2018 Ben Weitzman, Co-Star Astrology
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://gitlab.com/costar-astrology/freer-simple-contrib/tree/master/freer-simple-catching
+
+library
+  exposed-modules:
+      Control.Monad.Freer.Catching
+  other-modules:
+      Paths_freer_simple_catching
+  hs-source-dirs:
+      src
+  default-extensions: GADTs FlexibleContexts TypeOperators DataKinds StandaloneDeriving DeriveDataTypeable MultiParamTypeClasses FlexibleInstances UndecidableInstances TypeApplications ScopedTypeVariables TypeFamilies RankNTypes DeriveAnyClass OverloadedStrings FunctionalDependencies ConstraintKinds EmptyCase BangPatterns
+  build-depends:
+      base >=4.7 && <5
+    , freer-simple >=1.1 && <1.2
+  default-language: Haskell2010
+
+test-suite freer-simple-catching-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Control.Monad.Freer.CatchingSpec
+      Paths_freer_simple_catching
+  hs-source-dirs:
+      test
+  default-extensions: GADTs FlexibleContexts TypeOperators DataKinds StandaloneDeriving DeriveDataTypeable MultiParamTypeClasses FlexibleInstances UndecidableInstances TypeApplications ScopedTypeVariables TypeFamilies RankNTypes DeriveAnyClass OverloadedStrings FunctionalDependencies ConstraintKinds EmptyCase BangPatterns
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , freer-simple >=1.1 && <1.2
+    , freer-simple-catching
+    , hspec
+  default-language: Haskell2010
diff --git a/src/Control/Monad/Freer/Catching.hs b/src/Control/Monad/Freer/Catching.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Freer/Catching.hs
@@ -0,0 +1,92 @@
+{-|
+Module      : Control.Monad.Freer.Catching
+Description : Handle exceptions that are thrown during interpreation of free monad effects, at call time.
+Copyright   : (c) Ben Weitzman 2018
+License     : MIT
+Maintainer  : ben@costarastrolgoy.com
+Stability   : experimental
+Portability : POSIX
+
+The 'Catching' effect allows a way to keep track of effects that we might expect to throw
+exceptions during their handling, but whose signatures don't indicate this.
+
+As an example, consider an effect @Div@ that divides numbers:
+
+@
+  data Div a where
+   Div :: Int -> Int -> Div Int
+@
+
+The keen programmer is aware that this can throw an error. However, suppose that there is reason to believe that
+this effect will be rarely used in a way that fails. Adding an indicator to the interface (such as by saying @Div :: Int -> Int -> Div (Maybe Int)@) makes using this effect more annoying most of the time. 
+
+Nevertheless, it should be possible to handle this case when we want to. This is where 'Catching' can help.
+-}
+module Control.Monad.Freer.Catching
+  (Catching
+  ,catching
+  ,runCatching
+  ,runCatching2
+  )
+where
+
+import           Control.Exception
+import           Control.Monad
+import           Control.Monad.Freer
+import           Control.Monad.Freer.Internal
+import           Data.OpenUnion.Internal
+
+-- | The 'Catching' effect is parameterized by the effect it is handling and the type of exceptions it will
+-- attempt to handle (e.g. @Catching Div ArithException@)
+data Catching f e a where
+    Catching :: forall f e a . (Exception e)
+             => (forall r . Member f r => Eff r a)
+             -> Catching f e (Either e a)
+             
+-- | @catching@ will turn an effectful computation producing an @a@ and using effect @f@ into one that produces
+-- an @Either e a@. This allows any exception that is thrown during normal handling of @f@ be handled explicitly.
+catching :: forall e f a r
+          . (Exception e, Member (Catching f e) r)
+         => Eff '[f] a
+         -> Eff r (Either e a)
+catching f = send @(Catching f e) $ Catching (generalize f)
+
+generalize :: Member f r => Eff '[f] a -> Eff r a
+generalize (Val x)  = return x
+generalize (E u' q) = send (extract u') >>= qComp q generalize
+
+-- | Handle an effect @f@ and a @Catching f e@ simultaneously. In cases where 'catching' was called, on an
+-- effect, exceptions of type @e@ will be caught and handled. In cases where 'catching' was not called but
+-- @f@ was used directly, exceptions will not be caught and will bubble up.
+runCatching :: forall e r v f
+             . (Member IO r, LastMember IO (f ': r))
+            => (forall a q . Member IO q => Eff (f ': q) a -> Eff q a)
+            -> Eff (Catching f e : f : r) v
+            -> Eff r v
+runCatching runner = runner . interpretM handler
+    where handler :: Catching f e a -> IO a
+          handler (Catching f) = do
+            x <- try . runM $ evaluate <$> runner f
+            case x of
+              Left e -> return $ Left e
+              Right y -> try y
+
+-- | 'runCatching2' can catch exceptions in effects that don't interpret directly to 'IO' but instead
+-- go through an intermediary effect. In this case, three effects will be handled in one go:
+--
+--   * The effect @f@ that is being called and is expected to be the source of an exception
+--   * The effect @g@ which is not being called directly but is called instead by the handler @f@
+--   * The effect @Catching f e@ 
+runCatching2 :: forall e r v f g
+             . (Member IO r, Member IO (f : r), LastMember IO (f : g : r))
+            => (forall a q. Member g q => Eff (f : q) a -> Eff q a)
+            -> (forall a q. Member IO q => Eff (g : q) a -> Eff q a)
+            -> Eff (Catching f e : f : g : r) v
+            -> Eff r v
+runCatching2 runner1 runner2 = runner2 . runner1 . interpretM handler
+    where handler :: Catching f e a -> IO a
+          handler (Catching f) = do
+            x <- try . runM $ evaluate <$> (runner2 . runner1 $ f)
+            case x of
+              Left e -> return $ Left e
+              Right y -> try y
diff --git a/test/Control/Monad/Freer/CatchingSpec.hs b/test/Control/Monad/Freer/CatchingSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Control/Monad/Freer/CatchingSpec.hs
@@ -0,0 +1,69 @@
+module Control.Monad.Freer.CatchingSpec where
+
+import           Control.Monad
+import           Control.Exception
+import           Control.Monad.Freer
+import           Control.Monad.Freer.Catching
+import           Test.Hspec
+
+data Div a where
+  Div :: Int -> Int -> Div Int
+
+runDiv :: forall r v . Eff (Div ': r) v -> Eff r v
+runDiv = interpret handler
+  where
+    handler :: Div a -> Eff r a
+    handler (Div x y) = return $ x `div` y
+
+data Test a where
+  Succeed :: Test Int
+  Fail :: Test Bool
+
+data TestException = TestException deriving (Show, Exception, Eq)
+
+runTest :: forall r v . (Member IO r)
+        => Eff (Test ': r) v
+       -> Eff r v
+runTest = interpret handler
+  where
+    handler :: Test a -> Eff r a
+    handler Succeed = return 3
+    handler Fail = throw TestException
+
+spec :: Spec
+spec = do
+  describe "div" $ do
+    it "divides" $ do
+      (run . runDiv . send $ Div 4 2) `shouldBe` 2
+
+  describe "catching" $ do
+    it "lets unexceptional values through from pure code" $ do
+      result <- runM . runCatching @ArithException runDiv $
+        catching @ArithException @Div (send $ Div 2 1)
+      result `shouldBe` Right 2
+
+    it "catches exceptions from pure code" $ do
+      result <- runM . runCatching @ArithException runDiv $
+        catching @ArithException @Div (send $ Div 2 0)
+      result `shouldBe` Left DivideByZero
+
+    it "lets unexceptional io values through" $ do
+      result <- runM . runCatching @TestException runTest $
+        catching @TestException @Test (send Succeed)
+      result `shouldBe` Right 3
+
+    it "catches io exceptions" $ do
+      result <- runM . runCatching @TestException runTest $
+        catching @TestException @Test (send Fail)
+      result `shouldBe` Left TestException
+
+    it "catches inside forM" $ do
+      result <- runM . runCatching @TestException runTest $
+        forM [1,2,3] $ \i -> do
+          x <- catching @TestException @Test (send Fail)
+          y <- case x of
+            Left e -> return i
+            Right v -> if v then return 1 else return 2
+          z <- send Succeed
+          return $ y + z
+      result `shouldBe` [4,5,6]
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
