diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for optparse-enum
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Chris Dornan (c) 2019
+
+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 Chris Dornan 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+# optparse-enum
+
+An `enum-text` based toolkit for `optparse-applicative`.
+
+A simple but complete example:
+
+```haskell
+{-# LANGUAGE DeriveAnyClass    #-}
+{-# LANGUAGE DerivingVia       #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Fmt
+import Text.Enum.Optparse
+import Paths_optparse_enum
+
+data Choice
+  = C_version
+  | C_hello
+  deriving (Bounded,Enum,EnumText,Eq,Ord,Show)
+  deriving (Buildable,TextParsable) via UsingEnumText Choice
+
+parserDetails ::   ParserDetails
+parserDetails =
+  ParserDetails
+    { _pd_desc   = "optparse-enum example program"
+    , _pd_header = "A simple optparse-enum illustrative program"
+    , _pd_footer = "See the optparse-enum page on Hackage for details"
+    }
+
+main :: IO ()
+main = do
+  choice <- parseIO parserDetails enumSwitchesP
+  case choice of
+    C_version -> print    version
+    C_hello   -> putStrLn "Hello!"
+```
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/optparse-enum.cabal b/optparse-enum.cabal
new file mode 100644
--- /dev/null
+++ b/optparse-enum.cabal
@@ -0,0 +1,44 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.31.1.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 1edbb8960fca27e15a838fc0c6126dd9e32eae42fc52781c0dc6d41e293521a7
+
+name:           optparse-enum
+version:        1.0.0.0
+synopsis:       An enum-text based toolkit for optparse-applicative
+description:    Please see the README on GitHub at <https://github.com/cdornan/optparse-enum#readme>
+category:       System, CLI, Options, Parsing
+homepage:       https://github.com/cdornan/optparse-enum#readme
+bug-reports:    https://github.com/cdornan/optparse-enum/issues
+author:         Chris Dornan
+maintainer:     chris@chrisdornan.com
+copyright:      2019 Chris Dornan
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/cdornan/optparse-enum
+
+library
+  exposed-modules:
+      Text.Enum.Optparse
+  other-modules:
+      Paths_optparse_enum
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base >=4.8 && <10
+    , enum-text >=0.5.1.0
+    , fmt >=0.6
+    , optparse-applicative >=0.12
+    , text >=1.2.2.2
+  default-language: Haskell2010
diff --git a/src/Text/Enum/Optparse.hs b/src/Text/Enum/Optparse.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Enum/Optparse.hs
@@ -0,0 +1,192 @@
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE RecordWildCards            #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+
+module Text.Enum.Optparse
+  (
+  -- * A simple Whole Example
+  -- $example
+
+  -- * The Drivers
+    parseIO
+  , parseIOWithArgs
+  , pureParse
+  , testCLI
+  -- * mkParserInfo
+  , ParserDetails(..)
+  , mkParserInfo
+  -- * The Parser Generators
+  , MetaVar
+  , HelpText
+  , FlagName
+  , FlagChar
+  , enumArgP
+  , argP
+  , argP'
+  , enumOptP
+  , optP
+  , enumSwitchesP
+  , shortEnumSwitchesP
+  , module Text.Enum.Text
+  ) where
+
+
+import           Control.Applicative
+import           Data.Char
+import qualified Data.Text                      as T
+import           Fmt
+import           Options.Applicative
+import           System.Environment
+import           Text.Enum.Text
+
+{- $example
+
+A simple but complete example:
+
+@
+{\-\# LANGUAGE DeriveAnyClass    #-\}
+{\-\# LANGUAGE DerivingVia       #-\}
+{\-\# LANGUAGE OverloadedStrings #-\}
+
+import Fmt
+import Text.Enum.Optparse
+import Paths_optparse_enum
+
+data Choice
+  = C_version
+  | C_hello
+  deriving (Bounded,Enum,EnumText,Eq,Ord,Show)
+  deriving (Buildable,TextParsable) via UsingEnumText Choice
+
+parserDetails ::   ParserDetails
+parserDetails =
+  ParserDetails
+    { _pd_desc   = "optparse-enum example program"
+    , _pd_header = "A simple optparse-enum illustrative program"
+    , _pd_footer = "See the optparse-enum page on Hackage for details"
+    }
+
+main :: IO ()
+main = do
+  choice <- parseIO parserDetails enumSwitchesP
+  case choice of
+    C_version -> print    version
+    C_hello   -> putStrLn "Hello!"
+@
+-}
+
+--------------------------------------------------------------------------------
+-- the drivers
+--------------------------------------------------------------------------------
+
+-- | making an IO parser
+parseIO :: ParserDetails -> Parser a -> IO a
+parseIO pd psr = getArgs >>= parseIOWithArgs pd psr
+
+-- | making an IO parser, specifying the arguments
+parseIOWithArgs :: ParserDetails -> Parser a -> [String] -> IO a
+parseIOWithArgs pd psr as = handleParseResult $
+    execParserPure (prefs idm) (mkParserInfo pd psr) as
+
+-- | making a functional parser
+pureParse :: ParserDetails -> Parser a -> [String] -> Maybe a
+pureParse pd p =
+    getParseResult . execParserPure (prefs idm) (mkParserInfo pd p)
+
+-- | a testing helper
+testCLI :: Show a => ParserDetails -> Parser a -> [String] -> IO ()
+testCLI pd psr ss = do
+    x <- handleParseResult $
+              execParserPure (prefs idm) (mkParserInfo pd psr) ss
+    print x
+
+
+--------------------------------------------------------------------------------
+-- mkParserInfo
+--------------------------------------------------------------------------------
+
+data ParserDetails =
+  ParserDetails
+    { _pd_desc   :: String
+    , _pd_header :: String
+    , _pd_footer :: String
+    }
+  deriving (Show)
+
+-- | given a 'Parser' makes up a corresponding @ParserInfo@
+mkParserInfo :: ParserDetails -> Parser a -> ParserInfo a
+mkParserInfo ParserDetails{..} p =
+    info (helper <*> p)
+         $  fullDesc
+         <> progDesc _pd_desc
+         <> header   _pd_header
+         <> footer   _pd_footer
+
+
+--------------------------------------------------------------------------------
+-- Parser generators
+--------------------------------------------------------------------------------
+
+type MetaVar  = String -- ^ name of a meta variable to be used in the docs
+type HelpText = String -- ^ help text
+type FlagName = String -- ^ name of a flag (will be forced to lower case)
+type FlagChar = Char   -- ^ charcter used for a short flag
+
+-- | parsing an 'EnumText' argument
+enumArgP :: forall a . EnumText a => MetaVar -> Parser a
+enumArgP var = argP var hlp
+  where
+    hlp = T.unpack $ T.intercalate "|" $
+                map (fmt . build) [minBound..maxBound :: a]
+
+-- | pasring a 'TextParsable' argument
+argP :: TextParsable a => MetaVar -> HelpText -> Parser a
+argP = argP' parseText
+
+-- | pasring an 'TextParsable' argument, the parser being passed explicitly
+argP' :: (T.Text->Either String a) -> MetaVar -> String -> Parser a
+argP' prs var hlp = argument (eitherReader $ prs . T.pack)
+      $  metavar var
+      <> help    hlp
+
+-- | parsing an 'EnumText' option
+enumOptP :: forall a . EnumText a => FlagChar -> MetaVar -> Parser a
+enumOptP c var = optP c var hlp
+  where
+    hlp = T.unpack $ T.intercalate "|" $
+                map (fmt . build) [minBound..maxBound :: a]
+
+-- | parsing a 'TextParsable' option
+optP :: TextParsable a => FlagChar -> FlagName -> HelpText -> Parser a
+optP ch nme hlp = option (eitherReader parse_string)
+      $  metavar var
+      <> short   ch
+      <> long    lng
+      <> help    hlp
+  where
+    var = map toUpper nme
+    lng = map toLower nme
+
+-- | generate mutually exclusive switches based on 'EnumText' @a@
+enumSwitchesP :: EnumText a => Parser a
+enumSwitchesP = shortEnumSwitchesP $ const Nothing
+
+-- | generate mutually exclusive switches based on 'EnumText' @a@, with
+-- some short swich options as specified by the argument function
+shortEnumSwitchesP :: forall a . EnumText a => (a->Maybe FlagChar) -> Parser a
+shortEnumSwitchesP sh_f = foldr (<|>) empty $ map mk [minBound..maxBound]
+  where
+    mk :: a -> Parser a
+    mk x = flag' x $ (long $ fmt $ build x) <> shrt
+      where
+        shrt = case sh_f x of
+          Nothing -> mempty
+          Just c -> short c
+
+
+--------------------------------------------------------------------------------
+-- helpers
+--------------------------------------------------------------------------------
+
+parse_string :: TextParsable a => String -> Either String a
+parse_string = parseText . T.pack
