diff --git a/README.md b/README.md
deleted file mode 100644
--- a/README.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# getopt-generics
-
-## Status
-
-This library is experimental.
-
-## Usage
-
-`getopt-generics` tries to make it very simple to create executables that parse
-command line options. All you have to do is to define a type and derive some
-instances:
-
-~~~ {.haskell}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveGeneric #-}
-
-module Readme where
-
-import Data.Typeable
-import GHC.Generics
-import System.Console.GetOpt.Generics
-import System.Environment
-
-data Options
-  = Options {
-    port :: Int,
-    daemonize :: Bool,
-    config :: Maybe FilePath
-  }
-  deriving (Show, GHC.Generics.Generic)
-
-instance System.Console.GetOpt.Generics.Generic Options
-instance HasDatatypeInfo Options
-~~~
-
-Then you can use `getArguments` to create a command-line argument parser:
-
-~~~ {.haskell}
-main :: IO ()
-main = do
-  options <- getArguments
-  print (options :: Options)
-~~~
-
-This program has
-
-- a non-optional `--port` flag with an integer argument,
-- a boolean flag `--daemonize`,
-- an optional flag `--config` expecting a file argument and
-- a generic `--help` option.
-
-Here's in example of the program above in bash:
-``` bash
-$ program --port 8080 --config some/path
-Options {port = 8080, daemonize = False, config = Just "some/path"}
-$ program  --port 8080 --daemonize
-Options {port = 8080, daemonize = True, config = Nothing}
-$ program --port foo
-not an integer: foo
-$ program
-missing option: --port=int
-$ program --help
-program
-    --port=integer
-    --daemonize
-    --config=string (optional)
-```
-
-## Constraints
-
-There are some constraints that the defined datatype has to fulfill:
-
-  * It has to have only one constructor,
-  * that constructor has to have field selectors (i.e. use record syntax) and
-  * all fields have to be of a type that has an instance for `Option`.
-
-(Types declared with `newtype` are allowed with the same constraints.)
-
-## Using Custom Field Types
-
-It is possible to use custom field types by providing an instance for `Option`.
-Here's an example:
-
-~~~ {.haskell}
-data File = File FilePath
-  deriving (Show, Typeable)
-
-instance Option File where
-  argumentType Proxy = "file"
-  parseArgument f = Just (File f)
-
-data FileOptions
-  = FileOptions {
-    file :: File
-  }
-  deriving (Show, GHC.Generics.Generic)
-
-instance System.Console.GetOpt.Generics.Generic FileOptions
-instance HasDatatypeInfo FileOptions
-
--- Returns: FileOptions {file = File "some/file"}
-getFileOptions :: IO FileOptions
-getFileOptions = withArgs (words "--file some/file") getArguments
-~~~
diff --git a/examples/Example.hs b/examples/Example.hs
deleted file mode 100644
--- a/examples/Example.hs
+++ /dev/null
@@ -1,28 +0,0 @@
-{-# LANGUAGE DeriveGeneric #-}
-
-module Example where
-
-import qualified GHC.Generics
-import           System.Console.GetOpt.Generics
-
--- we specify a data type that maps to the commandline arguments
-
-data Foo
-  = Foo {
-      bar :: String
-    , baz :: Maybe String
-    , qux :: Int
-    }
-    deriving (Eq, Show, GHC.Generics.Generic)
-
-instance Generic Foo
-instance HasDatatypeInfo Foo
-
--- give it go
-
-main :: IO ()
-main = do
-  myFoo <- getArguments
-  print $ bar myFoo
-  print $ baz myFoo
-  print $ qux myFoo
diff --git a/examples/Readme.lhs b/examples/Readme.lhs
deleted file mode 100644
--- a/examples/Readme.lhs
+++ /dev/null
@@ -1,104 +0,0 @@
-# getopt-generics
-
-## Status
-
-This library is experimental.
-
-## Usage
-
-`getopt-generics` tries to make it very simple to create executables that parse
-command line options. All you have to do is to define a type and derive some
-instances:
-
-~~~ {.haskell}
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE DeriveGeneric #-}
-
-module Readme where
-
-import Data.Typeable
-import GHC.Generics
-import System.Console.GetOpt.Generics
-import System.Environment
-
-data Options
-  = Options {
-    port :: Int,
-    daemonize :: Bool,
-    config :: Maybe FilePath
-  }
-  deriving (Show, GHC.Generics.Generic)
-
-instance System.Console.GetOpt.Generics.Generic Options
-instance HasDatatypeInfo Options
-~~~
-
-Then you can use `getArguments` to create a command-line argument parser:
-
-~~~ {.haskell}
-main :: IO ()
-main = do
-  options <- getArguments
-  print (options :: Options)
-~~~
-
-This program has
-
-- a non-optional `--port` flag with an integer argument,
-- a boolean flag `--daemonize`,
-- an optional flag `--config` expecting a file argument and
-- a generic `--help` option.
-
-Here's in example of the program above in bash:
-``` bash
-$ program --port 8080 --config some/path
-Options {port = 8080, daemonize = False, config = Just "some/path"}
-$ program  --port 8080 --daemonize
-Options {port = 8080, daemonize = True, config = Nothing}
-$ program --port foo
-not an integer: foo
-$ program
-missing option: --port=int
-$ program --help
-program
-    --port=integer
-    --daemonize
-    --config=string (optional)
-```
-
-## Constraints
-
-There are some constraints that the defined datatype has to fulfill:
-
-  * It has to have only one constructor,
-  * that constructor has to have field selectors (i.e. use record syntax) and
-  * all fields have to be of a type that has an instance for `Option`.
-
-(Types declared with `newtype` are allowed with the same constraints.)
-
-## Using Custom Field Types
-
-It is possible to use custom field types by providing an instance for `Option`.
-Here's an example:
-
-~~~ {.haskell}
-data File = File FilePath
-  deriving (Show, Typeable)
-
-instance Option File where
-  argumentType Proxy = "file"
-  parseArgument f = Just (File f)
-
-data FileOptions
-  = FileOptions {
-    file :: File
-  }
-  deriving (Show, GHC.Generics.Generic)
-
-instance System.Console.GetOpt.Generics.Generic FileOptions
-instance HasDatatypeInfo FileOptions
-
--- Returns: FileOptions {file = File "some/file"}
-getFileOptions :: IO FileOptions
-getFileOptions = withArgs (words "--file some/file") getArguments
-~~~
diff --git a/getopt-generics.cabal b/getopt-generics.cabal
--- a/getopt-generics.cabal
+++ b/getopt-generics.cabal
@@ -3,9 +3,9 @@
 -- see: https://github.com/sol/hpack
 
 name:           getopt-generics
-version:        0.9
-synopsis:       Simple command line argument parsing
-description:    "getopt-generics" tries to make it very simple to create command line argument parsers. An introductory example can be found in the <https://github.com/zalora/getopt-generics#getopt-generics README>.
+version:        0.10
+synopsis:       Create command line interfaces with ease
+description:    Create command line interfaces with ease
 category:       Console, System
 homepage:       https://github.com/zalora/getopt-generics#readme
 bug-reports:    https://github.com/zalora/getopt-generics/issues
@@ -17,9 +17,6 @@
 build-type:     Simple
 cabal-version:  >= 1.10
 
-extra-source-files:
-    README.md
-
 source-repository head
   type: git
   location: https://github.com/zalora/getopt-generics
@@ -44,14 +41,45 @@
       System.Console.GetOpt.Generics.Simple
   default-language: Haskell2010
 
+test-suite examples
+  type: exitcode-stdio-1.0
+  main-is: Examples.hs
+  hs-source-dirs:
+      test
+  ghc-options: -Wall -fno-warn-name-shadowing -threaded -O0
+  build-depends:
+      base == 4.*
+    , base-compat >= 0.8
+    , base-orphans
+    , generics-sop
+    , tagged
+    , hspec >= 2.1.8
+    , temporary
+    , directory
+    , filepath
+    , process
+    , silently
+  other-modules:
+      BashProtocol
+      ModifiersSpec
+      ModifiersSpec.RenameOptionsSpec
+      ModifiersSpec.UseForPositionalArgumentsSpec
+      Spec
+      System.Console.GetOpt.Generics.FieldStringSpec
+      System.Console.GetOpt.Generics.ModifierSpec
+      System.Console.GetOpt.Generics.ResultSpec
+      System.Console.GetOpt.Generics.SimpleSpec
+      System.Console.GetOpt.GenericsSpec
+      Util
+  default-language: Haskell2010
+
 test-suite spec
   type: exitcode-stdio-1.0
   main-is: Spec.hs
   hs-source-dirs:
       src
     , test
-    , examples
-  ghc-options: -Wall -fno-warn-name-shadowing -threaded -O0 -pgmL markdown-unlit
+  ghc-options: -Wall -fno-warn-name-shadowing -threaded -O0
   build-depends:
       base == 4.*
     , base-compat >= 0.8
@@ -59,8 +87,6 @@
     , generics-sop
     , tagged
     , hspec >= 2.1.8
-    , hspec-expectations
-    , markdown-unlit
     , QuickCheck
     , silently
   other-modules:
@@ -70,7 +96,8 @@
       System.Console.GetOpt.Generics.Modifier
       System.Console.GetOpt.Generics.Result
       System.Console.GetOpt.Generics.Simple
-      ExamplesSpec
+      BashProtocol
+      Examples
       ModifiersSpec
       ModifiersSpec.RenameOptionsSpec
       ModifiersSpec.UseForPositionalArgumentsSpec
@@ -80,6 +107,4 @@
       System.Console.GetOpt.Generics.SimpleSpec
       System.Console.GetOpt.GenericsSpec
       Util
-      Example
-      Readme
   default-language: Haskell2010
diff --git a/src/System/Console/GetOpt/Generics.hs b/src/System/Console/GetOpt/Generics.hs
--- a/src/System/Console/GetOpt/Generics.hs
+++ b/src/System/Console/GetOpt/Generics.hs
@@ -2,6 +2,8 @@
 module System.Console.GetOpt.Generics (
   -- * IO API
   simpleCLI,
+  SimpleCLI,
+  ArgumentTypes,
   getArguments,
   modifiedGetArguments,
   -- * Pure API
@@ -11,11 +13,7 @@
   Modifier(..),
   deriveShortOptions,
   -- * Available Field Types
-  -- fixme: hide methods?
-  Option(..),
-  -- * SimpleCLI class
-  SimpleCLI,
-  ArgumentTypes,
+  Option(argumentType, parseArgument),
   -- * Re-exports from "Generics.SOP"
   Generic,
   HasDatatypeInfo,
diff --git a/src/System/Console/GetOpt/Generics/GetArguments.hs b/src/System/Console/GetOpt/Generics/GetArguments.hs
--- a/src/System/Console/GetOpt/Generics/GetArguments.hs
+++ b/src/System/Console/GetOpt/Generics/GetArguments.hs
@@ -20,10 +20,8 @@
 {-# OPTIONS_GHC -fno-warn-unrecognised-pragmas #-}
 
 -- | @getopt-generics@ tries to make it very simple to create command line
--- argument parsers. An introductory example can be found in the
--- <https://github.com/zalora/getopt-generics#getopt-generics README>.
-
-module System.Console.GetOpt.Generics.GetArguments  where
+-- argument parsers.
+module System.Console.GetOpt.Generics.GetArguments where
 
 import           Data.Orphans ()
 import           Prelude ()
@@ -46,13 +44,62 @@
 -- | Parses command line arguments (gotten from 'withArgs') and returns the
 --   parsed value. This function should be enough for simple use-cases.
 --
---   May throw the following exceptions:
+--   Throws the same exceptions as 'simpleCLI'.
 --
---   - @'ExitFailure' 1@ in case of invalid options. Error messages are written
---     to @stderr@.
---   - @'ExitSuccess'@ in case @--help@ is given. (@'ExitSuccess'@ behaves like
---     a normal exception, except that -- if uncaught -- the process will exit
---     with exit-code @0@.) Help output is written to @stdout@.
+-- Here's an example:
+
+-- ### Start "docs/RecordTypeExample.hs" Haddock ###
+
+-- |
+-- >  {-# LANGUAGE DeriveGeneric #-}
+-- >
+-- >  import GHC.Generics
+-- >  import System.Console.GetOpt.Generics
+-- >
+-- >  -- All you have to do is to define a type and derive some instances:
+-- >
+-- >  data Options
+-- >    = Options {
+-- >      port :: Int,
+-- >      daemonize :: Bool,
+-- >      config :: Maybe FilePath
+-- >    }
+-- >    deriving (Show, GHC.Generics.Generic)
+-- >
+-- >  instance System.Console.GetOpt.Generics.Generic Options
+-- >  instance HasDatatypeInfo Options
+-- >
+-- >  -- Then you can use `getArguments` to create a command-line argument parser:
+-- >
+-- >  main :: IO ()
+-- >  main = do
+-- >    options <- getArguments
+-- >    print (options :: Options)
+
+-- ### End ###
+
+-- | And this is how the above program behaves:
+
+-- ### Start "docs/RecordTypeExample.bash-protocol" Haddock ###
+
+-- |
+-- >  $ program --port 8080 --config some/path
+-- >  Options {port = 8080, daemonize = False, config = Just "some/path"}
+-- >  $ program  --port 8080 --daemonize
+-- >  Options {port = 8080, daemonize = True, config = Nothing}
+-- >  $ program --port foo
+-- >  cannot parse as INTEGER: foo
+-- >  $ program
+-- >  missing option: --port=INTEGER
+-- >  $ program --help
+-- >  program [OPTIONS]
+-- >        --port=INTEGER
+-- >        --daemonize
+-- >        --config=STRING (optional)
+-- >    -h  --help                      show help and exit
+
+-- ### End ###
+
 getArguments :: forall a . (Generic a, HasDatatypeInfo a, All2 Option (Code a)) =>
   IO a
 getArguments = modifiedGetArguments []
@@ -65,7 +112,7 @@
   progName <- getProgName
   handleResult $ parseArguments progName modifiers args
 
--- | Pure variant of 'getArguments'.
+-- | Pure variant of 'modifiedGetArguments'.
 --
 --   Does not throw any exceptions.
 parseArguments :: forall a . (Generic a, HasDatatypeInfo a, All2 Option (Code a)) =>
@@ -316,9 +363,44 @@
 --
 --   If you want to use custom field types you should implement an
 --   @instance Option YourCustomType@ containing implementations of
---   'argumentType' and 'parseArgument' (the minimal complete definition). For
---   an example see the
---   <https://github.com/zalora/getopt-generics#getopt-generics README>.
+--   'argumentType' and 'parseArgument' (the minimal complete definition).
+--
+-- Here's an example:
+
+-- ### Start "docs/CustomOptionsExample.hs" Haddock ###
+
+-- |
+-- >  {-# LANGUAGE DeriveDataTypeable #-}
+-- >
+-- >  import           Data.Typeable
+-- >  import           System.Console.GetOpt.Generics
+-- >
+-- >  data File = File FilePath
+-- >    deriving (Show, Typeable)
+-- >
+-- >  instance Option File where
+-- >    argumentType Proxy = "custom-file-type"
+-- >    parseArgument f = Just (File f)
+-- >
+-- >  main :: IO ()
+-- >  main = simpleCLI $ \ file -> do
+-- >    print (file :: File)
+
+-- ### End ###
+
+-- | This would give you:
+
+-- ### Start "docs/CustomOptionsExample.bash-protocol" Haddock ###
+
+-- |
+-- >  $ program some/file
+-- >  File "some/file"
+-- >  $ program --help
+-- >  program [OPTIONS] custom-file-type
+-- >    -h  --help  show help and exit
+
+-- ### End ###
+
 class Typeable a => Option a where
   {-# MINIMAL argumentType, parseArgument #-}
   -- | Name of the argument type, e.g. "bool" or "integer".
diff --git a/src/System/Console/GetOpt/Generics/Simple.hs b/src/System/Console/GetOpt/Generics/Simple.hs
--- a/src/System/Console/GetOpt/Generics/Simple.hs
+++ b/src/System/Console/GetOpt/Generics/Simple.hs
@@ -26,28 +26,49 @@
   _initialFieldStates :: Proxy main -> NP FieldState (ArgumentTypes main)
   _run :: NP I (ArgumentTypes main) -> main -> IO ()
 
--- | 'simpleCLI' converts an IO operation into a program with a nice CLI. @main@ can have
---   arbitrarily many parameters provided all parameters have an instance for 'Option'.
---
---   Example:
---
---   Given a file @myProgram.hs@:
+-- | 'simpleCLI' converts an IO operation into a program with a proper CLI.
+--   Retrieves command line arguments through 'withArgs'.
+--   @main@ (the given IO operation) can have arbitrarily many parameters
+--   provided all parameters have an instance for 'Option'.
 --
---   > main :: IO ()
---   > main = simpleCLI myMain
---   >
---   > myMain :: String -> Int -> Bool -> IO ()
---   > myMain s i b = print (s, i, b)
+--   May throw the following exceptions:
 --
---   you get:
+--   - @'ExitFailure' 1@ in case of invalid options. Error messages are written
+--     to @stderr@.
+--   - @'ExitSuccess'@ in case @--help@ is given. (@'ExitSuccess'@ behaves like
+--     a normal exception, except that -- if uncaught -- the process will exit
+--     with exit-code @0@.) Help output is written to @stdout@.
 --
---   > $ runhaskell myProgram.hs foo 42 true
---   > ("foo",42,True)
---   > $ runhaskell myProgram.hs foo 42 bar
---   > cannot parse as BOOL: bar
---   > $ runhaskell myProgram.hs --help
---   > myProgram.hs [OPTIONS] STRING INTEGER BOOL
---   >   -h  --help  show help and exit
+--   Example:
+
+-- ### Start "docs/SimpleExample.hs" Haddock ###
+
+-- |
+-- >  import           System.Console.GetOpt.Generics
+-- >
+-- >  main :: IO ()
+-- >  main = simpleCLI myMain
+-- >
+-- >  myMain :: String -> Int -> Bool -> IO ()
+-- >  myMain s i b = print (s, i, b)
+
+-- ### End ###
+
+-- | Using the above program in bash:
+
+-- ### Start "docs/SimpleExample.bash-protocol" Haddock ###
+
+-- |
+-- >  $ program foo 42 true
+-- >  ("foo",42,True)
+-- >  $ program foo 42 bar
+-- >  cannot parse as BOOL: bar
+-- >  $ program --help
+-- >  program [OPTIONS] STRING INTEGER BOOL
+-- >    -h  --help  show help and exit
+
+-- ### End ###
+
 simpleCLI :: forall main . (SimpleCLI main, All Option (ArgumentTypes main)) =>
   main -> IO ()
 simpleCLI main = do
diff --git a/test/BashProtocol.hs b/test/BashProtocol.hs
new file mode 100644
--- /dev/null
+++ b/test/BashProtocol.hs
@@ -0,0 +1,44 @@
+
+module BashProtocol (testBashProtocol) where
+
+import           Control.Exception
+import           Control.Monad
+import           Data.List
+import           System.Environment.Compat
+import           System.FilePath
+import           System.IO
+import           System.IO.Silently
+import           System.Process
+import           Test.Hspec
+
+testBashProtocol :: FilePath -> String -> IO ()
+testBashProtocol program bashProtocol = do
+  assert (takeFileName program == "program") (return ())
+  let protocol = parseProtocol bashProtocol
+  testProtocol (takeDirectory program) protocol
+
+data Protocol
+  = Protocol {
+    _command :: String,
+    _expected :: [String]
+  }
+  deriving (Show)
+
+parseProtocol :: String -> [Protocol]
+parseProtocol = inner . lines
+  where
+    inner :: [String] -> [Protocol]
+    inner [] = []
+    inner (('$' : ' ' : command) : rest) =
+      let (expected, next) = span (not . ("$ " `isPrefixOf`)) rest in
+      Protocol command expected : inner next
+    inner lines = error ("parseProtocol: cannot parse: " ++ show lines)
+
+testProtocol :: FilePath -> [Protocol] -> IO ()
+testProtocol programDir protocol = do
+  path <- getEnv "PATH"
+  setEnv "PATH" (programDir ++ ":" ++ path)
+  forM_ protocol $ \ (Protocol command expected) -> do
+    hPutStrLn stderr ("running: " ++ command)
+    output <- hCapture_ [stdout, stderr] $ system command
+    output `shouldBe` unlines expected
diff --git a/test/Examples.hs b/test/Examples.hs
new file mode 100644
--- /dev/null
+++ b/test/Examples.hs
@@ -0,0 +1,57 @@
+
+import           Prelude ()
+import           Prelude.Compat
+
+import           Control.Monad
+import           Data.List
+import           System.Directory
+import           System.Exit.Compat
+import           System.FilePath
+import           System.IO.Temp
+import           System.Process
+import           Test.Hspec
+
+import           BashProtocol
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+  files <- runIO $
+    map ("docs" </>) <$>
+    filter ((".hs" ==) . takeExtension) <$>
+    sort <$>
+    getDirectoryContents "docs"
+
+  forM_ files $ \ file -> do
+    describe "docs directory ghc" $ do
+      it ("compile and run " ++ file) $ do
+        withSystemTempDirectory "getopt-generics-test" $ \ tempDir -> do
+          compile tempDir file >>= execute file
+
+compile :: FilePath -> FilePath -> IO FilePath
+compile tempDir file = do
+  let program = tempDir </> "program"
+  callCommandCompat $ "cabal exec -- ghc " ++ file ++
+    " -outputdir " ++ (tempDir </> "build") ++
+    " -o " ++ program ++
+    " -isrc -O0" ++
+    " -Wall -Werror -fno-warn-unused-binds -fno-warn-name-shadowing"
+  return program
+
+execute :: FilePath -> FilePath -> IO ()
+execute haskellFile program = do
+  let bashProtocolFile = dropExtension haskellFile <.> "bash-protocol"
+  exists <- doesFileExist bashProtocolFile
+  if not exists
+    then callCommandCompat $ program ++ " --help"
+    else do
+      testBashProtocol program =<< readFile bashProtocolFile
+
+callCommandCompat :: String -> IO ()
+callCommandCompat command = do
+  exitCode <- system command
+  case exitCode of
+    ExitSuccess -> return ()
+    failure@ExitFailure{} -> exitWith failure
diff --git a/test/ExamplesSpec.hs b/test/ExamplesSpec.hs
deleted file mode 100644
--- a/test/ExamplesSpec.hs
+++ /dev/null
@@ -1,10 +0,0 @@
-
-module ExamplesSpec where
-
-import           Test.Hspec
-
-import           Example ()
-import           Readme ()
-
-spec :: Spec
-spec = return ()
