diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Gianluca Guarini (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 Gianluca Guarini 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,34 @@
+<p align="center">
+  <img src="rob-logo.svg" alt="rob logo"/>
+</p>
+
+<p align="center">
+Simple projects generator written in Haskell
+</p>
+
+---
+> Call on me in the day of trouble, and I will deliver, and thou shalt glorify me.</p>
+###### Daniel Defoe, Robinson Crusoe
+
+# Installation
+
+```shell
+$ cabal install rob
+```
+
+# Usage
+
+## TODO
+
+### Available commands
+
+```shell
+$ rob --help
+```
+
+# Todo
+
+- [ ] Unit test!
+- [ ] Improve performance
+- [ ] Write Documentation
+- [ ] Refactor the code and cleanup
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,29 @@
+module Main where
+
+import System.Environment
+import System.Exit
+import System.Console.CmdArgs (cmdArgsRun)
+import System.Console.CmdArgs.Explicit(helpText, HelpFormat(..))
+import Rob.Types (Task(..))
+import Rob.Tasks (mode)
+import qualified Rob.Actions.Add
+import qualified Rob.Actions.New
+import qualified Rob.Actions.List
+import qualified Rob.Actions.Remove
+
+main :: IO()
+main = do
+  args <- getArgs
+  if null args then exitWithHelp
+  else parse =<< cmdArgsRun mode
+
+parse :: Task -> IO ()
+parse Add  {name = n, path = p} = Rob.Actions.Add.main n p
+parse New = Rob.Actions.New.main
+parse List = Rob.Actions.List.main
+parse Remove = Rob.Actions.Remove.main
+
+exitWithHelp :: IO a
+exitWithHelp = do
+  putStr $ show $ helpText [] HelpFormatOne mode
+  exitSuccess
diff --git a/rob.cabal b/rob.cabal
new file mode 100644
--- /dev/null
+++ b/rob.cabal
@@ -0,0 +1,69 @@
+name:                rob
+version:0.0.1
+synopsis:            Simple projects generator
+description:         See README at <https://github.com/GianlucaGuarini/rob/blob/develop/README.md>
+homepage:            https://github.com/gianlucaguarini/rob#readme
+license:             MIT
+license-file:        LICENSE
+author:              Gianluca Guarini
+maintainer:          gianluca.guarini@gmail.com
+copyright:           Gianlua Guarini
+category:            CLI
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Rob.Config,
+                       Rob.Types,
+                       Rob.Project,
+                       Rob.Tasks,
+                       Rob.UserMessages,
+                       Rob.Questionnaire,
+                       Rob.Logger,
+                       Rob.Package,
+                       Rob.Actions.New,
+                       Rob.Actions.Remove,
+                       Rob.Actions.List,
+                       Rob.Actions.Add
+  build-depends:       base >= 4.7 && < 5,
+                       fortytwo <= 1.0.2,
+                       directory <= 1.3.0.0,
+                       filepath <= 1.4.1.2,
+                       pathwalk <= 0.3.1.2,
+                       Glob <= 0.9.1,
+                       yaml <= 0.8.23.3,
+                       vector <= 0.12.0.1,
+                       ede == 0.2.8.7,
+                       text <= 1.2.2.2,
+                       unordered-containers <= 0.2.8.0,
+                       cmdargs >= 0.10.17 && <= 0.10.18,
+                       ansi-terminal <= 0.6.3.1,
+                       bytestring <= 0.10.8.1,
+                       time <= 1.6.0.1
+  other-modules:       Paths_rob
+  default-language:    Haskell2010
+
+executable rob
+  hs-source-dirs:      app
+  main-is:             Main.hs
+  build-depends:       base >= 4.7 && < 5,
+                       cmdargs >= 0.10.17 && <= 0.10.18
+  build-depends:       base,
+                       rob
+  default-language:    Haskell2010
+
+test-suite rob-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base,
+                       directory,
+                       rob
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/gianlucaguarini/rob
diff --git a/src/Rob/Actions/Add.hs b/src/Rob/Actions/Add.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Actions/Add.hs
@@ -0,0 +1,26 @@
+module Rob.Actions.Add (main) where
+
+import Rob.Logger (err, success)
+import Rob.Config (get, addTemplate)
+import Rob.Project (hasPathQuestionnaire)
+import Rob.UserMessages (projectPathDoesNotExist, projectQuestionnaireMissing, projectAdded)
+
+import System.Exit (exitFailure, exitSuccess)
+import System.Directory (doesPathExist)
+
+main :: String -> FilePath -> IO()
+main name path = do
+  hasProjectPath <- doesPathExist path
+  if hasProjectPath then do
+    hasQuestionnaire <- hasPathQuestionnaire path
+    if hasQuestionnaire then do
+      config <- get
+      _ <- addTemplate config name path
+      success $ projectAdded name
+      exitSuccess
+    else do
+      err $ projectQuestionnaireMissing path
+      exitFailure
+  else do
+    err $ projectPathDoesNotExist path
+    exitFailure
diff --git a/src/Rob/Actions/List.hs b/src/Rob/Actions/List.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Actions/List.hs
@@ -0,0 +1,22 @@
+module Rob.Actions.List (main) where
+
+import Rob.Logger (info)
+import Rob.UserMessages (availableTemplates, emptyString)
+import Rob.Config (get, errorNoTemplatesAvailable)
+import Rob.Types(Config(..))
+
+import System.Exit (exitSuccess)
+
+main :: IO()
+main = do
+  config <- get
+  putStrLn emptyString
+  info availableTemplates
+  putStrLn emptyString
+  listTemplates config
+  exitSuccess
+
+-- | List all the templates as string
+listTemplates :: Config -> IO ()
+listTemplates (Config []) = errorNoTemplatesAvailable;
+listTemplates (Config templates) = putStrLn $ unlines $ map show templates
diff --git a/src/Rob/Actions/New.hs b/src/Rob/Actions/New.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Actions/New.hs
@@ -0,0 +1,45 @@
+module Rob.Actions.New (main) where
+
+import Rob.Logger (err, success)
+import Rob.Config (get, errorNoTemplatesAvailable)
+import Rob.Types (Config(..))
+import Rob.Questionnaire (run)
+import Rob.Project (getTemplatePathByName, getTemplateName, createFilesFromTemplate)
+import Rob.UserMessages (
+    choseATemplate,
+    noTemplateSelected,
+    projectSuccessfullyCreated,
+    projectPathDoesNotExist,
+    emptyString
+  )
+
+import System.Exit (exitFailure, exitSuccess)
+import System.Directory (doesPathExist)
+import FortyTwo (select)
+
+main :: IO ()
+main = do
+  config <- get
+  createNewProject config
+
+-- | Create a new project using one of the templates available
+createNewProject :: Config -> IO ()
+createNewProject (Config []) = errorNoTemplatesAvailable
+createNewProject (Config templates) = do
+  templateName <- select choseATemplate $ map getTemplateName templates
+  putStrLn emptyString
+  if not . null $ templateName then do
+    let path = getTemplatePathByName templates templateName
+    hasProjectPath <- doesPathExist path
+    if hasProjectPath then do
+      responses <- run path
+      putStrLn emptyString
+      createFilesFromTemplate path responses
+      success projectSuccessfullyCreated
+      exitSuccess
+    else do
+      err $ projectPathDoesNotExist path
+      exitFailure
+  else do
+    err noTemplateSelected
+    exitFailure
diff --git a/src/Rob/Actions/Remove.hs b/src/Rob/Actions/Remove.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Actions/Remove.hs
@@ -0,0 +1,32 @@
+module Rob.Actions.Remove (main) where
+
+import Rob.Logger (err)
+import Rob.Config (get, errorNoTemplatesAvailable, deleteTemplate)
+import Rob.Types (Config(..))
+import Rob.Project (getTemplateName)
+import Rob.UserMessages (
+    choseATemplateToDelete,
+    noTemplateSelected,
+    emptyString
+  )
+
+import System.Exit (exitFailure, exitSuccess)
+import FortyTwo (select)
+
+main :: IO ()
+main = do
+  config <- get
+  nukeTemplate config
+
+-- Remove a project template from the available ones
+nukeTemplate :: Config -> IO ()
+nukeTemplate (Config []) = errorNoTemplatesAvailable
+nukeTemplate (Config templates) = do
+  templateName <- select choseATemplateToDelete $ map getTemplateName templates
+  putStrLn emptyString
+  if (not . null) templateName then do
+    _ <- deleteTemplate (Config templates) templateName
+    exitSuccess
+  else do
+    err noTemplateSelected
+    exitFailure
diff --git a/src/Rob/Config.hs b/src/Rob/Config.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Config.hs
@@ -0,0 +1,68 @@
+module Rob.Config where
+
+import qualified Rob.Package as Package
+import Rob.Logger (err, warning, success, info, flatten)
+import Rob.UserMessages (configFileFound, noConfigFileFound, configFileCreated, noTemplatesAvailable, tryAddingATemplate)
+import Rob.Types (Config(..), Template(..))
+
+import Data.Maybe
+import System.Exit
+import System.FilePath (joinPath)
+import System.Directory (getHomeDirectory, doesFileExist)
+import Data.Yaml (encodeFile, decodeFile)
+
+-- | Get the config file name
+configFileName :: String
+configFileName = "." ++ Package.name
+
+-- | Get the whole path to the config file
+configFilePath :: IO FilePath
+configFilePath = do
+  home <- getHomeDirectory
+  return $ joinPath [home, configFileName]
+
+-- | Write the config file and return it
+write :: Config -> IO Config
+write config = do
+  configFilePath >>= \path -> encodeFile path config
+  return config
+
+-- | Get the current Config file Data
+-- | If it doesn't exist it will create a new one
+get :: IO Config
+get = do
+  path <- configFilePath
+  hasConfigPath <- doesFileExist path
+  if hasConfigPath
+    then do
+      success $ configFileFound path
+      config <- decodeFile path
+      return $ fromJust config
+    else do
+      warning $ noConfigFileFound configFileName
+      flatten info $ configFileCreated path
+      -- return an empty Config object and write it in the home directory
+      write $ Config []
+
+-- | Dispatch the no templates available error
+errorNoTemplatesAvailable :: IO ()
+errorNoTemplatesAvailable = do
+  err noTemplatesAvailable
+  warning tryAddingATemplate
+  exitFailure
+
+-- | Add a new template to the config object and write it
+addTemplate :: Config -> String -> String -> IO Config
+addTemplate (Config templates) name path = write $ Config newTemplates
+  where
+    newTemplate = Template name path
+    newTemplates = if newTemplate `elem` templates then
+        map (\t -> if t == newTemplate then newTemplate else t) templates
+      else
+        templates ++ [newTemplate]
+
+-- | Delete a template from the list of templates
+deleteTemplate :: Config -> String -> IO Config
+deleteTemplate (Config templates) nameToRemove = write $ Config newTemplates
+  where
+    newTemplates = (\(Template name _) -> name /= nameToRemove) `filter` templates
diff --git a/src/Rob/Logger.hs b/src/Rob/Logger.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Logger.hs
@@ -0,0 +1,48 @@
+module Rob.Logger where
+
+import System.Console.ANSI
+import Data.Time.Clock (getCurrentTime, UTCTime)
+import Data.Time.Format (formatTime, defaultTimeLocale)
+
+-- | Print a message highlighting it
+log' :: Color -> ColorIntensity -> String -> IO()
+log' color intensity message = do
+  setSGR [SetColor Foreground Dull White]
+  time <- getCurrentTime
+  print' $ formatTime' time
+  setSGR [Reset]
+  setSGR [SetColor Foreground intensity color]
+  print' $ message ++ "\n"
+  setSGR [Reset]
+
+-- | Format the time, showing it into the log message
+formatTime' :: UTCTime -> String
+formatTime' = formatTime defaultTimeLocale "[%T] "
+
+-- | Print a message in the console
+print' :: String -> IO()
+print' = putStr
+
+-- | Log success messages
+success :: String -> IO()
+success = log' Green Dull
+
+-- | Log error messages
+err :: String -> IO()
+err = log' Red Vivid
+
+-- | Log info messages
+info :: String -> IO()
+info = log' Cyan Dull
+
+-- | Log warning messages
+warning :: String -> IO()
+warning = log' Yellow Dull
+
+-- | Log a raw message without using colors
+raw :: String -> IO()
+raw = print'
+
+-- | Execute log on a list of messages
+flatten :: Monad m => (a -> m b) -> [a] -> m ()
+flatten = mapM_
diff --git a/src/Rob/Package.hs b/src/Rob/Package.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Package.hs
@@ -0,0 +1,22 @@
+module Rob.Package where
+
+-- TODO: get these props from the .cabal file
+
+import qualified Paths_rob
+import Data.Version (showVersion)
+
+-- | Return the Package version (stored in the .cabal file)
+version :: String
+version = showVersion Paths_rob.version
+
+-- | Return the package name
+name :: String
+name = "rob"
+
+-- | Return the package author
+author :: String
+author = "Author: Gianluca Guarini"
+
+-- | Return the package description
+description :: String
+description = "Projects generator"
diff --git a/src/Rob/Project.hs b/src/Rob/Project.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Project.hs
@@ -0,0 +1,181 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Rob.Project where
+
+import Rob.Types (Template(..))
+import Rob.Logger (warning, success)
+import Rob.UserMessages (parserError, fileCreated)
+
+import Data.Yaml (Value)
+import Control.Monad (forM_, unless)
+import Data.Text (Text)
+import qualified Data.ByteString.Lazy as BS
+import Data.Text.Lazy.Encoding (encodeUtf8)
+import System.FilePath.Posix (makeRelative)
+import Data.List (any, nub, intercalate)
+import System.FilePath.Glob (match, simplify, compile, Pattern)
+import Text.EDE (eitherRender, eitherParseFile, fromPairs)
+import System.Directory.PathWalk (pathWalkInterruptible, WalkStatus(..))
+import System.Directory (doesFileExist, createDirectoryIfMissing)
+import System.FilePath (joinPath, takeDirectory, normalise, isDrive, isValid, pathSeparator)
+
+-- | Get only the template name
+getTemplateName :: Template -> String
+getTemplateName (Template name _) = name
+
+-- | Get only the template path
+getTemplatePath :: Template -> FilePath
+getTemplatePath (Template _ path) = path
+
+-- | Get the template name by its path
+getTemplatePathByName :: [Template] -> String -> FilePath
+getTemplatePathByName [] [] = ""
+getTemplatePathByName [] _ = ""
+getTemplatePathByName (x:xs) name =
+  if templateName == name then
+    templatePath
+  else
+    getTemplatePathByName xs name
+  where
+    templateName = getTemplateName x
+    templatePath = getTemplatePath x
+
+-- | File where users can store all the project creation questions
+projectDataFile :: String
+projectDataFile = "project.yml"
+
+ignoreFiles :: [FilePath]
+ignoreFiles = [".gitignore", "svnignore.txt"]
+
+knownIgnoredFiles :: [Pattern]
+knownIgnoredFiles = globbifyList [".git", ".svn", projectDataFile]
+
+-- | Check if the path contains the questionnaire file
+hasPathQuestionnaire :: FilePath -> IO Bool
+hasPathQuestionnaire = doesFileExist . questionnaireFileByPath
+
+-- | Get the questionnaire file by project path
+questionnaireFileByPath :: FilePath -> FilePath
+questionnaireFileByPath path = joinPath [path, projectDataFile]
+
+-- | Start the template creation
+createFilesFromTemplate :: FilePath -> [(Text, Value)] -> IO ()
+createFilesFromTemplate root = walk knownIgnoredFiles root ""
+
+-- | Walk recursively a folder copying its files using
+walk :: [Pattern] -> FilePath -> FilePath -> [(Text, Value)] -> IO ()
+walk currentBlacklist templateRoot currentPath responses =
+  pathWalkInterruptible absolutePath $ \_ dirs files -> do
+    blacklist <- getBlacklist
+    render templateRoot relativePath files blacklist responses
+    mapM_ (\f ->
+        walk blacklist templateRoot (joinPath [relativePath, f]) responses
+      )
+      (whitelist dirs blacklist)
+    return StopRecursing
+    where
+      absolutePath = joinPath [templateRoot, currentPath]
+      relativePath = makeRelative templateRoot currentPath
+      getBlacklist = do
+        newBlacklist <- populateBlacklist absolutePath
+        return $ currentBlacklist ++ newBlacklist
+      whitelist dirs blacklist = [
+          f | f <- dirs,
+          not $ isInBlacklist f blacklist
+        ]
+
+-- | Add eventually new ignored files to the blacklist map
+populateBlacklist :: FilePath -> IO [Pattern]
+populateBlacklist root = getIgnoredPatterns (map (\f -> joinPath [root, f]) ignoreFiles)
+
+-- | Parse a directory copying the files found into the current one
+-- | where rob was called, it will also render eventually the answers to the questionnaire
+-- | if template token will be found in any of the files
+render :: FilePath -> FilePath -> [FilePath] -> [Pattern] -> [(Text, Value)] -> IO()
+render templateRoot path files blacklist responses = do
+  createDirectoryIfMissing True path
+  forM_ files $ \file ->
+    unless (isInBlacklist file blacklist) $ do
+      let fileAbsolutePath = joinPath [templateRoot, path, file]
+          fileRelativePath = joinPath [path, file]
+      success $ fileCreated fileRelativePath
+      template <- eitherParseFile fileAbsolutePath
+      case template of
+        Right t ->
+          case eitherRender t templateData of
+            Right res -> BS.writeFile fileRelativePath (encodeUtf8 res)
+            Left e -> fallback e fileAbsolutePath fileRelativePath
+        Left e -> fallback e fileAbsolutePath fileRelativePath
+  where
+    templateData = fromPairs responses
+    fallback e inPath outPath = do
+      warning parserError
+      putStrLn e
+      file <- BS.readFile inPath
+      BS.writeFile outPath file
+
+-- | Check whether a path is blacklisted looking it up in the blacklist map
+-- | here basically we try to emulate the gitignore behavior recursively
+isInBlacklist :: FilePath -> [Pattern] -> Bool
+isInBlacklist path = any (`match` path)
+
+-- | Get all the files to ignore uniquelly from a list of known .ignore files
+getIgnoredPatterns :: [FilePath] -> IO [Pattern]
+getIgnoredPatterns files = do
+  res <- mapM findIgnoredFilesList files
+  return $ nub $ intercalate [] res
+
+-- | Figure out which files must be ignored reading them from the .gitignore
+findIgnoredFilesList :: FilePath -> IO [Pattern]
+findIgnoredFilesList f = do
+  hasFile <- doesFileExist f
+  if hasFile then do
+    file <- readFile f
+    return $ (
+        globbifyList .
+        extendIgnoredFiles .
+        removeSeparatorPrefix .
+        cleanList
+      ) $ lines file
+  else return []
+  where
+    cleanList list = (\l -> (not . null) l && head l /= '#') `filter` list
+
+-- | Remove the initial separator prefix
+removeSeparatorPrefix :: [FilePath] -> [FilePath]
+removeSeparatorPrefix = map $ \p -> if head p == pathSeparator then tail p else p
+
+
+-- | Extend the ignored files in order to enhance the patterns matching
+-- | for example with the "/node_modules/*" pattern we will add also "/node_modules"
+-- | to the excluded folders
+extendIgnoredFiles :: [FilePath] -> [FilePath]
+extendIgnoredFiles (x:xs) =
+    if (not . null) extension then
+      x : extension : extendIgnoredFiles xs
+    else x : extendIgnoredFiles xs
+  where
+    extension = if all (\t -> t dirName) tests then dirName else []
+    dirName   = (takeDirectory . normalise) x
+    tests = [
+        isValid,
+        not . isDrive,
+        not . isDot,
+        not . isWildCard,
+        not . isDoubleWildCard
+      ]
+extendIgnoredFiles [] = []
+
+-- | Helpers to enhance the ignored files
+isDot :: FilePath -> Bool
+isDot = (==) "."
+
+isWildCard :: FilePath -> Bool
+isWildCard = (==) "*"
+
+isDoubleWildCard :: FilePath -> Bool
+isDoubleWildCard = (==) "**"
+
+-- | Map a list of file paths to glob patterns
+globbifyList :: [FilePath] -> [Pattern]
+globbifyList = map (simplify . compile)
diff --git a/src/Rob/Questionnaire.hs b/src/Rob/Questionnaire.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Questionnaire.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE NamedFieldPuns #-}
+module Rob.Questionnaire where
+import Rob.Types
+import Rob.Project (questionnaireFileByPath, hasPathQuestionnaire)
+import Rob.UserMessages (unableToParseQuestionnaire, projectQuestionnaireMissing)
+import qualified Rob.Logger as Logger
+
+import System.Exit (exitFailure)
+import FortyTwo
+import Data.Yaml
+import Data.Text (Text, pack)
+import Data.HashMap.Strict (toList)
+import qualified Data.Vector as V
+
+-- | Get only the questions out of a questionnaier data struct as list
+getQuestions :: Questionnaire -> [(Text, Question)]
+getQuestions Questionnaire { questions } = toList questions
+
+-- | Run the questionnaire
+run :: FilePath -> IO [(Text, Value)]
+run path = do
+  hasQuestionnaireFile <- hasPathQuestionnaire path
+  if hasQuestionnaireFile then do
+    questionnaire <- decodeFileEither questionnaireFile
+    case questionnaire of
+      Right q -> mapM mapQuestion (getQuestions q)
+      Left e -> do
+        Logger.err unableToParseQuestionnaire
+        Logger.warning $ show e
+        exitFailure
+  else do
+    Logger.err $ projectQuestionnaireMissing path
+    exitFailure
+
+  where
+    questionnaireFile = questionnaireFileByPath path
+
+-- Map all the questions to answers
+mapQuestion :: (Text, Question) -> IO (Text, Value)
+mapQuestion (key, q) = do
+  answer <- ask q
+  return (key, answer)
+
+-- Ask a Question to get a response from the user
+ask :: Question -> IO Value
+ask (PasswordQuestion question) = do
+  res <- password question
+  return (String $ pack res)
+ask (SimpleQuestion question defaultValue) = do
+  res <- inputWithDefault question defaultValue
+  return (String $ pack res)
+ask (SelectQuestion question answers defaultValue) = do
+  res <- selectWithDefault question answers defaultValue
+  return (String $ pack res)
+ask (ConfirmQuestion question defaultValue) = do
+  res <- confirmWithDefault question defaultValue
+  return (Bool res)
+ask (MultiselectQuestion question answers defaultValues) = do
+  res <- multiselectWithDefault question answers defaultValues
+  return (Array $ V.fromList $ map (String . pack) res)
diff --git a/src/Rob/Tasks.hs b/src/Rob/Tasks.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Tasks.hs
@@ -0,0 +1,32 @@
+module Rob.Tasks where
+
+import qualified Rob.Package as Package
+import Rob.UserMessages (newTaskHelp, addTaskHelp, listTaskHelp, removeTaskHelp)
+import qualified Rob.Types as Types (Task(..))
+
+import System.Console.CmdArgs
+
+list :: Types.Task
+list = Types.List &= help listTaskHelp
+
+-- | New task factory function
+new :: Types.Task
+new = Types.New &= help newTaskHelp
+
+-- | New task factory function
+remove :: Types.Task
+remove = Types.Remove &= help removeTaskHelp
+
+-- | Add task factory function
+add :: Types.Task
+add = Types.Add {
+    Types.name = def &= typ "template-name" &= argPos 0,
+    Types.path = def &= typ "path/to/the/template/folder" &= argPos 1
+  } &= help addTaskHelp
+
+-- | Export all the command line modes
+mode :: Mode (CmdArgs Types.Task)
+mode = cmdArgsMode $ modes [new, add, remove, list]
+     &= help Package.description
+     &= program Package.name
+     &= summary (unwords [Package.name, "- v", Package.version, Package.author])
diff --git a/src/Rob/Types.hs b/src/Rob/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/Types.hs
@@ -0,0 +1,84 @@
+{-# LANGUAGE DeriveGeneric, DuplicateRecordFields, DeriveDataTypeable, OverloadedStrings #-}
+
+module Rob.Types where
+
+import GHC.Generics (Generic(..))
+import Data.HashMap.Strict (HashMap)
+import System.FilePath.Glob (Pattern)
+import Data.Text (Text)
+import Data.Yaml
+import System.Console.CmdArgs
+
+-- | Task struct listing all the available actions
+data Task
+  = Add {
+    name :: String,
+    path :: FilePath
+  }
+  | List
+  | Remove
+  | New deriving (Data, Typeable, Show)
+
+-- | Template name + path
+data Template = Template String FilePath deriving (Generic)
+
+instance Show Template where
+  show (Template name path) = unlines [
+      "- Name: " ++ name,
+      "  Path: " ++ path
+    ]
+
+instance Eq Template where
+  (Template nameA _) == (Template nameB _) = nameA == nameB
+
+instance FromJSON Template
+instance ToJSON Template
+
+-- | Config file struct
+newtype Config = Config {
+  templates :: [Template]
+} deriving (Generic, Show, Eq)
+
+instance FromJSON Config
+instance ToJSON Config
+
+-- | Question struct
+data Question =
+    SimpleQuestion String String
+  | PasswordQuestion String
+  | ConfirmQuestion String Bool
+  | SelectQuestion String [String] String
+  | MultiselectQuestion String [String] [String]
+  deriving (Show, Eq)
+
+instance FromJSON Question where
+  parseJSON (Object v) = do
+    questionType <- v .:? "type" .!= "simple"
+    parseJSON (Object v) >>= parseQuestion questionType
+
+parseQuestion :: String -> Value -> Parser Question
+parseQuestion questionType =
+  case questionType of
+    "confirm" -> withObject "ConfirmQuestion"
+      (\o -> ConfirmQuestion <$> o .: questionKey <*> o .:? defaultKey .!= False)
+    "select" -> withObject "SelectQuestion"
+      (\o -> SelectQuestion <$> o .: questionKey <*> o .:? answersKey .!= [] <*> o .:? defaultKey .!= "")
+    "multiselect" -> withObject "MultiselectQuestion"
+      (\o -> MultiselectQuestion <$> o .: questionKey <*> o .:? answersKey .!= [] <*> o .:? defaultKey .!= [])
+    "password" -> withObject "Password"
+      (\o -> PasswordQuestion <$> o .: questionKey)
+    _ -> withObject "SimpleQuestion"
+      (\o -> SimpleQuestion <$> o .: questionKey <*> o .:? defaultKey .!= "")
+  where
+    questionKey = "question"
+    answersKey = "answers"
+    defaultKey = "default"
+
+-- | Questionnaiere struct
+newtype Questionnaire = Questionnaire {
+  questions :: HashMap Text Question
+} deriving (Generic, Show, Eq)
+
+instance FromJSON Questionnaire
+
+type Blacklist = [(FilePath, [Pattern])]
diff --git a/src/Rob/UserMessages.hs b/src/Rob/UserMessages.hs
new file mode 100644
--- /dev/null
+++ b/src/Rob/UserMessages.hs
@@ -0,0 +1,99 @@
+module Rob.UserMessages where
+
+import qualified Rob.Package as Package
+
+-- Questions messages
+
+choseATemplate :: String
+choseATemplate = "Which template do you want to use?"
+
+choseATemplateToDelete :: String
+choseATemplateToDelete = "Which template do you want to delete?"
+
+-- Config messages
+
+configFileFound :: FilePath -> String
+configFileFound path = unwords [path, "was found!"]
+
+noConfigFileFound :: String -> String
+noConfigFileFound configFileName = unwords [
+    "No",
+    configFileName,
+    "file was found in your $HOME path"
+  ]
+
+configFileCreated :: FilePath -> [String]
+configFileCreated path = [
+    "Creating a new config file in:",
+    path
+  ]
+
+-- Tasks help
+
+newTaskHelp :: String
+newTaskHelp = "Create a new project in the current folder"
+
+addTaskHelp :: String
+addTaskHelp = "Add a new project template"
+
+listTaskHelp :: String
+listTaskHelp = "List all the available projects templates"
+
+removeTaskHelp :: String
+removeTaskHelp = "Remove a template from the list of the ones available"
+
+-- Errors
+
+noTemplatesAvailable :: String
+noTemplatesAvailable = "It was not possible to find any project template. Have you ever tried adding one?"
+
+noTemplateSelected :: String
+noTemplateSelected = "No template selected. Please select one the list"
+
+tryAddingATemplate :: String
+tryAddingATemplate = "Try: " ++ Package.name ++ " " ++ "new template-name path/to/the/template/folder"
+
+unableToParseQuestionnaire :: String
+unableToParseQuestionnaire = "It was not able to parse the project questionnaire"
+
+
+projectPathDoesNotExist :: FilePath -> String
+projectPathDoesNotExist path = unwords [
+    "The path to",
+    "\"" ++ path ++ "\"",
+    "does not exist!"
+  ]
+
+projectQuestionnaireMissing :: FilePath -> String
+projectQuestionnaireMissing path = unwords [
+    "It was not possible to find any project.yml in",
+    "\"" ++ path ++ "\"",
+    "Please make sure to have a questionnaire project.yml in your template!"
+  ]
+
+projectAdded :: String -> String
+projectAdded name = unwords [
+    name,
+    "was added to your projects templates!"
+  ]
+
+parserError :: String
+parserError = "There was a parser error, this file will only be copied"
+
+-- General info
+
+availableTemplates :: String
+availableTemplates = "Available Templates:"
+
+-- Success messages
+
+projectSuccessfullyCreated :: String
+projectSuccessfullyCreated = "Your project was successfully created"
+
+fileCreated :: String -> String
+fileCreated file = unwords ["Create:", file]
+
+-- Helpers
+
+emptyString :: String
+emptyString = ""
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"
