diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2020, Henning Thielemann
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * The names of contributors may not be used to endorse or promote
+      products derived from this software without specific prior
+      written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#! /usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/doctest-exitcode-stdio.cabal b/doctest-exitcode-stdio.cabal
new file mode 100644
--- /dev/null
+++ b/doctest-exitcode-stdio.cabal
@@ -0,0 +1,40 @@
+Cabal-Version:  2.2
+Name:           doctest-exitcode-stdio
+Version:        0.0
+License:        BSD-3-Clause
+License-File:   LICENSE
+Author:         Henning Thielemann <haskell@henning-thielemann.de>
+Maintainer:     Henning Thielemann <haskell@henning-thielemann.de>
+Homepage:       https://hub.darcs.net/thielema/doctest-exitcode-stdio/
+Category:       Testing
+Synopsis:       Run doctest's in a Cabal.Test.exitcode-stdio environment
+Description:
+  Run doctest's in a Cabal.Test.exitcode-stdio environment.
+  For use with the @doctest-extract@ utility.
+  Normally, you should not need to import a module from this package,
+  only generated code will do this.
+Tested-With:    GHC==7.4.2, GHC==8.6.5
+Build-Type:     Simple
+
+Source-Repository this
+  Tag:         0.0
+  Type:        darcs
+  Location:    https://hub.darcs.net/thielema/doctest-exitcode-stdio/
+
+Source-Repository head
+  Type:        darcs
+  Location:    https://hub.darcs.net/thielema/doctest-exitcode-stdio/
+
+Library
+  Build-Depends:
+    doctest-lib >=0.1 && <0.2,
+    QuickCheck >=2.12.5 && <3,
+    transformers >=0.0 && <0.6,
+    semigroups >=0.18 && <0.20,
+    base >=4.3 && <5
+
+  GHC-Options:      -Wall
+  Hs-Source-Dirs:   src
+  Default-Language: Haskell98
+  Exposed-Modules:
+    Test.DocTest.Driver
diff --git a/src/Test/DocTest/Driver.hs b/src/Test/DocTest/Driver.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/DocTest/Driver.hs
@@ -0,0 +1,76 @@
+module Test.DocTest.Driver (
+   T,
+   printLine,
+   printPrefix,
+   Count(..),
+   run,
+   runWith,
+   example,
+   property,
+   ) where
+
+import qualified Test.DocTest.Base as DocTest
+import qualified Test.QuickCheck as QC
+
+import System.Exit (exitFailure)
+
+import Text.Printf (printf)
+
+import qualified Control.Monad.Trans.Writer.Strict as MW
+import qualified Control.Monad.Trans.Reader as MR
+import qualified Control.Monad.Trans.Class as MT
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad (when, void)
+
+import Data.Monoid (Monoid(mempty,mappend))
+import Data.Semigroup (Semigroup((<>)))
+
+
+type T = MR.ReaderT QC.Args (MW.WriterT Count IO)
+
+data Count = Count {numTotal, numFailures :: !Int}
+
+instance Semigroup Count where
+   Count t0 f0 <> Count t1 f1 = Count (t0+t1) (f0+f1)
+
+instance Monoid Count where
+   mempty = Count 0 0
+   mappend = (<>)
+
+
+printLine :: String -> T ()
+printLine = liftIO . putStrLn
+
+printPrefix :: String -> T ()
+printPrefix = liftIO . putStr
+
+
+run :: T () -> IO ()
+run = runWith QC.stdArgs
+
+runWith :: QC.Args -> T () -> IO ()
+runWith args act = do
+   count <- MW.execWriterT $ MR.runReaderT act args
+   putStrLn ""
+   void $ printf "Total: %d\n" $ numTotal count
+   void $ printf "Failures: %d\n" $ numFailures count
+   when (numFailures count > 0) exitFailure
+
+
+tell :: Count -> T ()
+tell = MT.lift . MW.tell
+
+example :: (Show a) => a -> DocTest.ExpectedResult -> T ()
+example actual expected = do
+   tell $ Count 1 0
+   case DocTest.checkResult expected (lines $ show actual) of
+      DocTest.Equal -> printLine "passed"
+      DocTest.NotEqual ls ->
+         printPrefix (unlines $ "*** Failed!":ls) >> tell (Count 0 1)
+
+property :: (QC.Testable prop) => prop -> T ()
+property prop = do
+   tell $ Count 1 0
+   args <- MR.ask
+   result <- liftIO $ QC.quickCheckWithResult args prop
+   when (not $ QC.isSuccess result) $ tell (Count 0 1)
