diff --git a/Specs.hs b/Specs.hs
--- a/Specs.hs
+++ b/Specs.hs
@@ -1,109 +1,33 @@
-{-# LANGUAGE StandaloneDeriving #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module Specs where
+{-# OPTIONS_GHC -fno-warn-deprecations #-}
+module Main (main) where
 
-import Test.Hspec
-import Test.Hspec.Runner (hHspecWithFormat, toExitCode)
-import Test.Hspec.Core (Spec(..), Result(..), quantify, failedCount, evaluateExample)
-import Test.Hspec.Formatters
-import Test.Hspec.QuickCheck
-import Test.Hspec.HUnit ()
-import Test.HUnit
-import System.IO
-import System.IO.Silently
-import System.Environment
-import System.Exit (exitWith)
-import Data.List (isPrefixOf)
-import qualified Test.HUnit as HUnit
+import           Test.Hspec.ShouldBe (Specs, describe, it, hspecX)
 
-deriving instance Show Result
+import qualified Test.Hspec as H
+import           Test.Hspec hiding (Specs, describe, it, hspecX)
+import           Test.Hspec.Runner (hHspecWithFormat)
+import           Test.Hspec.Internal (SpecTree(..), Spec(..), Result(..), quantify)
+import           Test.Hspec.Formatters
+import           Test.Hspec.QuickCheck
+import           Test.Hspec.HUnit ()
+import           Test.HUnit
+import           System.IO
+import           System.IO.Silently
+import           Data.List (isPrefixOf)
+import qualified Test.HUnit as HUnit
 
 main :: IO ()
-main = do
-  ar <- getArgs
-  specs' <- specs
-  ss <- case ar of
-    ["README"] -> withFile "README" WriteMode (\ h -> hPutStrLn h preamble >> hHspec h specs')
-    [filename] -> withFile filename WriteMode (\ h -> hHspec h specs')
-    _          -> hspec specs'
-  exitWith $ toExitCode (failedCount ss == 0)
-
-preamble :: String
-preamble = unlines [
-    "hspec aims to be a simple, extendable, and useful tool for Behavior Driven Development in Haskell.", "",
-    "",
-    "Step 1, write descriptions and examples of your desired behavior",
-    "> module Myabs where",
-    ">",
-    "> import Test.Hspec",
-    ">",
-    "> specs :: Specs",
-    "> specs = describe \"myabs\" [",
-    ">   it \"returns the original number when given a positive input\"",
-    ">     (myabs 1 == 1),",
-    "> ",
-    ">   it \"returns a positive number when given a negative input\"",
-    ">     (myabs (-1) == 1),",
-    "> ",
-    ">   it \"returns zero when given zero\"",
-    ">     (myabs 0 == 0)",
-    ">   ]",
-    "",
-    "Step 2, write whatever you are describing",
-    "> myabs n = undefined",
-    "",
-    "Step 3, watch your examples fail with red text by running from the .hs file itself",
-    "> main = hspec specs",
-    "",
-    "myabs",
-    " - returns the original number when given a positive input FAILED [1]",
-    " - returns a positive number when given a negative input FAILED [2]",
-    " - returns zero when given zero FAILED [3]",
-    "",
-    "1) myabs returns the original number when given a positive input FAILED",
-    "Prelude.undefined",
-    "",
-    "2) myabs returns a positive number when given a negative input FAILED",
-    "Prelude.undefined",
-    "",
-    "3) myabs returns zero when given zero FAILED",
-    "Prelude.undefined",
-    "",
-    "Finished in 0.0002 seconds",
-    "",
-    "3 examples, 3 failures",
-    "",
-    "",
-    "Specs can also be run from the command line using the hspec program",
-    "  $ hspec myabs.hs",
-    "",
-    "Step 4, implement your desired behavior",
-    "> myabs n = if n < 0 then negate n else n",
-    "",
-    "Step 5, watch your examples succeed with green text when rerun",
-    "myabs",
-    " - returns the original number when given a positive input",
-    " - returns a positive number when given a negative input",
-    " - returns zero when given zero",
-    "",
-    "Finished in 0.0000 seconds",
-    "",
-    "3 examples, 0 failures",
-    "",
-    "",
-    "",
-    "",
-    "Here's the report of hspec's behavior:" ]
+main = specs >>= hspecX
 
 specs :: IO Specs
 specs = do
-  let testSpecs = [describe "Example" [
-          it "success" (Success),
-          it "fail 1" (Fail "fail message"),
-          it "pending" (Pending "pending message"),
-          it "fail 2" (HUnit.assertEqual "assertEqual test" 1 (2::Int)),
-          it "exceptions" (undefined :: Bool),
-          it "quickcheck" (property $ \ i -> i == (i+1::Integer))]
+  let testSpecs = [H.describe "Example" [
+          H.it "success" (Success),
+          H.it "fail 1" (Fail "fail message"),
+          H.it "pending" (pending "pending message"),
+          H.it "fail 2" (HUnit.assertEqual "assertEqual test" 1 (2::Int)),
+          H.it "exceptions" (undefined :: Bool),
+          H.it "quickcheck" (property $ \ i -> i == (i+1::Integer))]
           ]
 
   (reportContents, exampleSpecs)     <- capture $ hHspecWithFormat specdoc         False stdout testSpecs
@@ -113,128 +37,122 @@
 
   let report = lines reportContents
 
-  return [
-    describe "the \"describe\" function" [
+  return $ do
+    describe "the \"describe\" function" $ do
         it "takes a description of what the behavior is for" $
             case exampleSpecs of
               [SpecGroup "Example" _] -> True
               _ -> False
-        ,
+
         it "groups behaviors for what's being described" $
             case exampleSpecs of
               [SpecGroup _ xs] -> length xs == 6
               _ -> False
-        ,
-        describe "a nested description" [
+
+        describe "a nested description" $ do
             it "has it's own specs"
                 (True)
-        ]
-    ],
-    describe "the \"it\" function" [
+
+    describe "the \"it\" function" $ do
         it "takes a description of a desired behavior" $
-            case it "whatever" Success of
+            case unSpec $ H.it "whatever" Success of
               SpecExample requirement _ -> requirement == "whatever"
               _ -> False
-        ,
+
         it "takes an example of that behavior" $ do
-            case it "whatever" Success of
+            case unSpec $ H.it "whatever" Success of
               SpecExample _ example -> do
-                r <- evaluateExample example
+                r <- example
                 r @?= Success
               SpecGroup _ _ -> assertFailure "unexpected SpecGroup"
-        ,
+
         it "can use a Bool, HUnit Test, QuickCheck property, or \"pending\" as an example"
-            (True),
+            (True)
 
         it "will treat exceptions as failures"
             (any (==" - exceptions FAILED [3]") report)
-    ],
-    describe "the \"hspec\" function" [
+
+    describe "the \"hspec\" function" $ do
         it "displays a header for each thing being described"
-            (any (=="Example") report),
+            (any (=="Example") report)
 
         it "displays one row for each behavior"
-            (HUnit.assertEqual "" 29 (length report)),
+            (HUnit.assertEqual "" 29 (length report))
 
         it "displays a row for each successfull, failed, or pending example"
-            (any (==" - success") report && any (==" - fail 1 FAILED [1]") report),
+            (any (==" - success") report && any (==" - fail 1 FAILED [1]") report)
 
         it "displays a detailed list of failed examples"
-            (any (=="1) Example fail 1 FAILED") report),
+            (any (=="1) Example fail 1 FAILED") report)
 
         it "displays a '#' with an additional message for pending examples"
-            (any (=="     # pending message") report ),
+            (any (=="     # PENDING: pending message") report )
 
         it "summarizes the time it takes to finish"
-            (any ("Finished in " `isPrefixOf`) report),
+            (any ("Finished in " `isPrefixOf`) report)
 
         it "summarizes the number of examples and failures"
-            (any (=="6 examples, 4 failures") report),
+            (any (=="6 examples, 4 failures") report)
 
         it "outputs failed examples in red, pending in yellow, and successful in green"
             (True)
-    ],
-    describe "Bool as an example" [
+
+    describe "Bool as an example" $ do
         it "is just an expression that evaluates to a Bool"
             (True)
-    ],
-    describe "HUnit TestCase as an example" [
+
+    describe "HUnit TestCase as an example" $ do
         it "is specified with the HUnit \"TestCase\" data constructor"
-            (HUnit.TestCase $ HUnit.assertBool "example" True),
+            (HUnit.TestCase $ HUnit.assertBool "example" True)
 
         it "is the assumed example for IO() actions"
-            (HUnit.assertBool "example" True),
+            (HUnit.assertBool "example" True)
 
-        it "will show the failed assertion text if available (e.g. assertBool)"
-            (HUnit.TestCase $ do
-              (innerReport, _) <- capture $ hspec $ [describe "" [ it "" (HUnit.assertBool "trivial" False)]]
-              HUnit.assertBool "should find assertion text" $ any (=="trivial") (lines innerReport)),
+        it "will show the failed assertion text if available (e.g. assertBool)" $ do
+          (innerReport, _) <- capture $ hspec $ [H.describe "" [ H.it "" (HUnit.assertBool "trivial" False)]]
+          HUnit.assertBool "should find assertion text" $ any (=="trivial") (lines innerReport)
 
-        it "will show the failed assertion expected and actual values if available (e.g. assertEqual)"
-            (HUnit.TestCase $ do
-              (innerReportContents, _) <- capture $ hspec $ [describe "" [ it "" (HUnit.assertEqual "trivial" (1::Int) 2)]]
-              let innerReport = lines innerReportContents
-              HUnit.assertBool "should find assertion text" $ any (=="trivial") innerReport
-              HUnit.assertBool "should find 'expected: 1'" $ any (=="expected: 1") innerReport
-              HUnit.assertBool "should find ' but got: 2'" $ any (==" but got: 2") innerReport)
-    ],
-    describe "QuickCheck property as an example" [
+        it "will show the failed assertion expected and actual values if available (e.g. assertEqual)" $ do
+          (innerReportContents, _) <- capture $ hspec $ [H.describe "" [ H.it "" (HUnit.assertEqual "trivial" (1::Int) 2)]]
+          let innerReport = lines innerReportContents
+          HUnit.assertBool "should find assertion text" $ any (=="trivial") innerReport
+          HUnit.assertBool "should find 'expected: 1'" $ any (=="expected: 1") innerReport
+          HUnit.assertBool "should find ' but got: 2'" $ any (==" but got: 2") innerReport
+
+    describe "QuickCheck property as an example" $ do
         it "is specified with the \"property\" function"
-            (property $ \ b -> b || True),
+            (property $ \ b -> b || True)
 
         it "will show what falsified it"
             (any (=="0") report)
-    ],
-    describe "pending as an example" [
-        it "is specified with the \"pending\" function and an explanation"
-            (pending "message" == Pending "message"),
 
-        it "accepts a message to display in the report"
-            (any (== "     # pending message") report)
-    ],
-    describe "the \"hHspecWithFormat\" function" [
+    describe "pending as an example" $ do
+        it "is specified with the \"pending\" function and an explanation" True
+
+        it "accepts a message to display in the report" True
+
+    describe "the \"hHspecWithFormat\" function" $ do
         it "can use the \"silent\" formatter to show no output"
-            (null silentReportContents),
+            (null silentReportContents)
 
         it "can use the \"progress\" formatter to show '..F...FF.F' style output"
-            (HUnit.assertEqual "" ".F.FFF" (head $ lines progressReportContents)),
+            (HUnit.assertEqual "" ".F.FFF" (head $ lines progressReportContents))
 
         it "can use the \"specdoc\" formatter to show all examples (default)"
-            (HUnit.assertEqual "" "Example" (lines reportContents !! 1)),
+            (HUnit.assertEqual "" "Example" (lines reportContents !! 1))
 
         it "can use the \"failed_examples\" formatter to show only failed examples"
             (HUnit.assertEqual "" "1) Example fail 1 FAILED" (lines failed_examplesReportContents !! 1))
-    ],
-    describe "quantify (an internal function)" [
+
+    describe "quantify (an internal function)" $ do
         it "returns an amount and a word given an amount and word"
-            (quantify (1::Int) "thing" == "1 thing"),
+            (quantify (1::Int) "thing" == "1 thing")
 
         it "returns a singular word given the number 1"
-            (quantify (1::Int) "thing" == "1 thing"),
+            (quantify (1::Int) "thing" == "1 thing")
 
         it "returns a plural word given a number greater than 1"
-            (quantify (2::Int) "thing" == "2 things"),
+            (quantify (2::Int) "thing" == "2 things")
 
         it "returns a plural word given the number 0"
             (quantify (0::Int) "thing" == "0 things")
-    ]]
diff --git a/Test/Hspec.hs b/Test/Hspec.hs
--- a/Test/Hspec.hs
+++ b/Test/Hspec.hs
@@ -1,28 +1,68 @@
-
--- | Hspec is a Behaviour-Driven Development tool for Haskell programmers. BDD is an approach
--- to software development that combines Test-Driven Development, Domain Driven Design, and
--- Acceptance Test-Driven Planning. Hspec helps you do the TDD part of that equation, focusing
--- on the documentation and design aspects of TDD.
+-- |
+-- Hspec is a Behaviour-Driven Development tool for Haskell programmers. BDD is
+-- an approach to software development that combines Test-Driven Development,
+-- Domain Driven Design, and Acceptance Test-Driven Planning. Hspec helps you
+-- do the TDD part of that equation, focusing on the documentation and design
+-- aspects of TDD.
 --
--- Hspec (and the preceding intro) are based on the Ruby library RSpec. Much of what applies to
--- RSpec also applies to Hspec. Hspec ties together /descriptions/ of behavior and /examples/ of
--- that behavior. The examples can also be run as tests and the output summarises what needs to
--- be implemented.
+-- Hspec (and the preceding intro) are based on the Ruby library RSpec. Much of
+-- what applies to RSpec also applies to Hspec. Hspec ties together
+-- /descriptions/ of behavior and /examples/ of that behavior. The examples can
+-- also be run as tests and the output summarises what needs to be implemented.
 --
--- The three functions you'll use the most are 'hspec', 'describe', and 'it'. Here is an
--- example of functions that format and unformat phone numbers and the specs for them.
+-- NOTE: There is a monadic and a non-monadic API.  This is the documentation
+-- for the non-monadic API.  The monadic API is more stable, so you may prefer
+-- it over this one.  For documentation on the monadic API look at
+-- "Test.Hspec.Monadic".
+
+module Test.Hspec (
+
+-- * Introduction
+-- $intro
+
+-- * Types
+  Spec
+, Specs
+, Example
+, Pending
+
+-- * Defining a spec
+, describe
+, it
+, pending
+
+-- * Running a spec
+, hspec
+, hspecB
+, hspecX
+, hHspec
+
+-- * Deprecated functions
+, descriptions
+) where
+
+import           Test.Hspec.Core
+import           Test.Hspec.Runner
+import           Test.Hspec.Pending
+
+-- $intro
 --
+-- The three functions you'll use the most are 'hspecX', 'describe', and 'it'.
+-- Here is an example of functions that format and unformat phone numbers and
+-- the specs for them.
+--
 -- > import Test.Hspec
 -- > import Test.Hspec.QuickCheck
--- > import Test.Hspec.HUnit
+-- > import Test.Hspec.HUnit ()
 -- > import Test.QuickCheck
 -- > import Test.HUnit
 -- >
--- > main = hspec mySpecs
+-- > main = hspecX mySpecs
 --
--- Since the specs are often used to tell you what to implement, it's best to start with
--- undefined functions. Once we have some specs, then you can implement each behavior
--- one at a time, ensuring that each behavior is met and there is no undocumented behavior.
+-- Since the specs are often used to tell you what to implement, it's best to
+-- start with undefined functions. Once we have some specs, then you can
+-- implement each behavior one at a time, ensuring that each behavior is met
+-- and there is no undocumented behavior.
 --
 -- > unformatPhoneNumber :: String -> String
 -- > unformatPhoneNumber number = undefined
@@ -30,69 +70,50 @@
 -- > formatPhoneNumber :: String -> String
 -- > formatPhoneNumber number = undefined
 --
--- The 'describe' function takes a list of behaviors and examples bound together with the 'it' function
+-- The 'describe' function takes a list of behaviors and examples bound
+-- together with the 'it' function
 --
 -- > mySpecs = [describe "unformatPhoneNumber" [
 --
 -- A boolean expression can act as a behavior's example.
 --
--- >   it "removes dashes, spaces, and parenthesies"
--- >       (unformatPhoneNumber "(555) 555-1234" == "5555551234"),
+-- >   it "removes dashes, spaces, and parenthesies" $
+-- >     unformatPhoneNumber "(555) 555-1234" == "5555551234"
+-- >   ,
 --
--- The 'pending' function marks a behavior as pending an example. The example doesn't count as failing.
+-- The 'pending' function marks a behavior as pending an example. The example
+-- doesn't count as failing.
 --
--- >   it "handles non-US phone numbers"
--- >       (pending "need to look up how other cultures format phone numbers"),
+-- >   it "handles non-US phone numbers" $
+-- >     pending "need to look up how other cultures format phone numbers"
+-- >   ,
 --
--- An HUnit 'Test' can act as a behavior's example. (must import @Test.Hspec.HUnit@)
+-- An HUnit 'Test.HUnit.Test' can act as a behavior's example. (must import
+-- "Test.Hspec.HUnit")
 --
--- >   it "removes the \"ext\" prefix of the extension"
--- >       (TestCase $ let expected = "5555551234135"
--- >                       actual   = unformatPhoneNumber "(555) 555-1234 ext 135"
--- >                   in assertEqual "remove extension" expected actual),
+-- >   it "removes the \"ext\" prefix of the extension" $ TestCase $ do
+-- >     let expected = "5555551234135"
+-- >         actual   = unformatPhoneNumber "(555) 555-1234 ext 135"
+-- >     expected @?= actual
+-- >   ,
 --
--- An @IO()@ action is treated like an HUnit 'TestCase'. (must import @Test.Hspec.HUnit@)
+-- An @IO()@ action is treated like an HUnit 'TestCase'. (must import
+-- "Test.Hspec.HUnit")
 --
--- >   it "converts letters to numbers"
--- >       (do
--- >         let expected = "6862377"
--- >         let actual   = unformatPhoneNumber "NUMBERS"
--- >         assertEqual "letters to numbers" expected actual),
+-- >   it "converts letters to numbers" $ do
+-- >     let expected = "6862377"
+-- >         actual   = unformatPhoneNumber "NUMBERS"
+-- >     actual @?= expected
+-- >   ,
 --
--- The 'property' function allows a QuickCheck property to act as an example. (must import @Test.Hspec.QuickCheck@)
+-- The 'property' function allows a QuickCheck property to act as an example.
+-- (must import "Test.Hspec.QuickCheck")
 --
--- >   it "can add and remove formatting without changing the number"
--- >       (property $ forAll phoneNumber $
--- >         \ n -> unformatPhoneNumber (formatPhoneNumber n) == n)
+-- >   it "can add and remove formatting without changing the number" $ property $
+-- >     forAll phoneNumber $ \n -> unformatPhoneNumber (formatPhoneNumber n) == n
 -- >   ]]
 -- >
 -- > phoneNumber :: Gen String
 -- > phoneNumber = do
--- >   nums <- elements [7,10,11,12,13,14,15]
--- >   vectorOf nums (elements "0123456789")
---
-module Test.Hspec (
-
-  -- * Types
-    Spec
-  , Result
-  , Specs
-
-  -- * Defining a spec
-  , describe
-  , it
-  , pending
-
-  -- * Running a spec
-  , hspec
-  , hspecB
-  , hspecX
-  , hHspec
-
-  -- * Deprecated functions
-  , descriptions
-) where
-
-import Test.Hspec.Core
-import Test.Hspec.Runner
-
+-- >   n <- elements [7,10,11,12,13,14,15]
+-- >   vectorOf n (elements "0123456789")
diff --git a/Test/Hspec/Core.hs b/Test/Hspec/Core.hs
--- a/Test/Hspec/Core.hs
+++ b/Test/Hspec/Core.hs
@@ -1,106 +1,78 @@
-{-# OPTIONS -XFlexibleInstances -XExistentialQuantification #-}
-
--- | This module contains the core types, constructors, classes,
--- instances, and utility functions common to hspec.
---
-module Test.Hspec.Core where
+{-# OPTIONS_GHC -fno-warn-deprecations #-}
+-- |
+-- This module contains the core types, constructors, classes, instances, and
+-- utility functions common to hspec.
+module Test.Hspec.Core (
+  SpecTree (..)
+, Example (..)
+, Result (..)
+, descriptions
 
-import System.IO.Silently
-import Control.Exception
+, describe
+, it
+, Spec
+, Specs
+, UnevaluatedSpec
+, EvaluatedSpec
 
--- | The result of running an example.
-data Result = Success | Pending String | Fail String
-  deriving Eq
+, quantify
 
+-- * Deprecated types and functions
+-- | The following types and functions are deprecated and will be removed with
+-- the next release.
+--
+-- If you still need any of those, please open an issue and describe your use
+-- case: <https://github.com/hspec/hspec/issues>
+, AnyExample
+, safeEvaluateExample
 
-type UnevaluatedSpec = Spec AnyExample
-type EvaluatedSpec = Spec Result
+, success
+, failure
+, isFailure
+, failedCount
+) where
 
-data Spec a = SpecGroup String [Spec a]
-            | SpecExample String a
+import           Test.Hspec.Internal hiding (safeEvaluateExample)
+import qualified Test.Hspec.Internal as Internal
 
-describe :: String -> [Spec a] -> Spec a
-describe = SpecGroup
+{-# DEPRECATED UnevaluatedSpec "use Spec instead" #-}
+type UnevaluatedSpec = Spec
 
 -- | DEPRECATED: This is no longer needed (it's just an alias for `id` now).
-descriptions :: [Spec a] -> [Spec a]
+descriptions :: Specs -> Specs
 descriptions = id
 {-# DEPRECATED descriptions "this is no longer needed, and will be removed in a future release" #-}
 
-safeEvaluateExample :: AnyExample -> IO Result
-safeEvaluateExample example' = do
-  evaluateExample example' `catches` [
-    -- Re-throw AsyncException, otherwise execution will not terminate on
-    -- SIGINT (ctrl-c).  All AsyncExceptions are re-thrown (not just
-    -- UserInterrupt) because all of them indicate severe conditions and
-    -- should not occur during normal test runs.
-    Handler (\e -> throw (e :: AsyncException)),
-
-    Handler (\e -> return $ Fail (show (e :: SomeException)))
-    ]
-
-
--- | Create a set of specifications for a specific type being described.
--- Once you know what you want specs for, use this.
---
--- > describe "abs" [
--- >   it "returns a positive number given a negative number"
--- >     (abs (-1) == 1)
--- >   ]
---
-it :: Example a => String -> a -> UnevaluatedSpec
-it requirement' example' = SpecExample requirement' (AnyExample example')
-
-class Example a where
-  evaluateExample :: a -> IO Result
-
-instance Example Bool where
-  evaluateExample bool = evaluateExample $ if bool then Success else Fail ""
-
-instance Example Result where
-  evaluateExample result' = silence $ result' `seq` return result'
-
--- | An existentially quantified @Example@. This way they can be mixed within the same set of Specs
-data AnyExample = forall a. Example a => AnyExample a
-
-instance Example AnyExample where
-  evaluateExample (AnyExample a) = evaluateExample a
-
-
-
--- | Declare an example as not successful or failing but pending some other work.
--- If you want to report on a behavior but don't have an example yet, use this.
---
--- > describe "fancyFormatter" [
--- >   it "can format text in a way that everyone likes"
--- >     (pending "waiting for clarification from the designers")
--- >   ]
---
-pending :: String  -- ^ An explanation for why this behavior is pending.
-        -> Result
-pending = Pending
+type Specs = [Spec]
 
+type EvaluatedSpec = SpecTree Result
 
-failedCount :: [EvaluatedSpec] -> Int
-failedCount = sum . map count
-  where
-    count (SpecGroup _ xs) = sum (map count xs)
-    count (SpecExample _ x) = if isFailure x then 1 else 0
+{-# DEPRECATED success "This will be removed with the next major release.  If you still need this, raise your voice!" #-}
+success :: [EvaluatedSpec] -> Bool
+success = not . failure
 
+{-# DEPRECATED failure "This will be removed with the next major release.  If you still need this, raise your voice!" #-}
 failure :: [EvaluatedSpec] -> Bool
 failure = any p
   where
     p (SpecGroup _ xs) = any p xs
     p (SpecExample _ x) = isFailure x
 
-success :: [EvaluatedSpec] -> Bool
-success = not . failure
-
+{-# DEPRECATED isFailure "This will be removed with the next major release.  If you still need this, raise your voice!" #-}
 isFailure :: Result -> Bool
 isFailure (Fail _) = True
 isFailure _        = False
 
--- | Create a more readable display of a quantity of something.
-quantify :: (Show a, Num a, Eq a) => a -> String -> String
-quantify 1 s = "1 " ++ s
-quantify n s = show n ++ " " ++ s ++ "s"
+{-# DEPRECATED failedCount "This will be removed with the next major release.  If you still need this, raise your voice!" #-}
+failedCount :: [EvaluatedSpec] -> Int
+failedCount = sum . map count
+  where
+    count (SpecGroup _ xs) = sum (map count xs)
+    count (SpecExample _ x) = if isFailure x then 1 else 0
+
+{-# DEPRECATED AnyExample "This will be removed with the next major release.  If you still need this, raise your voice!" #-}
+type AnyExample  = IO Result
+
+{-# DEPRECATED safeEvaluateExample "This will be removed with the next major release.  If you still need this, raise your voice!" #-}
+safeEvaluateExample :: AnyExample -> IO Result
+safeEvaluateExample = Internal.safeEvaluateExample
diff --git a/Test/Hspec/Formatters.hs b/Test/Hspec/Formatters.hs
--- a/Test/Hspec/Formatters.hs
+++ b/Test/Hspec/Formatters.hs
@@ -38,10 +38,11 @@
 , withFailColor
 ) where
 
-import Test.Hspec.Core (quantify)
-import Data.List (intersperse)
-import Text.Printf
-import Control.Monad (when)
+import           Data.Maybe
+import           Test.Hspec.Core (quantify)
+import           Data.List (intersperse)
+import           Text.Printf
+import           Control.Monad (unless)
 
 -- We use an explicit import list for "Test.Hspec.Formatters.Internal", to make
 -- sure, that we only use the public API to implement formatters.
@@ -92,11 +93,11 @@
     writeLine $ indentationForExample nesting ++ " - " ++ requirement
 
 , exampleFailed = \nesting requirement _ -> withFailColor $ do
-    failed <- getFailCount
-    writeLine $ indentationForExample nesting ++ " - " ++ requirement ++ " FAILED [" ++ show failed ++ "]"
+    n <- getFailCount
+    writeLine $ indentationForExample nesting ++ " - " ++ requirement ++ " FAILED [" ++ show n ++ "]"
 
 , examplePending = \nesting requirement reason -> withPendingColor $ do
-    writeLine $ indentationForExample nesting ++ " - " ++ requirement ++ "\n     # " ++ reason
+    writeLine $ indentationForExample nesting ++ " - " ++ requirement ++ "\n     # PENDING: " ++ fromMaybe "No reason given" reason
 
 , failedFormatter = defaultFailedFormatter
 
@@ -129,7 +130,7 @@
 defaultFailedFormatter = withFailColor $ do
   failures <- getFailMessages
   mapM_ writeLine ("" : intersperse "" failures)
-  when (not $ null failures) (writeLine "")
+  unless (null failures) (writeLine "")
 
 defaultFooter :: FormatM ()
 defaultFooter = do
diff --git a/Test/Hspec/Formatters/Internal.hs b/Test/Hspec/Formatters/Internal.hs
--- a/Test/Hspec/Formatters/Internal.hs
+++ b/Test/Hspec/Formatters/Internal.hs
@@ -30,11 +30,11 @@
 ) where
 
 import qualified System.IO as IO
-import System.IO (Handle)
-import Control.Monad (when)
-import Control.Exception (bracket_)
-import System.Console.ANSI
-import Control.Monad.Trans.State hiding (gets, modify)
+import           System.IO (Handle)
+import           Control.Monad (when)
+import           Control.Exception (bracket_)
+import           System.Console.ANSI
+import           Control.Monad.Trans.State hiding (gets, modify)
 import qualified Control.Monad.Trans.State as State
 import qualified Control.Monad.IO.Class as IOClass
 import qualified System.CPUTime as CPUTime
@@ -126,7 +126,7 @@
 -- | evaluated after each failed example
 , exampleFailed       :: Int -> String -> String -> FormatM ()
 -- | evaluated after each pending example
-, examplePending      :: Int -> String -> String -> FormatM ()
+, examplePending      :: Int -> String -> Maybe String -> FormatM ()
 -- | evaluated after a test run
 , failedFormatter     :: FormatM ()
 -- | evaluated after `failuresFormatter`
@@ -182,7 +182,7 @@
 getCPUTime = do
   t1 <- liftIO CPUTime.getCPUTime
   t0 <- gets cpuStartTime
-  return ((fromIntegral $ t1 - t0) / (10.0^(12::Integer)))
+  return (fromIntegral (t1 - t0) / (10.0^(12::Integer)))
 
 -- | Get the passed real time since the test run has been started.
 getRealTime :: FormatM Double
diff --git a/Test/Hspec/HUnit.hs b/Test/Hspec/HUnit.hs
--- a/Test/Hspec/HUnit.hs
+++ b/Test/Hspec/HUnit.hs
@@ -1,29 +1,37 @@
-{-# OPTIONS -XFlexibleInstances -fno-warn-orphans #-}
+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
+{-# OPTIONS -fno-warn-orphans #-}
 
--- | Importing this module allows you to use an @HUnit@ test case as an example
--- for a behavior. You can use an explicit @TestCase@ data constructor or
--- use an @IO()@ action. For an @IO()@ action, any exception means the example
--- failed; otherwise, it's successfull. Any output from the example to stdout is
--- ignored. If you need to write out for debugging, you can write to stderr or
--- a file handle.
+-- |
+-- Importing this module allows you to use an @HUnit@ `HU.Test` as an example
+-- for a behavior.  You can use an explicit `HU.TestCase` data constructor or
+-- use an `HU.Assertion`.  For an @Assertion@, any exception means the example
+-- failed; otherwise, it's successfull.
 --
--- > describe "cutTheDeck" [
--- >   it "puts the first half of a list after the last half"
--- >      (TestCase $ assertEqual "cut the deck" [3,4,1,2] (cutTheDeck [1,2,3,4])),
+-- NOTE: Any output from the example to @stdout@ is ignored.  If you need to
+-- write out for debugging, you can write to @stderr@ or a file handle.
+--
+-- > import Test.Hspec.Monadic
+-- > import Test.Hspec.HUnit ()
+-- > import Test.HUnit
 -- >
--- >   it "restores an even sized list when cut twice"
--- >      (assertEqual "cut the deck twice" [3,4,1,2] (cutTheDeck (cutTheDeck [1,2,3,4]))),
--- >   ]
+-- > main :: IO ()
+-- > main = hspecX $ do
+-- >   describe "reverse" $ do
+-- >     it "reverses a list" $ do
+-- >       reverse [1, 2, 3] @?= [3, 2, 1]
 -- >
+-- >     it "gives the original list, if applied twice" $ TestCase $
+-- >       (reverse . reverse) [1, 2, 3] @?= [1, 2, 3]
+--
 module Test.Hspec.HUnit (
 ) where
 
-import System.IO.Silently
-import Test.Hspec.Core
+import           System.IO.Silently
+import           Test.Hspec.Core
 import qualified Test.HUnit as HU
-import Data.List (intersperse)
+import           Data.List (intersperse)
 
-instance Example (IO ()) where
+instance Example HU.Assertion where
   evaluateExample io = evaluateExample (HU.TestCase io)
 
 instance Example HU.Test where
diff --git a/Test/Hspec/Internal.hs b/Test/Hspec/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Test/Hspec/Internal.hs
@@ -0,0 +1,95 @@
+{-# LANGUAGE FlexibleInstances #-}
+module Test.Hspec.Internal (
+  SpecTree (..)
+, Spec (..)
+, Example (..)
+, safeEvaluateExample
+, Result (..)
+
+, describe
+, it
+
+, quantify
+)
+where
+
+import           Control.Exception
+import qualified Test.Hspec.Pending as Pending
+
+-- | The result of running an example.
+data Result = Success | Pending (Maybe String) | Fail String
+  deriving (Eq, Show)
+
+newtype Spec = Spec {unSpec :: SpecTree (IO Result)}
+
+-- IMPORTANT: Remove this warnings and remove -fno-warn-deprecations from the
+-- following modules/files when making SpecGroup abstract.
+--
+--  * Spec.hs
+--  * Test.Hspec.Runner
+--  * Test.Hspec.Core
+--
+{-# WARNING SpecExample "This will be removed from the public interface with the next major release.  If you need this, raise your voice!" #-}
+{-# WARNING SpecGroup "This will be removed from the public interface with the next major release.  If you need this, raise your voice!" #-}
+
+-- | Internal representation of a spec.
+--
+-- This will be made abstract with the next release.  If you still need access
+-- to any constructors, open an issue and describe your use case:
+-- <https://github.com/hspec/hspec/issues>
+data SpecTree a = SpecGroup String [SpecTree a]
+            | SpecExample String a
+
+describe :: String -> [Spec] -> Spec
+describe str specs = Spec . SpecGroup str $ map unSpec specs
+
+safeEvaluateExample :: IO Result -> IO Result
+safeEvaluateExample action = do
+  action `catches` [
+    -- Re-throw AsyncException, otherwise execution will not terminate on
+    -- SIGINT (ctrl-c).  All AsyncExceptions are re-thrown (not just
+    -- UserInterrupt) because all of them indicate severe conditions and
+    -- should not occur during normal test runs.
+    Handler (\e -> throw (e :: AsyncException)),
+
+    Handler (\e -> return $ Fail (show (e :: SomeException)))
+    ]
+
+
+-- | Create a set of specifications for a specific type being described.
+-- Once you know what you want specs for, use this.
+--
+-- > describe "abs" [
+-- >   it "returns a positive number given a negative number"
+-- >     (abs (-1) == 1)
+-- >   ]
+--
+it :: Example a => String -> a -> Spec
+it requirement' = Spec . SpecExample requirement' . evaluateExample
+
+-- | A type class for examples.
+--
+-- To use an HUnit `Test.HUnit.Test` or an `Test.HUnit.Assertion` as an example
+-- you need to import "Test.Hspec.HUnit".
+--
+-- To use a QuickCheck `Test.QuickCheck.Property` as an example you need to
+-- import "Test.Hspec.QuickCheck".
+class Example a where
+  evaluateExample :: a -> IO Result
+
+instance Example Bool where
+  evaluateExample b = if b then return Success else return (Fail "")
+
+instance Example Result where
+  evaluateExample r = r `seq` return r
+
+instance Example Pending.Pending where
+  evaluateExample (Pending.Pending reason) = evaluateExample (Pending reason)
+
+instance Example (String -> Pending.Pending) where
+  evaluateExample _ = evaluateExample (Pending.Pending Nothing)
+
+-- | Create a more readable display of a quantity of something.
+quantify :: (Show a, Num a, Eq a) => a -> String -> String
+quantify 1 s = "1 " ++ s
+quantify n s = show n ++ " " ++ s ++ "s"
diff --git a/Test/Hspec/Monadic.hs b/Test/Hspec/Monadic.hs
--- a/Test/Hspec/Monadic.hs
+++ b/Test/Hspec/Monadic.hs
@@ -1,21 +1,66 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
--- | This module contains the runners that take a set of specs, specified in a monadic style, evaluate their examples, and
--- report to a given handle.
+-- |
+-- There is a monadic and a non-monadic API.  This is the documentation for the
+-- monadic API.  The monadic API is suitable for most use cases, and it is more
+-- stable than the non-monadic API.
 --
--- The three functions you'll use the most are 'hspec', 'describe', and 'it'. Here is an
--- example of functions that format and unformat phone numbers and the specs for them.
+-- For documentation on the non-monadic API look at "Test.Hspec".
 --
+module Test.Hspec.Monadic (
+-- * Introduction
+-- $intro
+-- * Types
+  Specs
+, Example
+, Pending
+
+-- * Defining a spec
+, describe
+-- , context
+, it
+, pending
+
+-- * Running a spec
+, hspec
+, hspecB
+, hspecX
+, hHspec
+
+-- * Interface to the non-monadic API
+, runSpecM
+, fromSpecList
+
+-- * Deprecated functions
+, descriptions
+) where
+
+import           System.IO
+import           Test.Hspec.Core (EvaluatedSpec, Example)
+import qualified Test.Hspec.Core as Core
+import qualified Test.Hspec.Runner as Runner
+import           Test.Hspec.Pending (Pending)
+import qualified Test.Hspec.Pending as Pending
+
+import           Control.Monad.Trans.Writer (Writer, execWriter, tell)
+
+-- $intro
+--
+-- The three functions you'll use the most are 'hspecX', 'describe', and 'it'.
+-- Here is an example of functions that format and unformat phone numbers and
+-- the specs for them.
+--
 -- > import Test.Hspec.Monadic
 -- > import Test.Hspec.QuickCheck
--- > import Test.Hspec.HUnit
+-- > import Test.Hspec.HUnit ()
 -- > import Test.QuickCheck
 -- > import Test.HUnit
 -- >
--- > main = hspec mySpecs
+-- > main = hspecX mySpecs
 --
--- Since the specs are often used to tell you what to implement, it's best to start with
--- undefined functions. Once we have some specs, then you can implement each behavior
--- one at a time, ensuring that each behavior is met and there is no undocumented behavior.
+-- Since the specs are often used to tell you what to implement, it's best to
+-- start with undefined functions. Once we have some specs, then you can
+-- implement each behavior one at a time, ensuring that each behavior is met
+-- and there is no undocumented behavior.
 --
 -- > unformatPhoneNumber :: String -> String
 -- > unformatPhoneNumber number = undefined
@@ -23,7 +68,8 @@
 -- > formatPhoneNumber :: String -> String
 -- > formatPhoneNumber number = undefined
 --
--- The 'describe' function takes a list of behaviors and examples bound together with the 'it' function
+-- The 'describe' function takes a list of behaviors and examples bound
+-- together with the 'it' function
 --
 -- > mySpecs = describe "unformatPhoneNumber" $ do
 --
@@ -32,79 +78,54 @@
 -- >   it "removes dashes, spaces, and parenthesies" $
 -- >     unformatPhoneNumber "(555) 555-1234" == "5555551234"
 --
--- The 'pending' function marks a behavior as pending an example. The example doesn't count as failing.
 --
+-- The 'pending' function marks a behavior as pending an example. The example
+-- doesn't count as failing.
+--
 -- >   it "handles non-US phone numbers" $
 -- >     pending "need to look up how other cultures format phone numbers"
 --
--- An HUnit 'Test' can act as a behavior's example. (must import @Test.Hspec.HUnit@)
 --
--- >   it "removes the \"ext\" prefix of the extension" $ do
+-- An HUnit 'Test.HUnit.Test' can act as a behavior's example. (must import
+-- "Test.Hspec.HUnit")
+--
+-- >   it "removes the \"ext\" prefix of the extension" $ TestCase $ do
 -- >     let expected = "5555551234135"
 -- >         actual   = unformatPhoneNumber "(555) 555-1234 ext 135"
--- >     assertEqual "remove extension" expected actual
+-- >     expected @?= actual
 --
--- An @IO()@ action is treated like an HUnit 'TestCase'. (must import @Test.Hspec.HUnit@)
 --
+-- An @IO()@ action is treated like an HUnit 'TestCase'. (must import
+-- "Test.Hspec.HUnit")
+--
 -- >   it "converts letters to numbers" $ do
 -- >     let expected = "6862377"
 -- >         actual   = unformatPhoneNumber "NUMBERS"
--- >     assertEqual "letters to numbers" expected actual
+-- >     actual @?= expected
 --
--- The 'property' function allows a QuickCheck property to act as an example. (must import @Test.Hspec.HUnit@)
 --
+-- The 'property' function allows a QuickCheck property to act as an example.
+-- (must import "Test.Hspec.QuickCheck")
+--
 -- >   it "can add and remove formatting without changing the number" $ property $
--- >     forAll phoneNumber $ \ n -> unformatPhoneNumber (formatPhoneNumber n) == n
+-- >     forAll phoneNumber $ \n -> unformatPhoneNumber (formatPhoneNumber n) == n
 -- >
 -- > phoneNumber :: Gen String
 -- > phoneNumber = do
--- >   nums <- elements [7,10,11,12,13,14,15]
--- >   vectorOf nums (elements "0123456789")
+-- >   n <- elements [7,10,11,12,13,14,15]
+-- >   vectorOf n (elements "0123456789")
 --
 
-module Test.Hspec.Monadic (
-
-  -- * Types
-    Spec
-  , Result
-  , Specs
-
-  -- * Defining a spec
-  , describe
-  , it
-  , pending
-
-  -- * Running a spec
-  , hspec
-  , hspecB
-  , hspecX
-  , hHspec
-
-  -- * Interface to the non-monadic API
-  , runSpecM
-  , fromSpecList
-
-  -- * Deprecated functions
-  , descriptions
-) where
-
-import System.IO
-import Test.Hspec.Core hiding (describe,descriptions,it)
-import qualified Test.Hspec.Core as Core
-import qualified Test.Hspec.Runner as Runner
-
-import Control.Monad.Trans.Writer (Writer, execWriter, tell)
-
 type Specs = SpecM ()
 
-newtype SpecM a = SpecM (Writer [UnevaluatedSpec] a)
+newtype SpecM a = SpecM (Writer [Core.Spec] a)
   deriving Monad
 
 -- | Create a document of the given specs and write it to stdout.
 hspec :: Specs -> IO [EvaluatedSpec]
 hspec = Runner.hspec . runSpecM
 
--- | Use in place of @hspec@ to also exit the program with an @ExitCode@
+-- | Use in place of `hspec` to also exit the program with an @ExitCode@
 hspecX :: Specs -> IO a
 hspecX = Runner.hspecX . runSpecM
 
@@ -114,24 +135,45 @@
 
 -- | Create a document of the given specs and write it to the given handle.
 --
--- > writeReport filename specs = withFile filename WriteMode (\ h -> hHspec h specs)
+-- > writeReport filename specs = withFile filename WriteMode (\h -> hHspec h specs)
 --
 hHspec :: Handle -> Specs -> IO [EvaluatedSpec]
 hHspec h = Runner.hHspec h . runSpecM
 
 -- | Convert a monadic spec into a non-monadic spec.
-runSpecM :: Specs -> [UnevaluatedSpec]
+runSpecM :: Specs -> [Core.Spec]
 runSpecM (SpecM specs) = execWriter specs
 
 -- | Convert a non-monadic spec into a monadic spec.
-fromSpecList :: [UnevaluatedSpec] -> Specs
+fromSpecList :: [Core.Spec] -> Specs
 fromSpecList = SpecM . tell
 
 describe :: String -> Specs -> Specs
 describe label action = SpecM . tell $ [Core.describe label (runSpecM action)]
 
+{-
+context :: String -> Specs -> Specs
+context = describe
+-}
+
 it :: Example v => String -> v -> Specs
 it label action = (SpecM . tell) [Core.it label action]
+
+-- | A pending example.
+--
+-- If you want to report on a behavior but don't have an example yet, use this.
+--
+-- > describe "fancyFormatter" $ do
+-- >   it "can format text in a way that everyone likes" $
+-- >     pending
+--
+-- You can give an optional reason for why it's pending.
+--
+-- > describe "fancyFormatter" $ do
+-- >   it "can format text in a way that everyone likes" $
+-- >     pending "waiting for clarification from the designers"
+pending :: String  -> Pending
+pending = Pending.pending
 
 -- | DEPRECATED: Use `sequence_` instead.
 descriptions :: [Specs] -> Specs
diff --git a/Test/Hspec/Pending.hs b/Test/Hspec/Pending.hs
new file mode 100644
--- /dev/null
+++ b/Test/Hspec/Pending.hs
@@ -0,0 +1,21 @@
+module Test.Hspec.Pending where
+
+newtype Pending = Pending (Maybe String)
+
+-- | A pending example.
+--
+-- If you want to report on a behavior but don't have an example yet, use this.
+--
+-- > describe "fancyFormatter" [
+-- >   it "can format text in a way that everyone likes" $
+-- >     pending
+-- > ]
+--
+-- You can give an optional reason for why it's pending.
+--
+-- > describe "fancyFormatter" [
+-- >   it "can format text in a way that everyone likes" $
+-- >     pending "waiting for clarification from the designers"
+-- > ]
+pending :: String -> Pending
+pending = Pending . Just
diff --git a/Test/Hspec/QuickCheck.hs b/Test/Hspec/QuickCheck.hs
--- a/Test/Hspec/QuickCheck.hs
+++ b/Test/Hspec/QuickCheck.hs
@@ -1,33 +1,35 @@
 {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
--- | Importing this module allows you to use a QuickCheck property as an example
--- for a behavior. Use the 'property' function to indicate a QuickCkeck property.
--- Any output from the example to stdout is ignored. If you need to write out for
--- debugging, you can write to stderr or a file handle.
+-- |
+-- Importing this module allows you to use a QuickCheck `QC.Property` as an
+-- example for a behavior.  Use `QC.property` to turn any `QC.Testable` into a
+-- @Property@.
 --
--- > describe "cutTheDeck" [
--- >   it "puts the first half of a list after the last half"
--- >      (property $ \ xs -> let top = take (length xs `div` 2) xs
--- >                              bot = drop (length xs `div` 2) xs
--- >                          in cutTheDeck xs == bot ++ top),
+-- NOTE: Any output from the example to @stdout@ is ignored.  If you need to
+-- write out for debugging, you can write to @stderr@ or a file handle.
+--
+-- > import Test.Hspec.Monadic
+-- > import Test.Hspec.QuickCheck
 -- >
--- >   it "restores an even sized list when cut twice"
--- >      (property $ \ xs -> even (length xs) ==> cutTheDeck (cutTheDeck xs) == xs)
--- >   ]
+-- > main :: IO ()
+-- > main = hspecX $ do
+-- >   describe "reverse" $ do
+-- >     it "gives the original list, if applied twice" $ property $
+-- >       \xs -> (reverse . reverse) xs == (xs :: [Int])
 --
 module Test.Hspec.QuickCheck (
   QC.property
 , prop
 ) where
 
-import System.IO.Silently
-import Test.Hspec.Core
+import           System.IO.Silently
+import           Test.Hspec.Core
 import qualified Test.QuickCheck as QC
 
 -- just for the prop shortcut
 import qualified Test.Hspec.Monadic as DSL
 
--- | Monadic DSL shortcut, use this instead of @it@
+-- | Monadic DSL shortcut, use this instead of `DSL.it`.
 prop :: QC.Testable t => String -> t -> DSL.Specs
 prop n p = DSL.it n (QC.property p)
 
diff --git a/Test/Hspec/Runner.hs b/Test/Hspec/Runner.hs
--- a/Test/Hspec/Runner.hs
+++ b/Test/Hspec/Runner.hs
@@ -1,4 +1,4 @@
-
+{-# OPTIONS_GHC -fno-warn-deprecations #-}
 -- | This module contains the runners that take a set of specs, evaluate their examples, and
 -- report to a given handle.
 --
@@ -6,55 +6,69 @@
   Specs, hspec, hspecX, hspecB, hHspec, hHspecWithFormat, describe, it, toExitCode
 ) where
 
-import Test.Hspec.Core
-import Test.Hspec.Formatters
-import Test.Hspec.Formatters.Internal
-import System.IO
-import System.Exit
-
-type Specs = [UnevaluatedSpec]
+import           Test.Hspec.Internal
+import           Test.Hspec.Core (EvaluatedSpec, Specs)
+import           Test.Hspec.Formatters
+import           Test.Hspec.Formatters.Internal
+import           System.IO
+import           System.Exit
 
 -- | Evaluate and print the result of checking the spec examples.
-runFormatter :: Formatter -> Int -> String -> UnevaluatedSpec -> FormatM EvaluatedSpec
-runFormatter formatter nesting _ (SpecGroup group xs) = do
-  exampleGroupStarted formatter (nesting) group
-  ys <- mapM (runFormatter formatter (succ nesting) group) xs
-  return (SpecGroup group ys)
-runFormatter formatter nesting group (SpecExample requirement e) = do
-  result <- liftIO $ safeEvaluateExample e
-  case result of
-    Success -> do
-      increaseSuccessCount
-      exampleSucceeded formatter nesting requirement
-    Fail err -> do
-      increaseFailCount
-      exampleFailed  formatter nesting requirement err
-      n <- getFailCount
-      addFailMessage $ failureDetails group requirement err n
-    Pending reason -> do
-      increasePendingCount
-      examplePending formatter nesting requirement reason
-  return (SpecExample requirement result)
+runFormatter :: Formatter -> Spec -> FormatM EvaluatedSpec
+runFormatter formatter = go 0 "" . unSpec
+  where
+    go nesting _ (SpecGroup group xs) = do
+      exampleGroupStarted formatter nesting group
+      ys <- mapM (go (succ nesting) group) xs
+      return (SpecGroup group ys)
+    go nesting group (SpecExample requirement e) = do
+      result <- liftIO $ safeEvaluateExample e
+      case result of
+        Success -> do
+          increaseSuccessCount
+          exampleSucceeded formatter nesting requirement
+        Fail err -> do
+          increaseFailCount
+          exampleFailed  formatter nesting requirement err
+          n <- getFailCount
+          addFailMessage $ failureDetails group requirement err n
+        Pending reason -> do
+          increasePendingCount
+          examplePending formatter nesting requirement reason
+      return (SpecExample requirement result)
 
 failureDetails :: String -> String -> String -> Int -> String
 failureDetails group requirement err i =
   concat [ show i, ") ", group, " ",  requirement, " FAILED", if null err then "" else "\n" ++ err ]
 
--- | Use in place of @hspec@ to also exit the program with an @ExitCode@
+-- | Use in place of `hspec` to also exit the program with an @ExitCode@
 hspecX :: Specs -> IO a
 hspecX ss = hspecB ss >>= exitWith . toExitCode
 
 -- | Use in place of hspec to also give a @Bool@ success indication
 hspecB :: Specs -> IO Bool
-hspecB ss = hspec ss >>= return . success
+hspecB ss = success `fmap` hspec ss
+  where
+    success :: [EvaluatedSpec] -> Bool
+    success = not . failure
 
+    failure :: [EvaluatedSpec] -> Bool
+    failure = any p
+      where
+        p (SpecGroup _ xs) = any p xs
+        p (SpecExample _ x) = isFailure x
+
+    isFailure :: Result -> Bool
+    isFailure (Fail _) = True
+    isFailure _        = False
+
 -- | Create a document of the given specs and write it to stdout.
 hspec :: Specs -> IO [EvaluatedSpec]
-hspec ss = hHspec stdout ss
+hspec = hHspec stdout
 
 -- | Create a document of the given specs and write it to the given handle.
 --
--- > writeReport filename specs = withFile filename WriteMode (\ h -> hHspec h specs)
+-- > writeReport filename specs = withFile filename WriteMode (\h -> hHspec h specs)
 --
 hHspec :: Handle -> Specs -> IO [EvaluatedSpec]
 hHspec h specs = do
@@ -65,7 +79,7 @@
 -- THIS IS LIKELY TO CHANGE
 hHspecWithFormat :: Formatter -> Bool -> Handle -> Specs -> IO [EvaluatedSpec]
 hHspecWithFormat formatter useColor h ss = runFormatM useColor h $ do
-  specList <- mapM (runFormatter formatter 0 "") ss
+  specList <- mapM (runFormatter formatter) ss
   failedFormatter formatter
   footerFormatter formatter
   return specList
@@ -73,4 +87,3 @@
 toExitCode :: Bool -> ExitCode
 toExitCode True  = ExitSuccess
 toExitCode False = ExitFailure 1
-
diff --git a/hspec.cabal b/hspec.cabal
--- a/hspec.cabal
+++ b/hspec.cabal
@@ -1,5 +1,5 @@
 name:           hspec
-version:        1.0.0.1
+version:        1.1.0
 cabal-version:  >= 1.8
 build-type:     Simple
 license:        BSD3
@@ -19,7 +19,8 @@
                 tests. Compared to other options, it provides a much nicer
                 syntax that makes tests very easy to read.
                 .
-                Read the introductory documentation: <http://hspec.github.com/>
+                New to Hspec?  Start with the introductory documentation:
+                <http://hspec.github.com/>
 
 source-repository head
   type: git
@@ -48,21 +49,37 @@
     , Test.Hspec.QuickCheck
 
   other-modules:
+      Test.Hspec.Pending
+      Test.Hspec.Internal
       Test.Hspec.Formatters.Internal
 
 test-suite spec
   type:
       exitcode-stdio-1.0
-
+  hs-source-dirs:
+      ., test
   main-is:
-      runtests.hs
-
-  other-modules:
-      Specs
-
+      Spec.hs
   ghc-options:
       -Wall -Werror
+  build-depends:
+      base >= 4 && <= 5
+    , silently >= 1.1.1 && < 2
+    , ansi-terminal == 0.5.5
+    , time < 1.5
+    , transformers >= 0.2.0 && < 0.4.0
+    , HUnit >= 1 && <= 2
+    , QuickCheck >= 2.4.0.1 && <= 2.5
+    , hspec-shouldbe
 
+-- this should be merged with spec
+test-suite old-spec
+  type:
+      exitcode-stdio-1.0
+  main-is:
+      Specs.hs
+  ghc-options:
+      -Wall -Werror
   build-depends:
       base >= 4 && <= 5
     , silently >= 1.1.1 && < 2
@@ -71,3 +88,4 @@
     , transformers >= 0.2.0 && < 0.4.0
     , HUnit >= 1 && <= 2
     , QuickCheck >= 2.4.0.1 && <= 2.5
+    , hspec-shouldbe
diff --git a/runtests.hs b/runtests.hs
deleted file mode 100644
--- a/runtests.hs
+++ /dev/null
@@ -1,5 +0,0 @@
-import Test.Hspec
-import Specs (specs)
-
-main :: IO ()
-main = specs >>= hspecX
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,9 @@
+module Main (main) where
+
+import           Test.Hspec.ShouldBe
+
+import qualified Test.Hspec.MonadicSpec
+
+main :: IO ()
+main = hspecX $ do
+  describe "Test.Hspec.Monadic" Test.Hspec.MonadicSpec.spec
