diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -15,3 +15,8 @@
 * The new v4 interface.
     * Unified first-order and higher-order effect interfaces.
     * Added a generic `Eff` carrier type.
+
+## 0.4.3.0 -- 2025-05-21
+
+* Add type classes for weaving
+* Fix the missing type role specification in `Data.Effect.OpenUnion`
diff --git a/data-effects-core.cabal b/data-effects-core.cabal
--- a/data-effects-core.cabal
+++ b/data-effects-core.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               data-effects-core
-version:            0.4.2.0
+version:            0.4.3.0
 
 -- A short (one-line) description of the package.
 synopsis: A basic framework for effect systems based on effects represented by GADTs.
diff --git a/src/Data/Effect.hs b/src/Data/Effect.hs
--- a/src/Data/Effect.hs
+++ b/src/Data/Effect.hs
@@ -44,8 +44,35 @@
     ) =>
     FirstOrder (e :: Effect)
 
--- | A higher-order polynomial functor.
+{- | A higher-order polynomial functor.
+
+Prevents resources from escaping the scope through unlift operations.
+-}
 class (FormOf e ~ 'Polynomial) => PolyHFunctor (e :: Effect)
+
+{- | Enables algebraic handling even in the presence of higher-order effects.
+In such cases, the scope of higher-order effects behaves according to a semantics similar to @mtl@,
+where it may or may not become transactional depending on the order of the effect stack.
+
+This follows the "weave" approach described in the *Effect Handlers in Scope* paper,
+and is the method used in libraries such as @fused-effects@ and @polysemy@.
+
+https://doi.org/10.1145/2633357.2633358
+-}
+class Weave (e :: Effect) where
+    -- | The @weave@ method from the *Effect Handlers in Scope* paper.
+    --
+    --   https://doi.org/10.1145/2633357.2633358
+    --
+    --   To accommodate the effect representation used by @data-effects@ (which is generally not a @Functor@),
+    --   the types have been transformed based on a Church encoding of @Coyoneda@.
+    weave
+        :: (Functor ctx)
+        => ctx ()
+        -> (forall x. ctx (m x) -> n (ctx x))
+        -> (forall x. e n x -> (x -> ctx a) -> r)
+        -> e m a
+        -> r
 
 -- * Nop Effect
 
diff --git a/src/Data/Effect/OpenUnion.hs b/src/Data/Effect/OpenUnion.hs
--- a/src/Data/Effect/OpenUnion.hs
+++ b/src/Data/Effect/OpenUnion.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE RoleAnnotations #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE ViewPatterns #-}
 {-# OPTIONS_GHC -Wno-redundant-constraints #-}
@@ -16,13 +17,14 @@
 import Control.Arrow ((&&&))
 import Data.Coerce (coerce)
 import Data.Data (Proxy (Proxy), (:~:) (Refl))
-import Data.Effect (Effect, EffectForm (Exponential, Polynomial), EffectOrder (FirstOrder, HigherOrder), FirstOrder, FormCase, FormOf, LabelOf, OrderCase, OrderOf, PolyHFunctor)
+import Data.Effect (Effect, EffectForm (Exponential, Polynomial), EffectOrder (FirstOrder, HigherOrder), FirstOrder, FormCase, FormOf, LabelOf, OrderCase, OrderOf, PolyHFunctor, Weave, weave)
 import Data.Effect.HFunctor (HFunctor, hfmap)
 import Data.Effect.Tag (type (#))
 import Data.Kind (Constraint, Type)
 import GHC.TypeLits (ErrorMessage (ShowType, Text, (:$$:), (:<>:)), KnownNat, Natural, Symbol, TypeError, natVal, type (+), type (-))
 import Unsafe.Coerce (unsafeCoerce)
 
+type role Union representational representational nominal
 data Union (es :: [Effect]) (f :: Type -> Type) (a :: Type) where
     UnsafeUnion
         :: {-# UNPACK #-} !Int
@@ -58,12 +60,39 @@
 instance PolyHFunctors '[]
 instance (PolyHFunctor e, PolyHFunctors es) => PolyHFunctors (e ': es)
 
+-- | The list @es@ consists only of weavable effects.
+class (Weave (Union es)) => Weaves (es :: [Effect])
+
+instance Weaves '[]
+instance (Weave e, Weaves es, KnownOrder e) => Weaves (e ': es)
+
+weaveUnion
+    :: (Weaves es, Functor ctx)
+    => ctx ()
+    -> (forall x. ctx (m x) -> n (ctx x))
+    -> (forall x. Union es n x -> (x -> ctx a) -> r)
+    -> Union es m a
+    -> r
+weaveUnion = weave
+{-# INLINE weaveUnion #-}
+
+instance Weave (Union '[]) where
+    weave _ _ _ = nil
+    {-# INLINE weave #-}
+
+instance (Weave e, Weave (Union es), KnownOrder e) => Weave (Union (e ': es)) where
+    weave ctx distrib f =
+        weave ctx distrib (f . inject Here)
+            !: weave ctx distrib (f . weaken)
+    {-# INLINE weave #-}
+
 coerceFOEs :: (FOEs es) => Union es f a -> Union es g a
 coerceFOEs = unsafeCoerce
 {-# INLINE coerceFOEs #-}
 
 type instance OrderOf (Union es) = 'HigherOrder
 
+type role Membership representational representational
 newtype Membership (e :: Effect) (es :: [Effect]) = UnsafeMembership {unMembership :: Int}
     deriving stock (Eq, Show)
 
@@ -339,7 +368,7 @@
 nil _ = error "Effect system internal error: nil - An empty effect union, which should not be possible to create, has been created."
 
 nilMembership :: Membership e '[] -> r
-nilMembership _ = error "Effect system internal error: nil - An empty effect union membership, which should not be possible to create, has been created."
+nilMembership _ = error "Effect system internal error: nilMmebership - An empty effect union membership, which should not be possible to create, has been created."
 
 weakensFor :: forall es es' e. (Suffix es es') => Membership e es -> Membership e es'
 weakensFor (UnsafeMembership n) = UnsafeMembership $ n + prefixLen @es @es'
