diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Sibi Prabakaran (c) 2017
+
+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 Author name here 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,11 @@
+# tldr
+
+Haskell client for tldr
+
+![tldr](https://cloud.githubusercontent.com/assets/737477/24076451/2a5a604c-0c57-11e7-9bf7-13d76e8e7f12.png)
+
+## Installation
+
+1. [Install stack](https://docs.haskellstack.org/en/stable/README/#how-to-install)
+2. Clone this repo  (TODO: Publish this to Stackage)
+3. `stack install`
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/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,90 @@
+module Main where
+
+import Tldr
+import Options.Applicative
+import Data.Semigroup ((<>))
+import Control.Monad
+import System.Directory
+import System.FilePath
+import Data.Conduit.Shell hiding (info)
+
+data TldrOpts = TldrOpts
+  { pageName :: String
+  , updateFlag :: Bool
+  } deriving (Show)
+
+tldrDirName :: String
+tldrDirName = ".tldr"
+
+repoHttpsUrl :: String
+repoHttpsUrl = "https://github.com/tldr-pages/tldr.git"
+
+checkDirs :: [String]
+checkDirs = ["common", "linux", "osx"]
+
+tldrInitialized :: IO Bool
+tldrInitialized = do
+  homeDir <- getHomeDirectory
+  let dir1 = homeDir </> tldrDirName
+      dir2 = homeDir </> tldrDirName </> "tldr"
+      pages = homeDir </> tldrDirName </> "tldr" </> "pages"
+  exists <- mapM doesDirectoryExist [dir1, dir2, pages]
+  return $ all (== True) exists
+
+initializeTldrPages :: IO ()
+initializeTldrPages = do
+  initialized <- tldrInitialized
+  if initialized
+    then return ()
+    else do
+      homeDir <- getHomeDirectory
+      run $
+        do mkdir (homeDir </> tldrDirName)
+           cd (homeDir </> tldrDirName)
+           git "clone" repoHttpsUrl
+
+updateTldrPages :: IO ()
+updateTldrPages = do
+  homeDir <- getHomeDirectory
+  let repoDir = homeDir </> tldrDirName <> "tldr"
+  run $
+    do cd repoDir
+       git "pull" ["origin", "master"]
+
+tldrParserInfo :: ParserInfo TldrOpts
+tldrParserInfo =
+  info
+    (helper <*> versionOption <*> programOptions)
+    (fullDesc <> progDesc "tldr Client program" <>
+     header "tldr - Simplified and community-driven man pages")
+  where
+    versionOption = infoOption "0.1" (long "version" <> help "Show version")
+    programOptions :: Parser TldrOpts
+    programOptions =
+      TldrOpts <$>
+      (strArgument (metavar "COMMAND" <> help "name of the command")) <*>
+      (switch (long "update" <> help "Update tldr pages"))
+
+pageExists :: FilePath -> IO (Maybe FilePath)
+pageExists fname = do
+  exists <- doesFileExist fname
+  if exists
+    then return $ Just fname
+    else return Nothing
+
+getPagePath :: String -> IO (Maybe FilePath)
+getPagePath page = do
+  homeDir <- getHomeDirectory
+  let pageDir = homeDir </> tldrDirName </> "tldr" </> "pages"
+      x@(f1:f2:f3:[]) = map (\x -> pageDir </> x </> page <.> "md") checkDirs
+  pageExists f1 <|> pageExists f2 <|> pageExists f3
+
+main :: IO ()
+main = do
+  initializeTldrPages
+  opts <- execParser tldrParserInfo
+  when (updateFlag opts) updateTldrPages
+  fname <- getPagePath (pageName opts)
+  case fname of
+    Nothing -> putStrLn ("No tldr entry for " <> (pageName opts))
+    Just fpath -> renderPage fpath
diff --git a/src/Tldr.hs b/src/Tldr.hs
new file mode 100644
--- /dev/null
+++ b/src/Tldr.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Tldr
+  ( parsePage
+  , renderPage
+  , ConsoleSetting(..)
+  , defConsoleSetting
+  , headingSetting
+  , toSGR
+  , renderNode
+  , changeConsoleSetting
+  ) where
+
+import Data.Text
+import qualified Data.Text.IO as TIO
+import CMark
+import System.Console.ANSI
+import Data.Monoid ((<>))
+
+data ConsoleSetting = ConsoleSetting
+  { italic :: Bool
+  , underline :: Underlining
+  , blink :: BlinkSpeed
+  , fgIntensity :: ColorIntensity
+  , fgColor :: Color
+  , bgIntensity :: ColorIntensity
+  , bgColor :: Color
+  , consoleIntensity :: ConsoleIntensity
+  }
+
+defConsoleSetting :: ConsoleSetting
+defConsoleSetting =
+  ConsoleSetting
+  { italic = False
+  , underline = NoUnderline
+  , blink = NoBlink
+  , fgIntensity = Dull
+  , fgColor = White
+  , bgIntensity = Dull
+  , bgColor = Black
+  , consoleIntensity = NormalIntensity
+  }
+
+headingSetting :: ConsoleSetting
+headingSetting =
+  defConsoleSetting
+  { consoleIntensity = BoldIntensity
+  }
+
+toSGR :: ConsoleSetting -> [SGR]
+toSGR cons =
+  [ SetItalicized (italic cons)
+  , SetConsoleIntensity (consoleIntensity cons)
+  , SetUnderlining (underline cons)
+  , SetBlinkSpeed (blink cons)
+  , SetColor Foreground (fgIntensity cons) (fgColor cons)
+  , SetColor Background (bgIntensity cons) (bgColor cons)
+  ]
+
+renderNode :: NodeType -> IO ()
+renderNode (TEXT txt) = TIO.putStrLn txt
+renderNode (HTML_BLOCK txt) = TIO.putStrLn txt
+renderNode (CODE_BLOCK _ txt) = TIO.putStrLn txt
+renderNode (HTML_INLINE txt) = TIO.putStrLn txt
+renderNode (CODE txt) = TIO.putStrLn ("   " <> txt)
+renderNode LINEBREAK = TIO.putStrLn ""
+renderNode (LIST _) = TIO.putStrLn "" >> TIO.putStr " - "
+renderNode _ = return ()
+
+changeConsoleSetting :: NodeType -> IO ()
+changeConsoleSetting (HEADING _) = setSGR $ toSGR headingSetting
+changeConsoleSetting BLOCK_QUOTE = setSGR $ toSGR headingSetting
+changeConsoleSetting ITEM =
+  setSGR $
+  toSGR $
+  defConsoleSetting
+  { fgColor = Green
+  }
+changeConsoleSetting (CODE _) =
+  setSGR $
+  toSGR $
+  defConsoleSetting
+  { fgColor = Yellow
+  }
+changeConsoleSetting _ = return ()
+
+handleNode :: Node -> IO ()
+handleNode (Node _ ntype xs) = do
+  changeConsoleSetting ntype
+  renderNode ntype
+  mapM_ (\(Node _ ntype' ns) -> renderNode ntype' >> mapM_ handleNode ns) xs
+
+parsePage :: FilePath -> IO Node
+parsePage fname = do
+  page <- TIO.readFile fname
+  let node = commonmarkToNode [] page
+  return node
+
+renderPage :: FilePath -> IO ()
+renderPage fname = do
+  node <- parsePage fname
+  handleNode node
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
diff --git a/tldr.cabal b/tldr.cabal
new file mode 100644
--- /dev/null
+++ b/tldr.cabal
@@ -0,0 +1,49 @@
+name:                tldr
+version:             0.1.0.0
+synopsis:            Haskell tldr client
+description:         Haskell tldr client with support for updating and viewing tldr pages.
+homepage:            https://github.com/psibi/tldr-hs#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Sibi
+maintainer:          sibi@psibi.in
+copyright:           2017 Sibi
+category:            Web
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Tldr
+  build-depends:       base >= 4.7 && < 5,
+                       cmark,
+                       text,
+                       bytestring,
+                       ansi-terminal
+  default-language:    Haskell2010
+
+executable tldr
+  hs-source-dirs:      app
+  main-is:             Main.hs
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  build-depends:       base
+                     , tldr
+                     , optparse-applicative
+                     , directory
+                     , filepath
+                     , shell-conduit
+  default-language:    Haskell2010
+
+test-suite tldr-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , tldr
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/psibi/tldr-hs
