diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,11 +1,13 @@
 Changelog for Shake (* = breaking change)
 
-0.9.8, released 2024, 2024-01-14
+0.19.9, released 2026-01-19
+    Test with GHC 9.12, improving some errors
+0.19.8, released 2024-01-14
     Test with GHC 9.8
     #844, optimise database reading/writing with use unsafeUseAsCString
     #836, add threaded flag to disable using threaded runtime
     #837, require filepath-1.14
-0.9.7, released 2022-09-15
+0.19.7, released 2022-09-15
     #815, improve corrupt database handling code
     Don't say (changed) for files that don't build
 0.19.6, released 2021-09-07
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright Neil Mitchell 2011-2024.
+Copyright Neil Mitchell 2011-2026.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/shake.cabal b/shake.cabal
--- a/shake.cabal
+++ b/shake.cabal
@@ -1,13 +1,13 @@
 cabal-version:      1.18
 build-type:         Simple
 name:               shake
-version:            0.19.8
+version:            0.19.9
 license:            BSD3
 license-file:       LICENSE
 category:           Development, Shake
 author:             Neil Mitchell <ndmitchell@gmail.com>
 maintainer:         Neil Mitchell <ndmitchell@gmail.com>
-copyright:          Neil Mitchell 2011-2024
+copyright:          Neil Mitchell 2011-2026
 synopsis:           Build system library, like Make, but more accurate dependencies.
 description:
     Shake is a Haskell library for writing build systems - designed as a
@@ -30,7 +30,7 @@
     (e.g. compiler version).
 homepage:           https://shakebuild.com
 bug-reports:        https://github.com/ndmitchell/shake/issues
-tested-with:        GHC==9.8, GHC==9.6, GHC==9.4, GHC==9.2, GHC==9.0, GHC==8.10, GHC==8.8
+tested-with:        GHC==9.12, GHC==9.10, GHC==9.8, GHC==9.6, GHC==9.4, GHC==9.2, GHC==9.0, GHC==8.10, GHC==8.8
 extra-doc-files:
     CHANGES.txt
     README.md
@@ -90,7 +90,7 @@
     default-language: Haskell2010
     hs-source-dirs:   src
     build-depends:
-        base >= 4.9,
+        base >= 4.9 && < 5,
         binary,
         bytestring,
         deepseq >= 1.1,
diff --git a/src/Development/Shake/Internal/Core/Types.hs b/src/Development/Shake/Internal/Core/Types.hs
--- a/src/Development/Shake/Internal/Core/Types.hs
+++ b/src/Development/Shake/Internal/Core/Types.hs
@@ -60,8 +60,14 @@
 --   To raise an exception call 'error', 'fail' or @'liftIO' . 'throwIO'@.
 --
 --   The 'Action' type is both a 'Monad' and 'Applicative'. Anything that is depended upon applicatively
---   will have its dependencies run in parallel. For example @'need' [\"a\"] *> 'need [\"b\"]@ is equivalent
---   to @'need' [\"a\", \"b\"]@.
+--   will have its dependencies run in parallel. For example,
+--   @'Development.Shake.Internal.Rules.File.need' [\"a\"] '*>' 'Development.Shake.Internal.Rules.File.need' [\"b\"]@
+--   is equivalent to @'need' [\"a\", \"b\"]@.
+--
+--   Note that since Shake 0.18, the non-capturing monadic bind ('>>') will also run its dependencies in parallel.
+--   For example,
+--   @'Development.Shake.Internal.Rules.File.need' [\"a\"] '>>' 'Development.Shake.Internal.Rules.File.need' [\"b\"]@
+--   is also equivalent to @'Development.Shake.Internal.Rules.File.need' [\"a\", \"b\"]@.
 newtype Action a = Action {fromAction :: RAW ([String],[Key]) [Value] Global Local a}
     deriving (Functor, Applicative, Monad, MonadIO, Typeable, Semigroup, Monoid, MonadFail)
 
diff --git a/src/Development/Shake/Internal/Rules/File.hs b/src/Development/Shake/Internal/Rules/File.hs
--- a/src/Development/Shake/Internal/Rules/File.hs
+++ b/src/Development/Shake/Internal/Rules/File.hs
@@ -206,7 +206,7 @@
     Nothing -> Nothing
 
 ruleRun :: ShakeOptions -> (FilePath -> Rebuild) -> BuiltinRun FileQ FileR
-ruleRun opts@ShakeOptions{..} rebuildFlags o@(FileQ (fileNameToString -> xStr)) oldBin@(fmap getEx -> old :: Maybe Answer) mode = do
+ruleRun opts@ShakeOptions{..} rebuildFlags o@(FileQ (fileNameToString -> xStr)) oldBin@(fmap getEx -> (old :: Maybe Answer)) mode = do
     -- for One, rebuild makes perfect sense
     -- for Forward, we expect the child will have already rebuilt - Rebuild just lets us deal with code changes
     -- for Phony, it doesn't make that much sense, but probably isn't harmful?
@@ -371,8 +371,13 @@
 --     'Development.Shake.cmd' \"rot13\" [src] \"-o\" [out]
 -- @
 --
---   Usually @need [foo,bar]@ is preferable to @need [foo] >> need [bar]@ as the former allows greater
---   parallelism, while the latter requires @foo@ to finish building before starting to build @bar@.
+--   Note that the following expressions are all equivalent. @foo@ and @bar@ are built in parallel:
+--
+--   - @need [foo,bar]@
+--   - @need [foo] '*>' need [bar]@
+--   - @need [foo] '>>' need [bar]@
+--
+--   In this situation, @need [foo, bar]@ is preferable, since the parallelism is the most obvious.
 --
 --   This function should not be called with wildcards (e.g. @*.txt@ - use 'getDirectoryFiles' to expand them),
 --   environment variables (e.g. @$HOME@ - use 'getEnv' to expand them) or directories (directories cannot be
diff --git a/src/Development/Shake/Internal/Rules/Files.hs b/src/Development/Shake/Internal/Rules/Files.hs
--- a/src/Development/Shake/Internal/Rules/Files.hs
+++ b/src/Development/Shake/Internal/Rules/Files.hs
@@ -90,7 +90,7 @@
 
 
 ruleRun :: ShakeOptions -> (FilePath -> Rebuild) -> BuiltinRun FilesQ FilesA
-ruleRun opts rebuildFlags k o@(fmap getEx -> old :: Maybe Result) mode = do
+ruleRun opts rebuildFlags k o@(fmap getEx -> (old :: Maybe Result)) mode = do
     let r = map (rebuildFlags . fileNameToString . fromFileQ) $ fromFilesQ k
 
     (ruleVer, ruleAct, ruleErr) <- getUserRuleInternal k (\(FilesRule s _) -> Just s) $ \(FilesRule _ f) -> f k
diff --git a/src/Development/Shake/Util.hs b/src/Development/Shake/Util.hs
--- a/src/Development/Shake/Util.hs
+++ b/src/Development/Shake/Util.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -Wno-unused-imports #-} -- Required since foldl' moves to the prelude
 
 -- | A module for useful utility functions for Shake build systems.
 module Development.Shake.Util(
@@ -10,7 +11,7 @@
 import qualified Data.ByteString.Char8 as BS
 import qualified General.Makefile as BS
 import Data.Tuple.Extra
-import Data.List
+import Data.List (foldl')
 import General.GetOpt
 import Data.IORef
 import Data.Maybe
diff --git a/src/General/Extra.hs b/src/General/Extra.hs
--- a/src/General/Extra.hs
+++ b/src/General/Extra.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ScopedTypeVariables, ConstraintKinds, GeneralizedNewtypeDeriving, ViewPatterns #-}
+{-# LANGUAGE CPP, ScopedTypeVariables, ConstraintKinds, GeneralizedNewtypeDeriving #-}
 {-# OPTIONS_GHC -Wno-x-partial -Wno-unrecognised-warning-flags #-}
 
 module General.Extra(
@@ -287,7 +287,9 @@
 
 callStackFull = parseCallStack $ prettyCallStack $ popCallStack callStack
 
-callStackFromException (fromException -> Just (ErrorCallWithLocation msg loc)) = (parseCallStack loc, toException $ ErrorCall msg)
+#if __GLASGOW_HASKELL__ < 912
+callStackFromException e | Just (ErrorCallWithLocation msg loc) <- fromException e = (parseCallStack loc, toException $ ErrorCall msg)
+#endif
 callStackFromException e = ([], e)
 
 
diff --git a/src/General/Intern.hs b/src/General/Intern.hs
--- a/src/General/Intern.hs
+++ b/src/General/Intern.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# OPTIONS_GHC -Wno-unused-imports #-} -- Required since foldl' moves to the prelude
 
 module General.Intern(
     Intern, Id(..),
@@ -8,9 +9,9 @@
 import Development.Shake.Classes
 import Foreign.Storable
 import Data.Word
-import Prelude hiding (lookup)
 import qualified Data.HashMap.Strict as Map
 import Data.List(foldl')
+import Prelude hiding (lookup)
 
 
 -- Invariant: The first field is the highest value in the Map
