diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,76 @@
 #Change Log
+
+##0.7
+
+Because this is a fairly major update, changes have been described in detail and organized into categories. Most of the potentially breaking changes are to the "intermediate" API that might affect library code or advanced applications; changes that are not entirely "user-facing" but also not quite "internal".
+
+Basic web test code only has to contend with a few additional symbol exports, overloading of type signatures on some existing functions, and the reworked session history API.
+
+###Top-level API (exposed by`Test.WebDriver` module)
+  * `withSession` is now overloaded over the new constraint alias `WDSessionStateControl` ([see below](#typeclass-api)). This means that it can be used with monad transformer stacks over `WD` without any lifting required.
+  * Added several new `WDConfig` convenience functions: `modifyCaps`, `useBrowser`, `useVersion`, `usePlatform`, `useProxy`; these functions are overloaded over the new `HasCapabilities` constraint alias ([see below](#typeclass-api))
+  * Reworked and improved session history API
+    * Added a `SessionHistory` record type to replace the old `(Request, Response ByteString)` type. The new type has the same data as the previous tuple, but additionally records the number of attempted HTTP retries, and instead of `Response ByteString` uses `Either SomeException (Response ByteString)` so that HTTP request errors can be logged.
+    * Removed `wdKeepSessHist` field from `WDConfig` and replaced it with `wdHistoryConfig`, which uses a new `SessionHistoryConfig` type.
+      
+      ```hs
+        -- |A function used to append new requests/responses to session history.
+        type SessionHistoryConfig = SessionHistory -> [SessionHistory] -> [SessionHistory]
+      ```
+    * The new field can be configured using several new constants: `noHistory`, `onlyMostRecentHistory`, and `unlimitedHistory`. Note: `unlimitedHistory` is now the default configuration for history. For the old behavior, use `onlyMostRecentHistory`.
+    * New top-level functions for accessing session history
+      
+      ```hs
+        -- |Gets the command history for the current session.
+        getSessionHistory :: WDSessionState wd => wd [SessionHistory]
+        
+        -- |Prints a history of API requests to stdout after computing the given action
+        --  or after an exception is thrown
+        dumpSessionHistory :: WDSessionStateControl wd => wd a -> wd a
+      ```
+
+###Implicit waits API (`Test.WebDriver.Commands.Wait`)
+* Added functions for checking some expected conditions in explicit waits: `expectNotStale`, `expectAlertOpen`, `catchFailedCommand`
+
+###Typeclass API
+* `WDSessionState` is now a superclass of `Monad` and `Applicative` instead of `MonadBaseControl IO`. This makes the class significantly more flexible in how it can be used, as it no longer requires `IO` as a base monad.
+  * For convenience the following constraint aliases were added (requires `ConstraintKinds` extension to use). Several existing API functions have been updated to use these new constraints where appropriate.
+    
+    ```hs
+      type WDSessionStateIO s = (WDSessionState s, MonadBase IO s)
+      type WDSessionStateControl s = (WDSessionState s, MonadBaseControl IO s)
+    ```
+    
+  * The `WDSessionStateControl` constraint is equivalent to the previous `WDSessionState` constraint.
+  * The `WebDriver` class is unaffected (it is now a superclass of `WDSessionStateControl`), so code using the basic `Test.WebDriver` API will not be affected.
+
+* New typeclasses added to `Test.WebDriver.Capabilities`: `GetCapabilities` and `SetCapabilities`; for convenience a constraint alias `HasCapabilities` has been added to work with both of these classes (requires `ConstraintKinds` extension to use)
+      
+      ```hs
+        -- |A typeclass for readable 'Capabilities'
+        class GetCapabilities t where
+          getCaps :: t -> Capabilities
+        
+        -- |A typeclass for writable 'Capabilities'
+        class SetCapabilities t where
+          setCaps :: Capabilities -> t -> t
+        
+        -- |Read/write 'Capabilities'
+        type HasCapabilities t = (GetCapabilities t, SetCapabilities t)
+      ```
+      
+###Minor API changes (not exposed to `Test.WebDriver` module)
+* `Test.WebDriver.Session` changes
+  * new function `mostRecentHistory` added
+  * `lastHTTPRequest` renamed to `mostRecentHTTPRequest` (for consistency)
+  * `mkSession` moved from `Test.WebDriver.Config` to `Test.WebDriver.Session`
+* `Test.WebDriver.Internal` changes
+  * `sendHTTPRequest` now returns `(Either SomeException (Response ByteString))` and catches any exceptions that occur during the request. When using default configuration, the exceptions are also saved in 'wdSessHist'.
+  * `Test.WebDriver.Internal` no longer defines and exports exception types. All exception defined here previously have been moved to an unexposed `Test.WebDriver.Exceptions.Internal` module. These types are still exported in the usual places.
+
+###Dependencies
+* Now supports http-types up to 0.9
+
 ##0.6.3.1
 * Fixed an issue with aeson 0.10 support
 
diff --git a/TODO.md b/TODO.md
--- a/TODO.md
+++ b/TODO.md
@@ -2,21 +2,16 @@
 - fix loadProfile so that it doesn't cause an overlap with user addExtension calls
 
 #features
-- add support for Opera profiles
+- support new w3c webdriver spec: http://www.w3.org/TR/webdriver/
+  - try to support backwards compatibility with old wire protocol, otherwise provide legacy API in submodule (?) 
+  - mock-up example of actions API: http://lpaste.net/3484676197546196992
+- allow WDConfig to automatically load drivers. add modules with driver loading functions
 - overload URL inputs/outputs to implicitly support structured URL types
-- provide exception handling utilities (maybeNotFound, ignoreNotFound, ...)
+- add support for Opera profiles
 - POST "/session/{sessionId}/phantom/execute"
 
 #documentation
 - document errors.
-- provide examples
-  - basic runSession usage
-  - intermediate usage
-  - exception handling with lifted-base
-  - explicit waits usage
-  - firefox profile usage
-  - REPL usage
-- allow WDConfig to automatically load drivers. add modules with driver loading functions
 
 
 #considerations
diff --git a/src/Test/WebDriver.hs b/src/Test/WebDriver.hs
--- a/src/Test/WebDriver.hs
+++ b/src/Test/WebDriver.hs
@@ -3,23 +3,37 @@
 providing most of the functionality you're likely to want.
 -}
 module Test.WebDriver
-       ( -- * WebDriver sessions
-         WD(..), WDConfig(..), defaultConfig
-         -- * Running WebDriver tests
-       , runWD, runSession, withSession, finallyClose, closeOnException, dumpSessionHistory
-         -- * WebDriver commands
-       , module Test.WebDriver.Commands
-         -- * Capabilities and configuration
-       , Capabilities(..), defaultCaps, allCaps
-       , Platform(..), ProxyType(..)
-         -- ** Browser-specific configuration
-       , Browser(..), LogLevel(..)
-       , firefox, chrome, ie, opera, iPhone, iPad, android
-         -- * Exceptions
-       , module Test.WebDriver.Exceptions
-       ) where
+  ( -- * WebDriver monad
+    WD(..) 
+    -- * Running WebDriver commands
+  , runWD, runSession, withSession
+    -- * WebDriver configuration
+  , WDConfig(..), defaultConfig
+    -- ** Configuration helper functions
+    -- | Instead of working with the 'Capabilities' record directly, you can use 
+    --   these config modifier functions to specify common options.
+  , useBrowser, useProxy, useVersion, usePlatform 
+    -- ** Session history configuration
+  , SessionHistoryConfig, noHistory, unlimitedHistory, onlyMostRecentHistory
+    -- * WebDriver commands
+  , module Test.WebDriver.Commands
+    -- * Capabilities (advanced configuration)
+  , Capabilities(..), defaultCaps, allCaps, modifyCaps
+  , Platform(..), ProxyType(..)
+    -- ** Browser-specific capabilities
+  , Browser(..), LogLevel(..)
+    -- *** Browser defaults
+  , firefox, chrome, ie, opera, iPhone, iPad, android
+   -- * Exception handling
+  , finallyClose, closeOnException
+  , module Test.WebDriver.Exceptions
+    -- * Accessing session history
+  , SessionHistory(..), getSessionHistory, dumpSessionHistory
+  ) where
 
 import Test.WebDriver.Types
 import Test.WebDriver.Commands
 import Test.WebDriver.Monad
 import Test.WebDriver.Exceptions
+import Test.WebDriver.Config
+import Test.WebDriver.Session
diff --git a/src/Test/WebDriver/Capabilities.hs b/src/Test/WebDriver/Capabilities.hs
--- a/src/Test/WebDriver/Capabilities.hs
+++ b/src/Test/WebDriver/Capabilities.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings, RecordWildCards
+{-# LANGUAGE OverloadedStrings, RecordWildCards, ConstraintKinds
   #-}
 module Test.WebDriver.Capabilities where
 
@@ -18,6 +18,38 @@
 
 import Control.Applicative
 import Control.Exception.Lifted (throw)
+
+-- |A typeclass for readable 'Capabilities'
+class GetCapabilities t where
+  getCaps :: t -> Capabilities
+
+-- |A typeclass for writable 'Capabilities'
+class SetCapabilities t where
+  setCaps :: Capabilities -> t -> t
+
+-- |Read/write 'Capabilities'
+type HasCapabilities t = (GetCapabilities t, SetCapabilities t)
+
+-- |Modifies the 'wdCapabilities' field of a 'WDConfig' by applying the given function. Overloaded to work with any 'HasCapabilities' instance.
+modifyCaps :: HasCapabilities t => (Capabilities -> Capabilities) -> t -> t
+modifyCaps f c = setCaps (f (getCaps c)) c
+
+-- |A helper function for setting the 'browser' capability of a 'HasCapabilities' instance
+useBrowser :: HasCapabilities t => Browser -> t -> t
+useBrowser b = modifyCaps $ \c -> c { browser = b }
+
+-- |A helper function for setting the 'version' capability of a 'HasCapabilities' instance
+useVersion :: HasCapabilities t => String -> t -> t
+useVersion v = modifyCaps $ \c -> c { version = Just v }
+
+-- |A helper function for setting the 'platform' capability of a 'HasCapabilities' instance 
+usePlatform :: HasCapabilities t => Platform -> t -> t
+usePlatform p = modifyCaps $ \c -> c { platform = p }
+
+-- |A helper function for setting the 'useProxy' capability of a 'HasCapabilities' instance
+useProxy :: HasCapabilities t => ProxyType -> t -> t
+useProxy p = modifyCaps $ \c -> c { proxy = p }
+
 
 {- |A structure describing the capabilities of a session. This record
 serves dual roles.
diff --git a/src/Test/WebDriver/Class.hs b/src/Test/WebDriver/Class.hs
--- a/src/Test/WebDriver/Class.hs
+++ b/src/Test/WebDriver/Class.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE OverloadedStrings, DeriveDataTypeable, FlexibleContexts,
-             GeneralizedNewtypeDeriving, RecordWildCards #-}
+             GeneralizedNewtypeDeriving, RecordWildCards, ConstraintKinds #-}
 module Test.WebDriver.Class
        ( -- * WebDriver class
          WebDriver(..), Method, methodDelete, methodGet, methodPost,
@@ -32,7 +32,7 @@
 -- operation underlying all of the high-level commands exported in
 -- "Test.WebDriver.Commands". For more information on the wire protocol see
 -- <http://code.google.com/p/selenium/wiki/JsonWireProtocol>
-class (WDSessionState wd) => WebDriver wd where
+class (WDSessionStateControl wd) => WebDriver wd where
   doCommand :: (ToJSON a, FromJSON b) =>
                 RequestHeaders -- ^Additional headers
                 -> Method      -- ^HTTP request method
diff --git a/src/Test/WebDriver/Commands.hs b/src/Test/WebDriver/Commands.hs
--- a/src/Test/WebDriver/Commands.hs
+++ b/src/Test/WebDriver/Commands.hs
@@ -4,7 +4,7 @@
 -- browser session.
 module Test.WebDriver.Commands
        ( -- * Sessions
-         createSession, closeSession, sessions, getCaps
+         createSession, closeSession, sessions, getActualCaps
          -- * Browser interaction
          -- ** Web navigation
        , openPage, forward, back, refresh
@@ -74,11 +74,11 @@
        ) where
 
 import Test.WebDriver.Commands.Internal
+import Test.WebDriver.Exceptions.Internal
 import Test.WebDriver.Class
 import Test.WebDriver.Session
 import Test.WebDriver.JSON
 import Test.WebDriver.Capabilities
-import Test.WebDriver.Internal
 import Test.WebDriver.Utils (urlEncode)
 
 import Data.Aeson
@@ -124,9 +124,9 @@
   objs <- doCommand headers methodGet "/sessions" Null
   forM objs $ parsePair "id" "capabilities" "sessions"
 
--- |Get the actual 'Capabilities' of the current session.
-getCaps :: WebDriver wd => wd Capabilities
-getCaps = doSessCommand methodGet "" Null
+-- |Get the actual server-side 'Capabilities' of the current session.
+getActualCaps :: WebDriver wd => wd Capabilities
+getActualCaps = doSessCommand methodGet "" Null
 
 -- |Close the current session and the browser associated with it.
 closeSession :: WebDriver wd => wd ()
@@ -725,7 +725,7 @@
 deleteKey :: WebDriver wd => WebStorageType -> Text -> wd ()
 deleteKey s k = noReturn $ doStorageCommand methodPost s ("/key/" `T.append` urlEncode k) Null
 
--- |A wrapper around 'doStorageCommand' to create web storage URLs.
+-- |A wrapper around 'doSessCommand' to create web storage requests.
 doStorageCommand :: (WebDriver wd, ToJSON a, FromJSON b) =>
                      Method -> WebStorageType -> Text -> a -> wd b
 doStorageCommand m s path a = doSessCommand m (T.concat ["/", s', path]) a
diff --git a/src/Test/WebDriver/Commands/Wait.hs b/src/Test/WebDriver/Commands/Wait.hs
--- a/src/Test/WebDriver/Commands/Wait.hs
+++ b/src/Test/WebDriver/Commands/Wait.hs
@@ -1,15 +1,19 @@
-{-# LANGUAGE CPP, DeriveDataTypeable, ScopedTypeVariables, FlexibleContexts #-}
+{-# LANGUAGE CPP, DeriveDataTypeable, ScopedTypeVariables, FlexibleContexts, ConstraintKinds #-}
 module Test.WebDriver.Commands.Wait
        ( -- * Wait on expected conditions
          waitUntil, waitUntil'
        , waitWhile, waitWhile'
          -- * Expected conditions
        , ExpectFailed, expect, unexpected
+       , expectAny, expectAll
+       , expectNotStale, expectAlertOpen
+       , catchFailedCommand
          -- ** Convenience functions
        , onTimeout
-       , expectAny, expectAll
        , ifM, (<||>), (<&&>), notM
        ) where
+import Test.WebDriver.Commands
+import Test.WebDriver.Class
 import Test.WebDriver.Exceptions
 import Test.WebDriver.Session
 
@@ -21,7 +25,7 @@
 
 import Data.Time.Clock
 import Data.Typeable
-
+import Data.Text (Text)
 
 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 706
 import Prelude hiding (catch)
@@ -55,34 +59,52 @@
 expectAll :: MonadBaseControl IO m => (a -> m Bool) -> [a] -> m ()
 expectAll p xs = expect . and =<< mapM p xs
 
+-- | 'expect' the given 'Element' to not be stale and returns it
+expectNotStale :: WebDriver wd => Element -> wd Element
+expectNotStale e = catchFailedCommand StaleElementReference $ do
+    _ <- isEnabled e -- Any command will force a staleness check
+    return e
+
+-- | 'expect' an alert to be present on the page, and returns its text.
+expectAlertOpen :: WebDriver wd => wd Text
+expectAlertOpen = catchFailedCommand NoAlertOpen getAlertText
+
+-- |Catches any `FailedCommand` exceptions with the given `FailedCommandType` and rethrows as 'ExpectFailed'
+catchFailedCommand :: MonadBaseControl IO m => FailedCommandType -> m a -> m a
+catchFailedCommand t1 m = m `catch` handler
+    where 
+        handler e@(FailedCommand t2 _) 
+            | t1 == t2 = unexpected . show $ e
+        handler e = throwIO e
+
 -- |Wait until either the given action succeeds or the timeout is reached.
 -- The action will be retried every .5 seconds until no 'ExpectFailed' or
 -- 'FailedCommand' 'NoSuchElement' exceptions occur. If the timeout is reached,
 -- then a 'Timeout' exception will be raised. The timeout value
 -- is expressed in seconds.
-waitUntil :: (WDSessionState m) => Double -> m a -> m a
+waitUntil :: (WDSessionStateControl m) => Double -> m a -> m a
 waitUntil = waitUntil' 500000
 
 -- |Similar to 'waitUntil' but allows you to also specify the poll frequency
 -- of the 'WD' action. The frequency is expressed as an integer in microseconds.
-waitUntil' :: (WDSessionState m) => Int -> Double -> m a -> m a
+waitUntil' :: (WDSessionStateControl m) => Int -> Double -> m a -> m a
 waitUntil' = waitEither id (\_ -> return)
 
 -- |Like 'waitUntil', but retries the action until it fails or until the timeout
 -- is exceeded.
-waitWhile :: (WDSessionState m)  => Double -> m a -> m ()
+waitWhile :: (WDSessionStateControl m)  => Double -> m a -> m ()
 waitWhile = waitWhile' 500000
 
 -- |Like 'waitUntil'', but retries the action until it either fails or
 -- until the timeout is exceeded.
-waitWhile' :: (WDSessionState m)  => Int -> Double -> m a -> m ()
+waitWhile' :: (WDSessionStateControl m)  => Int -> Double -> m a -> m ()
 waitWhile' =
   waitEither  (\_ _ -> return ())
               (\retry _ -> retry "waitWhile: action did not fail")
 
 
 -- |Internal function used to implement explicit wait commands using success and failure continuations
-waitEither :: (WDSessionState m) =>
+waitEither :: (WDSessionStateControl m) =>
                ((String -> m b) -> String -> m b)
             -> ((String -> m b) -> a -> m b)
             -> Int -> Double -> m a -> m b
@@ -99,7 +121,7 @@
 
     handleExpectFailed (e :: ExpectFailed) = return . Left . show $ e
 
-wait' :: (WDSessionState m) =>
+wait' :: (WDSessionStateIO m) =>
          ((String -> m b) -> m a -> m b) -> Int -> Double -> m a -> m b
 wait' handler waitAmnt t wd = waitLoop =<< liftBase getCurrentTime
   where
diff --git a/src/Test/WebDriver/Config.hs b/src/Test/WebDriver/Config.hs
--- a/src/Test/WebDriver/Config.hs
+++ b/src/Test/WebDriver/Config.hs
@@ -1,19 +1,20 @@
 {-# LANGUAGE OverloadedStrings, RecordWildCards, FlexibleContexts #-}
 module Test.WebDriver.Config(
     -- * WebDriver configuration
-    WDConfig(..), defaultConfig, mkSession
+      WDConfig(..), defaultConfig
+    -- * Capabilities helpers
+    , modifyCaps, useBrowser, useVersion, usePlatform, useProxy
+    -- * SessionHistoryConfig options
+    , SessionHistoryConfig, noHistory, unlimitedHistory, onlyMostRecentHistory
     ) where
-import Test.WebDriver.Session
 import Test.WebDriver.Capabilities
+import Test.WebDriver.Session.History
 
 import Data.Default (Default, def)
-import Data.String (fromString)
 
-import Network.HTTP.Client (Manager, newManager, defaultManagerSettings)
+import Network.HTTP.Client (Manager)
 import Network.HTTP.Types (RequestHeaders)
 
-import Control.Monad.Base (MonadBase, liftBase)
-
 -- |WebDriver session configuration
 data WDConfig = WDConfig {
      -- |Host name of the WebDriver server for this
@@ -25,27 +26,44 @@
     , wdRequestHeaders :: RequestHeaders
      -- |Capabilities to use for this session
     , wdCapabilities :: Capabilities
-     -- |Whether or not we should keep a history of HTTP requests/responses
-     --
-     -- By default, only the last request/response pair is stored (O(1) heap consumption).
-     -- Enable this option for more detailed debugging info for HTTP requests.
-    , wdKeepSessHist :: Bool
-     -- |Base path for all API requests (default "/wd/hub")
+     -- |Specifies behavior of HTTP request/response history. By default we use 'unlimitedHistory'.
+    , wdHistoryConfig :: SessionHistoryConfig
+     -- |Base path for all API requests (default "\/wd\/hub")
     , wdBasePath :: String
-     -- |Use the given http-client 'Manager' instead of the default
+     -- |Use the given http-client 'Manager' instead of automatically creating one.
     , wdHTTPManager :: Maybe Manager
      -- |Number of times to retry a HTTP request if it times out (default 0)
     , wdHTTPRetryCount :: Int
-
 }
 
+instance GetCapabilities WDConfig where
+  getCaps = wdCapabilities
+
+instance SetCapabilities WDConfig where
+  setCaps caps conf = conf { wdCapabilities = caps }
+
+-- |A function used by 'wdHistoryConfig' to append new entries to session history.
+type SessionHistoryConfig = SessionHistory -> [SessionHistory] -> [SessionHistory]
+
+-- |No session history is saved.
+noHistory :: SessionHistoryConfig
+noHistory _ _ = []
+
+-- |Keep unlimited history
+unlimitedHistory :: SessionHistoryConfig
+unlimitedHistory = (:)
+
+-- |Saves only the most recent history
+onlyMostRecentHistory :: SessionHistoryConfig
+onlyMostRecentHistory h _ = [h]
+
 instance Default WDConfig where
     def = WDConfig {
       wdHost              = "127.0.0.1"
     , wdPort              = 4444
     , wdRequestHeaders    = []
     , wdCapabilities      = def
-    , wdKeepSessHist      = False
+    , wdHistoryConfig     = unlimitedHistory
     , wdBasePath          = "/wd/hub"
     , wdHTTPManager       = Nothing
     , wdHTTPRetryCount    = 0
@@ -56,27 +74,3 @@
 polymorphic type. -}
 defaultConfig :: WDConfig
 defaultConfig = def
-
--- |Constructs a new 'WDSession' from a given 'WDConfig'
-mkSession :: MonadBase IO m => WDConfig -> m WDSession
-mkSession WDConfig{..} = do
-  manager <- maybe createManager return wdHTTPManager
-  return WDSession { wdSessHost = fromString $ wdHost
-                   , wdSessPort = wdPort
-                   , wdSessBasePath = fromString $ wdBasePath
-                   , wdSessId = Nothing
-                   , wdSessHist = []
-                   , wdSessHistUpdate = histUpdate
-                   , wdSessHTTPManager = manager
-                   , wdSessHTTPRetryCount = wdHTTPRetryCount }
-  where
-    createManager = liftBase $ newManager defaultManagerSettings
-    histUpdate
-      | wdKeepSessHist = (:)
-      | otherwise      = \x _ -> [x]
-
-
-
-
-
-
diff --git a/src/Test/WebDriver/Exceptions.hs b/src/Test/WebDriver/Exceptions.hs
--- a/src/Test/WebDriver/Exceptions.hs
+++ b/src/Test/WebDriver/Exceptions.hs
@@ -5,7 +5,7 @@
        , FailedCommand(..), FailedCommandType(..)
        , FailedCommandInfo(..), StackFrame(..)
        , mkFailedCommandInfo, failedCommand
-       )where
-import Test.WebDriver.Internal
+       ) where
 import Test.WebDriver.JSON
 import Test.WebDriver.Commands.Internal
+import Test.WebDriver.Exceptions.Internal
diff --git a/src/Test/WebDriver/Exceptions/Internal.hs b/src/Test/WebDriver/Exceptions/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/WebDriver/Exceptions/Internal.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE OverloadedStrings, RecordWildCards, DeriveDataTypeable, ConstraintKinds, FlexibleContexts #-}
+module Test.WebDriver.Exceptions.Internal
+       ( InvalidURL(..), HTTPStatusUnknown(..), HTTPConnError(..)
+       , UnknownCommand(..), ServerError(..)
+
+       , FailedCommand(..), failedCommand, mkFailedCommandInfo
+       , FailedCommandType(..), FailedCommandInfo(..), StackFrame(..)
+       ) where
+import Test.WebDriver.Session
+import Test.WebDriver.JSON
+
+import Data.Aeson
+import Data.Aeson.Types (Parser, typeMismatch)
+import Data.ByteString.Lazy.Char8 (ByteString)
+import Data.Text (Text)
+import qualified Data.Text.Lazy.Encoding as TLE
+
+import Control.Exception (Exception)
+import Control.Exception.Lifted (throwIO)
+import Control.Applicative
+
+import Data.Typeable (Typeable)
+import Data.Maybe (fromMaybe)
+import Data.Word (Word)
+
+instance Exception InvalidURL
+-- |An invalid URL was given
+newtype InvalidURL = InvalidURL String
+                deriving (Eq, Show, Typeable)
+
+instance Exception HTTPStatusUnknown
+-- |An unexpected HTTP status was sent by the server.
+data HTTPStatusUnknown = HTTPStatusUnknown Int String
+                       deriving (Eq, Show, Typeable)
+
+instance Exception HTTPConnError
+-- |HTTP connection errors.
+data HTTPConnError = HTTPConnError String Int
+                   deriving (Eq, Show, Typeable)
+
+instance Exception UnknownCommand
+-- |A command was sent to the WebDriver server that it didn't recognize.
+newtype UnknownCommand = UnknownCommand String
+                    deriving (Eq, Show, Typeable)
+
+instance Exception ServerError
+-- |A server-side exception occured
+newtype ServerError = ServerError String
+                      deriving (Eq, Show, Typeable)
+
+instance Exception FailedCommand
+-- |This exception encapsulates a broad variety of exceptions that can
+-- occur when a command fails.
+data FailedCommand = FailedCommand FailedCommandType FailedCommandInfo
+                   deriving (Show, Typeable)
+
+-- |The type of failed command exception that occured.
+data FailedCommandType = NoSuchElement
+                       | NoSuchFrame
+                       | UnknownFrame
+                       | StaleElementReference
+                       | ElementNotVisible
+                       | InvalidElementState
+                       | UnknownError
+                       | ElementIsNotSelectable
+                       | JavascriptError
+                       | XPathLookupError
+                       | Timeout
+                       | NoSuchWindow
+                       | InvalidCookieDomain
+                       | UnableToSetCookie
+                       | UnexpectedAlertOpen
+                       | NoAlertOpen
+                       | ScriptTimeout
+                       | InvalidElementCoordinates
+                       | IMENotAvailable
+                       | IMEEngineActivationFailed
+                       | InvalidSelector
+                       | SessionNotCreated
+                       | MoveTargetOutOfBounds
+                       | InvalidXPathSelector
+                       | InvalidXPathSelectorReturnType
+                       deriving (Eq, Ord, Enum, Bounded, Show)
+
+-- |Detailed information about the failed command provided by the server.
+data FailedCommandInfo =
+  FailedCommandInfo { -- |The error message.
+                      errMsg    :: String
+                      -- |The session associated with
+                      -- the exception.
+                    , errSess :: Maybe WDSession
+                      -- |A screen shot of the focused window
+                      -- when the exception occured,
+                      -- if provided.
+                    , errScreen :: Maybe ByteString
+                      -- |The "class" in which the exception
+                      -- was raised, if provided.
+                    , errClass  :: Maybe String
+                      -- |A stack trace of the exception.
+                    , errStack  :: [StackFrame]
+                    }
+
+-- |Provides a readable printout of the error information, useful for
+-- logging.
+instance Show FailedCommandInfo where
+  show i = showChar '\n'
+           . showString "Session: " . sess
+           . showChar '\n'
+           . showString className . showString ": " . showString (errMsg i)
+           . showChar '\n'
+           . foldl (\f s-> f . showString "  " . shows s) id (errStack i)
+           $ ""
+    where
+      className = fromMaybe "<unknown exception>" . errClass $ i
+
+      sess = case errSess i of
+        Nothing -> showString "None"
+        Just WDSession{..} ->
+            let sessId = maybe "<no session id>" show wdSessId
+            in showString sessId . showString " at "
+                . shows wdSessHost . showChar ':' . shows wdSessPort
+
+
+-- |Constructs a FailedCommandInfo from only an error message.
+mkFailedCommandInfo :: (WDSessionState s) => String -> s FailedCommandInfo
+mkFailedCommandInfo m = do
+  sess <- getSession
+  return $ FailedCommandInfo { errMsg = m 
+                             , errSess = Just sess
+                             , errScreen = Nothing
+                             , errClass = Nothing
+                             , errStack = [] }
+
+-- |Convenience function to throw a 'FailedCommand' locally with no server-side
+-- info present.
+failedCommand :: (WDSessionStateIO s) => FailedCommandType -> String -> s a
+failedCommand t m = throwIO . FailedCommand t =<< mkFailedCommandInfo m
+
+-- |An individual stack frame from the stack trace provided by the server
+-- during a FailedCommand.
+data StackFrame = StackFrame { sfFileName   :: String
+                             , sfClassName  :: String
+                             , sfMethodName :: String
+                             , sfLineNumber :: Word
+                             }
+                deriving (Eq)
+
+
+instance Show StackFrame where
+  show f = showString (sfClassName f) . showChar '.'
+           . showString (sfMethodName f) . showChar ' '
+           . showParen True ( showString (sfFileName f) . showChar ':'
+                              . shows (sfLineNumber f))
+           $ "\n"
+
+
+instance FromJSON FailedCommandInfo where
+  parseJSON (Object o) =
+    FailedCommandInfo <$> (req "message" >>= maybe (return "") return)
+                      <*> pure Nothing
+                      <*> (fmap TLE.encodeUtf8 <$> opt "screen" Nothing)
+                      <*> opt "class"      Nothing
+                      <*> opt "stackTrace" []
+    where req :: FromJSON a => Text -> Parser a
+          req = (o .:)            --required key
+          opt :: FromJSON a => Text -> a -> Parser a
+          opt k d = o .:?? k .!= d --optional key
+  parseJSON v = typeMismatch "FailedCommandInfo" v
+
+instance FromJSON StackFrame where
+  parseJSON (Object o) = StackFrame <$> reqStr "fileName"
+                                    <*> reqStr "className"
+                                    <*> reqStr "methodName"
+                                    <*> req    "lineNumber"
+    where req :: FromJSON a => Text -> Parser a
+          req = (o .:) -- all keys are required
+          reqStr :: Text -> Parser String
+          reqStr k = req k >>= maybe (return "") return
+  parseJSON v = typeMismatch "StackFrame" v
diff --git a/src/Test/WebDriver/Internal.hs b/src/Test/WebDriver/Internal.hs
--- a/src/Test/WebDriver/Internal.hs
+++ b/src/Test/WebDriver/Internal.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE FlexibleContexts, OverloadedStrings, DeriveDataTypeable,
-             RecordWildCards, ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts, OverloadedStrings, RecordWildCards, ScopedTypeVariables, ConstraintKinds, PatternGuards #-}
 -- |The HTTP/JSON plumbing used to implement the 'WD' monad.
 --
 -- These functions can be used to create your own 'WebDriver' instances, providing extra functionality for your application if desired. All exports
@@ -8,42 +7,32 @@
        ( mkRequest, sendHTTPRequest
        , getJSONResult, handleJSONErr, handleRespSessionId
        , WDResponse(..)
-
-       , InvalidURL(..), HTTPStatusUnknown(..), HTTPConnError(..)
-       , UnknownCommand(..), ServerError(..)
-
-       , FailedCommand(..), failedCommand, mkFailedCommandInfo
-       , FailedCommandType(..), FailedCommandInfo(..), StackFrame(..)
        ) where
 import Test.WebDriver.Class
 import Test.WebDriver.JSON
 import Test.WebDriver.Session
+import Test.WebDriver.Exceptions.Internal
 
 import Network.HTTP.Client (httpLbs, Request(..), RequestBody(..), Response(..), HttpException(ResponseTimeout))
 import Network.HTTP.Types.Header
 import Network.HTTP.Types.Status (Status(..))
 import Data.Aeson
-import Data.Aeson.Types (Parser, typeMismatch)
+import Data.Aeson.Types (typeMismatch)
 
 import Data.Text as T (Text, splitOn, null)
 import qualified Data.Text.Encoding as TE
-import qualified Data.Text.Lazy.Encoding as TLE
 import Data.ByteString.Lazy.Char8 (ByteString)
 import Data.ByteString.Lazy.Char8 as LBS (length, unpack, null, fromStrict)
 import qualified Data.ByteString.Char8 as BS
 import qualified Data.ByteString.Base64.Lazy as B64
-import System.IO (hPutStrLn, stderr)
 
 import Control.Monad.Base
 import Control.Exception.Lifted (throwIO)
 import Control.Applicative
-import Control.Exception (SomeException, toException, catch)
+import Control.Exception (Exception, SomeException(..), toException, fromException, try)
 
-import Control.Exception (Exception)
-import Data.Typeable (Typeable)
-import Data.Maybe (fromMaybe)
 import Data.String (fromString)
-import Data.Word (Word, Word8)
+import Data.Word (Word8)
 import Data.Default
 
 -- |Constructs an HTTP 'Request' value when given a list of headers, HTTP request method, and URL fragment
@@ -65,29 +54,35 @@
              , method = meth }
 
 -- |Sends an HTTP request to the remote WebDriver server
-sendHTTPRequest :: (WDSessionState s) => Request -> s (Response ByteString)
+sendHTTPRequest :: (WDSessionStateIO s) => Request -> s (Either SomeException (Response ByteString))
 sendHTTPRequest req = do
   s@WDSession{..} <- getSession
-  res <- liftBase $ retryOnTimeout wdSessHTTPRetryCount $ httpLbs req wdSessHTTPManager
-  putSession s {wdSessHist = wdSessHistUpdate (req, res) wdSessHist} 
-  return res
+  (nRetries, tryRes) <- liftBase . retryOnTimeout wdSessHTTPRetryCount $ httpLbs req wdSessHTTPManager
+  let h = SessionHistory { histRequest = req
+                         , histResponse = tryRes
+                         , histRetryCount = nRetries
+                         }
+  putSession s { wdSessHist = wdSessHistUpdate h wdSessHist } 
+  return tryRes
 
-retryOnTimeout :: Int -> IO a -> IO a
-retryOnTimeout retryCount go = go `catch` handleTimeout
+retryOnTimeout :: Int -> IO a -> IO (Int, (Either SomeException a))
+retryOnTimeout maxRetry go = retry' 0
   where
-  handleTimeout ResponseTimeout
-    | retryCount > 0 = do
-        hPutStrLn stderr "HTTP request timed out - retrying"
-        retryOnTimeout (retryCount - 1) go
-
-  handleTimeout e = throwIO e
+    retry' nRetries = do
+      eitherV <- try go
+      case eitherV of
+        (Left e)
+          | Just ResponseTimeout <- fromException e
+          , maxRetry > nRetries 
+          -> retry' (succ nRetries)
+        other -> return (nRetries, other)
  
 -- |Parses a 'WDResponse' object from a given HTTP response.
-getJSONResult :: (WDSessionState s, FromJSON a) => Response ByteString -> s (Either SomeException a)
+getJSONResult :: (WDSessionStateControl s, FromJSON a) => Response ByteString -> s (Either SomeException a)
 getJSONResult r
   --malformed request errors
   | code >= 400 && code < 500 = do
-    lastReq <- lastHTTPRequest <$> getSession
+    lastReq <- mostRecentHTTPRequest <$> getSession
     returnErr . UnknownCommand . maybe reason show $ lastReq
   --server-side errors
   | code >= 500 && code < 600 = 
@@ -136,7 +131,7 @@
     body = responseBody r  
     headers = responseHeaders r
 
-handleRespSessionId :: (WDSessionState s) => WDResponse -> s ()
+handleRespSessionId :: (WDSessionStateIO s) => WDResponse -> s ()
 handleRespSessionId WDResponse{rspSessId = sessId'} = do
     sess@WDSession { wdSessId = sessId} <- getSession
     case (sessId, (==) <$> sessId <*> sessId') of
@@ -147,7 +142,7 @@
                                  ++ ") does not match local session ID (" ++ show sessId ++ ")"
        _ ->  return ()
     
-handleJSONErr :: (WDSessionState s) => WDResponse -> s (Maybe SomeException)
+handleJSONErr :: (WDSessionStateControl s) => WDResponse -> s (Maybe SomeException)
 handleJSONErr WDResponse{rspStatus = 0} = return Nothing
 handleJSONErr WDResponse{rspVal = val, rspStatus = status} = do
   sess <- getSession
@@ -200,157 +195,3 @@
   parseJSON v = typeMismatch "WDResponse" v
 
 
-instance Exception InvalidURL
--- |An invalid URL was given
-newtype InvalidURL = InvalidURL String
-                deriving (Eq, Show, Typeable)
-
-instance Exception HTTPStatusUnknown
--- |An unexpected HTTP status was sent by the server.
-data HTTPStatusUnknown = HTTPStatusUnknown Int String
-                       deriving (Eq, Show, Typeable)
-
-instance Exception HTTPConnError
--- |HTTP connection errors.
-data HTTPConnError = HTTPConnError String Int
-                   deriving (Eq, Show, Typeable)
-
-instance Exception UnknownCommand
--- |A command was sent to the WebDriver server that it didn't recognize.
-newtype UnknownCommand = UnknownCommand String
-                    deriving (Eq, Show, Typeable)
-
-instance Exception ServerError
--- |A server-side exception occured
-newtype ServerError = ServerError String
-                      deriving (Eq, Show, Typeable)
-
-instance Exception FailedCommand
--- |This exception encapsulates a broad variety of exceptions that can
--- occur when a command fails.
-data FailedCommand = FailedCommand FailedCommandType FailedCommandInfo
-                   deriving (Show, Typeable)
-
--- |The type of failed command exception that occured.
-data FailedCommandType = NoSuchElement
-                       | NoSuchFrame
-                       | UnknownFrame
-                       | StaleElementReference
-                       | ElementNotVisible
-                       | InvalidElementState
-                       | UnknownError
-                       | ElementIsNotSelectable
-                       | JavascriptError
-                       | XPathLookupError
-                       | Timeout
-                       | NoSuchWindow
-                       | InvalidCookieDomain
-                       | UnableToSetCookie
-                       | UnexpectedAlertOpen
-                       | NoAlertOpen
-                       | ScriptTimeout
-                       | InvalidElementCoordinates
-                       | IMENotAvailable
-                       | IMEEngineActivationFailed
-                       | InvalidSelector
-                       | SessionNotCreated
-                       | MoveTargetOutOfBounds
-                       | InvalidXPathSelector
-                       | InvalidXPathSelectorReturnType
-                       deriving (Eq, Ord, Enum, Bounded, Show)
-
--- |Detailed information about the failed command provided by the server.
-data FailedCommandInfo =
-  FailedCommandInfo { -- |The error message.
-                      errMsg    :: String
-                      -- |The session associated with
-                      -- the exception.
-                    , errSess :: Maybe WDSession
-                      -- |A screen shot of the focused window
-                      -- when the exception occured,
-                      -- if provided.
-                    , errScreen :: Maybe ByteString
-                      -- |The "class" in which the exception
-                      -- was raised, if provided.
-                    , errClass  :: Maybe String
-                      -- |A stack trace of the exception.
-                    , errStack  :: [StackFrame]
-                    }
-
--- |Provides a readable printout of the error information, useful for
--- logging.
-instance Show FailedCommandInfo where
-  show i = showChar '\n'
-           . showString "Session: " . sess
-           . showChar '\n'
-           . showString className . showString ": " . showString (errMsg i)
-           . showChar '\n'
-           . foldl (\f s-> f . showString "  " . shows s) id (errStack i)
-           $ ""
-    where
-      className = fromMaybe "<unknown exception>" . errClass $ i
-
-      sess = case errSess i of
-        Nothing -> showString "None"
-        Just WDSession{..} ->
-            let sessId = maybe "<no session id>" show wdSessId
-            in showString sessId . showString " at "
-                . shows wdSessHost . showChar ':' . shows wdSessPort
-
-
--- |Constructs a FailedCommandInfo from only an error message.
-mkFailedCommandInfo :: (WDSessionState s) => String -> s FailedCommandInfo
-mkFailedCommandInfo m = do
-  sess <- getSession
-  return $ FailedCommandInfo { errMsg = m 
-                             , errSess = Just sess
-                             , errScreen = Nothing
-                             , errClass = Nothing
-                             , errStack = [] }
-
--- |Convenience function to throw a 'FailedCommand' locally with no server-side
--- info present.
-failedCommand :: (WDSessionState s) => FailedCommandType -> String -> s a
-failedCommand t m = throwIO . FailedCommand t =<< mkFailedCommandInfo m
-
--- |An individual stack frame from the stack trace provided by the server
--- during a FailedCommand.
-data StackFrame = StackFrame { sfFileName   :: String
-                             , sfClassName  :: String
-                             , sfMethodName :: String
-                             , sfLineNumber :: Word
-                             }
-                deriving (Eq)
-
-
-instance Show StackFrame where
-  show f = showString (sfClassName f) . showChar '.'
-           . showString (sfMethodName f) . showChar ' '
-           . showParen True ( showString (sfFileName f) . showChar ':'
-                              . shows (sfLineNumber f))
-           $ "\n"
-
-
-instance FromJSON FailedCommandInfo where
-  parseJSON (Object o) =
-    FailedCommandInfo <$> (req "message" >>= maybe (return "") return)
-                      <*> pure Nothing
-                      <*> (fmap TLE.encodeUtf8 <$> opt "screen" Nothing)
-                      <*> opt "class"      Nothing
-                      <*> opt "stackTrace" []
-    where req :: FromJSON a => Text -> Parser a
-          req = (o .:)            --required key
-          opt :: FromJSON a => Text -> a -> Parser a
-          opt k d = o .:?? k .!= d --optional key
-  parseJSON v = typeMismatch "FailedCommandInfo" v
-
-instance FromJSON StackFrame where
-  parseJSON (Object o) = StackFrame <$> reqStr "fileName"
-                                    <*> reqStr "className"
-                                    <*> reqStr "methodName"
-                                    <*> req    "lineNumber"
-    where req :: FromJSON a => Text -> Parser a
-          req = (o .:) -- all keys are required
-          reqStr :: Text -> Parser String
-          reqStr k = req k >>= maybe (return "") return
-  parseJSON v = typeMismatch "StackFrame" v
diff --git a/src/Test/WebDriver/Monad.hs b/src/Test/WebDriver/Monad.hs
--- a/src/Test/WebDriver/Monad.hs
+++ b/src/Test/WebDriver/Monad.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE FlexibleContexts, TypeFamilies, GeneralizedNewtypeDeriving,
-             MultiParamTypeClasses, CPP, UndecidableInstances #-}
+             MultiParamTypeClasses, CPP, UndecidableInstances, ConstraintKinds #-}
 module Test.WebDriver.Monad
-       ( WD(..), runWD, runSession, withSession, finallyClose, closeOnException, dumpSessionHistory
+       ( WD(..), runWD, runSession, finallyClose, closeOnException, getSessionHistory, dumpSessionHistory
        ) where
 
 import Test.WebDriver.Class
@@ -13,15 +13,14 @@
 import Control.Monad.Base (MonadBase, liftBase)
 import Control.Monad.Reader
 import Control.Monad.Trans.Control (MonadBaseControl(..), StM)
-import Control.Monad.State.Strict (StateT, MonadState, evalStateT, get, put)
+import Control.Monad.State.Strict (StateT, evalStateT, get, put)
 --import Control.Monad.IO.Class (MonadIO)
 import Control.Exception.Lifted
 import Control.Monad.Catch (MonadThrow, MonadCatch)
 import Control.Applicative
 
 
-{- |A monadic interface to the WebDriver server. This monad is simply a
-    state monad transformer over 'IO', threading session information between sequential webdriver commands
+{- |A state monad for WebDriver commands.
 -}
 newtype WD a = WD (StateT WDSession IO a)
   deriving (Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch)
@@ -56,12 +55,12 @@
   doCommand headers method path args =
     mkRequest headers method path args
     >>= sendHTTPRequest
+    >>= either throwIO return
     >>= getJSONResult
     >>= either throwIO return
 
-
 -- |Executes a 'WD' computation within the 'IO' monad, using the given
--- 'WDSession'.
+-- 'WDSession' as state for WebDriver requests.
 runWD :: WDSession -> WD a -> IO a
 runWD sess (WD wd) = evalStateT wd sess
 
@@ -69,18 +68,13 @@
 --
 -- NOTE: session is not automatically closed when complete. If you want this behavior, use 'finallyClose'.
 -- Example:
+--
 -- >    runSessionThenClose action = runSession myConfig . finallyClose $ action
 runSession :: WDConfig -> WD a -> IO a
 runSession conf wd = do
   sess <- mkSession conf
   runWD sess $ createSession (wdRequestHeaders conf) (wdCapabilities conf) >> wd
 
--- |Locally sets a 'WDSession' for use within the given 'WD' action.
--- The state of the outer action is unaffected by this function.
--- This function is useful if you need to work with multiple sessions at once.
-withSession :: WDSession -> WD a -> WD a
-withSession s' (WD wd) = WD . lift $ evalStateT wd s'
-
 -- |A finalizer ensuring that the session is always closed at the end of
 -- the given 'WD' action, regardless of any exceptions.
 finallyClose:: WebDriver wd => wd a -> wd a
@@ -92,9 +86,10 @@
 closeOnException :: WebDriver wd => wd a -> wd a
 closeOnException wd = wd `onException` closeSession
 
+-- |Gets the command history for the current session.
+getSessionHistory :: WDSessionState wd => wd [SessionHistory]
+getSessionHistory = fmap wdSessHist getSession 
+
 -- |Prints a history of API requests to stdout after computing the given action.
-dumpSessionHistory :: (MonadIO wd, WebDriver wd) => wd a -> wd a
-dumpSessionHistory wd = do
-    v <- wd
-    getSession >>= liftIO . print . wdSessHist
-    return v
+dumpSessionHistory :: WDSessionStateControl wd => wd a -> wd a
+dumpSessionHistory = (`finally` (getSession >>= liftBase . print . wdSessHist))
diff --git a/src/Test/WebDriver/Session.hs b/src/Test/WebDriver/Session.hs
--- a/src/Test/WebDriver/Session.hs
+++ b/src/Test/WebDriver/Session.hs
@@ -1,18 +1,25 @@
-{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, FlexibleContexts,
-             GeneralizedNewtypeDeriving, RecordWildCards #-}
-module Test.WebDriver.Session(
-         -- * WDSessionState class
-         WDSessionState(..), modifySession
-         -- ** WebDriver sessions
-       , WDSession(..), lastHTTPRequest, SessionId(..)
-    ) where
+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, FlexibleContexts, ScopedTypeVariables,
+             GeneralizedNewtypeDeriving, RecordWildCards, ConstraintKinds #-}
+module Test.WebDriver.Session
+  ( -- * WDSessionState class
+    WDSessionState(..), WDSessionStateIO, WDSessionStateControl, modifySession, withSession
+    -- ** WebDriver sessions
+  , WDSession(..), mkSession, mostRecentHistory, mostRecentHTTPRequest, SessionId(..), SessionHistory(..)
+    -- * SessionHistoryConfig options
+  , SessionHistoryConfig, noHistory, unlimitedHistory, onlyMostRecentHistory
+  ) where
 
+import Test.WebDriver.Config
+import Test.WebDriver.Session.History
+
 import Data.Aeson
 import Data.ByteString as BS(ByteString) 
-import Data.ByteString.Lazy as LBS(ByteString)
 import Data.Text (Text)
-import Data.Maybe
+import Data.Maybe (listToMaybe)
+import Data.String (fromString)
 
+import Control.Applicative
+import Control.Monad.Base
 import Control.Monad.Trans.Control
 import Control.Monad.Trans.Maybe
 import Control.Monad.Trans.Identity
@@ -27,8 +34,11 @@
 import Control.Monad.RWS.Strict as SRWS
 import Control.Monad.RWS.Lazy as LRWS
 
-import Network.HTTP.Client (Manager, Request, Response)
+import Control.Exception.Lifted (SomeException, try, throwIO)
 
+--import Network.HTTP.Types.Header (RequestHeaders)
+import Network.HTTP.Client (Manager, Request, newManager, defaultManagerSettings)
+
 {- |An opaque identifier for a WebDriver session. These handles are produced by
 the server on session creation, and act to identify a session in progress. -}
 newtype SessionId = SessionId Text
@@ -53,32 +63,71 @@
                            , wdSessId   :: Maybe SessionId
                              -- |The complete history of HTTP requests and
                              -- responses, most recent first.
-                           , wdSessHist :: [(Request, Response LBS.ByteString)]
+                           , wdSessHist :: [SessionHistory]
                              -- |Update function used to append new entries to session history
-                           , wdSessHistUpdate :: (Request, Response LBS.ByteString)
-                                                 -> [(Request, Response LBS.ByteString)]
-                                                 -> [(Request, Response LBS.ByteString)]
+                           , wdSessHistUpdate :: SessionHistoryConfig
                              -- |HTTP 'Manager' used for connection pooling by the http-client library.
                            , wdSessHTTPManager :: Manager
-
                              -- |Number of times to retry a HTTP request if it times out
                            , wdSessHTTPRetryCount :: Int
+                           --, wdSessRequestHeaders :: RequestHeaders
                            }
-    
--- |The last HTTP request issued by this session, if any.
-lastHTTPRequest :: WDSession -> Maybe Request
-lastHTTPRequest = fmap fst . listToMaybe . wdSessHist
 
-
 -- |A class for monads that carry a WebDriver session with them. The
 -- MonadBaseControl superclass is used for exception handling through
 -- the lifted-base package.
-class MonadBaseControl IO s => WDSessionState s where
-  getSession :: s WDSession
-  putSession :: WDSession -> s ()
+class (Monad m, Applicative m) => WDSessionState m where
+  
+  -- |Retrieves the current session state of the monad
+  getSession :: m WDSession
+  
+  -- |Sets a new session state for the monad
+  putSession :: WDSession -> m ()
 
+-- |Constraint synonym for the common pairing of 'WDSessionState' and 'MonadBase' 'IO'.
+type WDSessionStateIO s = (WDSessionState s, MonadBase IO s)
+
+-- |Constraint synonym for another common pairing of 'WDSessionState' and 'MonadBaseControl' 'IO'. This
+-- is commonly used in library types to indicate use of lifted exception handling.
+type WDSessionStateControl s = (WDSessionState s, MonadBaseControl IO s) 
+
 modifySession :: WDSessionState s => (WDSession -> WDSession) -> s ()
 modifySession f = getSession >>= putSession . f
+
+-- |Locally sets a session state for use within the given action.
+-- The state of any outside action is unaffected by this function.
+-- This function is useful if you need to work with multiple sessions simultaneously.
+withSession :: WDSessionStateControl m => WDSession -> m a -> m a
+withSession s m = do
+  s' <- getSession
+  putSession s
+  (a :: Either SomeException a) <- try m
+  putSession s'
+  either throwIO return a
+
+-- |Constructs a new 'WDSession' from a given 'WDConfig'
+mkSession :: MonadBase IO m => WDConfig -> m WDSession
+mkSession WDConfig{..} = do
+  manager <- maybe createManager return wdHTTPManager
+  return WDSession { wdSessHost = fromString $ wdHost
+                   , wdSessPort = wdPort
+                   , wdSessBasePath = fromString $ wdBasePath
+                   , wdSessId = Nothing
+                   , wdSessHist = []
+                   , wdSessHistUpdate = wdHistoryConfig
+                   , wdSessHTTPManager = manager
+                   , wdSessHTTPRetryCount = wdHTTPRetryCount }
+  where
+    createManager = liftBase $ newManager defaultManagerSettings
+
+-- |The most recent SessionHistory entry recorded by this session, if any.
+mostRecentHistory :: WDSession -> Maybe SessionHistory
+mostRecentHistory = listToMaybe . wdSessHist
+    
+-- |The most recent HTTP request issued by this session, if any.
+mostRecentHTTPRequest :: WDSession -> Maybe Request
+mostRecentHTTPRequest = fmap histRequest . mostRecentHistory
+
                             
 instance WDSessionState m => WDSessionState (LS.StateT s m) where
   getSession = lift getSession
@@ -115,4 +164,3 @@
 instance (Monoid w, WDSessionState wd) => WDSessionState (LRWS.RWST r w s wd) where
   getSession = lift getSession
   putSession = lift . putSession
-  
diff --git a/src/Test/WebDriver/Session/History.hs b/src/Test/WebDriver/Session/History.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/WebDriver/Session/History.hs
@@ -0,0 +1,13 @@
+module Test.WebDriver.Session.History where
+
+import Data.ByteString.Lazy (ByteString)
+import Network.HTTP.Client (Request, Response)
+import Control.Exception (SomeException)
+
+
+data SessionHistory = SessionHistory 
+    { histRequest :: Request
+    , histResponse :: Either SomeException (Response ByteString)
+    , histRetryCount :: Int
+    }
+    deriving (Show)
diff --git a/src/Test/WebDriver/Types.hs b/src/Test/WebDriver/Types.hs
--- a/src/Test/WebDriver/Types.hs
+++ b/src/Test/WebDriver/Types.hs
@@ -1,9 +1,9 @@
 {-# OPTIONS_HADDOCK not-home #-}
 module Test.WebDriver.Types
        ( -- * WebDriver sessions
-         WD(..), WDSession(..), SessionId(..)
+         WD(..), WDSession(..), SessionId(..), SessionHistory
          -- * WebDriver configuration
-       , WDConfig(..), defaultConfig
+       , WDConfig(..), defaultConfig, SessionHistoryConfig
          -- * Capabilities
        , Capabilities(..), defaultCaps, allCaps
        , Platform(..), ProxyType(..), UnexpectedAlertBehavior(..)
diff --git a/test/search-baidu.hs b/test/search-baidu.hs
--- a/test/search-baidu.hs
+++ b/test/search-baidu.hs
@@ -7,11 +7,10 @@
 import           Data.List
 import qualified Data.Text                    as T
 import           Test.WebDriver
---import           Test.WebDriver.Classes
 import           Test.WebDriver.Commands.Wait
 
-capsChrome = defaultCaps { browser = chrome }
-capsFF = defaultCaps
+chromeConf = useBrowser chrome defaultConfig
+ffConf = defaultConfig
 
 -- Have no fun with baidu but only cause it is loading fast than google in China.
 --
@@ -20,7 +19,7 @@
 
 searchBaidu :: WD Bool
 searchBaidu = do
-  searchBox <- findElem (ById "kw1")
+  searchBox <- findElem (ById "kw")
   sendKeys "Cheese!" searchBox
   submit searchBox
   setImplicitWait 50
@@ -28,9 +27,9 @@
     title <- getTitle
     return ("cheese!" `T.isSuffixOf` title)
 
-testCase c = void $ runSession (defaultConfig { wdCapabilities = c }) (baidu >> searchBaidu)
+testCase c = void . runSession c . finallyClose $ (baidu >> searchBaidu)
 
-testSuits = mapM_ testCase  [capsFF, capsChrome]
+testSuits = mapM_ testCase  [ffConf, chromeConf]
 
 main = do
   --testCase capsChrome `seq` testCase capsFF
diff --git a/webdriver.cabal b/webdriver.cabal
--- a/webdriver.cabal
+++ b/webdriver.cabal
@@ -1,5 +1,5 @@
 Name: webdriver
-Version: 0.6.3.1
+Version: 0.7
 Cabal-Version: >= 1.8
 License: BSD3
 License-File: LICENSE
@@ -36,7 +36,7 @@
   build-depends:   base == 4.*
                  , aeson >= 0.6.2.0 && < 0.11
                  , http-client >= 0.3 && < 0.5
-                 , http-types >= 0.8 && < 0.9
+                 , http-types >= 0.8 && < 0.10
                  , text >= 0.11.3 && < 1.3
                  , bytestring >= 0.9 && < 0.11
                  , attoparsec < 0.14
@@ -68,6 +68,7 @@
                    Test.WebDriver.Class
                    Test.WebDriver.Monad
                    Test.WebDriver.Session
+                   Test.WebDriver.Session.History
                    Test.WebDriver.Config
                    Test.WebDriver.Exceptions
                    Test.WebDriver.Commands
@@ -82,6 +83,7 @@
                    Test.WebDriver.Utils
 
   other-modules:   Test.WebDriver.Internal
+                   Test.WebDriver.Exceptions.Internal
 
 Test-Suite test-search-baidu
   type: exitcode-stdio-1.0
@@ -91,3 +93,11 @@
                  webdriver,
                  text,
                  parallel
+
+--Test-Suite all-tests
+--  type: detailed-0.9
+--  test-module: all-tests.hs
+--  ghc-options: -Wall -threaded
+--  build-depends:  base,
+--                  webdriver,
+--                  hspec
