diff --git a/pipes-concurrency.cabal b/pipes-concurrency.cabal
--- a/pipes-concurrency.cabal
+++ b/pipes-concurrency.cabal
@@ -1,5 +1,5 @@
 Name: pipes-concurrency
-Version: 2.0.3
+Version: 2.0.4
 Cabal-Version: >=1.8.0.2
 Build-Type: Simple
 License: BSD3
diff --git a/src/Pipes/Concurrent.hs b/src/Pipes/Concurrent.hs
--- a/src/Pipes/Concurrent.hs
+++ b/src/Pipes/Concurrent.hs
@@ -14,6 +14,7 @@
     -- * Actors
     spawn,
     spawn',
+    withSpawn,
     Buffer(..),
     unbounded,
     bounded,
@@ -32,6 +33,7 @@
 import Control.Concurrent (forkIO)
 import Control.Concurrent.STM (atomically, STM, mkWeakTVar, newTVarIO, readTVar)
 import qualified Control.Concurrent.STM as S
+import Control.Exception (bracket)
 import Control.Monad (when,void, MonadPlus(..))
 import Data.Monoid (Monoid(mempty, mappend))
 import Pipes (MonadIO(liftIO), yield, await, Producer', Consumer')
@@ -202,6 +204,20 @@
         _recv   = readOrEnd   <* readTVar rRecv
     return (Output _send, Input _recv, seal)
 {-# INLINABLE spawn' #-}
+
+{-| 'withSpawn' passes its enclosed action an 'Output' and 'Input' like you'd get from 'spawn',
+    but automatically @seal@s them after the action completes.  This can be used when you need the
+    @seal@ing behavior available from 'spawn\'', but want to work at a bit higher level:
+
+> withSpawn buffer $ \(output, input) -> ...
+
+    'withSpawn' is exception-safe, since it uses 'bracket' internally.
+-}
+withSpawn :: Buffer a -> ((Output a, Input a) -> IO r) -> IO r
+withSpawn buffer action = bracket
+    (spawn' buffer)
+    (\(_, _, seal) -> atomically seal)
+    (\(output, input, _) -> action (output, input))
 
 -- | 'Buffer' specifies how to buffer messages stored within the mailbox
 data Buffer a
