diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+# 0.4.3.0
+
+* Add `Bluefin.GadtEffect`
+
+* Add `Bluefin.HandleReader.asksHandle`
+
+* Restrict type parameter of `PrimStateEff` to `Effects`
+
+  This is technically a breaking change, but we did not enforce a
+  major version bump for it.
+
 # 0.4.2.0
 
 * Add `Bluefin.DslBuilderEff`
diff --git a/bluefin.cabal b/bluefin.cabal
--- a/bluefin.cabal
+++ b/bluefin.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               bluefin
-version:            0.4.2.0
+version:            0.4.3.0
 license:            MIT
 license-file:       LICENSE
 author:             Tom Ellis
@@ -31,6 +31,7 @@
       Bluefin.Eff,
       Bluefin.Exception,
       Bluefin.Exception.GeneralBracket,
+      Bluefin.GadtEffect,
       Bluefin.HandleReader,
       Bluefin.IO,
       Bluefin.Jump,
@@ -44,6 +45,6 @@
       Bluefin.System.IO,
       Bluefin.Writer,
     build-depends:
-      bluefin-internal >= 0.4.1.0 && < 0.5
+      bluefin-internal >= 0.4.3.0 && < 0.5
     hs-source-dirs:   src
     default-language: Haskell2010
diff --git a/src/Bluefin/GadtEffect.hs b/src/Bluefin/GadtEffect.hs
new file mode 100644
--- /dev/null
+++ b/src/Bluefin/GadtEffect.hs
@@ -0,0 +1,252 @@
+module Bluefin.GadtEffect
+  ( -- * Introduction
+
+    -- | The Haskell effect systems @effectful@ and @polysemy@ allow
+    -- users to define new effects by defining a GADT (generalized
+    -- algebraic data type) whose contructors correspond to primitive
+    -- operations of the effect, and then creating values of the GADT
+    -- and interpreting them in terms of existing effects.  This
+    -- module provides Bluefin's equivalent.  In fact, it @effectful@
+    -- and @polysemy@ this is essentially the /only/ way you can
+    -- create new effects. That's not true for Bluefin. Bluefin
+    -- supports a rich collection of ways to create new effects, most
+    -- of which are documented at "Bluefin.Compound".  This particular
+    -- module might be helpful for users coming from @effectful@ and
+    -- @polysemy@, however.
+
+    -- * Example filesystem effect
+
+    -- | First we define a GADT with a constructor for each primitive
+    -- operation of the effect we want to define.  Here the primitive
+    -- operations are to read a file, write a file and to wrap an
+    -- effectful computation in a "trace" block.
+    --
+    -- @
+    -- data FileSystem :: 'Effect' where
+    --   ReadFile :: FilePath -> FileSystem m String
+    --   WriteFile :: FilePath -> String -> FileSystem m ()
+    --   Trace :: String -> m r -> FileSystem m r
+    -- @
+    --
+    -- Then we need to define two instances for @FileSystem@:
+    --
+    -- @
+    -- instance
+    --   (e :> es) =>
+    --   t'Bluefin.Compound.OneWayCoercible' ('GadtEffect' FileSystem r e) (GadtEffect FileSystem r es)
+    --   where
+    --   'Bluefin.Compound.oneWayCoercibleImpl' = 'oneWayCoercibleGadtEffectTrustMe' $ \\case
+    --     ReadFile path -> ReadFile path
+    --     WriteFile path contents -> WriteFile path contents
+    --     Trace msg body -> Trace msg (useImpl body)
+    --
+    -- deriving via
+    --   t'Bluefin.Compound.OneWayCoercibleHandle' ('GadtEffect' FileSystem r)
+    --   instance
+    --     t'Bluefin.Compound.Handle' (GadtEffect FileSystem r)
+    -- @
+    --
+    -- Then we can define functions that implement the primitive
+    -- effectful operations for @FileSystem@:
+    --
+    -- @
+    -- readFile ::
+    --   (e1 :> es) =>
+    --   'Send' FileSystem e1 ->
+    --   FilePath ->
+    --   Eff es String
+    -- readFile fc path =
+    --   'send' fc (ReadFile path)
+    --
+    -- writeFile ::
+    --   (e1 :> es) =>
+    --   Send FileSystem e1 ->
+    --   FilePath ->
+    --   String ->
+    --   Eff es ()
+    -- writeFile fc path content =
+    --   send fc (WriteFile path content)
+    --
+    -- trace ::
+    --   (e1 :> es) =>
+    --   Send FileSystem e1 ->
+    --   String ->
+    --   Eff es r ->
+    --   Eff es r
+    -- trace fc msg body =
+    --   send fc (Trace msg body)
+    -- @
+    --
+    -- The instances and primitive effectful operations are
+    -- boilerplate.  @effectful@ and @polysemy@ have Template Haskell
+    -- for generating their boilerplate
+    -- ([@makeEffect@](https://hackage.haskell.org/package/effectful-th/docs/Effectful-TH.html#v:makeEffect)
+    -- and
+    -- [@makeSem@](https://hackage.haskell.org/package/polysemy-1.9.2.0/docs/Polysemy.html#v:makeSem)
+    -- respectively) but there is no such thing for Bluefin yet,
+    -- sorry!  Please [open an
+    -- issue](https://github.com/tomjaguarpaw/bluefin/issues/new) if
+    -- that causes difficulties for you.
+    --
+    -- Finally we can write a handler for the @'Send' FileSystem@
+    -- effect that gives it an interpretation via 'interpret':
+    --
+    -- @
+    -- import System.IO qualified as IO
+    --
+    -- runFileSystem ::
+    --   forall es e1 e2 r.
+    --   (e1 :> es, e2 :> es) =>
+    --   t'Bluefin.IO.IOE' e1 ->
+    --   t'Bluefin.Exception.Exception' t'Control.Exception.IOException' e2 ->
+    --   (forall e. 'Send' FileSystem e -> Eff (e :& es) r) ->
+    --   Eff es r
+    -- runFileSystem io ex = 'interpret' $ \\case
+    --   ReadFile path ->
+    --     adapt (IO.'System.IO.readFile' path)
+    --   WriteFile path contents ->
+    --     adapt (IO.'System.IO.writeFile' path contents)
+    --   Trace msg body -> do
+    --     'Bluefin.IO.effIO' io (putStrLn ("Start: " <> msg))
+    --     r <- 'Bluefin.Compound.useImpl' body
+    --     effIO io (putStrLn ("End: " <> msg))
+    --     pure r
+    --   where
+    --     -- If you don't want to write this signature you can use
+    --     -- {-# LANGUAGE NoMonoLocalBinds #-}
+    --     adapt :: (e1 :> es', e2 :> es') => IO r' -> Eff es' r'
+    --     adapt m = 'Bluefin.IO.rethrowIO' io ex (effIO io m)
+    -- @
+
+    -- * @interpose@ example
+
+    -- | If you're familiar with @effectful@'s @interpose@ function
+    -- you may want to use Bluefin's equivalent.  To see how, let's
+    -- replicate [@effectful@'s interpose
+    -- example](https://hackage-content.haskell.org/package/effectful-core-2.6.1.0/docs/Effectful-Dispatch-Dynamic.html#v:interpose). First
+    -- we define a simple effect with three primitive operations:
+    --
+    -- @
+    -- data E :: 'Effect' where
+    --   Op1 :: E m ()
+    --   Op2 :: E m ()
+    --   Op3 :: E m ()
+    -- @
+    --
+    -- Then we define the boilerplate instances
+    --
+    -- @
+    -- instance
+    --   (e :> es) =>
+    --   t'Bluefin.Compound.OneWayCoercible' ('GadtEffect' E r e) (GadtEffect E r es)
+    --   where
+    --   'Bluefin.Compound.oneWayCoercibleImpl' = 'oneWayCoercibleGadtEffectTrustMe' $ \\case
+    --     Op1 -> Op1
+    --     Op2 -> Op2
+    --     Op3 -> Op3
+    --
+    -- deriving via
+    --   t'Bluefin.Compound.OneWayCoercibleHandle' (GadtEffect E r)
+    --   instance
+    --     t'Bluefin.Compound.Handle' (GadtEffect E r)
+    -- @
+    --
+    -- and a handler for the @'Send' E@ effect:
+    --
+    -- @
+    -- runE ::
+    --   (e1 :> es) =>
+    --   IOE e1 ->
+    --   (forall e. Send E e -> Eff (e :& es) r) ->
+    --   Eff es r
+    -- runE io = interpret $ \\case
+    --   Op1 -> effIO io (putStrLn "op1")
+    --   Op2 -> effIO io (putStrLn "op2")
+    --   Op3 -> effIO io (putStrLn "op3")
+    -- @
+    --
+    -- Before using 'interpose', let's look at a use of its simpler
+    -- cousin, 'interpret':
+    --
+    -- @
+    -- augmentOp2Interpret ::
+    --   (e1 :> es, e2 :> es) =>
+    --   IOE e2 ->
+    --   Send E e1 ->
+    --   (forall e. Send E e -> Eff (e :& es) r) ->
+    --   Eff es r
+    -- augmentOp2Interpret io fc = 'interpret' $ \\case
+    --   Op2 -> effIO io (putStrLn "augmented op2") >> send fc Op2
+    --   op -> 'passthrough' fc op
+    -- @
+    --
+    -- Using 'interpose' is similar:
+    --
+    -- @
+    -- augmentOp2Interpose ::
+    --   (e1 :> es, e2 :> es) =>
+    --   IOE e2 ->
+    --   t'Bluefin.HandleReader.HandleReader' (Send E) e1 ->
+    --   Eff es r ->
+    --   Eff es r
+    -- augmentOp2Interpose io = 'interpose' $ \\fc -> \\case
+    --   Op2 -> effIO io (putStrLn "augmented op2") >> send fc Op2
+    --   op -> 'passthrough' fc op
+    -- @
+    --
+    -- And now let's see what they each do:
+    --
+    -- @
+    -- example :: IO ()
+    -- example = runEff $ \\io -> do
+    --   let action fc = do
+    --         send fc Op1
+    --         send fc Op2
+    --         send fc Op3
+    --
+    --   effIO io (putStrLn "-- interpret:")
+    --   runE io $ \\fc -> do
+    --     augmentOp2Interpret io fc $ \\fc' -> action fc'
+    --
+    --   effIO io (putStrLn "-- interpose:")
+    --   runE io $ \\fc -> 'Bluefin.HandleReader.runHandleReader' fc $ \\hr -> do
+    --     augmentOp2Interpose io hr $ 'Bluefin.HandleReader.asksHandle' hr action
+    -- @
+    --
+    -- @
+    -- ghci> example
+    -- -- interpret:
+    -- op1
+    -- augmented op2
+    -- op2
+    -- op3
+    -- -- interpose:
+    -- op1
+    -- augmented op2
+    -- op2
+    -- op3
+    -- @
+
+    -- * Handle
+
+    Send,
+
+    -- * Effectful operations
+    send,
+    passthrough,
+
+    -- * Interpretation
+    EffectHandler,
+    interpret,
+    interpose,
+
+    -- * @Effect@
+    Effect,
+
+    -- * @GadtEffect@
+    GadtEffect,
+    oneWayCoercibleGadtEffectTrustMe,
+  )
+where
+
+import Bluefin.Internal.GadtEffect
diff --git a/src/Bluefin/HandleReader.hs b/src/Bluefin/HandleReader.hs
--- a/src/Bluefin/HandleReader.hs
+++ b/src/Bluefin/HandleReader.hs
@@ -6,9 +6,12 @@
 -- exception.
 --
 -- @HandleReader@ supports functionality similiar to @effectful@'s
--- 'Effectful.Dispatch.Dynamic.interpose' and @polysemy@'s
--- 'Polysemy.intercept', that is, locally augmenting an effect with
--- new behaviors.
+-- [@interpose@](https://hackage.haskell.org/package/effectful-core/docs/Effectful-Dispatch-Dynamic.html#v:interpose)
+-- and @polysemy@'s
+-- [@intercept@](https://hackage.haskell.org/package/polysemy/docs/Polysemy.html#v:intercept),
+-- that is, locally augmenting an effect with new behaviors.  If you
+-- want to do the same in Bluefin you may want to start with
+-- @Bluefin.FunctorCoroutine.'Bluefin.FunctorCoroutine.interpose`@.
 
 module Bluefin.HandleReader
   ( -- * Handle
@@ -19,6 +22,7 @@
 
     -- * Effectful operations
     askHandle,
+    asksHandle,
     localHandle,
   )
 where
