diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.0.5.0
+
+* Fix roles on `Eff` (thanks to @Lysxia)
+
+* Add `bracket` (thanks to @Lysxia)
+
 ## 0.0.4.2
 
 * Add documentation for `Handle`
diff --git a/bluefin-internal.cabal b/bluefin-internal.cabal
--- a/bluefin-internal.cabal
+++ b/bluefin-internal.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               bluefin-internal
-version:            0.0.4.2
+version:            0.0.5.0
 license:            MIT
 license-file:       LICENSE
 author:             Tom Ellis
diff --git a/src/Bluefin/Internal.hs b/src/Bluefin/Internal.hs
--- a/src/Bluefin/Internal.hs
+++ b/src/Bluefin/Internal.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE DerivingVia #-}
 {-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RoleAnnotations #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UnboxedTuples #-}
 {-# LANGUAGE UnliftedNewtypes #-}
@@ -33,6 +34,7 @@
 
 type (:&) = Union
 
+type role Eff nominal representational
 newtype Eff (es :: Effects) a = UnsafeMkEff {unsafeUnEff :: IO a}
   deriving stock (Functor)
   deriving newtype (Applicative, Monad)
@@ -388,6 +390,19 @@
   Eff es a
 catch f h = handle h f
 
+-- | @bracket acquire release body@: @acquire@ a resource, perform the
+-- @body@ with it, and @release@ the resource even if @body@ threw an
+-- exception.  This is essentially the same as
+-- @Control.Exception.'Control.Exception.bracket'@, whose
+-- documentation you can inspect for further details.
+bracket ::
+  Eff es a ->
+  (a -> Eff es ()) ->
+  (a -> Eff es b) ->
+  Eff es b
+bracket before after body = UnsafeMkEff $ Control.Exception.bracket
+  (unsafeUnEff before) (unsafeUnEff . after) (unsafeUnEff . body)
+
 -- |
 -- @
 -- >>> runPureEff $ runState 10 $ \\st -> do
@@ -455,11 +470,11 @@
 
 -- |
 -- @
--- runPureEff $ withStateSource $ \\source -> do
---   n <- newState source 5
+-- 'runPureEff' $ 'withStateSource' $ \\source -> do
+--   n <- 'newState' source 5
 --   total <- newState source 0
 --
---   'Bluefin.Jump.withJump' $ \\done -> forever $ do
+--   'withJump' $ \\done -> forever $ do
 --     n' <- 'Bluefin.State.get' n
 --     'Bluefin.State.modify' total (+ n')
 --     when (n' == 0) $ 'Bluefin.Jump.jumpTo' done
@@ -476,8 +491,8 @@
 
 -- |
 -- @
--- runPureEff $ withStateSource $ \\source -> do
---   n <- newState source 5
+-- runPureEff $ 'withStateSource' $ \\source -> do
+--   n <- 'newState' source 5
 --   total <- newState source 0
 --
 --   'Bluefin.Jump.withJump' $ \\done -> forever $ do
@@ -819,12 +834,42 @@
 
 type Jump = EarlyReturn ()
 
+-- |
+-- @
+-- runPureEff $ 'withStateSource' $ \\source -> do
+--   n <- 'newState' source 5
+--   total <- newState source 0
+--
+--   'Bluefin.Jump.withJump' $ \\done -> forever $ do
+--     n' <- 'Bluefin.State.get' n
+--     'Bluefin.State.modify' total (+ n')
+--     when (n' == 0) $ 'Bluefin.Jump.jumpTo' done
+--     modify n (subtract 1)
+--
+--   get total
+-- 15
+-- @
 withJump ::
   (forall j. Jump j -> Eff (j :& es) ()) ->
   -- | ͘
   Eff es ()
 withJump = withEarlyReturn
 
+-- |
+-- @
+-- runPureEff $ 'withStateSource' $ \\source -> do
+--   n <- 'newState' source 5
+--   total <- newState source 0
+--
+--   'Bluefin.Jump.withJump' $ \\done -> forever $ do
+--     n' <- 'Bluefin.State.get' n
+--     'Bluefin.State.modify' total (+ n')
+--     when (n' == 0) $ 'Bluefin.Jump.jumpTo' done
+--     modify n (subtract 1)
+--
+--   get total
+-- 15
+-- @
 jumpTo ::
   (j :> es) =>
   Jump j ->
diff --git a/src/Bluefin/Internal/Examples.hs b/src/Bluefin/Internal/Examples.hs
--- a/src/Bluefin/Internal/Examples.hs
+++ b/src/Bluefin/Internal/Examples.hs
@@ -114,6 +114,18 @@
             pure (n', m')
    in (example2 (5, 10), example2 (12, 5))
 
+example3' :: Int -> Either String Int
+example3' n = runPureEff $
+  try $ \ex -> do
+    evalState 0 $ \total -> do
+      for_ [1 .. n] $ \i -> do
+        soFar <- get total
+        when (soFar > 20) $ do
+          throw ex ("Became too big: " ++ show soFar)
+        put total (soFar + i)
+
+      get total
+
 -- Count non-empty lines from stdin, and print a friendly message,
 -- until we see "STOP".
 example3_ :: IO ()
