diff --git a/Test/Tasty.hs b/Test/Tasty.hs
--- a/Test/Tasty.hs
+++ b/Test/Tasty.hs
@@ -23,9 +23,6 @@
   -- a file or a socket. We want to create or grab the resource before
   -- the tests are run, and destroy or release afterwards.
   , withResource
-
-  -- ** Accessing the resource
-  -- $example
   )
   where
 
@@ -53,44 +50,18 @@
 localOption :: IsOption v => v -> TestTree -> TestTree
 localOption v = PlusTestOptions (setOption v)
 
+-- | Customize the test tree based on the run-time options
 askOption :: IsOption v => (v -> TestTree) -> TestTree
 askOption f = AskOptions $ f . lookupOption
 
--- | Add resource initialization and finalization to the test tree
+-- | Acquire the resource to run this test (sub)tree and release it
+-- afterwards
 withResource
   :: IO a -- ^ initialize the resource
   -> (a -> IO ()) -- ^ free the resource
-  -> TestTree
+  -> (IO a -> TestTree)
+    -- ^ @'IO' a@ is an action which returns the acquired resource.
+    -- Despite it being an 'IO' action, the resource it returns will be
+    -- acquired only once and shared across all the tests in the tree.
   -> TestTree
 withResource acq rel = WithResource (ResourceSpec acq rel)
-
--- $example
---
--- If you need to access the resource in your tests, just put it in an
--- IORef during initialization, and get it from there in the tests.
---
--- Here's an example:
---
--- >import Test.Tasty
--- >import Test.Tasty.HUnit
--- >import Data.IORef
--- >
--- >-- assumed defintions
--- >data Foo
--- >acquire :: IO Foo
--- >release :: Foo -> IO ()
--- >testWithFoo :: Foo -> Assertion
--- >
--- >main = do
--- >  ref <- newIORef $
--- >    -- If you get this error, then either you forgot to actually write to
--- >    -- the IORef, or it's a bug in tasty
--- >    error "Resource isn't accessible"
--- >  defaultMain $
--- >    withResource (do r <- acquire; writeIORef ref r; return r) release (tests ref)
--- >
--- >tests :: IORef Foo -> TestTree
--- >tests ref =
--- >  testGroup "Tests"
--- >    [ testCase "x" $ readIORef ref >>= testWithFoo
--- >    ]
diff --git a/Test/Tasty/Core.hs b/Test/Tasty/Core.hs
--- a/Test/Tasty/Core.hs
+++ b/Test/Tasty/Core.hs
@@ -1,9 +1,10 @@
 -- | Core types and definitions
 {-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts,
-             ExistentialQuantification, RankNTypes #-}
+             ExistentialQuantification, RankNTypes, DeriveDataTypeable #-}
 module Test.Tasty.Core where
 
 import Control.Applicative
+import Control.Exception
 import Test.Tasty.Options
 import Test.Tasty.Patterns
 import Data.Foldable
@@ -11,6 +12,7 @@
 import Data.Typeable
 import qualified Data.Map as Map
 import Data.Tagged
+import Text.Printf
 
 -- | A test result
 data Result = Result
@@ -62,11 +64,22 @@
 
 -- | 'ResourceSpec' describes how to acquire a resource (the first field)
 -- and how to release it (the second field).
-data ResourceSpec =
-  forall a . ResourceSpec
-    (IO a)
-    (a -> IO ())
+data ResourceSpec a = ResourceSpec (IO a) (a -> IO ())
 
+data ResourceError
+  = NotRunningTests
+  | UnexpectedState String
+  deriving Typeable
+
+instance Show ResourceError where
+  show NotRunningTests =
+    "Unhandled resource. Probably a bug in the runner you're using."
+  show (UnexpectedState state) =
+    printf "Unexpected state of the resource (%s). Report as a tasty bug."
+      state
+
+instance Exception ResourceError
+
 -- | The main data structure defining a test suite.
 --
 -- It consists of individual test cases and properties, organized in named
@@ -84,15 +97,52 @@
     -- ^ Assemble a number of tests into a cohesive group
   | PlusTestOptions (OptionSet -> OptionSet) TestTree
     -- ^ Add some options to child tests
-  | WithResource ResourceSpec TestTree
+  | forall a . WithResource (ResourceSpec a) (IO a -> TestTree)
+    -- ^ Acquire the resource before the tests in the inner tree start and
+    -- release it after they finish. The tree gets an `IO` action which
+    -- yields the resource, although the resource is shared across all the
+    -- tests.
   | AskOptions (OptionSet -> TestTree)
+    -- ^ Ask for the options and customize the tests based on them
 
 -- | Create a named group of test cases or other groups
 testGroup :: TestName -> [TestTree] -> TestTree
 testGroup = TestGroup
 
+-- | An algebra for folding a `TestTree`.
+--
+-- Instead of constructing fresh records, build upon `trivialFold`
+-- instead. This way your code won't break when new nodes/fields are
+-- indroduced.
+data TreeFold b = TreeFold
+  { foldSingle :: forall t . IsTest t => OptionSet -> TestName -> t -> b
+  , foldGroup :: TestName -> b -> b
+  , foldResource :: forall a . ResourceSpec a -> (IO a -> b) -> b
+  }
+
+-- | 'trivialFold' can serve as the basis for custom folds. Just override
+-- the fields you need.
+--
+-- Here's what it does:
+--
+-- * single tests are mapped to `mempty` (you probably do want to override that)
+--
+-- * test groups are returned unmodified
+--
+-- * for a resource, an IO action that throws an exception is passed (you
+-- want to override this for runners/ingredients that execute tests)
+trivialFold :: Monoid b => TreeFold b
+trivialFold = TreeFold
+  { foldSingle = \_ _ _ -> mempty
+  , foldGroup = const id
+  , foldResource = \_ f -> f $ throwIO NotRunningTests
+  }
+
 -- | Fold a test tree into a single value.
 --
+-- The fold result type should be a monoid. This is used to fold multiple
+-- results in a test group. In particular, empty groups get folded into 'mempty'.
+--
 -- Apart from pure convenience, this function also does the following
 -- useful things:
 --
@@ -108,16 +158,14 @@
 -- in practice; OTOH, this behaviour may be changed later.
 foldTestTree
   :: Monoid b
-  => (forall t . IsTest t => OptionSet -> TestName -> t -> b)
-     -- ^ interpret a single test
-  -> (TestName -> b -> b)
-     -- ^ interpret a test group
-  -> (ResourceSpec -> b -> b)
-     -- ^ deal with the resource
+  => TreeFold b
+     -- ^ the algebra (i.e. how to fold a tree)
   -> OptionSet
      -- ^ initial options
-  -> TestTree -> b
-foldTestTree fTest fGroup fResource opts tree =
+  -> TestTree
+     -- ^ the tree to fold
+  -> b
+foldTestTree (TreeFold fTest fGroup fResource) opts tree =
   let pat = lookupOption opts
   in go pat [] opts tree
   where
@@ -130,7 +178,7 @@
         TestGroup name trees ->
           fGroup name $ foldMap (go pat (path ++ [name]) opts) trees
         PlusTestOptions f tree -> go pat path (f opts) tree
-        WithResource res tree -> fResource res (go pat path opts tree)
+        WithResource res tree -> fResource res $ \res -> go pat path opts (tree res)
         AskOptions f -> go pat path opts (f opts)
 
 -- | Useful wrapper for use with foldTestTree
@@ -147,9 +195,7 @@
   Map.elems .
 
   foldTestTree
-    (\_ _ -> getTestOptions)
-    (const id)
-    (const id)
+    trivialFold { foldSingle = \_ _ -> getTestOptions }
     mempty
 
   where
diff --git a/Test/Tasty/Ingredients/ConsoleReporter.hs b/Test/Tasty/Ingredients/ConsoleReporter.hs
--- a/Test/Tasty/Ingredients/ConsoleReporter.hs
+++ b/Test/Tasty/Ingredients/ConsoleReporter.hs
@@ -78,9 +78,10 @@
 computeAlignment opts =
   fromMonoid .
   foldTestTree
-    (\_ name _ level -> Maximum (length name + level))
-    (\_ m -> m . (+ indentSize))
-    (const id)
+    trivialFold
+      { foldSingle = \_ name _ level -> Maximum (length name + level)
+      , foldGroup = \_ m -> m . (+ indentSize)
+      }
     opts
   where
     fromMonoid m =
@@ -159,9 +160,10 @@
   st <-
     flip execStateT initialState $ getApp $ fst $
       foldTestTree
-        (runSingleTest smap)
-        runGroup
-        (const id)
+        trivialFold
+          { foldSingle = runSingleTest smap
+          , foldGroup = runGroup
+          }
         opts
         tree
 
diff --git a/Test/Tasty/Ingredients/ListTests.hs b/Test/Tasty/Ingredients/ListTests.hs
--- a/Test/Tasty/Ingredients/ListTests.hs
+++ b/Test/Tasty/Ingredients/ListTests.hs
@@ -35,9 +35,10 @@
 testsNames :: OptionSet -> TestTree -> [TestName]
 testsNames {- opts -} {- tree -} =
   foldTestTree
-    (\_opts name _test -> [name])
-    (\groupName names -> map ((groupName ++ "/") ++) names)
-    (const id)
+    trivialFold
+      { foldSingle = \_opts name _test -> [name]
+      , foldGroup = \groupName names -> map ((groupName ++ "/") ++) names
+      }
 
 -- | The ingredient that provides the test listing functionality
 listingTests :: Ingredient
diff --git a/Test/Tasty/Patterns.hs b/Test/Tasty/Patterns.hs
--- a/Test/Tasty/Patterns.hs
+++ b/Test/Tasty/Patterns.hs
@@ -39,8 +39,8 @@
 
 import Test.Tasty.Options
 
-import Text.Regex.Posix.Wrap
-import Text.Regex.Posix.String()
+import Text.Regex.TDFA
+import Text.Regex.TDFA.String()
 
 import Data.List
 import Data.Typeable
diff --git a/Test/Tasty/Run.hs b/Test/Tasty/Run.hs
--- a/Test/Tasty/Run.hs
+++ b/Test/Tasty/Run.hs
@@ -138,9 +138,10 @@
   liftM (map (first ($ (Seq.empty, Seq.empty)))) $
   execWriterT $ getApp $
   (foldTestTree
-    runSingleTest
-    (const id)
-    addInitAndRelease
+    trivialFold
+      { foldSingle = runSingleTest
+      , foldResource = addInitAndRelease
+      }
     opts
     tree
     :: AppMonoid (WriterT [(InitFinPair -> IO (), TVar Status)] IO))
@@ -153,14 +154,23 @@
       tell [(act, statusVar)]
     addInitAndRelease (ResourceSpec doInit doRelease) a =
       AppMonoid . WriterT . fmap ((,) ()) $ do
-        tests <- execWriterT $ getApp a
-        let ntests = length tests
         initVar <- newMVar NotCreated
+        tests <- execWriterT $ getApp $ a (getResource initVar)
+        let ntests = length tests
         finishVar <- newMVar ntests
         let
           ini = Initializer doInit initVar
           fin = Finalizer doRelease initVar finishVar
         return $ map (first $ local $ (Seq.|> ini) *** (fin Seq.<|)) tests
+
+-- | Used to create the IO action which is passed in a WithResource node
+getResource :: MVar (Resource r) -> IO r
+getResource var =
+  readMVar var >>= \rState ->
+    case rState of
+      Created r -> return r
+      NotCreated -> throwIO $ UnexpectedState "not created"
+      FailedToCreate {} -> throwIO $ UnexpectedState "failed to create"
 
 -- | Start running all the tests in a test tree in parallel. The number of
 -- threads is determined by the 'NumThreads' option.
diff --git a/Test/Tasty/Runners.hs b/Test/Tasty/Runners.hs
--- a/Test/Tasty/Runners.hs
+++ b/Test/Tasty/Runners.hs
@@ -4,6 +4,8 @@
     -- * Working with the test tree
     TestTree(..)
   , foldTestTree
+  , TreeFold(..)
+  , trivialFold
   , AppMonoid(..)
   , ResourceSpec(..)
     -- * Ingredients
diff --git a/tasty.cabal b/tasty.cabal
--- a/tasty.cabal
+++ b/tasty.cabal
@@ -2,7 +2,7 @@
 --  see http://haskell.org/cabal/users-guide/
 
 name:                tasty
-version:             0.6
+version:             0.7
 synopsis:            Modern and extensible testing framework
 description:         See <http://documentup.com/feuerbach/tasty>
 license:             MIT
@@ -46,7 +46,7 @@
     containers,
     mtl,
     tagged >= 0.5,
-    regex-posix,
+    regex-tdfa >= 1.1.8,
     optparse-applicative >= 0.6,
     deepseq >= 1.3,
     either >= 4.0
