diff --git a/Test/Robot.hs b/Test/Robot.hs
--- a/Test/Robot.hs
+++ b/Test/Robot.hs
@@ -5,7 +5,6 @@
       -- * Running your robot
       Robot()  -- hide implementation
     , runRobot
-    , runRobotWithConnection
 
       -- * Key and button constants
     , module Test.Robot.Types
@@ -18,14 +17,17 @@
 
       -- * Miscellaneous
     , sleep
+    , module Test.Robot.Connection
 
     ) where
 
 
 import Control.Applicative
 import Control.Concurrent (threadDelay)
+import Control.Monad.Catch
 import Control.Monad.IO.Class
 
+import Test.Robot.Connection
 import Test.Robot.Internal
 import Test.Robot.Types
 
@@ -54,7 +56,7 @@
     -- of an exception.
     --
     hold :: x -> Robot a -> Robot a
-    hold = bracketRobot_ <$> press <*> release
+    hold = bracket_ <$> press <*> release
 
 instance Pressable Key where
     press = keyboard True
@@ -93,6 +95,15 @@
 
 
 -- | Press the argument, then release it.
+--
+-- Note that the underlying events are fired very quickly; much faster
+-- than some applications (such as Xmonad) can handle. If this becomes
+-- an issue, you may introduce a delay using 'sleep':
+--
+-- @
+-- slowTap x = x \`hold\` sleep 0.1
+-- @
+--
 tap :: Pressable x => x -> Robot ()
 tap = (`hold` return ())
 
diff --git a/Test/Robot/Connection.hs b/Test/Robot/Connection.hs
new file mode 100644
--- /dev/null
+++ b/Test/Robot/Connection.hs
@@ -0,0 +1,35 @@
+-- | Functions for managing connections manually.
+
+module Test.Robot.Connection
+    (
+      -- * Managing connections
+      -- $connections
+      runRobotWith
+    , connect
+
+    ) where
+
+
+import Test.Robot.Internal
+
+
+-- $connections
+--
+-- 'runRobot' opens a new connection every time it is called. If you
+-- call it too many times, it will exhaust the connection pool, causing
+-- a \"maximum number of clients reached\" error.
+--
+-- This module lets you avoid this error by handling the connection
+-- manually.
+--
+-- Example:
+--
+-- @
+-- main = do
+--     Just conn <- 'connect'
+--     replicateM_ 500 $ do
+--         'runRobotWith' conn $ tap _A
+--         putStrLn \"Ducks!\"
+-- @
+--
+--
diff --git a/Test/Robot/Internal.hs b/Test/Robot/Internal.hs
--- a/Test/Robot/Internal.hs
+++ b/Test/Robot/Internal.hs
@@ -8,13 +8,11 @@
       -- * The Robot monad
       Robot(..)
     , runRobot
-    , runRobotWithConnection
+    , runRobotWith
+    , connect
     , mkRobot
     , mkRobot'
 
-      -- * Exception safety
-    , bracketRobot_
-
       -- * Synthesizing events
     , keyboard
     , button
@@ -24,45 +22,50 @@
 
 
 import Control.Applicative
-import Control.Exception (bracket_)
+import Control.Monad.Catch
 import Control.Monad.IO.Class
 import Control.Monad.Trans.Reader
 import Data.Map (Map)
 import qualified Data.Map as M
 
-import Graphics.XHB
+import Graphics.XHB hiding (connect)
+import qualified Graphics.XHB as X
 
 import qualified Test.Robot.Internal.XTest as X
 import Test.Robot.Types
 
 
--- | The Robot monad: a reader monad over IO.
+-- | A @Robot@ is a program that interacts with the GUI.
+--
+-- Use 'runRobot' to execute your Robot, and 'liftIO' to perform
+-- arbitrary I/O.
+--
 newtype Robot a = Robot { unRobot :: ReaderT (Connection, Map KEYSYM KEYCODE) IO a }
-    deriving (Functor, Applicative, Monad, MonadIO)
+    deriving (Functor, Applicative, Monad, MonadIO, MonadCatch, MonadMask, MonadThrow)
 
 -- | Run the robot, connecting to the display automatically.
 runRobot :: Robot a -> IO a
 runRobot m = do
-    Just c <- connect
-    runRobotWithConnection m c
+    c <- connect
+    runRobotWith c m
 
 -- | Run the robot using an existing connection.
-runRobotWithConnection :: Robot a -> Connection -> IO a
-runRobotWithConnection (Robot m) c = do
+runRobotWith :: Connection -> Robot a -> IO a
+runRobotWith c (Robot m) = do
     keymap <- X.getKeysymMap c
     runReaderT m (c, keymap)
 
+-- | Connect to the X11 server.
+connect :: IO Connection
+connect = do
+    Just c <- X.connect
+    return c
+
 mkRobot :: ((Connection, Map KEYSYM KEYCODE) -> IO a) -> Robot a
 mkRobot = Robot . ReaderT
 
 mkRobot' :: (Connection -> IO a) -> Robot a
 mkRobot' = mkRobot . (. fst)
-
-
-bracketRobot_ :: Robot a -> Robot z -> Robot r -> Robot r
-bracketRobot_ (Robot before) (Robot after) (Robot middle)
-    = mkRobot $ \env -> let run = flip runReaderT env
-                        in bracket_ (run before) (run after) (run middle)
 
 
 keyboard :: Bool -> Key -> Robot ()
diff --git a/robot.cabal b/robot.cabal
--- a/robot.cabal
+++ b/robot.cabal
@@ -1,5 +1,5 @@
 Name:                robot
-Version:             1.2
+Version:             1.3
 Synopsis:            Simulate keyboard and mouse events
 Homepage:            https://github.com/lfairy/robot
 License:             OtherLicense
@@ -21,6 +21,7 @@
 Library
     Exposed-Modules:
         Test.Robot
+        Test.Robot.Connection
         Test.Robot.Internal
         Test.Robot.Internal.XTest
         Test.Robot.Types
@@ -31,6 +32,7 @@
 
     Build-Depends:    base == 4.*
                     , containers
+                    , exceptions == 0.6.*
                     , transformers
                     , xhb
 
