diff --git a/CHANGES.markdown b/CHANGES.markdown
--- a/CHANGES.markdown
+++ b/CHANGES.markdown
@@ -1,3 +1,7 @@
+Changes in 0.22.5
+  - Add (experimental) `cabal-doctest` executable.  This is guarded behind a
+    flag for now, use `cabal install doctest -f -cabal-doctest` to install it.
+
 Changes in 0.22.4
   - Use `-Wno-unused-packages` for GHC `8.10` / `9.0` / `9.2`
 
diff --git a/doctest.cabal b/doctest.cabal
--- a/doctest.cabal
+++ b/doctest.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           doctest
-version:        0.22.4
+version:        0.22.5
 synopsis:       Test interactive Haskell examples
 description:    `doctest` is a tool that checks [examples](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810775744)
                 and [properties](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810771856)
@@ -107,6 +107,11 @@
   type: git
   location: https://github.com/sol/doctest
 
+flag cabal-doctest
+  description: Install (experimental) cabal-doctest executable
+  manual: True
+  default: False
+
 library
   ghc-options: -Wall
   hs-source-dirs:
@@ -156,6 +161,31 @@
     ghc-options: -fwarn-unused-packages
   if impl(ghc >= 9.8)
     ghc-options: -fno-warn-x-partial
+
+executable cabal-doctest
+  main-is: driver/cabal-doctest.hs
+  other-modules:
+      Paths_doctest
+  default-extensions:
+      NamedFieldPuns
+      RecordWildCards
+      DeriveFunctor
+      NoImplicitPrelude
+  ghc-options: -Wall -threaded
+  build-depends:
+      base >=4.7 && <5
+    , filepath
+    , process
+    , temporary
+  default-language: Haskell2010
+  if impl(ghc >= 9.0)
+    ghc-options: -fwarn-unused-packages
+  if impl(ghc >= 9.8)
+    ghc-options: -fno-warn-x-partial
+  if flag(cabal-doctest)
+    buildable: True
+  else
+    buildable: False
 
 executable doctest
   main-is: driver/doctest.hs
diff --git a/driver/cabal-doctest.hs b/driver/cabal-doctest.hs
new file mode 100644
--- /dev/null
+++ b/driver/cabal-doctest.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE LambdaCase #-}
+module Main (main) where
+
+import           Prelude
+
+import           Data.Version
+import           System.Environment
+import           System.Exit
+import           System.FilePath
+import           System.IO.Temp (withSystemTempDirectory)
+import           System.Process
+
+import           Paths_doctest (version)
+
+main :: IO ()
+main = do
+  args <- getArgs
+  lookupEnv "CABAL" >>= \ case
+    Nothing -> run "cabal" args
+    Just cabal -> run cabal (drop 1 args)
+
+run :: String -> [String] -> IO ()
+run cabal args = withSystemTempDirectory "doctest" $ \ dir -> do
+  let
+    doctest = dir </> "doctest"
+    script = dir </> "init-ghci"
+  callProcess cabal ["install", "--ignore-project", "--installdir", dir, "--install-method=symlink", "doctest-" ++ showVersion version]
+  callProcess (dir </> "doctest") ["--version"]
+  callProcess cabal ("build" : "--only-dependencies" : args)
+  writeFile script ":seti -w -Wdefault"
+  spawnProcess cabal ("repl"
+    : "--build-depends=QuickCheck"
+    : "--build-depends=template-haskell"
+    : ("--repl-options=-ghci-script=" ++ script)
+    : "--with-compiler" : doctest
+    : args) >>= waitForProcess >>= exitWith
