diff --git a/.ghci b/.ghci
new file mode 100644
--- /dev/null
+++ b/.ghci
@@ -0,0 +1,1 @@
+:set -isrc -idist/build/autogen -optP-include -optPdist/build/autogen/cabal_macros.h
diff --git a/.gitignore b/.gitignore
new file mode 100644
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+dist
+docs
+wiki
+TAGS
+tags
+wip
+.DS_Store
+.*.swp
+.*.swo
+*.o
+*.hi
+*~
+*#
+.cabal-sandbox
+cabal.sandbox.config
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,24 @@
+# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.
+env:
+ - GHCVER=7.4.2 CABALVER=1.16
+ - GHCVER=7.6.3 CABALVER=1.18
+ - GHCVER=head CABALVER=1.18 # see section about GHC HEAD snapshots
+
+before_install:
+ - sudo add-apt-repository -y ppa:hvr/ghc
+ - sudo apt-get update
+ - sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER happy hlint
+ - export PATH=/opt/ghc/$GHCVER/bin:$PATH
+
+install:
+ - cabal-$CABALVER update
+ - cabal-$CABALVER install --only-dependencies --enable-tests --enable-benchmarks -j
+
+script:
+ - travis/script.sh
+ - hlint src
+
+matrix:
+  allow_failures:
+   - env: GHCVER=head CABALVER=1.18
+  fast_finish: true
diff --git a/.vim.custom b/.vim.custom
new file mode 100644
--- /dev/null
+++ b/.vim.custom
@@ -0,0 +1,31 @@
+" Add the following to your .vimrc to automatically load this on startup
+
+" if filereadable(".vim.custom")
+"     so .vim.custom
+" endif
+
+function StripTrailingWhitespace()
+  let myline=line(".")
+  let mycolumn = col(".")
+  silent %s/  *$//
+  call cursor(myline, mycolumn)
+endfunction
+
+" enable syntax highlighting
+syntax on
+
+" search for the tags file anywhere between here and /
+set tags=TAGS;/
+
+" highlight tabs and trailing spaces
+set listchars=tab:‗‗,trail:‗
+set list
+
+" f2 runs hasktags
+map <F2> :exec ":!hasktags -x -c --ignore src"<CR><CR>
+
+" strip trailing whitespace before saving
+" au BufWritePre *.hs,*.markdown silent! cal StripTrailingWhitespace()
+
+" rebuild hasktags after saving
+au BufWritePost *.hs silent! :exec ":!hasktags -x -c --ignore src"
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright 2013 Benno Fünfstück
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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,88 @@
+Themplate
+=========
+
+[![Build Status](https://travis-ci.org/bennofs/themplate.png?branch=master)](https://travis-ci.org/bennofs/themplate)
+
+This is a very simple program for creating project templates. 
+
+Installing Themplate
+--------------------
+
+### From hackage:
+
+```
+$ cabal install themplate
+```
+
+### From repository:
+
+Checkout the source code:
+
+```
+$ git clone https://github.com/bennofs/themplate
+$ cd themplate
+```
+
+Build in a cabal sandbox and install:
+
+```
+$ cabal sandbox init
+$ cabal install --prefix=~/.cabal   # Install themplate executable to ~/.cabal/bin/themplate
+```
+
+Using Themplate
+---------------
+
+To use a exisiting template with themplate, just run:
+
+```
+$ themplate init <project name> <template name>
+```
+
+This will initialize the template with the given name in a new directory with the name of the project.
+
+To list all available templates, run:
+
+```
+$ themplate list
+```
+
+Configuration file
+------------------
+
+The configuration file is read using configurator, the syntax is described [here](http://hackage.haskell.org/package/configurator-0.2.0.2/docs/Data-Configurator.html).
+The options are passed to the template, so they can use patterns to include user-specific information. An example configuration file could look like this:
+
+```
+user { 
+  name = "Benno Fünfstück"
+  email = "benno.fuenfstueck@gmail.com"
+}
+
+github {
+  user = "bennofs"
+}
+```
+
+This will make the options `user.name`, `user.email` and `github.user` available to templates.
+
+Creating templates
+------------------
+
+A template is just a subdirectory in `~/.themplate`. When a new project is created with the template, the files in that directory are
+copied to the project directory. The files contents and the file names in the template can contain patterns. Patterns are enclosed
+in `{{` and `}}`. In a pattern, the following special forms are substituted:
+
+- `$$name$$` will be substituted for the value of the configuration option `name`. An error is thrown if the configuration option doesn't exist.
+- `??name??` will be substituted for the value of the configuration option `name`. If the configuration option doesn't exist, the pattern will
+   evaluate to the empty string.
+
+There is one special configuration option, `project.name`. This will always be set to the current project's name. `??name??` patterns are checked prior to ``$$name$$`` patterns, so the following:
+
+```
+{{homepage:      http://github.com/??github.user??/$$project.name$$/}}
+```
+
+won't throw an error if `github.user` is unset, even if `project.name` was unset.
+
+You can find an example template at https://github.com/bennofs/dotfiles/tree/master/.themplate/.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,7 @@
+{-# OPTIONS_GHC -Wall #-}
+module Main (main) where
+
+import Distribution.Simple ( defaultMain )
+
+main :: IO ()
+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,112 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module Main where
+
+import           Control.Error
+import           Control.Exception
+import           Control.Monad
+import           Control.Monad.Trans.Class
+import           Data.Configurator
+import           Data.Configurator.Types(Config())
+import           Data.Monoid
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import           Options.Applicative
+import           Pattern
+import           Prelude hiding (lookup)
+import           System.Directory
+import           System.Exit
+import           System.FilePath
+
+-- | This data type represents the result of parsing the command line options.
+data Cmd = Init String String Bool
+         | List
+
+-- | Command line argument parser for the 'init' subcommand. The init command can be used to instantiate templates.
+initCmd :: ParserInfo Cmd
+initCmd = info (helper <*> parser) (fullDesc <> progDesc "Use an installed template.")
+  where nameOpt = argument Just (metavar "NAME" <> help "The project name")
+        templatesOpt = argument Just (metavar "TEMPLATE" <> help "Name of the template which to use for this project")
+        amendOpt = switch (short 'a' <> long "amend" <> help "Don't fail when a file exists. Instead, ignore it and continue.")
+        parser = Init <$> nameOpt <*> templatesOpt <*> amendOpt
+
+-- | Command line argument parser for the 'list' subcommand. The list subcommand prints all installed templates.
+listCmd :: ParserInfo Cmd
+listCmd = info (helper <*> pure List) (briefDesc <> progDesc "List all installed templates")
+
+-- | Top level command line argument parser. Aggregates all subcommands.
+themplateCmds :: Parser Cmd
+themplateCmds = subparser $ mconcat
+  [ command "init"      initCmd
+  , command "list"      listCmd
+  ]
+
+-- | The parser info for this program. Specifies help and other information.
+optsInfo :: ParserInfo Cmd
+optsInfo = info (helper <*> themplateCmds) $ mconcat
+  [ fullDesc
+  , progDesc "Use project patterns to quickly create a new project"
+  ]
+
+-- | Get a list of all available templates in the given directory. The list of available templates
+-- is just the list of all directories under the given path.
+availableTemplates :: String -> IO [String]
+availableTemplates appData = getDirectoryContents appData >>= filterM f
+  where f x
+          | x `elem` [".",".."] = return False
+          | otherwise = doesDirectoryExist $ appData </> x
+
+-- | Instantiate a template, copying the files and resolving all conditionals and variables.
+-- The first argument is the project name, the second argument the directory of the template and the third argument is
+-- the target directory, to which the files get copied.
+instantiateTemplate :: String -> Bool -> Config -> FilePath -> FilePath -> EitherT T.Text IO ()
+instantiateTemplate proj amend c temp target = do
+  contents <- lift $ filter (not . flip elem [".",".."]) <$> getDirectoryContents temp
+  dirs <- lift $ filterM (doesDirectoryExist . (temp </>)) contents
+  files <- lift $ filterM (doesFileExist . (temp </>)) contents
+  
+  forM_ files $ \file -> do
+    let lookupVar "project.name" = return $ Just $ T.pack proj
+        lookupVar x = lookup c x 
+    let substitute = fmapLT (mappend $ T.pack file <> ":Error: Undeclared variable ") . substituteBetween "{{" "}}" (evalPattern lookupVar)
+
+    content <- lift $ T.readFile (temp </> file)
+    content' <- substitute content
+    file' <- fmap T.unpack $ substitute $ T.pack file
+
+    e <- lift $ doesFileExist (target </> file')
+    when (e && not amend) $ left $ ":Error: Target file " <> T.pack (target </> file') <> " does already exist."
+    unless e $ lift $ T.writeFile (target </> file') content'
+    
+  forM_ dirs $ \dir -> do 
+    lift $ createDirectoryIfMissing True $ target </> dir 
+    instantiateTemplate proj amend c (temp </> dir) (target </> dir)
+
+-- | Top level subcommand handler. Switches on the subcommand and performs the given action.
+-- Takes 3 arguments: The configuration, the path to the appUserDataDirectory and the command.
+handleCmd :: Config -> String -> Cmd -> IO ()
+handleCmd _ appData List = mapM_ putStrLn =<< availableTemplates appData
+handleCmd c appData (Init proj temp amend) = do
+  e <- doesDirectoryExist (appData </> temp)
+  unless e $ do
+    putStrLn $ "Error: Template " <> temp <> " is not installed."
+    exitFailure
+  targetExists <- doesDirectoryExist proj
+  unless targetExists $ createDirectory proj
+  projPath <- canonicalizePath proj
+  res <- runEitherT (instantiateTemplate proj amend c (appData </> temp) projPath) `catch` \(exc :: SomeException) ->
+    unless targetExists (removeDirectoryRecursive projPath) >> throw exc
+  case res of
+    Left m -> do
+      T.putStrLn m
+      removeDirectoryRecursive projPath
+      exitFailure
+    Right () -> exitSuccess
+
+main :: IO ()
+main = do
+  cmd <- execParser optsInfo
+  appData <- getAppUserDataDirectory "themplate"
+  createDirectoryIfMissing True appData
+  config <- load [Required $ appData </> "config.cfg"]
+  handleCmd config appData cmd
diff --git a/src/Pattern.hs b/src/Pattern.hs
new file mode 100644
--- /dev/null
+++ b/src/Pattern.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Pattern where
+
+import           Control.Applicative
+import           Control.Monad.Trans.Class
+import           Control.Monad.Trans.Either
+import           Control.Monad.Trans.Maybe
+import           Data.Maybe
+import           Data.Monoid
+import qualified Data.Text as T
+
+-- | Apply a function to replace the text between a given start and end tag.
+-- Example:
+--
+-- >>> runIdentity $ substituteBetween "%" "%" (return . map toUpper) "abcd%def%gh"
+-- "abcdDEFgh"
+substituteBetween :: Applicative f => T.Text -> T.Text -> (T.Text -> f T.Text) -> T.Text -> f T.Text
+substituteBetween open close f t
+  | T.null t = pure t
+  | T.null pat = (b <>) <$> substituteBetween open close f e
+  | otherwise = (\x y -> b <> x <> y) <$> f pat <*> substituteBetween open close f e
+  where (b,r) = T.breakOn open t
+        (pat,e') = T.breakOn close $ T.drop (T.length open) r
+        e = T.drop (T.length close) e'
+
+-- | Evaluate a pattern using the lookup function @f@. A pattern may contain the following special expressions:
+--
+--   - $$a$$ will be replaced with @f a@, returning Left a if @f@ returns Nothing
+--   - ??a?? will be replaced with @f a@, returning an empty string if @f@ returns Nothing
+evalPattern :: Monad f => (T.Text -> f (Maybe T.Text)) -> T.Text -> EitherT T.Text f T.Text
+evalPattern f t = replaceRequiredVar . fromMaybe T.empty =<< runMaybeT (replaceOptionalVar t)
+  where replaceRequiredVar = substituteBetween "$$" "$$" (\x -> maybe (left x) return =<< lift (f x))
+        replaceOptionalVar = substituteBetween "??" "??" (MaybeT . lift . f)
diff --git a/themplate.cabal b/themplate.cabal
new file mode 100644
--- /dev/null
+++ b/themplate.cabal
@@ -0,0 +1,43 @@
+name:          themplate
+version:       0.1
+license:       BSD3
+cabal-version: >= 1.10
+license-file:  LICENSE
+author:        Benno Fünfstück
+maintainer:    Benno Fünfstück <benno.fuenfstueck@gmail.com>
+stability:     experimental
+homepage:      http://github.com/bennofs/themplate/
+bug-reports:   http://github.com/bennofs/themplate/issues
+copyright:     Copyright (C) 2013 Benno Fünfstück
+synopsis:      themplate
+description:   themplate
+build-type:    Simple
+category:      Application, Console, Development, Template
+
+extra-source-files:
+  .ghci
+  .gitignore
+  .travis.yml
+  .vim.custom
+  README.md
+
+source-repository head
+  type: git
+  location: https://github.com/bennofs/themplate.git
+
+executable themplate
+  hs-source-dirs: src
+  main-is: Main.hs
+  other-modules: Pattern
+  default-language: Haskell2010
+  ghc-options: -Wall
+  build-depends:
+      base >= 4.4 && < 5
+    , filepath
+    , directory
+    , text
+    , transformers
+    , either
+    , optparse-applicative
+    , configurator
+    , errors
