diff --git a/Control/Proxy/Safe.hs b/Control/Proxy/Safe.hs
new file mode 100644
--- /dev/null
+++ b/Control/Proxy/Safe.hs
@@ -0,0 +1,577 @@
+-- | Exception handling and resource management integrated with proxies
+
+{-# LANGUAGE Rank2Types, CPP, KindSignatures #-}
+
+module Control.Proxy.Safe (
+    -- * Exception Handling
+    -- $exceptionp
+    module Control.Proxy.Trans.Either,
+    module Exception,
+    ExceptionP,
+    throw,
+    catch,
+    handle,
+
+    -- * Safe IO
+    SafeIO,
+    runSafeIO,
+    runSaferIO,
+    trySafeIO,
+    trySaferIO,
+
+    -- * Checked Exceptions
+    -- $check
+    CheckP(..),
+    tryK,
+    tryIO,
+
+    -- * Finalization
+    onAbort,
+    finally,
+    bracket,
+    bracket_,
+    bracketOnAbort,
+
+    -- * Prompt Finalization
+    -- $prompt
+    unsafeCloseU,
+    unsafeCloseD,
+    unsafeClose
+    ) where
+
+import qualified Control.Exception as Ex
+import Control.Exception as Exception (SomeException, Exception)
+import Control.Applicative (Applicative(pure, (<*>)))
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Reader (ReaderT(ReaderT, runReaderT), asks)
+import qualified Control.Proxy as P
+import qualified Control.Proxy.Core.Fast as PF
+import qualified Control.Proxy.Core.Correct as PC
+import Control.Proxy ((>->))
+import Control.Proxy.Trans.Identity
+import qualified Control.Proxy.Trans.Either as E
+import qualified Control.Proxy.Trans.Reader as R
+import Control.Proxy.Trans.Either hiding (throw, catch, handle)
+import Data.IORef (IORef, newIORef, readIORef, writeIORef)
+#if MIN_VERSION_base(4,6,0)
+#else
+import Prelude hiding (catch)
+#endif
+
+{- $exceptionp
+    This library checks and stores all exceptions using the 'EitherP' proxy
+    transformer.  The following type synonym simplifies type signatures.
+
+    Use 'runEitherP' / 'runEitherK' from the re-exported
+    @Control.Proxy.Trans.Either@ to convert 'ExceptionP' back to the base
+    monad
+
+    This module does not re-export 'E.throw', 'E.catch', and 'E.handle' from
+    @Control.Proxy.Trans.Either@ and instead defines new versions similar to the
+    API from @Control.Exception@.  If you want the old versions you will need to
+    import them qualified.
+
+    This module only re-exports 'SomeException' from @Control.Exception@.
+-}
+
+-- | A proxy transformer that stores exceptions using 'EitherP'
+type ExceptionP = EitherP SomeException
+
+-- | Analogous to 'Ex.throwIO' from @Control.Exception@
+throw :: (Monad m, P.Proxy p, Ex.Exception e) => e -> ExceptionP p a' a b' b m r
+throw = E.throw . Ex.toException
+
+-- | Analogous to 'Ex.catch' from @Control.Exception@
+catch
+ :: (Ex.Exception e, Monad m, P.Proxy p)
+ => ExceptionP p a' a b' b m r         -- ^ Original computation
+ -> (e -> ExceptionP p a' a b' b m r)  -- ^ Handler
+ -> ExceptionP p a' a b' b m r
+catch p f = p `E.catch` (\someExc ->
+    case Ex.fromException someExc of
+        Nothing -> E.throw someExc
+        Just e  -> f e )
+
+-- | Analogous to 'Ex.handle' from @Control.Exception@
+handle
+ :: (Ex.Exception e, Monad m, P.Proxy p)
+ => (e -> ExceptionP p a' a b' b m r)  -- ^ Handler
+ -> ExceptionP p a' a b' b m r         -- ^ Original computation
+ -> ExceptionP p a' a b' b m r
+handle = flip catch
+
+data Status = Status {
+    restore    :: forall a . IO a -> IO a,
+    upstream   :: IORef (IO ())          ,
+    downstream :: IORef (IO ())          }
+
+{-| 'SafeIO' masks asynchronous exceptions by default, and only unmasks them
+    during 'try' or 'tryIO' blocks in order to check all asynchronous
+    exceptions.
+
+    'SafeIO' also saves all finalizers dropped as a result of premature
+    termination and runs them when the 'P.Session' completes.
+-}
+newtype SafeIO r = SafeIO { unSafeIO :: ReaderT Status IO r }
+
+instance Functor SafeIO where
+    fmap f m = SafeIO (fmap f (unSafeIO m))
+
+instance Applicative SafeIO where
+    pure r  = SafeIO (pure r)
+    f <*> x = SafeIO (unSafeIO f <*> unSafeIO x)
+
+instance Monad SafeIO where
+    return r = SafeIO (return r)
+    m >>= f  = SafeIO (unSafeIO m >>= \a -> unSafeIO (f a))
+
+{-| Convert back to the 'IO' monad, running all dropped finalizers at the very
+    end and rethrowing any checked exceptions
+
+    This uses 'Ex.mask' to mask asynchronous exceptions and only unmasks them
+    during 'try' or 'tryIO'.
+-}
+runSafeIO :: SafeIO (Either SomeException r) -> IO r
+runSafeIO m =
+    Ex.mask $ \restore -> do
+        huRef <- newIORef (return ())
+        hdRef <- newIORef (return ())
+        e <- runReaderT (unSafeIO m) (Status restore huRef hdRef)
+            `Ex.finally` (do
+                hu <- readIORef huRef
+                hu
+                hd <- readIORef hdRef
+                hd )
+        case e of
+            Left exc -> Ex.throwIO exc
+            Right r  -> return r
+
+{-| Convert back to the 'IO' monad, running all dropped finalizers at the very
+    end and rethrowing any checked exceptions
+
+    This uses 'Ex.uninterruptibleMask' to mask asynchronous exceptions and only
+    unmasks them during 'try' or 'tryIO'.
+-}
+runSaferIO :: SafeIO (Either SomeException r) -> IO r
+runSaferIO m =
+    Ex.uninterruptibleMask $ \restore -> do
+        huRef <- newIORef (return ())
+        hdRef <- newIORef (return ())
+        e <- runReaderT (unSafeIO m) (Status restore huRef hdRef)
+            `Ex.finally` (do
+                hu <- readIORef huRef
+                hu
+                hd <- readIORef hdRef
+                hd )
+        case e of
+            Left exc -> Ex.throwIO exc
+            Right r  -> return r
+
+{-| Convert back to the 'IO' monad, running all dropped finalizers at the very
+    end and preserving exceptions as 'Left's
+
+    This uses 'Ex.mask' to mask asynchronous exceptions and only unmasks them
+    during 'try' or 'tryIO'.
+-}
+trySafeIO :: SafeIO e -> IO e
+trySafeIO m =
+    Ex.mask $ \restore -> do
+        huRef <- newIORef (return ())
+        hdRef <- newIORef (return ())
+        runReaderT (unSafeIO m) (Status restore huRef hdRef) `Ex.finally` (do
+            hu <- readIORef huRef
+            hu
+            hd <- readIORef hdRef
+            hd )
+
+{-| Convert back to the 'IO' monad, running all dropped finalizers at the very
+    end and preserving exceptions as 'Left's
+
+    This uses 'Ex.uninterruptibleMask' to mask asynchronous exceptions and only
+    unmasks them during 'try' or 'tryIO'.
+-}
+trySaferIO :: SafeIO e -> IO e
+trySaferIO m =
+    Ex.uninterruptibleMask $ \restore -> do
+        huRef <- newIORef (return ())
+        hdRef <- newIORef (return ())
+        runReaderT (unSafeIO m) (Status restore huRef hdRef) `Ex.finally` (do
+            hu <- readIORef huRef
+            hu
+            hd <- readIORef hdRef
+            hd )
+
+
+{- I don't export registerK/register only because people rarely want to guard
+   solely against premature termination.  Usually they also want to guard
+   against exceptions, too.
+
+    'registerK' should satisfy the following laws:
+
+* 'registerK' defines a functor from finalizers to functions:
+
+> registerK morph m1 . registerK morph m2 = registerK morph (m2 >> m1)
+> 
+> registerK morph (return ()) = id
+
+* 'registerK' is a functor between Kleisli categories:
+
+> registerK morph m (p1 >=> p2) = registerK morph m p1 >=> registerK morph m p2
+>
+> registerK morph m return = return
+
+    These laws are not provable using the current set of proxy laws, mainly
+    because the proxy laws do not yet specify how proxies interact with the
+    'Arrow' instance for the Kleisli category.  However, I'm reasonably sure
+    that when I do specify this interaction that the above laws will hold.
+
+    For now, just consider the above laws the contract for 'registerK' and
+    consider any violations of the above laws as bugs.
+-}
+registerK
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x)
+ -> IO ()
+ -> (b' -> p a' a b' b m r)
+ -> (b' -> p a' a b' b m r)
+registerK morph h k =
+    P.runIdentityK (P.hoistK morph up) >-> k >-> P.runIdentityK (P.hoistK morph dn)
+  where
+    dn b'0 = do
+        b0 <- P.request b'0
+        huRef <- lift $ SafeIO $ asks downstream
+        let dn' b = do
+                hu <- lift $ SafeIO $ lift $ do
+                    hu <- readIORef huRef
+                    writeIORef huRef (hu >> h)
+                    return hu
+                b' <- P.respond b
+                lift $ SafeIO $ lift $ writeIORef huRef hu
+                b2 <- P.request b'
+                dn' b2
+        dn' b0
+    up a'0 = do
+        hdRef <- lift $ SafeIO $ asks upstream
+        let up' a' = do
+                hd  <- lift $ SafeIO $ lift $ do
+                    hd <- readIORef hdRef
+                    writeIORef hdRef (h >> hd)
+                    return hd
+                a   <- P.request a'
+                lift $ SafeIO $ lift $ writeIORef hdRef hd
+                a'2 <- P.respond a
+                up' a'2
+        up' a'0
+
+register
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x)
+ -> IO ()
+ -> p a' a b' b m r
+ -> p a' a b' b m r
+register morph h p = registerK morph h (\_ -> p) undefined
+{- This is safe and there is a way that does not use 'undefined' if I slightly
+   restructure the Proxy type class, but this will work for now. -}
+
+{- $check
+    The following @try@ functions are the only way to convert 'IO' actions to
+    'SafeIO'.  These functions check all exceptions, including asynchronous
+    exceptions, and store them in the 'ExceptionP' proxy transformer.
+-}
+
+{-| You can retroactively check all exceptions for proxies that implement
+    'CheckP'.
+
+    'try' is /almost/ a proxy morphism, which means that @tryK = (try .)@
+    defines a functor that preserves five categories.  I say \"almost\" because
+    it unmasks asynchronous exceptions for 'return'.  However, this does not
+    affect the exception safety of this implementation.
+
+    Functor between \'@K@\'leisli categories:
+
+> tryK f >=> tryK g = tryK (f >=> g)
+>
+> tryK return = return  -- Not true for asynchronous exceptions
+
+    Functor between 'P.Proxy' categories:
+
+> tryK f >-> tryK g = tryK (f >-> g)
+>
+> tryK idT = idT
+
+> tryK f >~> tryK g = tryK (f >~> g)
+> 
+> tryK coidT = coidT
+
+    Functor between \"request\" categories:
+
+> tryK f \>\ tryK g = tryK (f \>\ g)
+>
+> tryK request = request
+
+    Functor between \"respond\" categories:
+
+> tryK f />/ tryK g = tryK (f />/ g)
+>
+> tryK respond = respond
+-}
+class (P.Proxy p) => CheckP p where
+    try :: p a' a b' b IO r -> ExceptionP p a' a b' b SafeIO r
+
+instance CheckP PF.ProxyFast where
+    try p0 = EitherP (go p0) where
+        go p = case p of
+            PF.Request a' fa  -> PF.Request a' (\a  -> go (fa  a ))
+            PF.Respond b  fb' -> PF.Respond b  (\b' -> go (fb' b'))
+            PF.M m -> PF.M (SafeIO (ReaderT (\s -> do
+                e <- Ex.try (restore s m)
+                case e of
+                    Left exc -> return (PF.Pure (Left exc))
+                    Right p' -> return (go p') )))
+            PF.Pure r -> PF.Pure (Right r)
+
+instance CheckP PC.ProxyCorrect where
+    try p0 = EitherP (go p0) where
+        go p = PC.Proxy (SafeIO (ReaderT (\s -> do
+            e <- Ex.try (restore s (PC.unProxy p))
+            case e of
+                Left exc -> return (PC.Pure (Left exc))
+                Right fp -> case fp of
+                    PC.Request a' fa  ->
+                        return (PC.Request a' (\a  -> go (fa  a )))
+                    PC.Respond b  fb' ->
+                        return (PC.Respond b  (\b' -> go (fb' b')))
+                    PC.Pure r -> return (PC.Pure (Right r)) )))
+
+instance (CheckP p) => CheckP (IdentityP p) where
+    try = EitherP . IdentityP . runEitherP . try . runIdentityP
+
+instance (CheckP p) => CheckP (R.ReaderP i p) where
+    try p = EitherP $ R.ReaderP $ \i -> runEitherP $ try (R.unReaderP p i)
+
+-- | Check all exceptions for a 'P.Proxy' \'@K@\'leisli arrow
+tryK
+ :: (CheckP p)
+ => (q -> p a' a b' b IO r) -> (q -> ExceptionP p a' a b' b SafeIO r)
+tryK = (try .)
+
+{-| Check all exceptions for an 'IO' action
+
+> (tryIO .) f >=> (tryIO .) g = (tryIO .) (f >=> g)
+>
+> (tryIO .) return = return  -- Not true for asynchronous exceptions
+-}
+tryIO :: (P.Proxy p) => IO r -> ExceptionP p a' a b' b SafeIO r
+tryIO io = EitherP $ P.runIdentityP $ lift $ SafeIO $ ReaderT $ \s ->
+    Ex.try $ restore s io
+
+{-| Similar to 'Ex.onException' from @Control.Exception@, except this also
+    protects against:
+
+    * premature termination, and
+
+    * exceptions in other proxy stages.
+
+    The first argument lifts 'onAbort' to work with other base monads.  Use
+    'id' if your base monad is already 'SafeIO'.
+
+> do x <- onAbort morph fin m
+>    onAbort morph fin (f x)
+> = onAbort morph fin $ do x <- m
+>                          f x
+>
+> onAbort morph fin (return x) = return x
+
+> onAbort morph fin1 . onAbort morph fin2 = onAbort morph (fin2 >> fin1)
+>
+> onAbort morph (return ()) = id
+-}
+onAbort
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x)  -- ^ Monad morphism
+ -> IO r'                         -- ^ Action to run on abort
+ -> ExceptionP p a' a b' b m r    -- ^ Guarded computation
+ -> ExceptionP p a' a b' b m r
+onAbort morph after p =
+    register morph (after >> return ()) p
+        `E.catch` (\e -> do
+            P.hoist morph $ tryIO after
+            E.throw e )
+
+{-| Analogous to 'Ex.finally' from @Control.Exception@
+
+    The first argument lifts 'finally' to work with other base monads.  Use 'id'
+    if your base monad is already 'SafeIO'.
+
+> finally morph after p = do
+>     r <- onAbort morph after p
+>     hoist morph $ tryIO after
+>     return r
+-}
+finally
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x) -- ^ Monad morphism
+ -> IO r'                        -- ^ Guaranteed final action
+ -> ExceptionP p a' a b' b m r   -- ^ Guarded computation
+ -> ExceptionP p a' a b' b m r
+finally morph after p = do
+    r <- onAbort morph after p
+    P.hoist morph $ tryIO after
+    return r
+
+{-| Analogous to 'Ex.bracket' from @Control.Exception@
+
+    The first argument lifts 'bracket' to work with other base monads.  Use 'id'
+    if your base monad is already 'SafeIO'.
+
+    'bracket' guarantees that if the resource acquisition completes, then the
+    resource will be released.
+
+> bracket morph before after p = do
+>     h <- hoist morph $ tryIO before
+>     finally morph (after h) (p h)
+-}
+bracket
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x)       -- ^ Monad morphism
+ -> IO h                               -- ^ Acquire resource
+ -> (h -> IO r')                       -- ^ Release resource
+ -> (h -> ExceptionP p a' a b' b m r)  -- ^ Use resource
+ -> ExceptionP p a' a b' b m r
+bracket morph before after p = do
+    h <- P.hoist morph $ tryIO before
+    finally morph (after h) (p h)
+
+{-| Analogous to 'Ex.bracket_' from @Control.Exception@
+
+    The first argument lifts 'bracket_' to work with any base monad.  Use 'id'
+    if your base monad is already 'SafeIO'.
+
+> bracket_ morph before after p = do
+>     hoist morph $ tryIO before
+>     finally morph after p
+-}
+bracket_
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x)  -- ^ Monad morphism
+ -> IO r1                         -- ^ Acquire resource
+ -> IO r2                         -- ^ Release resource
+ -> ExceptionP p a' a b' b m r    -- ^ Use resource
+ -> ExceptionP p a' a b' b m r
+bracket_ morph before after p = do
+    P.hoist morph $ tryIO before
+    finally morph after p
+
+{-| Analogous to 'Ex.bracketOnAbort' from @Control.Exception@
+
+    The first argument lifts 'bracketOnAbort' to work with any base monad.  Use
+    'id' if your base monad is already 'SafeIO'.
+
+> bracketOnAbort morph before after p = do
+>     h <- hoist morph $ tryIO before
+>     onAbort morph (after h) (p h)
+-}
+bracketOnAbort
+ :: (Monad m, P.Proxy p)
+ => (forall x . SafeIO x -> m x)       -- ^ Monad morphism
+ -> IO h                               -- ^ Acquire resource
+ -> (h -> IO r')                       -- ^ Release resource
+ -> (h -> ExceptionP p a' a b' b m r)  -- ^ Use resource
+ -> ExceptionP p a' a b' b m r
+bracketOnAbort morph before after p = do
+    h <- P.hoist morph $ tryIO before
+    onAbort morph (after h) (p h)
+
+{- $prompt
+    This implementation will not /promptly/ finalize a 'P.Proxy' if another
+    composed 'P.Proxy' prematurely terminates.  However, the implementation will
+    still save the dropped finalizer and run it when the 'P.Session' completes
+    in order to guarantee deterministic finalization.
+
+    To see why, consider the following 'P.Proxy' assembly:
+
+> p1 >-> ((p2 >-> p3) >=> p4)
+
+    Now ask yourself the question, \"If @p3@ prematurely terminates, should it
+    promptly finalize @p1@?\"
+
+    If you answered \"yes\", then you would have a bug if @p4@ were to
+    'request', which would restore control to @p1@ after we already finalized
+    it.
+
+    If you answered \"no\", then consider the case where @p2 = idT@ and
+    @p4 = return@:
+
+> p1 >-> ((idT >-> p3) >=> return)
+> p1 >-> (idT >-> p3)               -- f   >=> return = f
+> p1 >-> p3                         -- idT >-> p      = p
+
+    Answering \"no\" means that @p3@ would be unable to promptly finalize a
+    'P.Proxy' immediately upstream of it.
+
+    There is a solution that permits perfectly prompt finalization, but it
+    requires indexed monads to guarantee the necessary safety through the type
+    system.  In the absence of indexed monads, the next best solution is to let
+    you promptly finalize things yourself, but then /you/ must prove that this
+    finalization is safe and that all upstream pipes are unreachable.
+
+    The following two unsafe operations allow you to trade safety for prompt
+    finalization.  Use them if you desire prompter finalization guarantees and
+    if you can prove their usage is safe.  However, this proof is not trivial.
+
+    For example, you might suppose that the following usage of 'unsafeCloseU' is
+    safe because it never 'request's after closing upstream, nor does it
+    terminate:
+
+> falseSenseOfSecurity () = do
+>     x <- request ()
+>     unsafeCloseU
+>     forever $ respond x
+
+    However, this is not safe, as the following counter-example demonstrates:
+
+> p1 >-> ((falseSenseOfSecurity >-> request) >=> request)
+
+    @falseSenseOfSecurity@ will finalize the upstream @p1@, but then will
+    abort when the downstream 'request' terminates, and then the second
+    'request' will illegally access @p1@ after we already finalized it.
+
+    In other words, you cannot prove any prompt finalization is safe unless you
+    control the entire 'P.Session'.  Therefore, do not use the following unsafe
+    operations in 'P.Proxy' libraries.  Only the end user assembling the
+    final 'P.Session' may safely insert these calls.
+-}
+
+{-| 'unsafeCloseU' calls all finalizers registered upstream of the current
+    'P.Proxy'. -}
+unsafeCloseU :: (P.Proxy p) => r -> ExceptionP p a' a b' b SafeIO r
+unsafeCloseU r = do
+    (huRef, hu) <- lift $ SafeIO $ do
+        huRef <- asks upstream
+        hu    <- lift $ readIORef huRef
+        return (huRef, hu)
+    tryIO hu
+    lift $ SafeIO $ lift $ writeIORef huRef (return ())
+    return r
+
+{-| 'unsafeCloseD' calls all finalizers registered downstream of the current
+    'P.Proxy'. -}
+unsafeCloseD :: (P.Proxy p) => r -> ExceptionP p a' a b' b SafeIO r
+unsafeCloseD r = do
+    (hdRef, hd) <- lift $ SafeIO $ do
+        hdRef <- asks downstream
+        hd    <- lift $ readIORef hdRef
+        return (hdRef, hd)
+    tryIO hd
+    lift $ SafeIO $ lift $ writeIORef hdRef (return ())
+    return r
+
+{-| 'unsafeClose' calls all registered finalizers
+
+    'unsafeClose' is a Kleisli arrow so that you can easily seal terminating
+    proxies if there is a risk of delayed finalization:
+
+> (producer >-> (takeB_ 10 >=> unsafeClose) >-> consumer) >=> later
+-}
+unsafeClose :: (P.Proxy p) => r -> ExceptionP p a' a b' b SafeIO r
+unsafeClose = unsafeCloseU P.>=> unsafeCloseD
diff --git a/Control/Proxy/Safe/Tutorial.hs b/Control/Proxy/Safe/Tutorial.hs
new file mode 100644
--- /dev/null
+++ b/Control/Proxy/Safe/Tutorial.hs
@@ -0,0 +1,484 @@
+{-| This module provides the tutorial for the @pipes-safe@ library
+
+    This tutorial assumes that you have already read the main @pipes@ tutorial
+    in @Control.Proxy.Tutorial@.
+-}
+
+module Control.Proxy.Safe.Tutorial (
+    -- * Introduction
+    -- $intro
+
+    -- * Resource Safety
+    -- $safety
+
+    -- * Native Exception Handling
+    -- $native
+
+    -- * Checked Exceptions
+    -- $checked
+
+    -- * Prompt Finalization
+    -- $prompt
+
+    -- * Upgrade Proxy Transformers
+    -- $trytransformer
+
+    -- * Backwards Compatibility
+    -- $backwards
+
+    -- * Laziness
+    -- $laziness
+
+    -- * Conclusion
+    -- $conclusion
+    ) where
+
+import Control.Proxy
+import Control.Proxy.Safe
+import System.IO (withFile)
+
+{- $intro
+    @pipes-safe@ adds exception-safe resource management to the @pipes@
+    ecosystem.  Use this library if you want to:
+
+    * Safely acquire and release resources within proxies
+
+    * Natively catch and handle exceptions, including asynchronous exceptions
+
+    The following example shows how to use 'P.Proxy' resource management to
+    safely open and close a file:
+
+> import Control.Monad (unless)
+> import Control.Proxy
+> import Control.Proxy.Safe
+> import System.IO
+> 
+> readFileS
+>  :: (Proxy p) => FilePath -> () -> Producer (ExceptionP p) String SafeIO ()
+> readFileS file () = bracket id
+>     (do h <- openFile file ReadMode
+>         putStrLn $ "{File Open}"
+>         return h )
+>     (\h -> do putStrLn "{Closing File}"
+>               hClose h )
+>     (\h -> let loop = do
+>                    eof <- tryIO $ hIsEOF h
+>                    unless eof $ do
+>                        str <- tryIO $ hGetLine h
+>                        respond str
+>                        loop
+>             in loop )
+
+    @readFileS@ uses 'bracket' from "Control.Proxy.Safe" to guard the file
+    handle, which imposes two constraints on the type:
+
+    * 'bracket' requires the 'ExceptionP' proxy transformer in order to handle
+      exceptions
+
+    * 'bracket' requires 'SafeIO' as the base monad, which checks all
+      asynchronous exceptions and stores registered finalizers
+
+    But what if we already wrote a 'Consumer' that doesn't use 'ExceptionP' or
+    'SafeIO'?
+
+> printer :: (Proxy p, Show a) => () -> Consumer p a IO r
+> printer () = runIdentityP $ forever $ do
+>     a <- request ()
+>     lift $ print a
+
+    Do we need to rewrite it to use resource management abstractions?  Not at
+    all!  We can use 'try' / 'tryK' to automatically promote any \"unmanaged\"
+    proxy to a \"managed\" proxy:
+
+> tryK
+>  :: CheckP p
+>  => (q -> p a' a b' b IO r) -> q -> ExceptionP p a' a b' b SafeIO r 
+>
+> tryK printer :: (CheckP p, Show a) => () -> Consumer (Exception p) a SafeIO r
+>
+> session :: (CheckP p) => () -> Session (Exception p) SafeIO ()
+> session = readFileS "test.txt" >-> tryK printer
+
+    The 'CheckP' constraint indicates that the base 'Proxy' type must be
+    promotable using 'try'.
+
+    To run this 'Session', we unwrap each layer:
+
+>>> runSafeIO $ runProxy $ runEitherK session :: IO ()
+{File Open}
+"Line 1"
+"Line 2"
+"Line 3"
+"Line 4"
+{Closing File}
+
+-}
+
+{- $safety
+    'bracket' guarantees that every successful resource acquisition is paired
+    with finalization, even in the face of exceptions or premature 'Session'
+    termination.
+
+    For example, if we only draw two lines of input, 'bracket' will still safely
+    finalize the handle:
+
+> main = runSafeIO $ runProxy $ runEitherK $
+>     readFileS "test.txt" >-> takeB_ 2 >-> tryK printD
+
+>>> main
+{File Open}
+"Line 1"
+"Line 2"
+{Closing File}
+
+    We can even sabotage ourselves by killing our own thread after a delay:
+
+> import Control.Concurrent
+>
+> main = do
+>     tID <- myThreadId
+>     forkIO $ do
+>         threadDelay 1000
+>         killThread tID
+>     runSafeIO $ runProxy $ runEitherK $
+>         foreverK (readFileS "test.txt") >-> tryK printD
+
+>>> main
+...
+"Line 2"
+"Line 3"
+"Line 4"
+{Closing File}
+{File Open}
+"Line 1"
+"Line 2"
+{Closing File}
+*** Exception: thread killed
+
+    ... yet 'bracket' still ensures deterministic resource finalization in the
+    face of asynchronous exceptions.
+-}
+
+{- $native
+    Let's study the types a bit to understand what is going on:
+
+> type ExceptionP = EitherP SomeException
+
+    'ExceptionP' is just a type synonym around 'EitherP'.  @pipes-safe@ uses
+    'EitherP' to check all exceptions in order to take advantage of the ability
+    to 'catch' and 'throw' exceptions locally.  In fact, "Control.Proxy.Safe"
+    defines specialized versions of 'throw' and 'catch' that mirror their
+    equivalents in @Control.Exception@:
+
+> throw :: (Monad m, Proxy p, Exception e) => e -> ExceptionP p a' a b' b m r
+>
+> catch
+>  :: (Monad m, Proxy p, Exception e)
+>  => ExceptionP p a' a b' b m r
+>  -> (e -> ExceptionP p a' a b' b m r)
+>  -> ExceptionP p a' a b' b m r
+
+    These let you embed native exception handling into proxies.  For example,
+    we could exception handling to recover from a file opening error:
+
+> import Prelude hiding (catch) -- if using base <= 4.5
+>
+> openFileS :: (CheckP p) => () -> Producer (ExceptionP p) String SafeIO ()
+> openFileS () = (do
+>     tryIO $ putStrLn "Select a file:"
+>     file <- tryIO getLine
+>     readFileS file ())
+>   `catch` (\e -> do
+>       tryIO $ print (e :: IOException)
+>       openFileS () )
+
+>>> runSafeIO $ runProxy $ runEitherK $ openFileS >-> tryK printD
+Select a file:
+oops
+oops: openFile: does not exist (No such file or directory)
+Select a file:
+test.txt
+{File Open}
+"Line 1"
+"Line 2"
+"Line 3"
+"Line 4"
+{Closing File}
+
+    You can even catch and resume from asynchronous exceptions:
+
+> heartbeat
+>   :: Proxy p
+>   => ExceptionP p a' a b' b SafeIO r -> ExceptionP p a' a b' b SafeIO r
+> heartbeat p = p `catch` (\e -> do
+>            let _ = e :: SomeException
+>            tryIO $ putStrLn "<Nice try!>"
+>            heartbeat p )
+>
+> main = do
+>     tid <- myThreadId
+>     forkIO $ forever $ do
+>         threadDelay 5000000  -- Every 5 seconds
+>         killThread tid
+>     trySafeIO $ runProxy $ runEitherK $
+>         heartbeat . (openFileS >-> tryK printD)
+
+>>> main
+Select a file:
+te<Nice Try!>
+Select a file:
+st.txt
+{File Open}
+"Line 1"
+"Line 2"
+"Line 3"
+"Line 4"
+{Closing File}
+
+-}
+
+{- $checked
+    Exception handling works because 'SafeIO' checks all exceptions and stores
+    them using the 'ExceptionP' proxy transformer.  'SafeIO' masks all
+    asynchronous exceptions by default and only unmasks them in the middle of a
+    'try' or 'tryIO' block.  This prevents asynchronous exceptions from leaking
+    between the cracks.
+
+    'runSafeIO' reraises the stored exception when the 'Session' completes, but
+    you can also choose to preserve the exception as a 'Left' by using
+    'trySafeIO' instead:
+
+> main = do
+>     tID <- myThreadId
+>     forkIO $ do
+>         threadDelay 1000
+>         killThread tID
+>     runSafeIO $ runProxy $ runEitherK $
+>         foreverK (readFileS "test.txt") >-> tryK printD
+
+>>> main
+...
+"Line 2"
+"Line 3"
+"Line 4"
+{Closing File}
+{File Open}
+"Line 1"
+"Line 2"
+{Closing File}
+Left thread killed
+
+    You can even choose whether to use 'mask' or 'uninterruptibleMask':
+
+    * 'runSafeIO' and 'trySafeIO' both use 'mask'
+
+    * 'runSaferIO' and 'trySaferIO' both use 'uninterruptibleMask'.
+-}
+
+{- $prompt
+    Resource management primitives like 'bracket' only guarantee prompt
+    finalization in the face of exceptions.  Premature termination of
+    composition will delay the finalizer until the end of the 'Session'.
+
+    For example, consider the following 'Session':
+
+> session () = do
+>    (readFileS "test.hs" >-> takeB_ 2 >-> tryK printD) ()
+>    tryIO $ putStrLn "Look busy"
+
+>>> runSafeIO $ runProxy $ runEitherK session
+{File Open}
+"Line 1"
+"Line 2"
+Look busy
+{Closing File}
+
+    @readFileS@ is interrupted when @takeB_@ terminates, so it does not get
+    finalized until the very end of the 'Session'.
+
+    The \"Prompt Finalization\" section of "Control.Proxy.Safe" documents why
+    this behavior is the only safe default.  However, often we can prove that
+    prompter finalization is safe, in which case we can take matters into our
+    own hands and manually finalize things even more promptly:
+
+> session () = do
+>     (readFileS "test.hs" >-> (takeB_ 2 >=> unsafeClose) >-> tryK printD) ()
+>     tryIO $ putStrLn "Look busy"
+
+>>> runSafeIO $ runProxy $ runEitherK session
+{File Open}
+"import Control.Concurrent"
+"import Control.Monad (unless)"
+{Closing File}
+Look busy
+
+    Fortunately, most of the time you will just assemble linear composition
+    chains that look like this:
+
+> runSafeIO $ runProxy $ runEitherK $ p1 >-> p2 >-> p3 >-> p4
+
+    ... in which case the end of composition coincides with the end of the
+    'Session' and there is no delay in finalization.  You only need to manually
+    manage prompt finalization if you sequence anything after composition.
+-}
+
+{- $trytransformer
+    Not all proxy transformers implement 'try'.  You can look at the instance
+    list for 'CheckP' and you will see that it mainly covers the base
+    proxy implementations:
+
+> instance CheckP ProxyFast
+> instance CheckP ProxyCorrect
+> instance (CheckP p) => CheckP (IdentityP p)
+> instance (CheckP p) => CheckP (ReaderP   p)
+
+    However, you actually can upgrade more sophisticated proxy transformer
+    stacks.  I've relaxed the type signature of the 'PFunctor' type class to
+    accept proxy morphisms that change the base monad, so now it accepts 'try'
+    as a valid argument.  This means that you can use 'hoistP' as many times as
+    necessary to target 'try' to the base proxy:
+
+> p :: (CheckP p) => Producer (StateP s (MaybeP p)) IO r
+>
+> hoistP (hoistP try) p
+>   :: (CheckP p) => Producer (StateP s (MaybeP (ExceptionP p))) SafeIO r
+
+    'hoistP' expects a proxy morphism for its argument, but is 'try' a proxy
+    morphism?  Yes!  'try' satisfies the proxy morphism laws, which are the same
+    as the proxy transformer laws.  The documentation for 'try' lists the full
+    set of equations, but the ones you should remember are:
+
+> tryK (f >-> g) = tryK f >-> tryK g
+
+> try (request a') = request a'
+
+> try (respond b ) = respond b
+
+>   do x <- try m
+>      try (f x)
+> = try $ do x <- m
+>            f x
+>
+> try (return x) = return x -- Almost true!
+
+    The last equation is slightly incorrect.  The left hand-side may throw an
+    asynchronous exception, but the right-hand side will not.  This does not
+    compromise the safety of this library.  At worst, it will just overzealously
+    mask pure segments of code if you don't wrap them in 'try', which just
+    delays the asynchronous exception until the next 'IO' action.
+
+    There is one upgrade scenario that this library does not yet cover, which is
+    upgrading proxies that have base monads other than 'IO'.  For now, you will
+    have to rewrite the proxy if that happens.
+-}
+
+{- $backwards
+    The biggest strength of @pipes-safe@ is that it requires no buy-in from the
+    rest of the @pipes@ ecosystem.  Many proxies require no resource-management
+    at all, so why should they clutter their implementation with such concerns?
+
+    @pipes-safe@ lets you write these proxies using the simpler \"unmanaged\"
+    types, and then transparently promote them with 'try' later on if you need
+    to use them within a resource-managed 'Session'.
+
+    For example, the main body of @readFileS@ is identical to the implementation
+    of 'hGetLineS' from the proxy prelude:
+
+> hGetLineS :: (Proxy p) => Handle -> () -> Producer p String IO ()
+> hGetLineS h () = runIdentityP loop where
+>     loop = do
+>         eof <- lift $ hIsEOF h
+>         if eof
+>             then return ()
+>             else do
+>                 str <- lift $ hGetLine h
+>                 respond str
+>                 loop
+
+    We can reuse 'hGetLineS' by define a 'withFileS' that abstracts away the
+    handle management:
+
+> withFileS
+>  :: (Proxy p)
+>  => FilePath
+>  -> (Handle -> b' -> ExceptionP p a' a b' b SafeIO r)
+>  -> b' -> ExceptionP p a' a b' b SafeIO r
+> withFileS file p b' = bracket id
+>     (do h <- openFile file ReadMode
+>         putStrLn "{File Open}"
+>         return h )
+>     (\h -> do putStrLn "{Closing File}"
+>               hClose h )
+>     (\h -> p h b')
+
+    ... and now we can 'readFileS' in terms of 'withFileS' and 'hGetLineS':
+
+> readFileS file = withFileS file (\h -> tryK (hGetLineS h))
+
+    If 'hGetLineS' throws an error within its own code, 'withFileS' will still
+    properly finalize the handle.  This works in spite of 'hGetLineS' never
+    having been written to be resource safe.
+-}
+
+{- $laziness
+    Now you no longer need to open all resources before a 'Session' and close
+    them afterwards.  Instead, you can lazily open resources in response to
+    demand and trust that they finalize safely upon termination:
+
+> files () = do
+>     readFileS "file1.txt" () -- 3 lines long
+>     readFileS "file2.txt" () -- 4 lines long
+> -- or: files = readFileS "file1.txt" >=> readFileS "file2.txt"
+
+>>> runSafeIO $ runProxy $ runEitherK $ files >-> takeB_ 2 >-> printD
+{File Open}
+"Line 1 of file1.txt"
+"Line 2 of file1.txt"
+{Closing File}
+
+    @\"file2.txt\"@ never opens because we only demand two lines.
+
+    Even if we use both files, we never keep more than one handle open at a
+    time:
+ 
+>>> runSafeIO $ runProxy $ runEitherK $ files >-> takeB_ 5 >-> printD
+{File Open}
+"Line 1 of file1.txt"
+"Line 2 of file1.txt"
+"Line 3 of file1.txt"
+{Closing File}
+{File Open}
+"Line 1 of file2.txt"
+"Line 2 of file2.txt"
+{Closing File}
+
+-}
+
+{- $conclusion
+    @pipes-safe@ lets you package streaming resources into self-contained units
+    that include:
+
+    * their allocation/deallocation code, and
+
+    * their exception-handling strategies.
+
+    @pipes-safe@ reuses 'EitherP' to let you easily reason about how local
+    exception handling behaves.  More importantly, multiple resources can
+    concurrently coexist with each other and not interfere with each other's
+    exception-handling logic.  @pipes-safe@ isolates each streaming component's
+    behavior so that you reason about it how it deals with failure independently
+    of other components.
+
+    I hope this inspires people to package up more powerful streaming
+    abstractions into indivisible units.  Also, don't limit yourself to simple
+    file or network resources.  You will find that @pipes-safe@ can also
+    simplify and package up:
+
+    * progress meters,
+
+    * input devices (i.e. mice and keyboards), and
+
+    * user interfaces.
+
+    I encourage you to be creative!
+-}
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2013, Gabriel Gonzalez
+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 Gabriel Gonzalez 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/pipes-safe.cabal b/pipes-safe.cabal
new file mode 100644
--- /dev/null
+++ b/pipes-safe.cabal
@@ -0,0 +1,45 @@
+Name: pipes-safe
+Version: 1.0.0
+Cabal-Version: >=1.14.0
+Build-Type: Simple
+License: BSD3
+License-File: LICENSE
+Copyright: 2013 Gabriel Gonzalez
+Author: Gabriel Gonzalez
+Maintainer: Gabriel439@gmail.com
+Bug-Reports: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library/issues
+Synopsis: Safety for the pipes ecosystem
+Description:
+    This package adds resource management and exception handling to the @pipes@
+    ecosystem.  Notable features include:
+    .
+    * /Resource Safety/: Guarantee finalization using @finally@, @bracket@ and
+      more
+    .
+    * /Laziness/: Only acquire resources when you need them
+    .
+    * /Exception safe/: Even against asynchronous exceptions!
+    .
+    * /Native Exception Handling/: Catch and resume from exceptions within any
+      @Session@
+    .
+    * /No Buy-in/: Managed pipes play nice with unmanaged pipes
+    .
+    Import @Control.Proxy.Safe@ to use this library
+    .
+    Read @Control.Proxy.Safe.Tutorial@ for an introductory tutorial.
+Category: Control, Pipes, Proxies
+Tested-With: GHC ==7.4.1
+Source-Repository head
+    Type: git
+    Location: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library
+
+Library
+    Build-Depends:
+        base >= 4 && < 5,
+        transformers >= 0.2.0.0,
+        pipes >= 3.1.0
+    Exposed-Modules:
+        Control.Proxy.Safe,
+        Control.Proxy.Safe.Tutorial
+    Default-Language: Haskell98
