diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2016, Tom Murphy
+
+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.
+
+    * Neither the name of Tom Murphy nor the names of other
+      contributors may 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.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Test/Microspec.hs b/Test/Microspec.hs
new file mode 100644
--- /dev/null
+++ b/Test/Microspec.hs
@@ -0,0 +1,272 @@
+-- | Tests can be structured as nested 'it' / 'describe' statements
+-- 
+--   E.g.
+-- 
+--   > microspec $ do
+--   >    describe "plus" $ do
+--   >       it "adds positive numbers" $ do
+--   >          it "does 1 + 1" $
+--   >             1 + 1 == 2
+--   >          it "does 2 + 2" $
+--   >             2 + 2 == 4
+--   >       it "is commutative" $
+--   >          \x y -> x + y == y + (x :: Int)
+-- 
+--   ...which will return, nicely in green instead of bold:
+-- 
+--   @
+--   plus
+--     adds positive numbers
+--       __does 1 + 1__
+--       __does 2 + 2__
+--     __is commutative__
+--   @
+
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE LambdaCase #-}
+
+module Test.Microspec (
+     -- * Specification
+     microspec
+   , microspecWith
+   , describe
+   , it
+   , pending
+   , prop
+   , Microspec
+   , MTestable
+
+     -- * Configuration
+   , MArgs(..)
+   , defaultMArgs
+
+     -- * Compatibility
+   , shouldBe
+
+     -- Reexports
+   , module Test.QuickCheck
+   , module Test.QuickCheck.Modifiers
+   , module Test.QuickCheck.Monadic
+   -- , module Test.QuickCheck.Property
+   ) where
+
+import Control.Monad
+-- import Data.Time (getCurrentTime, diffUTCTime)
+import Test.QuickCheck as QC
+import Test.QuickCheck
+import Test.QuickCheck.Modifiers
+import Test.QuickCheck.Monadic
+-- import Test.QuickCheck.Property
+
+---------- User-facing:
+
+-- | Run your spec. Put this at the top level, e.g.:
+-- 
+--   > main = microspec $ do
+--   >    describe "plus 1" $
+--   >       3 + 1 == 4
+microspec :: Microspec () -> IO ()
+microspec = microspecWith defaultMArgs
+
+-- | 'microspec' with 'MArgs'
+microspecWith :: MArgs -> Microspec () -> IO ()
+microspecWith args spec = do
+   putStrLn ""
+   forM_ (buildTestTrees spec) $ \test -> do
+      (runTestWith args {- 1 -} 0) test
+      putStrLn ""
+
+runTestWith :: MArgs -> Int -> TestTree -> IO ()
+runTestWith args depth = \case
+   TestLeaf testLabel (Right aProp) -> do
+      let timeoutMaybe = case _mArgs_timeoutSecs args of
+           Nothing -> id
+           Just numSecs -> within $ fromEnum $ numSecs * (10^(6::Int))
+      result <- quickCheckWithResult (_mArgs_qcArgs args) $ timeoutMaybe aProp
+      putStrLn $ showResult testLabel result
+   TestLeaf testLabel (Left Pending) ->
+      putStrLn $ indentationFor depth ++ inYellow (testLabel ++ " - PENDING")
+   TestBranch testLabel forest -> do
+      putStrLn $ indentationFor depth ++ testLabel
+      forM_ forest $ runTestWith args (depth + 1)
+ where
+   indentationFor :: Int -> String
+   indentationFor n = replicate (n*2) ' ' -- ++ "- "
+
+   showResult :: String -> QC.Result -> String
+   showResult testLabel = \case
+       -- note: if we wanted to show quickcheck labels, this is where we would:
+      Success _ _ _ ->
+         indentationFor depth ++ inGreen testLabel
+      failure@(Failure{theException=Nothing}) ->
+         indentationFor depth
+           ++ inRed (testLabel ++ " - "++replaceNewline (output failure))
+{-
+           ++ "\n"
+           ++ indentationFor (depth + 1) ++ inRed (show $ usedSeed failure)
+-}
+      failure {- @(Failure{}) -} ->
+         indentationFor depth
+           ++ inRed (testLabel ++" - "++replaceNewline (output failure))
+   replaceNewline = concatMap $ \case '\n' -> " | " ; x -> [x]
+
+
+-- If you like the word 'pending', this is the place for you!:
+data Pending = Pending
+-- | Describe a test as unwritten, e.g.:
+-- 
+--   > describe "meaning of life" $ pending
+pending :: Pending
+pending = Pending
+
+
+---------- Handy
+
+-- | An alias for 'describe'. Usually used inside a 'describe' block:
+-- 
+--   >  describe "replicate" $ do
+--   >     it "doubles with 2" $
+--   >        replicate 2 'x' === "xx"
+--   >     it "creates a list of the right size" $
+--   >        \(Positive n) -> length (replicate n 'x') == n
+it :: MTestable t => String -> t -> Microspec ()
+it = describe
+
+-- | Make a test case from a QuickCheck function. Alias for 'Test.QuickCheck.property'.
+-- 
+--   Note that you don't need to use this to create a test, e.g.:
+-- 
+--   > describe "reverse preserves length" $
+--   >    \l -> length (reverse l) == length l
+prop :: Testable prop => prop -> Property
+prop = property
+
+
+
+---------- Constructing a test tree:
+
+addTestTree :: TestTree -> Microspec ()
+addTestTree tree = Microspec [tree] ()
+
+-- | Something which can be tested
+-- 
+--   Note both Bools and Properties can be tested, but only Properties show
+--   the values that weren't equal
+-- 
+--   For both unit tests and property tests, if you want to see the outputs
+--   of failed tests use 'Test.QuickCheck.==='. If you just want to test for
+--   equality, use 'Prelude.=='.
+-- 
+--   For example, the outputs of running:
+-- 
+--   @
+--   microspec $ do
+--      describe "baddies" $ do
+--         it "isn't 1 =="  $ 0 == (1 :: Int)
+--         it "isn't 1 ===" $ 0 === (1 :: Int)
+--         it "isn't always 1 =="  $ \x -> x == (1 :: Int)
+--         it "isn't always 1 ===" $ \x -> x === (1 :: Int)
+--   @
+-- 
+--   are:
+-- 
+--   @
+--   isn't 1 == - *** Failed! Falsifiable (after 1 test)
+--   isn't 1 === - *** Failed! Falsifiable (after 1 test):  | 0 /= 1
+--   isn't always 1 == - *** Failed! Falsifiable (after 1 test):  | 0
+--   isn't always 1 === - *** Failed! Falsifiable (after 1 test):  | 0 | 0 /= 1
+--   @
+
+
+class MTestable t where
+   -- | Describe a test, e.g.:
+   -- 
+   --   > describe "reverse 'foo' is 'oof'" $
+   --   >    reverse "foo" === "oof"
+   describe :: String -> t -> Microspec ()
+instance MTestable Property where
+   describe testLabel aProp = addTestTree $ TestLeaf testLabel (Right aProp)
+instance MTestable Bool where
+   describe testLabel bool = describe testLabel $ property bool
+instance MTestable TestTree where
+   describe testLabel x = addTestTree $ TestBranch testLabel [x]
+instance MTestable Pending where
+   describe testLabel pend = addTestTree $ TestLeaf testLabel (Left pend)
+instance MTestable (Microspec ()) where
+   describe testLabel x =
+      let forest = buildTestTrees x
+      in addTestTree $ TestBranch testLabel forest
+instance (Arbitrary a, Show a, Testable prop) => MTestable (a -> prop) where
+   describe testLabel f = describe testLabel $ property f
+
+data TestTree
+   = TestBranch String [TestTree]
+   | TestLeaf String (Either Pending Property)
+
+instance Show TestTree where
+ show = \case
+   TestBranch testLabel subs -> "Branch "++show testLabel++" "++show subs
+   TestLeaf testLabel _ -> "Leaf " ++ show testLabel
+
+-- Basically a writer monad:
+
+-- | A series of tests, to run with 'microspec'
+data Microspec a = Microspec [TestTree] a
+
+instance Functor Microspec where
+   fmap f (Microspec forest a) = Microspec forest (f a)
+instance Applicative Microspec where
+   pure a = Microspec [] a
+   f <*> a =
+      let Microspec forest0 f' = f
+          Microspec forest1 a' = a
+      in Microspec (forest0 ++ forest1) (f' a')
+instance Monad Microspec where
+   return = pure
+   ma >>= f =
+      let Microspec forest0 a = ma
+          Microspec forest1 b = f a
+      in Microspec (forest0 ++ forest1) b
+
+buildTestTrees :: Microspec () -> [TestTree]
+buildTestTrees (Microspec x _) = x
+
+
+
+
+---------- Configuration:
+
+-- | Default arguments. Calling \"microspec\" is the same as calling
+--   \"microspecWith defaultMArgs\".
+defaultMArgs :: MArgs
+defaultMArgs = MArgs {
+    _mArgs_timeoutSecs = Nothing -- Just 60
+   ,_mArgs_qcArgs = QC.stdArgs { chatty = False }
+   }
+
+-- | Tweak how tests are run, with 'microspecWith'.
+data MArgs = MArgs {
+    _mArgs_timeoutSecs :: Maybe Double -- ^ Number of seconds before each
+                                        --   test times out. If you want to
+                                        --   do this on a per-test basis, try
+                                        --   'Test.QuickCheck.Property.within'
+   ,_mArgs_qcArgs :: QC.Args -- ^ Arguments to use with QuickCheck tests
+   }
+ deriving (Show, Read) -- , Eq, Ord)
+
+
+
+---------- Pretty-printing:
+
+inRed, inGreen, inYellow :: String -> String
+[inRed,inGreen, inYellow] = (`map` [31,32,33]) $ \colorNum ->
+   \s -> "\ESC["++show (colorNum::Int)++"m"++s++"\ESC[m"
+
+
+
+---------- HSpec compatibility
+
+-- | Hspec compatibility. Equivalent to using 'Test.QuickCheck.==='
+shouldBe :: (Eq x, Show x) => x -> x -> Property
+shouldBe = (===)
+
diff --git a/microspec.cabal b/microspec.cabal
new file mode 100644
--- /dev/null
+++ b/microspec.cabal
@@ -0,0 +1,56 @@
+name:                microspec
+version:             0.1.0.0
+synopsis:            Tiny QuickCheck test library with minimal dependencies
+description:         
+  A tiny (1 module, <500 lines) property-based (and unit) testing library with minimal dependencies.
+  .
+  Don't add a bunch of transitive dependencies just to test your code!
+  .
+  Instead of reinventing the wheel (<https://xkcd.com/927>), we use a
+  RSpec/HSpec-like API and run tests with QuickCheck.
+  .
+  > import Test.Microspec
+  > 
+  > main :: IO ()
+  > main = microspec $ do
+  >    describe "replicate" $ do
+  >       it "doubles with 2" $
+  >          replicate 2 'x' == "xx"
+  >       it "creates a list of the right size" $
+  >          \(Positive n) -> length (replicate n 'x') == n
+  > 
+  >    describe "reverse" $ do
+  >       it "reverse . reverse == id" $ \l ->
+  >          reverse (reverse l) == (l :: [Int])
+  > 
+  >    describe "tail" $
+  >       it "length is -1" $ \(NonEmpty l) ->
+  >          length (tail l :: [Int]) == length l - 1
+  > 
+  >    describe "solve the halting problem" $
+  >       pending
+license:             BSD3
+license-file:        LICENSE
+author:              Tom Murphy
+maintainer:          Tom Murphy
+-- copyright:           
+category:            Test, Testing
+build-type:          Simple
+cabal-version:       >=1.10
+stability:           experimental
+
+library
+  exposed-modules:
+    Test.Microspec
+  -- other-modules:       
+  other-extensions:
+      FlexibleInstances
+    , LambdaCase
+  build-depends:
+      -- PVP compat:
+    --   base >=4.9 && <5
+    -- , QuickCheck >=2.9 && <2.10
+      base <5
+    , QuickCheck
+  -- hs-source-dirs:      
+  default-language:    Haskell2010
