diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,9 @@
+MIT License (MIT)
+
+Copyright (c) 2016 uecmma
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+# CLI Builder
+
+This packages contains builders to make cli application easily based `optparse-applicative`.
+
+## Getting Started
+
+Here is a simple example:
+
+```haskell
+{-# LANGUAGE RecordWildCards #-}
+
+import System.CLI.Builder
+
+data Options = Options
+  { isSampleOption :: Bool
+  } deriving (Eq, Show)
+
+optionsParser :: OptionParser Options
+optionsParser = Options
+  <$> switch (long "sample" <> help "Sample switch")
+
+cliInfo :: CLIInfo
+cliInfo = baseCLIInfo "Simple CLI" "Example for simple CLI"
+
+run :: Options -> IO ()
+run Options{..} = do
+  putStrLn "Sample application"
+  putStrLn $ "Is sample: " ++ show isSampleOption
+
+main :: IO ()
+main = buildSimpleCLI cliInfo optionsParser run
+```
+
+This action is such as:
+
+```bash
+$ sampleApp
+Sample application
+Is sample: False
+$ sampleApp --sample
+Sample application
+Is sample: True
+$ sampleApp --help
+Simple CLI
+
+Usage: <interactive> [--help]
+  Example for simple CLI
+
+Available options:
+  --help                   Show this help text
+  --sample                 Sample switch
+```
+
+For more examples, see [examples](examples).
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,4 @@
+import           Distribution.Simple
+
+main :: IO ()
+main = defaultMain
diff --git a/cli-builder.cabal b/cli-builder.cabal
new file mode 100644
--- /dev/null
+++ b/cli-builder.cabal
@@ -0,0 +1,70 @@
+name:           cli-builder
+version:        0.1.0
+synopsis:       Simple project template from stack
+description:    Please see README.md
+category:       Tool
+homepage:       https://github.com/uecmma/haskell-library-collections/tree/master/cli-builder
+bug-reports:    https://github.com/uecmma/haskell-library-collections/issues
+author:         uecmma
+maintainer:     developer@mma.club.uec.ac.jp
+copyright:      2016 uecmma
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    README.md
+
+source-repository head
+  type: git
+  location: git+https://gitlab.mma.club.uec.ac.jp/uecmma/haskell-library-collections.git
+
+flag test-doctest
+  default: True
+  manual:  True
+
+library
+  ghc-options: -Wall
+  hs-source-dirs:
+      src
+  exposed-modules:
+      System.CLI.Builder
+      System.CLI.Builder.Internal
+      System.CLI.Builder.Option
+      System.CLI.Builder.Types
+  build-depends:
+      base >= 4.7 && < 5
+    , either
+    , exceptions >= 0.8.0.2
+    , optparse-applicative >= 0.12 && < 0.14
+    , transformers >= 0.3.0.0 && < 0.6
+  default-language: Haskell2010
+
+test-suite spec-test
+  type: exitcode-stdio-1.0
+  ghc-options: -Wall
+  main-is: Spec.hs
+  hs-source-dirs:
+      test
+  other-modules:
+      System.CLI.BuilderSpec
+  build-depends:
+      base
+    , cli-builder
+    , QuickCheck
+    , hspec
+  default-language: Haskell2010
+
+test-suite doc-test
+  type: exitcode-stdio-1.0
+  ghc-options: -Wall -threaded
+  main-is: test/Doctests.hs
+  default-language: Haskell2010
+
+  if !flag (test-doctest)
+    buildable: False
+  else
+    build-depends:
+        base
+      , doctest
+      , filemanip
diff --git a/src/System/CLI/Builder.hs b/src/System/CLI/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/System/CLI/Builder.hs
@@ -0,0 +1,223 @@
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE QuasiQuotes     #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
+
+module System.CLI.Builder
+  ( CommandExecutes
+  , module System.CLI.Builder.Option
+  , CLIInfo (..)
+  , baseCLIInfo
+  , buildCLIApp
+  , buildCLIGeneralApp
+  , buildSimpleCLI
+  , buildCLI
+  , cmdProgram
+  , Middleware
+  , addCommandExecutes
+  , cmdMiddleware
+  , cmdCommonMiddleware
+  , addCommand
+  , addSimpleCommand
+  , MiddlewareIO
+  , cmdMiddlewareIO
+  , cmdCommonMiddlewareIO
+  , addCommandIO
+  , addSimpleCommandIO
+  ) where
+
+import           Control.Applicative
+import           Control.Arrow               hiding (left, right)
+import           Control.Category
+import           Control.Monad
+import           Control.Monad.IO.Class
+import           Control.Monad.Trans.Class
+import           Control.Monad.Trans.Either
+import           Control.Monad.Trans.Reader
+import           Options.Applicative
+import           Options.Applicative.Types
+import           Prelude                     hiding (id, (.))
+import           System.CLI.Builder.Internal
+import           System.CLI.Builder.Option
+import           System.CLI.Builder.Types
+import           System.Environment
+
+-- | a builder for CLI application
+--
+-- Examples:
+--
+-- >>> :{
+-- let cliInfo = baseCLIInfo "CLI Application" "Example of CLI Application"
+-- in withArgs ["--help"] $ buildCLIApp cliInfo return (pure ()) $ do
+--      cmdProgram $ \_ ->
+--        putStrLn "Hello, World!"
+-- :}
+-- CLI Application
+-- <BLANKLINE>
+-- Usage: <interactive> [--help]
+--   Example of CLI Application
+-- <BLANKLINE>
+-- Available options:
+--   --help                   Show this help text
+-- *** Exception: ExitSuccess
+--
+-- >>> :{
+-- let cliInfo = baseCLIInfo "CLI Application" "Example of CLI Application"
+-- in withArgs [] $ buildCLIApp cliInfo return (pure ()) $ do
+--      cmdProgram $ \_ ->
+--        putStrLn "Hello, World!"
+-- :}
+-- Hello, World!
+--
+-- >>> :{
+-- let cliInfo = baseCLIInfo "CLI Application" "Example of CLI Application"
+-- in withArgs ["--illegal"] $ buildCLIApp cliInfo return (pure ()) $ do
+--      cmdProgram $ \_ ->
+--        putStrLn "Hello, World!"
+-- :}
+-- Invalid option `--illegal'
+-- <BLANKLINE>
+-- Usage: <interactive> [--help]
+--   Example of CLI Application
+-- *** Exception: ExitFailure 1
+--
+buildCLIApp
+  :: MonadIO m
+  => CLIInfo
+  -> (c -> m d)
+  -> Parser c
+  -> CommandExecutes d (m a)
+  -> m a
+buildCLIApp cliInfo middleware commonParser commands
+  = join $ buildCLI cliInfo Nothing parser
+  where
+    parser = complicatedMonadParser
+      (middleware <$> commonParser)
+      commands
+
+buildCLIGeneralApp
+  :: MonadIO m
+  => CLIInfo
+  -> Parser c
+  -> Maybe (ParserFailure ParserHelp -> [String] -> m a)
+  -> CommandExecutes c a
+  -> m a
+buildCLIGeneralApp cliInfo commonParser mOnFailure commands
+  = buildCLI cliInfo mOnFailure parser
+  where
+    parser = complicatedParser commonParser commands
+
+-- | a builder for simple CLI application
+--
+-- Examples:
+--
+-- >>> :{
+-- let cliInfo = baseCLIInfo "Simple CLI Application" "Example of Simple CLI Application"
+-- in withArgs ["--help"] $ buildSimpleCLI cliInfo (pure ()) $ \x -> do
+--      putStrLn "Hello, World!"
+-- :}
+-- Simple CLI Application
+-- <BLANKLINE>
+-- Usage: <interactive> [--help]
+--   Example of Simple CLI Application
+-- <BLANKLINE>
+-- Available options:
+--   --help                   Show this help text
+-- *** Exception: ExitSuccess
+--
+-- >>> :{
+-- let cliInfo = baseCLIInfo "Simple CLI Application" "Example of Simple CLI Application"
+-- in withArgs [] $ buildSimpleCLI cliInfo (pure ()) $ \x -> do
+--      putStrLn "Hello, World!"
+-- :}
+-- Hello, World!
+--
+-- >>> :{
+-- let cliInfo = baseCLIInfo "Simple CLI Application" "Example of Simple CLI Application"
+-- in withArgs ["--illegal"] $ buildSimpleCLI cliInfo (pure ()) $ \x -> do
+--      putStrLn "Hello, World!"
+-- :}
+-- Invalid option `--illegal'
+-- <BLANKLINE>
+-- Usage: <interactive> [--help]
+--   Example of Simple CLI Application
+-- *** Exception: ExitFailure 1
+--
+buildSimpleCLI
+  :: MonadIO m
+  => CLIInfo
+  -> Parser c
+  -> (c -> m a)
+  -> m a
+buildSimpleCLI cliInfo parser cmd
+  = join $ buildCLI cliInfo Nothing $ cmd <$> parser
+
+buildCLI
+  :: MonadIO m
+  => CLIInfo
+  -> Maybe (ParserFailure ParserHelp -> [String] -> m a)
+  -> Parser a
+  -> m a
+buildCLI CLIInfo{..} mOnFailure optParser = do
+  args <- liftIO getArgs
+
+  result <- case execParserPure (prefs noBacktrack) parser args of
+    Failure _   | null args -> liftIO $ withArgs ["--help"] $ execParser parser
+    Failure f   | Just onFailure <- mOnFailure -> onFailure f args
+    parseResult -> do
+      liftIO $ handleParseResult parseResult
+
+  return result
+  where
+    parser = info
+      (   helpOption
+      <*> mayVersionOption
+      <*> optParser
+      )
+      $  fullDesc
+      <> header cliTitle
+      <> progDesc cliDescription
+      <> maybe mempty footer cliFooter
+
+    mayVersionOption = maybe (pure id) versionOption cliVersion
+
+    versionOption verStr = infoOption verStr
+      $  long "version"
+      <> help "Show version"
+
+cmdProgram :: (c -> a) -> CommandExecutes c a
+cmdProgram = left
+
+cmdMiddleware :: (a -> b) -> Middleware c a b
+cmdMiddleware = arr
+
+cmdCommonMiddleware :: (a -> c -> b) -> Middleware c a b
+cmdCommonMiddleware f = Kleisli $ \a -> f a <$> ask
+
+addCommand :: String -> String -> Parser a -> Middleware c a b -> CommandExecutes c b
+addCommand name desc parser middleware
+  = addCommandExecutes $ command name $
+    info (runReader . runKleisli middleware <$> parser)
+    $ progDesc desc
+
+addSimpleCommand :: String -> String -> Parser a -> (a -> c -> b) -> CommandExecutes c b
+addSimpleCommand name desc parser
+  = addCommand name desc parser . cmdCommonMiddleware
+
+cmdMiddlewareIO :: MonadIO m => (a -> m b) -> MiddlewareIO c m a b
+cmdMiddlewareIO f = Kleisli $ lift . f
+
+cmdCommonMiddlewareIO :: MonadIO m => (a -> c -> m b) -> MiddlewareIO c m a b
+cmdCommonMiddlewareIO f = Kleisli $ \a -> ask >>= (lift . f a)
+
+addCommandIO :: MonadIO m
+  => String -> String -> Parser a -> MiddlewareIO c m a b -> CommandExecutes c (m b)
+addCommandIO name desc parser middleware
+  = addCommandExecutes $ command name $
+    info (runReaderT . runKleisli middleware <$> parser)
+    $ progDesc desc
+
+addSimpleCommandIO :: MonadIO m
+  => String -> String -> Parser a -> (a -> c -> m b) -> CommandExecutes c (m b)
+addSimpleCommandIO name desc parser
+  = addCommandIO name desc parser . cmdCommonMiddlewareIO
diff --git a/src/System/CLI/Builder/Internal.hs b/src/System/CLI/Builder/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/System/CLI/Builder/Internal.hs
@@ -0,0 +1,50 @@
+module System.CLI.Builder.Internal
+  ( runCommandExecutes
+  , addCommandExecutes
+  , fromCommandFields
+  , complicatedParser
+  , complicatedMonadParser
+  , helpOption
+  ) where
+
+import           Control.Monad.Trans.Class
+import           Control.Monad.Trans.Either
+import           Control.Monad.Trans.Writer
+import           Options.Applicative
+import           Options.Applicative.Builder.Internal
+import           Options.Applicative.Types
+import           System.CLI.Builder.Types
+
+addCommandExecutes :: ModCommandFields (c -> a) -> CommandExecutes c a
+addCommandExecutes = lift . tell
+
+complicatedParser :: Parser c -> CommandExecutes c a -> Parser a
+complicatedParser commonParser commands = commandParser <*> commonParser
+  where
+    commandParser = runCommandExecutes commands
+
+complicatedMonadParser :: Monad m
+  => Parser (m c) -> CommandExecutes c (m a) -> Parser (m a)
+complicatedMonadParser commonParser commands = (>>=) <$> commonParser <*> commandParser
+  where
+    commandParser = runCommandExecutes commands
+
+runCommandExecutes :: CommandExecutes c a -> Parser (c -> a)
+runCommandExecutes commands = case runWriter $ runEitherT commands of
+  (Right _, d) -> fromCommandFields d
+  (Left b , _) -> pure b
+
+fromCommandFields :: ModCommandFields a -> Parser a
+fromCommandFields m = mkParser d g rdr
+  where
+    Mod _ d g = metavar "COMMAND" <> m
+    (cmds, subs) = mkCommand m
+    rdr = CmdReader cmds (fmap add_helper . subs)
+    add_helper pinfo = pinfo
+      { infoParser = infoParser pinfo <**> helpOption
+      }
+
+helpOption :: Parser (a -> a)
+helpOption = abortOption ShowHelpText
+  $  long "help"
+  <> help "Show this help text"
diff --git a/src/System/CLI/Builder/Option.hs b/src/System/CLI/Builder/Option.hs
new file mode 100644
--- /dev/null
+++ b/src/System/CLI/Builder/Option.hs
@@ -0,0 +1,9 @@
+module System.CLI.Builder.Option
+  ( OptionParser
+  , module OptionsApplicative
+  ) where
+
+import           Options.Applicative as OptionsApplicative hiding (Parser)
+import           Options.Applicative (Parser)
+
+type OptionParser a = Parser a
diff --git a/src/System/CLI/Builder/Types.hs b/src/System/CLI/Builder/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/System/CLI/Builder/Types.hs
@@ -0,0 +1,41 @@
+module System.CLI.Builder.Types
+  ( CLIInfo (..)
+  , baseCLIInfo
+  , ModCommandFields
+  , CommandExecutes
+  , Parser
+  , Middleware
+  , MiddlewareIO
+  ) where
+
+import           Control.Arrow              hiding (left, right)
+import           Control.Monad.Trans.Either
+import           Control.Monad.Trans.Reader
+import           Control.Monad.Trans.Writer
+import           Options.Applicative
+
+data CLIInfo = CLIInfo
+  { cliTitle       :: !String
+  , cliDescription :: !String
+  , cliVersion     :: !(Maybe String)
+  , cliFooter      :: !(Maybe String)
+  } deriving (Eq, Show)
+
+baseCLIInfo :: String -> String -> CLIInfo
+baseCLIInfo title desc = CLIInfo
+  { cliTitle       = title
+  , cliDescription = desc
+  , cliVersion     = Nothing
+  , cliFooter      = Nothing
+  }
+
+type ModCommandFields a = Mod CommandFields a
+
+type CommandExecutes c a
+  = EitherT (c -> a)
+  (Writer (ModCommandFields (c -> a)))
+  ()
+
+type Middleware c a b = Kleisli (Reader c) a b
+
+type MiddlewareIO c m a b = Kleisli (ReaderT c m) a b
diff --git a/test/Doctests.hs b/test/Doctests.hs
new file mode 100644
--- /dev/null
+++ b/test/Doctests.hs
@@ -0,0 +1,20 @@
+module Main where
+
+import           Data.Semigroup
+import           System.FilePath.Find
+import           Test.DocTest
+
+main :: IO ()
+main = do
+  files <- find always (extension ==? ".hs") "src"
+  tfiles <- find always (extension ==? ".hs") "test"
+  doctest $
+    [ "-isrc"
+    , "-XOverloadedStrings"
+    , "-XFlexibleInstances"
+    , "-XMultiParamTypeClasses"
+    , "-XTemplateHaskell"
+    , "-XQuasiQuotes"
+    ]
+    <> files
+    <> filter (`notElem` ["test/Doctests.hs"]) tfiles
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/System/CLI/BuilderSpec.hs b/test/System/CLI/BuilderSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/System/CLI/BuilderSpec.hs
@@ -0,0 +1,6 @@
+module System.CLI.BuilderSpec where
+
+import           Test.Hspec
+
+spec :: Spec
+spec = pure ()
