diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,8 +1,12 @@
 # ChangeLog for typed-process
 
+## 0.2.11.1
+
+* No user-visible changes
+
 ## 0.2.11.0
 
-* Expose `System.Process.Typed.Internal`
+* Expose more from `System.Process.Typed.Internal`
 
 ## 0.2.10.0
 
diff --git a/src/System/Process/Typed.hs b/src/System/Process/Typed.hs
--- a/src/System/Process/Typed.hs
+++ b/src/System/Process/Typed.hs
@@ -178,7 +178,7 @@
 -- @since 0.1.0.0
 startProcess :: MonadIO m
              => ProcessConfig stdin stdout stderr
-             -- ^
+             -- ^ 
              -> m (Process stdin stdout stderr)
 startProcess pConfig'@ProcessConfig {..} = liftIO $ do
     ssStream pcStdin $ \realStdin ->
@@ -256,25 +256,8 @@
                       -- Process didn't exit yet, let's terminate it and
                       -- then call waitForProcess ourselves
                       Left _ -> do
-                          eres <- try $ P.terminateProcess pHandle
-                          ec <-
-                            case eres of
-                              Left e
-                                -- On Windows, with the single-threaded runtime, it
-                                -- seems that if a process has already exited, the
-                                -- call to terminateProcess will fail with a
-                                -- permission denied error. To work around this, we
-                                -- catch this exception and then immediately
-                                -- waitForProcess. There's a chance that there may be
-                                -- other reasons for this permission error to appear,
-                                -- in which case this code may allow us to wait too
-                                -- long for a child process instead of erroring out.
-                                -- Recommendation: always use the multi-threaded
-                                -- runtime!
-                                | isPermissionError e && not multiThreadedRuntime && isWindows ->
-                                  P.waitForProcess pHandle
-                                | otherwise -> throwIO e
-                              Right () -> P.waitForProcess pHandle
+                          terminateProcess pHandle
+                          ec <- P.waitForProcess pHandle
                           success <- atomically $ tryPutTMVar pExitCode ec
                           evaluate $ assert success ()
 
@@ -282,6 +265,26 @@
   where
     pConfig = clearStreams pConfig'
 
+    terminateProcess pHandle = do
+      eres <- try $ P.terminateProcess pHandle
+      case eres of
+          Left e
+            -- On Windows, with the single-threaded runtime, it
+            -- seems that if a process has already exited, the
+            -- call to terminateProcess will fail with a
+            -- permission denied error. To work around this, we
+            -- catch this exception and then immediately
+            -- waitForProcess. There's a chance that there may be
+            -- other reasons for this permission error to appear,
+            -- in which case this code may allow us to wait too
+            -- long for a child process instead of erroring out.
+            -- Recommendation: always use the multi-threaded
+            -- runtime!
+            | isPermissionError e && not multiThreadedRuntime && isWindows ->
+              pure ()
+            | otherwise -> throwIO e
+          Right () -> pure ()
+
 foreign import ccall unsafe "rtsSupportsBoundThreads"
   multiThreadedRuntime :: Bool
 
@@ -314,9 +317,9 @@
 -- @since 0.2.5.0
 withProcessTerm :: (MonadUnliftIO m)
   => ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> (Process stdin stdout stderr -> m a)
-  -- ^
+  -- ^ 
   -> m a
 withProcessTerm config = bracket (startProcess config) stopProcess
 
@@ -331,9 +334,9 @@
 -- @since 0.2.5.0
 withProcessWait :: (MonadUnliftIO m)
   => ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> (Process stdin stdout stderr -> m a)
-  -- ^
+  -- ^ 
   -> m a
 withProcessWait config f =
   bracket
@@ -349,7 +352,7 @@
   -> (Process stdin stdout stderr -> m a)
   -> m a
 withProcess = withProcessTerm
-{-# DEPRECATED withProcess "Please consider using withProcessWait, or instead use withProcessTerm" #-}
+{-# DEPRECATED withProcess "Please consider using `withProcessWait`, or instead use `withProcessTerm`" #-}
 
 -- | Same as 'withProcessTerm', but also calls 'checkExitCode'
 --
@@ -359,9 +362,9 @@
 -- @since 0.2.5.0
 withProcessTerm_ :: (MonadUnliftIO m)
   => ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> (Process stdin stdout stderr -> m a)
-  -- ^
+  -- ^ 
   -> m a
 withProcessTerm_ config = bracket
     (startProcess config)
@@ -372,9 +375,9 @@
 -- @since 0.2.5.0
 withProcessWait_ :: (MonadUnliftIO m)
   => ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> (Process stdin stdout stderr -> m a)
-  -- ^
+  -- ^ 
   -> m a
 withProcessWait_ config f = bracket
     (startProcess config)
@@ -389,7 +392,7 @@
   -> (Process stdin stdout stderr -> m a)
   -> m a
 withProcess_ = withProcessTerm_
-{-# DEPRECATED withProcess_ "Please consider using withProcessWait_, or instead use withProcessTerm_" #-}
+{-# DEPRECATED withProcess_ "Please consider using `withProcessWait_`, or instead use `withProcessTerm_`" #-}
 
 -- | Run a process, capture its standard output and error as a
 -- 'L.ByteString', wait for it to complete, and then return its exit
@@ -401,7 +404,7 @@
 -- @since 0.1.0.0
 readProcess :: MonadIO m
             => ProcessConfig stdin stdoutIgnored stderrIgnored
-            -- ^
+            -- ^ 
             -> m (ExitCode, L.ByteString, L.ByteString)
 readProcess pc =
     liftIO $ withProcess pc' $ \p -> atomically $ (,,)
@@ -420,7 +423,7 @@
 -- @since 0.1.0.0
 readProcess_ :: MonadIO m
              => ProcessConfig stdin stdoutIgnored stderrIgnored
-             -- ^
+             -- ^ 
              -> m (L.ByteString, L.ByteString)
 readProcess_ pc =
     liftIO $ withProcess pc' $ \p -> atomically $ do
@@ -441,7 +444,7 @@
 readProcessStdout
   :: MonadIO m
   => ProcessConfig stdin stdoutIgnored stderr
-  -- ^
+  -- ^ 
   -> m (ExitCode, L.ByteString)
 readProcessStdout pc =
     liftIO $ withProcess pc' $ \p -> atomically $ (,)
@@ -459,7 +462,7 @@
 readProcessStdout_
   :: MonadIO m
   => ProcessConfig stdin stdoutIgnored stderr
-  -- ^
+  -- ^ 
   -> m L.ByteString
 readProcessStdout_ pc =
     liftIO $ withProcess pc' $ \p -> atomically $ do
@@ -478,7 +481,7 @@
 readProcessStderr
   :: MonadIO m
   => ProcessConfig stdin stdout stderrIgnored
-  -- ^
+  -- ^ 
   -> m (ExitCode, L.ByteString)
 readProcessStderr pc =
     liftIO $ withProcess pc' $ \p -> atomically $ (,)
@@ -496,7 +499,7 @@
 readProcessStderr_
   :: MonadIO m
   => ProcessConfig stdin stdout stderrIgnored
-  -- ^
+  -- ^ 
   -> m L.ByteString
 readProcessStderr_ pc =
     liftIO $ withProcess pc' $ \p -> atomically $ do
@@ -510,9 +513,9 @@
 
 withProcessInterleave :: (MonadUnliftIO m)
   => ProcessConfig stdin stdoutIgnored stderrIgnored
-  -- ^
+  -- ^ 
   -> (Process stdin (STM L.ByteString) () -> m a)
-  -- ^
+  -- ^ 
   -> m a
 withProcessInterleave pc inner =
     -- Create a pipe to be shared for both stdout and stderr
@@ -538,7 +541,7 @@
 readProcessInterleaved
   :: MonadIO m
   => ProcessConfig stdin stdoutIgnored stderrIgnored
-  -- ^
+  -- ^ 
   -> m (ExitCode, L.ByteString)
 readProcessInterleaved pc =
     liftIO $
@@ -556,9 +559,9 @@
 readProcessInterleaved_
   :: MonadIO m
   => ProcessConfig stdin stdoutIgnored stderrIgnored
-  -- ^
+  -- ^ 
   -> m L.ByteString
-  -- ^
+  -- ^ 
 readProcessInterleaved_ pc =
     liftIO $
     withProcessInterleave pc $ \p -> atomically $ do
@@ -574,9 +577,9 @@
 -- @since 0.1.0.0
 runProcess :: MonadIO m
            => ProcessConfig stdin stdout stderr
-           -- ^
+           -- ^ 
            -> m ExitCode
-           -- ^
+           -- ^ 
 runProcess pc = liftIO $ withProcess pc waitExitCode
 
 -- | Same as 'runProcess', but instead of returning the
@@ -585,7 +588,7 @@
 -- @since 0.1.0.0
 runProcess_ :: MonadIO m
             => ProcessConfig stdin stdout stderr
-            -- ^
+            -- ^ 
             -> m ()
 runProcess_ pc = liftIO $ withProcess pc checkExitCode
 
diff --git a/src/System/Process/Typed/Internal.hs b/src/System/Process/Typed/Internal.hs
--- a/src/System/Process/Typed/Internal.hs
+++ b/src/System/Process/Typed/Internal.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE DataKinds #-}
@@ -223,9 +224,9 @@
 --
 -- @since 0.1.0.0
 setStdin :: StreamSpec 'STInput stdin
-         -- ^
+         -- ^ 
          -> ProcessConfig stdin0 stdout stderr
-         -- ^
+         -- ^ 
          -> ProcessConfig stdin stdout stderr
 setStdin spec pc = pc { pcStdin = spec }
 
@@ -235,9 +236,9 @@
 --
 -- @since 0.1.0.0
 setStdout :: StreamSpec 'STOutput stdout
-          -- ^
+          -- ^ 
           -> ProcessConfig stdin stdout0 stderr
-          -- ^
+          -- ^ 
           -> ProcessConfig stdin stdout stderr
 setStdout spec pc = pc { pcStdout = spec }
 
@@ -247,9 +248,9 @@
 --
 -- @since 0.1.0.0
 setStderr :: StreamSpec 'STOutput stderr
-          -- ^
+          -- ^ 
           -> ProcessConfig stdin stdout stderr0
-          -- ^
+          -- ^ 
           -> ProcessConfig stdin stdout stderr
 setStderr spec pc = pc { pcStderr = spec }
 
@@ -259,9 +260,9 @@
 --
 -- @since 0.1.0.0
 setWorkingDir :: FilePath
-              -- ^
+              -- ^ 
               -> ProcessConfig stdin stdout stderr
-              -- ^
+              -- ^ 
               -> ProcessConfig stdin stdout stderr
 setWorkingDir dir pc = pc { pcWorkingDir = Just dir }
 
@@ -270,7 +271,7 @@
 -- @since 0.2.2.0
 setWorkingDirInherit
   :: ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> ProcessConfig stdin stdout stderr
 setWorkingDirInherit pc = pc { pcWorkingDir = Nothing }
 
@@ -280,9 +281,9 @@
 --
 -- @since 0.1.0.0
 setEnv :: [(String, String)]
-       -- ^
+       -- ^ 
        -> ProcessConfig stdin stdout stderr
-       -- ^
+       -- ^ 
        -> ProcessConfig stdin stdout stderr
 setEnv env pc = pc { pcEnv = Just env }
 
@@ -291,7 +292,7 @@
 -- @since 0.2.2.0
 setEnvInherit
   :: ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> ProcessConfig stdin stdout stderr
 setEnvInherit pc = pc { pcEnv = Nothing }
 
@@ -303,9 +304,9 @@
 -- @since 0.1.0.0
 setCloseFds
     :: Bool
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setCloseFds x pc = pc { pcCloseFds = x }
 
@@ -316,9 +317,9 @@
 -- @since 0.1.0.0
 setCreateGroup
     :: Bool
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setCreateGroup x pc = pc { pcCreateGroup = x }
 
@@ -330,9 +331,9 @@
 -- @since 0.1.0.0
 setDelegateCtlc
     :: Bool
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setDelegateCtlc x pc = pc { pcDelegateCtlc = x }
 
@@ -345,9 +346,9 @@
 -- @since 0.1.0.0
 setDetachConsole
     :: Bool
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setDetachConsole x pc = pc { pcDetachConsole = x }
 
@@ -358,9 +359,9 @@
 -- @since 0.1.0.0
 setCreateNewConsole
     :: Bool
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setCreateNewConsole x pc = pc { pcCreateNewConsole = x }
 
@@ -372,9 +373,9 @@
 -- @since 0.1.0.0
 setNewSession
     :: Bool
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setNewSession x pc = pc { pcNewSession = x }
 #endif
@@ -388,9 +389,9 @@
 -- @since 0.1.0.0
 setChildGroup
     :: GroupID
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setChildGroup x pc = pc { pcChildGroup = Just x }
 
@@ -399,7 +400,7 @@
 -- @since 0.2.2.0
 setChildGroupInherit
   :: ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> ProcessConfig stdin stdout stderr
 setChildGroupInherit pc = pc { pcChildGroup = Nothing }
 
@@ -411,9 +412,9 @@
 -- @since 0.1.0.0
 setChildUser
     :: UserID
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
-    -- ^
+    -- ^ 
     -> ProcessConfig stdin stdout stderr
 setChildUser x pc = pc { pcChildUser = Just x }
 
@@ -422,7 +423,7 @@
 -- @since 0.2.2.0
 setChildUserInherit
   :: ProcessConfig stdin stdout stderr
-  -- ^
+  -- ^ 
   -> ProcessConfig stdin stdout stderr
 setChildUserInherit pc = pc { pcChildUser = Nothing }
 #endif
@@ -443,9 +444,9 @@
 --
 -- @since 0.1.0.0
 mkStreamSpec :: P.StdStream
-             -- ^
+             -- ^ 
              -> (ProcessConfig () () () -> Maybe Handle -> IO (a, IO ()))
-             -- ^
+             -- ^ 
              -> StreamSpec streamType a
 mkStreamSpec ss f = mkManagedStreamSpec ($ ss) f
 
@@ -460,9 +461,9 @@
 --
 -- @since 0.2.10.0
 mkPipeStreamSpec :: (ProcessConfig () () () -> Handle -> IO (a, IO ()))
-                 -- ^
+                 -- ^ 
                  -> StreamSpec streamType a
-                 -- ^
+                 -- ^ 
 mkPipeStreamSpec f = mkStreamSpec P.CreatePipe $ \pc mh ->
     case mh of
         Just h -> f pc h
@@ -472,9 +473,9 @@
 -- 'P.StdStream' and a helper function.  This function is the same as
 -- the helper in 'mkStreamSpec'
 mkManagedStreamSpec :: (forall b. (P.StdStream -> IO b) -> IO b)
-                    -- ^
+                    -- ^ 
                     -> (ProcessConfig () () () -> Maybe Handle -> IO (a, IO ()))
-                    -- ^
+                    -- ^ 
                     -> StreamSpec streamType a
 mkManagedStreamSpec ss f = StreamSpec ss (\pc mh -> Cleanup (f pc mh))
 
diff --git a/typed-process.cabal b/typed-process.cabal
--- a/typed-process.cabal
+++ b/typed-process.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           typed-process
-version:        0.2.11.0
+version:        0.2.11.1
 synopsis:       Run external processes, with strong typing of streams
 description:    Please see the tutorial at <https://github.com/fpco/typed-process#readme>
 category:       System
@@ -53,12 +53,14 @@
   hs-source-dirs:
       test
   ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-tool-depends:
+      hspec-discover:hspec-discover
   build-depends:
       async >=2.0
     , base >=4.12 && <5
     , base64-bytestring
     , bytestring
-    , hspec
+    , hspec ==2.*
     , process >=1.2
     , stm
     , temporary
@@ -75,12 +77,14 @@
       Paths_typed_process
   hs-source-dirs:
       test
+  build-tool-depends:
+      hspec-discover:hspec-discover
   build-depends:
       async >=2.0
     , base >=4.12 && <5
     , base64-bytestring
     , bytestring
-    , hspec
+    , hspec ==2.*
     , process >=1.2
     , stm
     , temporary
