diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2016
+
+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/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,20 @@
+module Main where
+
+import           System.Environment (getArgs, getProgName)
+import           Templating
+
+main :: IO ()
+main =
+  do
+    args <- getArgs
+    progName <- getProgName
+
+    case args of
+      [filename, iface, ssid, passphrase] ->
+        do
+          (scriptFile, dataFile) <- createFiles filename iface ssid passphrase
+          putStrLn $ "Created " ++ scriptFile ++ " and " ++ dataFile
+
+      _ ->
+        putStrLn $ "Usage:\n\t"
+        ++ progName ++ " <filename> <interface> <ssid> <passphrase>"
diff --git a/hifi.cabal b/hifi.cabal
new file mode 100644
--- /dev/null
+++ b/hifi.cabal
@@ -0,0 +1,50 @@
+name:                hifi
+version:             0.1.0.0
+synopsis:            Initial project template from stack
+description:         Please see README.md
+homepage:            https://gitlab.com/gonz/hifi
+license:             BSD3
+license-file:        LICENSE
+author:              Rickard Andersson
+maintainer:          gonz@severnatazvezda.com
+copyright:           2016 Rickard Andersson
+category:            CLI
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+data-files:          templates/*.mustache
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Templating, Config
+  build-depends:       base >= 4.7 && < 5
+                     , mustache
+                     , directory
+                     , text
+                     , process
+                     , parsec
+                     , filepath
+                     , unix
+  default-language:    Haskell2010
+  other-modules:       Paths_hifi
+
+executable hifi
+  hs-source-dirs:      app
+  main-is:             Main.hs
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  build-depends:       base
+                     , hifi
+  default-language:    Haskell2010
+
+test-suite hifi-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , hifi
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://gitlab.com/gonz/hifi
diff --git a/src/Config.hs b/src/Config.hs
new file mode 100644
--- /dev/null
+++ b/src/Config.hs
@@ -0,0 +1,16 @@
+module Config (templateDir, dataDir, scriptDir) where
+
+import System.Directory
+import Paths_hifi
+
+createIfMissingPath :: FilePath -> IO FilePath
+createIfMissingPath path = createDirectoryIfMissing True path >> return path
+
+templateDir :: IO FilePath
+templateDir = getDataFileName "templates"
+
+dataDir :: IO FilePath
+dataDir = getXdgDirectory XdgData "hifi/data" >>= createIfMissingPath
+
+scriptDir :: IO FilePath
+scriptDir = getXdgDirectory XdgData "hifi/scripts" >>= createIfMissingPath
diff --git a/src/Templating.hs b/src/Templating.hs
new file mode 100644
--- /dev/null
+++ b/src/Templating.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Templating (createFiles) where
+
+import qualified Config
+import qualified Data.Text.IO      as TextIO
+import           System.FilePath   ((</>))
+import           System.Posix.Files
+import qualified System.IO         as IO
+import           System.Process
+import           Text.Mustache
+import           Text.Parsec.Error (ParseError)
+
+data ScriptSpec = ScriptSpec { interface :: String, dataFilename :: String}
+
+instance ToMustache ScriptSpec where
+  toMustache spec = object ["interface" ~> interface spec,
+                            "data_filename" ~> dataFilename spec]
+
+data DataSpec = DataSpec { wpaPassphraseOutput :: String}
+
+instance ToMustache DataSpec where
+  toMustache spec = object ["wpa_passphrase_output" ~> wpaPassphraseOutput spec]
+
+type Interface = String
+type SSID = String
+type Passphrase = String
+
+createScript :: FilePath -> Interface -> FilePath -> IO (Either ParseError FilePath)
+createScript filename iface dataFile =
+  createFile filename Config.scriptDir scriptSpec "script.mustache"
+  where scriptSpec = ScriptSpec { interface = iface, dataFilename = dataFile }
+
+runWPAPassphrase :: SSID -> Passphrase -> IO String
+runWPAPassphrase ssid passphrase = do
+  (_, Just hout, _, _) <- createProcess wpa_passphrase_process
+                          { std_out = CreatePipe }
+  IO.hGetContents hout
+  where wpa_passphrase_process = (proc "wpa_passphrase" [ssid, passphrase])
+
+createData :: FilePath -> String -> IO (Either ParseError FilePath)
+createData filename wpaPPoutput =
+  createFile filename Config.dataDir dataSpec "data.mustache"
+  where dataSpec = DataSpec {wpaPassphraseOutput = wpaPPoutput}
+
+createFile :: ToMustache a => FilePath -> IO FilePath -> a -> FilePath
+  -> IO (Either ParseError FilePath)
+createFile filename outputDirFunc spec templateFile = do
+  templateDir <- Config.templateDir
+  outputDir <- outputDirFunc
+  compiled <- automaticCompile [templateDir] templateFile
+  let outputPath = outputDir </> filename
+  case compiled of
+    Left err -> return (Left err)
+    Right template -> do
+      TextIO.writeFile outputPath $ substitute template spec
+      return (Right outputPath)
+
+createFiles :: FilePath -> Interface -> SSID -> Passphrase
+  -> IO (FilePath, FilePath)
+createFiles filename iface ssid passphrase = do
+  wpaPPoutput <- runWPAPassphrase ssid passphrase
+  (Right dataFile) <- createData filename wpaPPoutput
+  (Right scriptFile) <- createScript filename iface dataFile
+  setFileMode scriptFile ownerModes
+  setFileMode dataFile (unionFileModes ownerWriteMode ownerReadMode)
+  return (dataFile, scriptFile)
diff --git a/templates/data.mustache b/templates/data.mustache
new file mode 100644
--- /dev/null
+++ b/templates/data.mustache
@@ -0,0 +1,3 @@
+ctrl_interface=DIR=/run/wpa_supplicant
+{{{wpa_passphrase_output}}}
+
diff --git a/templates/script.mustache b/templates/script.mustache
new file mode 100644
--- /dev/null
+++ b/templates/script.mustache
@@ -0,0 +1,4 @@
+#!/bin/bash
+sudo ip link set {{interface}} up
+sudo wpa_supplicant -B -D nl80211 -c {{data_filename}} -i {{interface}}
+sudo dhcpcd -A {{interface}}
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"
