diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, dbushenko
+
+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 dbushenko 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/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/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,29 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Trurl
+import System.Environment
+
+help :: IO ()
+help = do
+  putStrLn "trurl <command> [parameters]"
+  putStrLn "  update -- fetch the updates from repository"
+  putStrLn "  create <name> <project_template> -- create project of specified type with specified name"
+  putStrLn "  new <name> <template> <parameters_string> -- create file from the template with specified parameters, wrap it with \"\""
+  putStrLn "  list -- print all available templates"
+  putStrLn "  help <template> -- print template info"
+  putStrLn "  help -- print this help"
+  
+main :: IO ()
+main = do
+  args <- getArgs
+  case args of
+    []                              -> help
+    ["help"]                        -> help
+    ["help", template]              -> helpTemplate template
+    ["update"]                      -> updateFromRepository
+    ["create", name, project]       -> createProject name project
+    ["new", name, template, params] -> newTemplate name template params
+    ["list"]                        -> listTemplates
+    _                               -> putStrLn "Unknown command"
diff --git a/src/Trurl.hs b/src/Trurl.hs
new file mode 100644
--- /dev/null
+++ b/src/Trurl.hs
@@ -0,0 +1,130 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Trurl where
+
+import GHC.Exts
+import System.Directory
+import Network.HTTP.Conduit
+import Codec.Archive.Tar
+import Data.List
+import Text.Hastache 
+import Text.Hastache.Context
+import Data.Aeson
+import Data.Maybe
+import Data.Scientific
+import Data.String.Utils
+
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import qualified Data.Text.Lazy.IO as TL
+import qualified Data.ByteString.Lazy as BL
+import qualified Data.ByteString.Lazy.Char8 as BLC8
+import qualified Data.HashMap.Strict as HM
+
+mainRepoFile :: String
+mainRepoFile = "mainRepo.tar"
+
+mainRepo :: String
+mainRepo = "https://github.com/dbushenko/trurl/raw/master/repository/" ++ mainRepoFile
+
+getLocalRepoDir :: IO String
+getLocalRepoDir = do
+  home <- getHomeDirectory
+  return $ home ++ "/.trurl/repo/"
+  
+
+-- Команда "update"
+-- 1) Создать $HOME/.trurl/repo
+-- 2) Забрать из репозитория свежий tar-архив с апдейтами
+-- 3) Распаковать его в $HOME/.trurl/repo
+
+updateFromRepository :: IO ()
+updateFromRepository = do
+  repoDir <- getLocalRepoDir
+  createDirectoryIfMissing True repoDir
+  let tarFile = repoDir ++ mainRepoFile
+  simpleHttp mainRepo >>= BL.writeFile tarFile
+  extract repoDir tarFile
+  removeFile tarFile
+
+
+-- Команда "create <project> <name>"
+-- 1) Найти в $HOME/.trurl/repo архив с именем project.tar
+-- 2) Создать дирректорию ./name
+-- 3) Распаковать в ./name содержимое project.tar
+
+createProject :: String -> String -> IO ()
+createProject name project = do
+  repoDir <- getLocalRepoDir
+  createDirectoryIfMissing True name
+  extract name $ repoDir ++ project ++ ".tar"
+
+-- Команда "new <file> <parameters>"
+-- 1) Найти в $HOME/.trurl/repo архив с именем file.hs.
+--    Если имя файла передано с расширением, то найти точное имя файла, не подставляя *.hs
+-- 2) Прочитать содержимое шаблона
+-- 3) Отрендерить его с применением hastache и переденных параметров
+-- 4) Записать файл в ./
+
+getFileName :: String -> String
+getFileName template =
+  if "." `isInfixOf` template then template
+  else template ++ ".hs"
+
+getFullFileName :: String -> String -> String
+getFullFileName repoDir template = repoDir ++ getFileName template
+
+mkVariable :: Monad m => Maybe Value -> MuType m
+mkVariable (Just (String s)) = MuVariable s
+mkVariable (Just (Bool b)) = MuBool b
+mkVariable (Just (Number n)) = let e = floatingOrInteger n
+                                   mkval (Left r) = MuVariable (r :: Double)
+                                   mkval (Right i) = MuVariable (i :: Integer)
+                               in mkval e
+
+mkVariable (Just (Array ar)) = MuList $ map (mkStrContext . aesonContext . Just) (toList ar)
+mkVariable (Just o@(Object _)) = MuList [ mkStrContext $ aesonContext $ Just o ]
+mkVariable (Just Null) = MuVariable ("" :: String)                               
+mkVariable Nothing = MuVariable ("" :: String)
+
+aesonContext :: Monad m => Maybe Value -> String -> MuType m
+aesonContext mobj k = let obj = fromJust mobj
+                          Object o = obj
+                          v = HM.lookup (T.pack k) o
+                      in mkVariable v
+
+mkContext :: Monad m => String -> String -> MuType m
+mkContext paramsStr =
+  let mobj = decode (BLC8.pack paramsStr) :: Maybe Value
+  in if isNothing mobj then \_ -> MuVariable ("" :: String)
+     else aesonContext mobj
+
+newTemplate :: String -> String -> String -> IO ()
+newTemplate name templateName paramsStr = do
+  repoDir <- getLocalRepoDir
+  let templPath = getFullFileName repoDir templateName
+  template <- T.readFile templPath
+  generated <- hastacheStr defaultConfig template (mkStrContext (mkContext paramsStr))
+  TL.writeFile (getFileName name) generated
+
+printFile :: FilePath -> FilePath -> IO ()
+printFile dir fp = do
+  file <- readFile (dir ++ fp)
+  putStrLn file 
+
+printFileHeader :: FilePath -> FilePath -> IO ()
+printFileHeader dir fp = do
+  file <- readFile (dir ++ fp)
+  putStrLn $ head $ split "\n" file
+
+listTemplates :: IO ()
+listTemplates = do
+  repoDir <- getLocalRepoDir
+  files <- getDirectoryContents repoDir
+  let mpaths = filter (endswith ".metainfo") files
+  mapM_ (printFileHeader repoDir) mpaths
+
+helpTemplate :: String -> IO ()
+helpTemplate template = do
+  repoDir <- getLocalRepoDir
+  printFile repoDir ((getFileName template) ++ ".metainfo")
diff --git a/tests/Main.hs b/tests/Main.hs
new file mode 100644
--- /dev/null
+++ b/tests/Main.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+import Text.Hastache 
+import Text.Hastache.Context
+
+import qualified Trurl as T
+
+main :: IO ()
+main = defaultMain tests
+
+tests :: TestTree
+tests = testGroup "Tests" [unitTests]
+
+unitTests :: TestTree
+unitTests = testGroup "Unit tests"
+  [ testCase "getFullFileName" $
+      assertEqual "Checking full template path" "a/b.hs" (T.getFullFileName "a/" "b")
+
+  , testCase "getFileName" $
+      assertEqual "Checking file name" "abc.hs" (T.getFileName "abc")
+
+  , testCase "getFileName" $
+      assertEqual "Checking file name" "abc.html" (T.getFileName "abc.html")
+
+  , testCase "mkContext empty" $ do
+      generated <- hastacheStr defaultConfig "" (mkStrContext (T.mkContext "{\"a\":11}"))
+      assertEqual "Checking generated text" generated ""
+
+  , testCase "mkContext simple object" $ do
+      generated <- hastacheStr defaultConfig "{{a}}" (mkStrContext (T.mkContext "{\"a\":11}"))
+      assertEqual "Checking generated text" generated "11"
+
+  , testCase "mkContext complex object" $ do
+      generated <- hastacheStr defaultConfig "{{a}}-{{b}}" (mkStrContext (T.mkContext "{\"a\":11,\"b\":\"abc\"}"))
+      assertEqual "Checking generated text" generated "11-abc"
+
+  , testCase "mkContext complex array" $ do
+      generated <- hastacheStr defaultConfig "{{#abc}}{{name}}{{/abc}}" (mkStrContext (T.mkContext "{\"abc\":[{\"name\":\"1\"},{\"name\":\"2\"},{\"name\":\"3\"}]}"))
+      assertEqual "Checking generated text" generated "123"
+
+  , testCase "mkContext nested object" $ do
+      generated <- hastacheStr defaultConfig "{{#abc}}{{name}}{{/abc}}" (mkStrContext (T.mkContext "{\"abc\":{\"name\":\"1\"}}"))
+      assertEqual "Checking generated text" generated "1"
+
+  ]
diff --git a/trurl.cabal b/trurl.cabal
new file mode 100644
--- /dev/null
+++ b/trurl.cabal
@@ -0,0 +1,55 @@
+-- Initial trurl.cabal generated by cabal init.  For further documentation,
+--  see http://haskell.org/cabal/users-guide/
+
+name:                trurl
+version:             0.1.0.0
+synopsis:            Haskell template code generator
+-- description:         
+homepage:            http://github.com/dbushenko/trurl
+license:             BSD3
+license-file:        LICENSE
+author:              dbushenko
+maintainer:          d.bushenko@gmail.com
+-- copyright:           
+category:            Development
+build-type:          Simple
+-- extra-source-files:  
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Trurl
+  hs-source-dirs:      src
+  build-depends:       base >=4.7 && <4.8
+                     , http-conduit
+                     , directory
+                     , bytestring
+                     , text
+                     , tar
+                     , hastache
+                     , aeson
+                     , scientific
+                     , unordered-containers
+                     , MissingH
+                     
+  default-language:    Haskell2010
+
+
+executable trurl
+  main-is:             src/Main.hs
+  build-depends:       base >=4.7 && <4.8
+                     , trurl
+
+  default-language:    Haskell2010
+
+
+  
+test-suite tests
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          tests/Main.hs
+  build-depends:    base >=4.7 && <4.8
+                  , hastache
+                  , tasty
+                  , tasty-hunit
+                  , trurl
+                  
