diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2015 Alexander Thiemann <mail@athiemann.net>
+Copyright (c) 2015 - 2016 Alexander Thiemann <mail@athiemann.net>
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,14 +1,15 @@
 typed-wire
 =====
 
-[![Build Status](https://travis-ci.org/agrafix/typed-wire.svg)](https://travis-ci.org/agrafix/typed-wire)
+[![Build Status](https://travis-ci.org/typed-wire/typed-wire.svg)](https://travis-ci.org/typed-wire/typed-wire)
 [![Hackage](https://img.shields.io/hackage/v/typed-wire.svg)](http://hackage.haskell.org/package/typed-wire)
 
 ## Intro
 
 Hackage: [typed-wire](http://hackage.haskell.org/package/typed-wire)
+Stackage: [typed-wire](https://www.stackage.org/package/typed-wire)
 
-WIP: Language idependent type-safe communication
+Language idependent type-safe communication
 
 ## Cli Usage: twirec
 
@@ -17,7 +18,7 @@
 Generate bindings using typed-wire for different languages
 
 Usage: twirec [--version] [-i|--include-dir DIR] [-e|--entrypoint MODULE-NAME]
-              [--hs-out DIR] [--elm-out DIR]
+              [--hs-out DIR] [--elm-out DIR] [--purescript-out DIR]
   Language idependent type-safe communication
 
 Available options:
@@ -28,14 +29,16 @@
                            Entrypoint for compiler
   --hs-out DIR             Generate Haskell bindings to specified dir
   --elm-out DIR            Generate Elm bindings to specified dir
+  --purescript-out DIR     Generate PureScript bindings to specified dir
 
 ```
 
 ## Install
 
 * Using cabal: `cabal install typed-wire`
-* From Source (cabal): `git clone https://github.com/agrafix/typed-wire.git && cd typed-wire && cabal install`
-* From Source (stack): `git clone https://github.com/agrafix/typed-wire.git && cd typed-wire && stack build`
+* Using Stack: `stack install typed-wire`
+* From Source (cabal): `git clone https://github.com/typed-wire/typed-wire.git && cd typed-wire && cabal install`
+* From Source (stack): `git clone https://github.com/typed-wire/typed-wire.git && cd typed-wire && stack build`
 
 
 ## Misc
@@ -47,4 +50,4 @@
 ### License
 
 Released under the MIT license.
-(c) 2015 Alexander Thiemann <mail@athiemann.net>
+(c) 2015 - 2016 Alexander Thiemann <mail@athiemann.net>
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -6,8 +6,10 @@
 import TW.Check
 import TW.Loader
 import TW.Parser
+import TW.Types
 import qualified TW.CodeGen.Elm as Elm
 import qualified TW.CodeGen.Haskell as HS
+import qualified TW.CodeGen.PureScript as PS
 
 import qualified Paths_typed_wire as Meta
 
@@ -27,6 +29,7 @@
    , o_entryPoints :: [ModuleName]
    , o_hsOutDir :: Maybe FilePath
    , o_elmOutDir :: Maybe FilePath
+   , o_psOutDir :: Maybe FilePath
    }
 
 optParser :: Parser Options
@@ -37,6 +40,7 @@
     <*> entryPointsP
     <*> hsOutP
     <*> elmOutP
+    <*> psOutP
 
 sourceDirsP :: Parser [FilePath]
 sourceDirsP =
@@ -63,6 +67,11 @@
     optional $ strOption $
     long "elm-out" <> metavar "DIR" <> help "Generate Elm bindings to specified dir"
 
+psOutP :: Parser (Maybe FilePath)
+psOutP =
+    optional $ strOption $
+    long "purescript-out" <> metavar "DIR" <> help "Generate PureScript bindings to specified dir"
+
 main :: IO ()
 main =
     execParser opts >>= run
@@ -103,19 +112,21 @@
                Left err -> fail err
                Right readyModules ->
                    do _ <- T.forM (o_hsOutDir opts) $ \dir ->
-                          do storeLib dir HS.makeLibraryModule
+                          do T.putStrLn $
+                                  "Required Haskell library is "
+                                  <> li_name HS.libraryInfo <> "@" <> li_version HS.libraryInfo
                              mapM_ (runner dir HS.makeModule HS.makeFileName) readyModules
                       _ <- T.forM (o_elmOutDir opts) $ \dir ->
-                          do storeLib dir Elm.makeLibraryModule
+                          do T.putStrLn $
+                                  "Required Elm library is "
+                                  <> li_name Elm.libraryInfo <> " version " <> li_version Elm.libraryInfo
                              mapM_ (runner dir Elm.makeModule Elm.makeFileName) readyModules
+                      _ <- T.forM (o_psOutDir opts) $ \dir ->
+                          do T.putStrLn $
+                                  "Required PureScript library is "
+                                  <> li_name PS.libraryInfo <> " version " <> li_version PS.libraryInfo
+                             mapM_ (runner dir PS.makeModule PS.makeFileName) readyModules
                       return ()
-
-storeLib :: FilePath -> (FilePath, T.Text) -> IO ()
-storeLib baseDir (baseLoc, content) =
-    do let loc = baseDir </> baseLoc
-       createDirectoryIfMissing True (takeDirectory loc)
-       putStrLn $ "Writing library " <> loc <> " ..."
-       T.writeFile loc content
 
 runner :: FilePath -> (Module -> T.Text) -> (ModuleName -> FilePath) -> Module -> IO ()
 runner baseDir mkModule mkFilename m =
diff --git a/src/TW/Ast.hs b/src/TW/Ast.hs
--- a/src/TW/Ast.hs
+++ b/src/TW/Ast.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 module TW.Ast where
 
+import Network.HTTP.Types.Method
 import qualified Data.Text as T
 
 newtype ModuleName
@@ -30,6 +31,14 @@
     = ChoiceName { unChoiceName :: T.Text }
       deriving (Show, Eq, Ord)
 
+newtype ApiName
+    = ApiName { unApiName :: T.Text }
+      deriving (Show, Eq, Ord)
+
+newtype EndpointName
+    = EndpointName { unEndpointName :: T.Text }
+      deriving (Show, Eq, Ord)
+
 data QualTypeName
    = QualTypeName
    { qtn_module :: ModuleName
@@ -41,7 +50,41 @@
    { m_name :: ModuleName
    , m_imports :: [ModuleName]
    , m_typeDefs :: [TypeDef]
+   , m_apis :: [ApiDef]
    } deriving (Show, Eq)
+
+data ApiDef
+   = ApiDef
+   { ad_name :: ApiName
+   , ad_headers :: [ApiHeader]
+   , ad_endpoints :: [ApiEndpointDef]
+   } deriving (Show, Eq)
+
+data ApiEndpointDef
+   = ApiEndpointDef
+   { aed_name :: EndpointName
+   , aed_verb :: StdMethod
+   , aed_route :: [ApiRouteComp]
+   , aed_headers :: [ApiHeader]
+   , aed_req :: Maybe Type
+   , aed_resp :: Type
+   } deriving (Show, Eq)
+
+data ApiRouteComp
+   = ApiRouteStatic T.Text
+   | ApiRouteDynamic Type
+     deriving (Show, Eq)
+
+data ApiHeader
+   = ApiHeader
+   { ah_name :: T.Text
+   , ah_value :: ApiHeaderValue
+   } deriving (Show, Eq)
+
+data ApiHeaderValue
+   = ApiHeaderValueStatic T.Text
+   | ApiHeaderValueDynamic
+     deriving (Show, Eq)
 
 data TypeDef
    = TypeDefEnum EnumDef
diff --git a/src/TW/BuiltIn.hs b/src/TW/BuiltIn.hs
--- a/src/TW/BuiltIn.hs
+++ b/src/TW/BuiltIn.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 module TW.BuiltIn
     ( BuiltIn(..)
-    , allBuiltIns, isBuiltIn
+    , allBuiltIns, isBuiltIn, builtInAsType, pathPieceTypes, isPathPiece
     , tyString, tyInt, tyFloat, tyBool, tyMaybe, tyBytes, tyList, tyDateTime, tyDate, tyTime
     )
 where
@@ -17,8 +17,17 @@
    , bi_args :: [TypeVar]
    } deriving (Show, Eq)
 
+builtInAsType :: BuiltIn -> Type
+builtInAsType (BuiltIn qt args) = TyCon qt (map TyVar args)
+
 allBuiltIns :: [BuiltIn]
 allBuiltIns = [tyString, tyInt, tyFloat, tyBool, tyMaybe, tyBytes, tyList, tyDateTime, tyDate, tyTime]
+
+pathPieceTypes :: [BuiltIn]
+pathPieceTypes = [tyString, tyInt, tyFloat, tyBool]
+
+isPathPiece :: Type -> Bool
+isPathPiece t = t `elem` map builtInAsType pathPieceTypes
 
 isBuiltIn :: Type -> Maybe (BuiltIn, [Type])
 isBuiltIn ty =
diff --git a/src/TW/Check.hs b/src/TW/Check.hs
--- a/src/TW/Check.hs
+++ b/src/TW/Check.hs
@@ -43,9 +43,8 @@
        let isValidType args t =
                case t of
                  TyVar tv ->
-                     if tv `elem` args
-                     then return ()
-                     else throwError $ "Undefined type variable " ++ show tv ++ " in " ++ currentMStr
+                     unless (tv `elem` args) $
+                     throwError $ "Undefined type variable " ++ show tv ++ " in " ++ currentMStr
                  TyCon qt qtArgs ->
                      case M.lookup qt defTypes of
                        Nothing ->
@@ -55,16 +54,26 @@
                               when (length tvars /= length qtArgs) $
                                    throwError $
                                    "Type " ++ show qt ++ " got applied wrong number of arguments in " ++ currentMStr
+           checkRoute r =
+               case r of
+                 ApiRouteDynamic t ->
+                   unless (isPathPiece t) $
+                   throwError $
+                   "Invalid route parameter " ++ show t ++ ". Route parameters can only be primitive types!"
+                 _ -> return ()
        forM_ (m_typeDefs m) $ \td ->
            case td of
              TypeDefEnum ed ->
                  forM_ (ed_choices ed) $ \ch ->
-                 case ec_arg ch of
-                   Nothing -> return ()
-                   Just ty -> isValidType (ed_args ed) ty
+                 forM_ (ec_arg ch) (isValidType (ed_args ed))
              TypeDefStruct sd ->
                  forM_ (sd_fields sd) $ \fld ->
-                 do isValidType (sd_args sd) (sf_type fld)
+                 isValidType (sd_args sd) (sf_type fld)
+       forM_ (m_apis m) $ \api ->
+          forM_ (ad_endpoints api) $ \ep ->
+          do mapM_ (isValidType []) (aed_req ep)
+             isValidType [] (aed_resp ep)
+             mapM_ checkRoute (aed_route ep)
        return m
     where
       getDefinedTypes m =
diff --git a/src/TW/CodeGen/Elm.hs b/src/TW/CodeGen/Elm.hs
--- a/src/TW/CodeGen/Elm.hs
+++ b/src/TW/CodeGen/Elm.hs
@@ -1,16 +1,15 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
 module TW.CodeGen.Elm
     ( makeFileName, makeModule
-    , makeLibraryModule
+    , libraryInfo
     )
 where
 
 import TW.Ast
 import TW.BuiltIn
 import TW.JsonRepr
+import TW.Types
 
-import Data.FileEmbed
 import Data.Maybe
 import Data.Monoid
 import System.FilePath
@@ -29,16 +28,13 @@
 jsonDec :: T.Text -> T.Text
 jsonDec x = jsonDecQual <> "." <> x
 
-makeLibraryModule :: (FilePath, T.Text)
-makeLibraryModule =
-    ( "TW/Support/Lib.elm"
-    , $(embedStringFile "support/elm/Lib.elm")
-    )
-
 makeFileName :: ModuleName -> FilePath
 makeFileName (ModuleName parts) =
     (L.foldl' (</>) "" $ map T.unpack parts) ++ ".elm"
 
+libraryInfo :: LibraryInfo
+libraryInfo = LibraryInfo "elm-typed-wire-utils" "1.0.0"
+
 makeModule :: Module -> T.Text
 makeModule m =
     T.unlines
@@ -47,7 +43,7 @@
     , ""
     , T.intercalate "\n" (map makeImport $ m_imports m)
     , ""
-    , "import TW.Support.Lib as ELib"
+    , "import TypedWire as ELib"
     , "import List as L"
     , "import Json.Decode as " <> jsonDecQual
     , "import Json.Decode exposing ((:=))"
diff --git a/src/TW/CodeGen/Haskell.hs b/src/TW/CodeGen/Haskell.hs
--- a/src/TW/CodeGen/Haskell.hs
+++ b/src/TW/CodeGen/Haskell.hs
@@ -1,35 +1,33 @@
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 module TW.CodeGen.Haskell
     ( makeFileName, makeModule
-    , makeLibraryModule
+    , libraryInfo
     )
 where
 
 import TW.Ast
 import TW.BuiltIn
 import TW.JsonRepr
+import TW.Types
+import TW.Utils
 
 import Data.Char
-import Data.FileEmbed
 import Data.Maybe
 import Data.Monoid
 import System.FilePath
 import qualified Data.List as L
 import qualified Data.Text as T
 
+libraryInfo :: LibraryInfo
+libraryInfo = LibraryInfo "typed-wire-utils" "0.1.0.0"
+
 aesonQual :: T.Text
 aesonQual = "Data_Aeson_Lib"
 
 aeson :: T.Text -> T.Text
 aeson x = aesonQual <> "." <> x
 
-makeLibraryModule :: (FilePath, T.Text)
-makeLibraryModule =
-    ( "TW/Support/Lib.hs"
-    , $(embedStringFile "support/haskell/Lib.hs")
-    )
-
 makeFileName :: ModuleName -> FilePath
 makeFileName (ModuleName parts) =
     (L.foldl' (</>) "" $ map T.unpack parts) ++ ".hs"
@@ -44,20 +42,123 @@
     , ""
     , T.intercalate "\n" (map makeImport $ m_imports m)
     , ""
-    , "import qualified TW.Support.Lib as HLib"
+    , "import qualified Text.TypedWire as HLib"
     , "import Control.Applicative"
     , "import Control.Monad (join)"
     , "import Data.Time"
     , "import qualified Data.Aeson as " <> aesonQual
     , "import qualified Data.Text as T"
     , "import qualified Data.Vector as V"
+    , if not (null (m_apis m)) then "import Web.Spock\nimport Control.Monad.Trans" else ""
     , ""
     , T.intercalate "\n" (map makeTypeDef $ m_typeDefs m)
+    , T.intercalate "\n" (map makeApiDef $ m_apis m)
     ]
 
 makeImport :: ModuleName -> T.Text
 makeImport m =
     "import qualified " <> printModuleName m
+
+makeApiDef :: ApiDef -> T.Text
+makeApiDef ad =
+    T.unlines
+    [ "data " <> handlerType <> " m"
+    , "   = " <> handlerType
+    , "   { " <> T.intercalate "\n   , " (map makeEndPoint $ ad_endpoints ad)
+    , "   }"
+    , fromMaybe "" $ makeHeaderDef apiHeaderType ahprefix (ad_headers ad)
+    , T.intercalate "\n" (mapMaybe (\ep -> makeHeaderDef (headerType ep) (hprefix ep) (aed_headers ep)) $ ad_endpoints ad)
+    , "wire" <> apiCapitalized <> " :: MonadIO m => " <> handlerType <> " (ActionCtxT ctx m) -> SpockCtxT ctx m ()"
+    , "wire" <> apiCapitalized <> " handler ="
+    , "    do " <> T.intercalate "\n       " (map makeEndPointImpl $ ad_endpoints ad)
+    ]
+    where
+      apiCapitalized = capitalizeText (unApiName $ ad_name ad)
+      handlerType = "ApiHandler" <> apiCapitalized
+      apiHeaderType = handlerType <> "Headers"
+      headerType ep = handlerType <> capitalizeText (unEndpointName (aed_name ep)) <> "Headers"
+      hprefix ep = makeFieldPrefix $ TypeName (headerType ep)
+      ahprefix = makeFieldPrefix $ TypeName apiHeaderType
+      prefix = makeFieldPrefix $ TypeName handlerType
+      makeHeaderDef tyName tyPrefix headerList =
+        case headerList of
+          [] -> Nothing
+          _ ->
+            Just $ T.unlines
+            [ "data " <> tyName
+            , "   = " <> tyName
+            , "   { " <> T.intercalate "\n   , " (mapMaybe makeHeaderField headerList)
+            , "   }"
+            ]
+        where
+          makeHeaderField h =
+            case ah_value h of
+              ApiHeaderValueStatic _ -> Nothing
+              ApiHeaderValueDynamic ->
+                Just $
+                tyPrefix <> makeSafePrefixedFieldName (ah_name h) <> " :: !T.Text"
+      makeEndPoint ep =
+        prefix <> unEndpointName (aed_name ep) <> " :: "
+        <> (if not (null $ ad_headers ad) then apiHeaderType <> " -> " else "")
+        <> (if not (null $ aed_headers ep) then headerType ep <> " -> " else "")
+        <> T.intercalate " -> " (map makeType pathTypes)
+        <> (if not (null pathTypes) then " -> " else "")
+        <> maybe "" (\x -> makeType x <> " -> ") (aed_req ep)
+        <> "m " <> makeType (aed_resp ep) <> ""
+        where
+          pathTypes =
+            flip mapMaybe (aed_route ep) $ \x ->
+            case x of
+              ApiRouteDynamic dyn -> Just dyn
+              _ -> Nothing
+      makeHeaderLoader tyName headerList =
+        "do {"
+        <> T.intercalate "" (map makeGetter headerList)
+        <> T.intercalate "" (mapMaybe makeChecker headerList)
+        <> "return (" <> tyName <> " " <> T.intercalate " " (mapMaybe makeSetter headerList) <> ");"
+        <> "}"
+        where
+          varName h = "hp" <> makeSafePrefixedFieldName (ah_name h)
+          makeGetter h =
+            varName h <> " <- header " <> T.pack (show (ah_name h)) <> " >>= maybe jumpNext return;"
+          makeChecker h =
+            case ah_value h of
+              ApiHeaderValueStatic val ->
+                Just $ "when (" <> varName h <> " /= " <> T.pack (show val) <> ") jumpNext; "
+              _ -> Nothing
+          makeSetter h =
+            case ah_value h of
+              ApiHeaderValueDynamic -> Just (varName h)
+              _ -> Nothing
+      makeEndPointImpl ep =
+        "hookRoute " <> (T.pack $ show $ aed_verb ep)  <> " ("
+        <> T.intercalate " <//> " (map makePathComp  $ aed_route ep) <> ") $ "
+        <> (if not (null pathVars) then "\\" <> T.intercalate " " pathVars <> " -> " else "")
+        <> "do {"
+        <> (if not (null (ad_headers ad)) then "apiHeaders <- " <> makeHeaderLoader apiHeaderType (ad_headers ad) <> "; " else "")
+        <> (if not (null (aed_headers ep)) then "localHeaders <- " <> makeHeaderLoader (headerType ep) (aed_headers ep) <> "; " else "")
+        <> maybe "" (const "reqVal <- jsonBody';") (aed_req ep)
+        <> "out <- " <> prefix <> unEndpointName (aed_name ep) <> " handler "
+        <> (if not (null (ad_headers ad)) then "apiHeaders " else "")
+        <> (if not (null (aed_headers ep)) then "localHeaders " else "")
+        <> T.intercalate " " pathVars
+        <> " "
+        <> maybe "" (const "reqVal ") (aed_req ep)
+        <> ";"
+        <> "json out;"
+        <> "}"
+        where
+          pathVars =
+            map ((\(i :: Int) -> T.pack $ "pv" ++ show i) . snd) $
+            flip zip [0..] $
+            flip mapMaybe (aed_route ep) $ \x ->
+            case x of
+              ApiRouteDynamic _ -> Just ()
+              _ -> Nothing
+          makePathComp pc =
+            case pc of
+              ApiRouteStatic str -> T.pack (show str)
+              ApiRouteDynamic _ -> "var"
 
 makeTypeDef :: TypeDef -> T.Text
 makeTypeDef td =
diff --git a/src/TW/CodeGen/PureScript.hs b/src/TW/CodeGen/PureScript.hs
new file mode 100644
--- /dev/null
+++ b/src/TW/CodeGen/PureScript.hs
@@ -0,0 +1,296 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module TW.CodeGen.PureScript
+    ( makeFileName, makeModule
+    , libraryInfo
+    )
+where
+
+import TW.Ast
+import TW.BuiltIn
+import TW.JsonRepr
+import TW.Types
+import TW.Utils
+
+import Data.Maybe
+import Data.Monoid
+import System.FilePath
+import qualified Data.List as L
+import qualified Data.Text as T
+
+libraryInfo :: LibraryInfo
+libraryInfo = LibraryInfo "purescript-typed-wire" "0.2.0"
+
+makeFileName :: ModuleName -> FilePath
+makeFileName (ModuleName parts) =
+    (L.foldl' (</>) "" $ map T.unpack parts) ++ ".purs"
+
+makeModule :: Module -> T.Text
+makeModule m =
+    T.unlines
+    [ "module " <> printModuleName (m_name m) <> " where"
+    , ""
+    , T.intercalate "\n" (map makeImport $ m_imports m)
+    , ""
+    , "import Data.TypedWire.Prelude"
+    , if not (null (m_apis m)) then "import Data.TypedWire.Api" else ""
+    , ""
+    , T.intercalate "\n" (map makeTypeDef $ m_typeDefs m)
+    , T.intercalate "\n" (map makeApiDef $ m_apis m)
+    ]
+
+makeApiDef :: ApiDef -> T.Text
+makeApiDef ad =
+    T.unlines $
+    catMaybes
+    [ apiHeader
+    , Just $ T.intercalate "\n" (map makeEndPoint (ad_endpoints ad))
+    ]
+    where
+      apiHeader =
+        case not (null (ad_headers ad)) of
+          True -> Just $ makeHeaderType apiHeaderType (ad_headers ad)
+          False -> Nothing
+      apiCapitalized = capitalizeText (unApiName $ ad_name ad)
+      handlerType = "ApiHandler" <> apiCapitalized
+      apiHeaderType = handlerType <> "Headers"
+      headerType ep = handlerType <> capitalizeText (unEndpointName (aed_name ep)) <> "Headers"
+      makeHeaderName hdr = uncapitalizeText $ makeSafePrefixedFieldName (ah_name hdr)
+      makeHeaderType ty headers =
+        T.unlines
+        [ "type " <> ty <> " = "
+        , "    { " <> T.intercalate "\n    , " (map makeHeaderField headers)
+        , "    }"
+        ]
+      makeHeaderField hdr =
+        makeHeaderName hdr <> " :: String"
+      makeEndPoint ep =
+        T.unlines $
+        catMaybes
+        [ epHeader
+        , Just $ funName <> " :: forall m. (Monad m) => "
+          <> (maybe "" (const $ apiHeaderType <> " -> ") apiHeader)
+          <> (maybe "" (const $ headerType ep <> " -> ") epHeader)
+          <> urlParamSig
+          <> (maybe "" (\t -> makeType t <> " -> ") $ aed_req ep)
+          <> "ApiCall m " <> (maybe "Unit" makeType $ aed_req ep) <> " " <> makeType (aed_resp ep)
+        , Just $ funName
+          <> " "
+          <> (maybe "" (const "apiHeaders ") apiHeader)
+          <> (maybe "" (const "endpointHeaders ") epHeader)
+          <> urlParams
+          <> (maybe "" (const "reqBody ") $ aed_req ep)
+          <> "runRequest = do"
+        , Just $ "    let coreHeaders = [" <> T.intercalate ", " (map (headerPacker "apiHeaders") $ ad_headers ad) <> "]"
+        , Just $ "    let fullHeaders = coreHeaders ++ [" <> T.intercalate ", " (map (headerPacker "endpointHeaders") $ aed_headers ep) <> "]"
+        , Just $ "    let url = " <> T.intercalate " ++ \"/\" ++ " (map urlPacker routeInfo)
+        , Just $ "    let method = " <> T.pack (show $ aed_verb ep)
+        , Just $ "    let body = " <> (maybe "Nothing" (const "Just $ encodeJson reqBody") $ aed_req ep)
+        , Just $ "    let req = { headers: fullHeaders, method: method, body: body, url: url }"
+        , Just $ "    resp <- runRequest req"
+        , Just $ "    return $ if (resp.statusCode /= 200) then Left \"Return code was not 200\" else decodeJson resp.body"
+        ]
+        where
+          urlPacker (r, p) =
+            case r of
+              ApiRouteStatic t -> T.pack (show t)
+              ApiRouteDynamic _ -> "toPathPiece p" <> T.pack (show p) <> ""
+          headerPacker apiVar hdr =
+             "{ key: " <> T.pack (show $ ah_name hdr) <> ", value: " <> apiVar <> "." <> makeHeaderName hdr <> " }"
+          funName = unApiName (ad_name ad) <> capitalizeText (unEndpointName $ aed_name ep)
+          routeInfo = zip (aed_route ep) ([0..] :: [Int])
+          urlParams =
+            T.concat $ flip mapMaybe routeInfo $ \(r,p) ->
+            case r of
+              ApiRouteStatic _ -> Nothing
+              ApiRouteDynamic _ -> Just $ "p" <> T.pack (show p) <> " "
+          urlParamSig =
+            T.concat $ flip mapMaybe (aed_route ep) $ \r ->
+            case r of
+              ApiRouteStatic _ -> Nothing
+              ApiRouteDynamic ty -> Just (makeType ty <> " -> ")
+          epHeader =
+            case not (null (aed_headers ep)) of
+              True -> Just $ makeHeaderType (headerType ep) (aed_headers ep)
+              False -> Nothing
+
+makeImport :: ModuleName -> T.Text
+makeImport m =
+    "import qualified " <> printModuleName m <> " as " <> printModuleName m
+
+makeTypeDef :: TypeDef -> T.Text
+makeTypeDef td =
+    case td of
+      TypeDefEnum ed ->
+          makeEnumDef ed
+      TypeDefStruct sd ->
+          makeStructDef sd
+
+decoderName :: TypeName -> T.Text
+decoderName ty = "dec" <> unTypeName ty
+
+encoderName :: TypeName -> T.Text
+encoderName ty = "enc" <> unTypeName ty
+
+eqName :: TypeName -> T.Text
+eqName ty = "eq" <> unTypeName ty
+
+showName :: TypeName -> T.Text
+showName ty = "show" <> unTypeName ty
+
+makeStructDef :: StructDef -> T.Text
+makeStructDef sd =
+    T.unlines
+    [ "data " <> fullType
+    , "   = " <> unTypeName (sd_name sd)
+    , "   { " <> T.intercalate "\n   , " (map makeStructField $ sd_fields sd)
+    , "   }"
+    , ""
+    , "instance " <> eqName (sd_name sd) <> " :: "
+      <> tcPreds (sd_args sd) ["Eq"] <> "Eq (" <> fullType <> ") where "
+      <> "eq (" <> justType <> " a) (" <> justType <> " b) = "
+      <> T.intercalate " && " (map makeFieldEq (sd_fields sd))
+    , "instance " <> showName (sd_name sd) <> " :: "
+      <> tcPreds (sd_args sd) ["Show"] <> "Show (" <> fullType <> ") where "
+      <> "show (" <> justType <> " a) = " <> T.pack (show justType) <> " ++ \"{\" ++ "
+      <> T.intercalate " ++ " (map makeFieldShow (sd_fields sd))
+      <> " ++ \"}\""
+    , "instance " <> encoderName (sd_name sd) <> " :: "
+      <> tcPreds (sd_args sd) ["EncodeJson"] <> "EncodeJson" <> " (" <> fullType <> ") where"
+    , "    encodeJson (" <> unTypeName (sd_name sd) <> " objT) ="
+    , "        " <> T.intercalate "\n         ~> " (map makeToJsonFld $ sd_fields sd)
+    , "        ~> jsonEmptyObject"
+    , "instance " <> decoderName (sd_name sd) <> " :: "
+      <> tcPreds (sd_args sd) ["DecodeJson"] <> "DecodeJson" <> " (" <> fullType <> ") where"
+    , "    decodeJson jsonT = do"
+    , "        objT <- decodeJson jsonT"
+    , "        " <> T.intercalate "\n        " (map makeFromJsonFld $ sd_fields sd)
+    , "        pure $ " <> unTypeName (sd_name sd) <> " { " <> T.intercalate ", " (map makeFieldSetter $ sd_fields sd) <> " }"
+    ]
+    where
+      makeFieldShow fld =
+          let name = unFieldName $ sf_name fld
+          in  T.pack (show name) <> " ++ \": \" ++ show a." <> name
+      makeFieldEq fld =
+          let name = unFieldName $ sf_name fld
+          in  "a." <> name <> " == " <> "b." <> name
+      makeFieldSetter fld =
+          let name = unFieldName $ sf_name fld
+          in name <> " : " <> "v" <> name
+      makeFromJsonFld fld =
+          let name = unFieldName $ sf_name fld
+          in case sf_type fld of
+               (TyCon q _) | q == bi_name tyMaybe ->
+                  "v" <> name <> " <- objT .?? " <> T.pack (show name)
+               _ ->
+                  "v" <> name <> " <- objT .? " <> T.pack (show name)
+      makeToJsonFld fld =
+          let name = unFieldName $ sf_name fld
+          in T.pack (show name) <> " " <> ":=" <> " objT." <> name
+      justType = unTypeName (sd_name sd)
+      fullType =
+          unTypeName (sd_name sd) <> " " <> T.intercalate " " (map unTypeVar $ sd_args sd)
+
+makeStructField :: StructField -> T.Text
+makeStructField sf =
+    unFieldName (sf_name sf) <> " :: " <> makeType (sf_type sf)
+
+tcPreds :: [TypeVar] -> [T.Text] -> T.Text
+tcPreds args tyClasses =
+    if null args
+    then ""
+    else let mkPred (TypeVar tv) =
+                 T.intercalate "," $ flip map tyClasses $ \tyClass -> tyClass <> " " <> tv
+         in "(" <> T.intercalate "," (map mkPred args) <> ") => "
+
+makeEnumDef :: EnumDef -> T.Text
+makeEnumDef ed =
+    T.unlines
+    [ "data " <> fullType
+    , "   = " <> T.intercalate "\n   | " (map makeEnumChoice $ ed_choices ed)
+    , ""
+    , "instance " <> eqName (ed_name ed) <> " :: "
+      <> tcPreds (ed_args ed) ["Eq"] <> "Eq (" <> fullType <> ") where "
+    , "    " <> T.intercalate "\n    " (map makeChoiceEq $ ed_choices ed)
+    , "    eq _ _ = false"
+    , "instance " <> showName (ed_name ed) <> " :: "
+      <> tcPreds (ed_args ed) ["Show"] <> "Show (" <> fullType <> ") where "
+    , "    " <> T.intercalate "\n    " (map makeChoiceShow $ ed_choices ed)
+    , "instance " <> encoderName (ed_name ed) <> " :: "
+      <> tcPreds (ed_args ed) ["EncodeJson"] <> "EncodeJson" <> " (" <> fullType <> ") where"
+    , "    encodeJson x ="
+    , "        case x of"
+    , "          " <> T.intercalate "\n          " (map mkToJsonChoice $ ed_choices ed)
+    , "instance " <> decoderName (ed_name ed) <> " :: "
+      <> tcPreds (ed_args ed) ["DecodeJson"] <> "DecodeJson" <> " (" <> fullType <> ") where"
+    , "    decodeJson jsonT ="
+    , "        decodeJson jsonT >>= \\objT -> "
+    , "        " <> T.intercalate "\n        <|> " (map mkFromJsonChoice $ ed_choices ed)
+    ]
+    where
+      makeChoiceShow ec =
+          let constr = unChoiceName $ ec_name ec
+          in case ec_arg ec of
+                 Nothing -> "show (" <> constr <> ") = " <> T.pack (show constr)
+                 Just _ -> "show (" <> constr <> " a) = " <> T.pack (show constr) <> " ++ show a"
+      makeChoiceEq ec =
+          let constr = unChoiceName $ ec_name ec
+          in case ec_arg ec of
+                 Nothing -> "eq (" <> constr <> ") (" <> constr <> ") = true"
+                 Just _ -> "eq (" <> constr <> " a) (" <> constr <> " b) = a == b"
+      mkFromJsonChoice ec =
+          let constr = unChoiceName $ ec_name ec
+              tag = camelTo2 '_' $ T.unpack constr
+              (op, opEnd) =
+                  case ec_arg ec of
+                    Nothing -> ("<$ (eatBool <$> (", "))")
+                    Just _ -> ("<$>", "")
+          in "(" <> constr <> " " <> op <> " objT " <> ".?" <> " " <> T.pack (show tag) <> opEnd <> ")"
+      mkToJsonChoice ec =
+          let constr = unChoiceName $ ec_name ec
+              tag = camelTo2 '_' $ T.unpack constr
+              (argParam, argVal) =
+                  case ec_arg ec of
+                    Nothing -> ("", "true")
+                    Just _ -> ("y", "y")
+          in constr <> " " <> argParam <> " -> "
+             <> " " <> T.pack (show tag) <> " " <> " := " <> " " <> argVal <> " ~> jsonEmptyObject"
+      fullType =
+          unTypeName (ed_name ed) <> " " <> T.intercalate " " (map unTypeVar $ ed_args ed)
+
+makeEnumChoice :: EnumChoice -> T.Text
+makeEnumChoice ec =
+    (unChoiceName $ ec_name ec) <> fromMaybe "" (fmap ((<>) " " . makeType) $ ec_arg ec)
+
+makeType :: Type -> T.Text
+makeType t =
+    case isBuiltIn t of
+      Nothing ->
+          case t of
+            TyVar (TypeVar x) -> x
+            TyCon qt args ->
+                let ty = makeQualTypeName qt
+                in case args of
+                     [] -> ty
+                     _ -> "(" <> ty <> " " <> T.intercalate " " (map makeType args) <> ")"
+      Just (bi, tvars)
+          | bi == tyString -> "String"
+          | bi == tyInt -> "Int"
+          | bi == tyBool -> "Boolean"
+          | bi == tyFloat -> "Number"
+          | bi == tyMaybe -> "(Maybe " <> T.intercalate " " (map makeType tvars) <> ")"
+          | bi == tyBytes -> "AsBase64"
+          | bi == tyList -> "(Array " <> T.intercalate " " (map makeType tvars) <> ")"
+          | bi == tyDateTime -> "DateTime"
+          | bi == tyTime -> "TimeOfDay"
+          | bi == tyDate -> "Day"
+          | otherwise ->
+              error $ "Haskell: Unimplemented built in type: " ++ show t
+
+makeQualTypeName :: QualTypeName -> T.Text
+makeQualTypeName qtn =
+    case unModuleName $ qtn_module qtn of
+      [] -> ty
+      _ -> printModuleName (qtn_module qtn) <> "." <> ty
+    where
+      ty = unTypeName $ qtn_type qtn
diff --git a/src/TW/Parser.hs b/src/TW/Parser.hs
--- a/src/TW/Parser.hs
+++ b/src/TW/Parser.hs
@@ -8,10 +8,14 @@
 
 import TW.Ast
 
+import Data.Either
+import Data.Maybe
 import Control.Monad.Identity
 import Data.Char
 import Text.Parsec
+import Network.HTTP.Types.Method
 import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
 import qualified Data.Text.IO as T
 import qualified Text.Parsec.Token as P
 
@@ -41,8 +45,8 @@
        moduleName <- parseModuleName
        _ <- semi
        imports <- many parseImport
-       tyDefs <- many parseTypeDef
-       return $ Module moduleName imports tyDefs
+       tyDefs <- many ((Left <$> parseTypeDef) <|> (Right <$> parseApiDef))
+       return $ Module moduleName imports (lefts tyDefs) (rights tyDefs)
 
 parseModuleName :: Parser ModuleName
 parseModuleName =
@@ -56,6 +60,56 @@
        _ <- semi
        return m
 
+parseApiDef :: Parser ApiDef
+parseApiDef =
+    do reserved "api"
+       name <- identifier
+       (headers, endpoints) <-
+         braces $
+         do headers <-
+              optionMaybe $ try $ brackets (commaSep1 parseApiHeader) <* semi
+            ep <- many parseApiEndpoint
+            return (fromMaybe [] headers, ep)
+       return (ApiDef (ApiName $ T.pack name) headers endpoints)
+
+parseApiEndpoint :: Parser ApiEndpointDef
+parseApiEndpoint =
+    do name <- identifier
+       reservedOp "="
+       verbStr <- identifier
+       verb <-
+         case parseMethod (T.encodeUtf8 $ T.toUpper $ T.pack verbStr) of
+           Left _ -> fail $ "Unknown http verb: " ++ verbStr
+           Right v -> return v
+       route <- parens (slashSep1 parseRouteComp)
+       headers <- optionMaybe $ try $ brackets (commaSep1 parseApiHeader)
+       reservedOp ":"
+       req <- optionMaybe $ try (parseType <* reservedOp "->")
+       resp <- parseType
+       _ <- semi
+       return
+         ApiEndpointDef
+         { aed_name = EndpointName $ T.pack name
+         , aed_verb = verb
+         , aed_headers = fromMaybe [] headers
+         , aed_route = route
+         , aed_req = req
+         , aed_resp = resp
+         }
+
+parseApiHeader :: Parser ApiHeader
+parseApiHeader =
+    do name <- stringLiteral
+       val <-
+          (reservedOp "=" *> (ApiHeaderValueStatic <$> (T.pack <$> stringLiteral))) <|>
+          pure ApiHeaderValueDynamic
+       return (ApiHeader (T.pack name) val)
+
+parseRouteComp :: Parser ApiRouteComp
+parseRouteComp =
+    ApiRouteStatic <$> (T.pack <$> stringLiteral) <|>
+    ApiRouteDynamic <$> parseType
+
 parseTypeDef :: Parser TypeDef
 parseTypeDef =
     TypeDefEnum <$> parseEnumDef <|>
@@ -84,7 +138,7 @@
 
 parseStructField :: Parser StructField
 parseStructField =
-    do name <- (FieldName . T.pack <$> identifier)
+    do name <- FieldName . T.pack <$> identifier
        reservedOp ":"
        ty <- parseType
        _ <- semi
@@ -138,20 +192,27 @@
     , P.identLetter = alphaNum <|> oneOf "_"
     , P.opStart = oneOf ":!#$%&*+./<=>?@\\^|-~"
     , P.opLetter = oneOf ":!#$%&*+./<=>?@\\^|-~"
-    , P.reservedNames = ["module", "type", "enum", "import", "as"]
-    , P.reservedOpNames = [":", "->"]
+    , P.reservedNames =
+        [ "module", "type", "enum", "api", "import", "as" ]
+    , P.reservedOpNames = [":", "->", "/", "="]
     , P.caseSensitive = False
     }
 
 lexer :: P.GenTokenParser T.Text () Identity
 lexer = P.makeTokenParser languageDef
 
+stringLiteral :: Parser String
+stringLiteral = P.stringLiteral lexer
+
 parens :: Parser a -> Parser a
 parens = P.parens lexer
 
 braces :: Parser a -> Parser a
 braces = P.braces lexer
 
+brackets :: Parser a -> Parser a
+brackets = P.brackets lexer
+
 angles :: Parser a -> Parser a
 angles = P.angles lexer
 
@@ -175,6 +236,9 @@
 
 dotSep1 :: Parser a -> Parser [a]
 dotSep1 p = sepBy p dot
+
+slashSep1 :: Parser a -> Parser [a]
+slashSep1 p = sepBy p (reservedOp "/")
 
 commaSep1 :: Parser a -> Parser [a]
 commaSep1 = P.commaSep1 lexer
diff --git a/src/TW/Types.hs b/src/TW/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/TW/Types.hs
@@ -0,0 +1,9 @@
+module TW.Types where
+
+import qualified Data.Text as T
+
+data LibraryInfo
+   = LibraryInfo
+   { li_name :: T.Text
+   , li_version :: T.Text
+   }
diff --git a/src/TW/Utils.hs b/src/TW/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/TW/Utils.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE OverloadedStrings #-}
+module TW.Utils where
+
+import Data.Char
+import qualified Data.Text as T
+
+capitalizeText :: T.Text -> T.Text
+capitalizeText =
+    T.pack . go . T.unpack
+    where
+       go (x:xs) = toUpper x : xs
+       go [] = []
+
+uncapitalizeText :: T.Text -> T.Text
+uncapitalizeText =
+    T.pack . go . T.unpack
+    where
+       go (x:xs) = toLower x : xs
+       go [] = []
+
+makeSafePrefixedFieldName :: T.Text -> T.Text
+makeSafePrefixedFieldName = T.filter isAlphaNum
diff --git a/test/TW/CodeGen/HaskellTest.hs b/test/TW/CodeGen/HaskellTest.hs
new file mode 100644
--- /dev/null
+++ b/test/TW/CodeGen/HaskellTest.hs
@@ -0,0 +1,113 @@
+{-# OPTIONS_GHC -F -pgmF htfpp #-}
+{-# LANGUAGE OverloadedStrings #-}
+module TW.CodeGen.HaskellTest where
+
+import TW.Ast
+import TW.Check
+import TW.Loader
+import TW.Types
+import qualified TW.CodeGen.Haskell as HS
+
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import Data.Monoid
+import Test.Framework
+import System.IO.Temp
+import System.Directory
+import System.FilePath
+import System.Process
+import System.Exit
+
+mainTemplate :: T.Text
+mainTemplate =
+  T.unlines
+  [ "module Main where"
+  , "import Basic"
+  , "import Data.Aeson"
+  , "main :: IO ()"
+  , "main = "
+  , "  do putStrLn \"Lauching self-check ...\""
+  , "     let b = Bar True 42"
+  , "         bEnc = encode b"
+  , "         bDec = decode' bEnc"
+  , "     if (Just b /= bDec) then fail \"Bar enc/dec check ... failed\" else putStrLn \"Bar enc/dec check ... ok\""
+  ]
+
+stackTemplate :: T.Text
+stackTemplate =
+  T.unlines
+  [ "resolver: lts-3.10"
+  , "packages:"
+  , "- '.'"
+  , "extra-deps:"
+  , "- Spock-0.10.0.1"
+  , "- " <> li_name HS.libraryInfo <> "-" <> li_version HS.libraryInfo
+  ]
+
+cabalTemplate :: T.Text
+cabalTemplate =
+  T.unlines
+  [ "name: typed-wire-haskell-test"
+  , "version:             0.1.0.0"
+  , "synopsis:            Just Testing..."
+  , "description:         Please see README.md"
+  , "homepage:            http://github.com/typed-wire/typed-wire#readme"
+  , "license:             MIT"
+  , "author:              Alexander Thiemann <mail@athiemann.net>"
+  , "maintainer:          Alexander Thiemann <mail@athiemann.net>"
+  , "copyright:           (c) 2015 Alexander Thiemann <mail@athiemann.net>"
+  , "category:            Web"
+  , "build-type:          Simple"
+  , "cabal-version:       >=1.10"
+  , "tested-with:         GHC==7.10.2"
+  , "executable test"
+  , "  hs-source-dirs:      src"
+  , "  main-is:             Main.hs"
+  , "  other-modules:"
+  , "                Basic"
+  , "              , Other"
+  , "  ghc-options:         -threaded -rtsopts -with-rtsopts=-N"
+  , "  build-depends:"
+  , "                base >= 4.7 && < 5"
+  , "              , aeson"
+  , "              , time"
+  , "              , text"
+  , "              , vector"
+  , "              , mtl"
+  , "              , Spock"
+  , "              , " <> li_name HS.libraryInfo <> " == " <> li_version HS.libraryInfo
+  , "  default-language:    Haskell2010"
+  ]
+
+test_haskellCodeGen :: IO ()
+test_haskellCodeGen =
+  withSystemTempDirectory "haskellCodeGenX" $ \dir ->
+  do let srcDir = dir </> "src"
+     loaded <- loadModules ["samples"] [ModuleName ["Basic"]]
+     allModules <- assertRight loaded
+     checkedModules <- assertRight $ checkModules allModules
+     mapM_ (runner srcDir HS.makeModule HS.makeFileName) checkedModules
+     T.writeFile (dir </> "typed-wire-haskell-test.cabal") cabalTemplate
+     T.writeFile (dir </> "stack.yaml") stackTemplate
+     T.writeFile (srcDir </> "Main.hs") mainTemplate
+     let p =
+           (shell "stack build --pedantic")
+           { cwd = Just dir
+           }
+     (_, _, _, handle) <- createProcess p
+     ec <- waitForProcess handle
+     assertEqual ExitSuccess ec
+     let pRun =
+           (shell "stack exec test")
+           { cwd = Just dir
+           }
+     (_, _, _, hRun) <- createProcess pRun
+     ecRun <- waitForProcess hRun
+     assertEqual ExitSuccess ecRun
+
+runner :: FilePath -> (Module -> T.Text) -> (ModuleName -> FilePath) -> Module -> IO ()
+runner baseDir mkModule mkFilename m =
+    let moduleSrc = mkModule m
+        moduleFp = baseDir </> mkFilename (m_name m)
+    in do createDirectoryIfMissing True (takeDirectory moduleFp)
+          T.writeFile moduleFp moduleSrc
diff --git a/test/TW/CodeGen/PureScriptTest.hs b/test/TW/CodeGen/PureScriptTest.hs
new file mode 100644
--- /dev/null
+++ b/test/TW/CodeGen/PureScriptTest.hs
@@ -0,0 +1,102 @@
+{-# OPTIONS_GHC -F -pgmF htfpp #-}
+{-# LANGUAGE OverloadedStrings #-}
+module TW.CodeGen.PureScriptTest where
+
+import TW.Ast
+import TW.Check
+import TW.Loader
+import TW.Types
+import qualified TW.CodeGen.PureScript as PS
+
+import Data.Aeson ((.=))
+import System.Directory
+import System.Exit
+import System.FilePath
+import System.IO.Temp
+import System.Process
+import Test.Framework
+import qualified Data.Aeson as A
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.IO as T
+
+mainTemplate :: T.Text
+mainTemplate =
+  T.unlines
+  [ "module Main where"
+  , "import Basic"
+  , "import Data.Either"
+  , "import Data.TypedWire.Prelude"
+  , "import Control.Monad.Eff.Console"
+  , "import Control.Monad.Eff"
+  , ""
+  , "main :: forall a. Eff (console :: CONSOLE | a) Unit"
+  , "main = "
+  , "  do log \"Lauching self-check ...\""
+  , "     let b = Bar { someField: true, moreFields: 42 }"
+  , "         bEnc = encodeJson b"
+  , "         bDec = decodeJson bEnc"
+  , "     if (Right b /= bDec) then error \"Bar enc/dec check ... failed\" else log \"Bar enc/dec check ... ok\""
+  ]
+
+bowerTemplate :: T.Text
+bowerTemplate =
+  T.decodeUtf8 $
+  BSL.toStrict $
+  A.encode $
+  A.object
+  [ "name" .= T.pack "purescript-typed-wire-test"
+  , "version" .= T.pack "0.1.0"
+  , "moduleType" .= [T.pack "node"]
+  , "ignore" .= map T.pack ["**/.*", "node_modules", "bower_components", "output"]
+  , "dependencies" .=
+      A.object
+      [ (li_name PS.libraryInfo) .= (li_version PS.libraryInfo)
+      , "purescript-console" .= T.pack "0.1.1"
+      ]
+  , "repository" .=
+       A.object
+       [ "type" .= T.pack "git"
+       , "url" .= T.pack "git://github.com/typed-wire/purescript-typed-wire"
+       ]
+  ]
+
+test_pureScriptCodeGen :: IO ()
+test_pureScriptCodeGen =
+  withSystemTempDirectory "purescriptCodeGenX" $ \dir ->
+  do let srcDir = dir </> "src"
+     loaded <- loadModules ["samples"] [ModuleName ["Basic"]]
+     allModules <- assertRight loaded
+     checkedModules <- assertRight $ checkModules allModules
+     mapM_ (runner srcDir PS.makeModule PS.makeFileName) checkedModules
+     T.writeFile (dir </> "bower.json") bowerTemplate
+     T.writeFile (srcDir </> "Main.purs") mainTemplate
+     let pDeps =
+           (shell "pulp dep install")
+           { cwd = Just dir
+           }
+     (_, _, _, hDeps) <- createProcess pDeps
+     ecDeps <- waitForProcess hDeps
+     assertEqual ExitSuccess ecDeps
+     let p =
+           (shell "pulp build")
+           { cwd = Just dir
+           }
+     (_, _, _, handle) <- createProcess p
+     ec <- waitForProcess handle
+     assertEqual ExitSuccess ec
+     let pRun =
+           (shell "pulp run")
+           { cwd = Just dir
+           }
+     (_, _, _, hRun) <- createProcess pRun
+     ecRun <- waitForProcess hRun
+     assertEqual ExitSuccess ecRun
+
+runner :: FilePath -> (Module -> T.Text) -> (ModuleName -> FilePath) -> Module -> IO ()
+runner baseDir mkModule mkFilename m =
+    let moduleSrc = mkModule m
+        moduleFp = baseDir </> mkFilename (m_name m)
+    in do createDirectoryIfMissing True (takeDirectory moduleFp)
+          T.writeFile moduleFp moduleSrc
diff --git a/test/Test.hs b/test/Test.hs
new file mode 100644
--- /dev/null
+++ b/test/Test.hs
@@ -0,0 +1,10 @@
+{-# OPTIONS_GHC -F -pgmF htfpp #-}
+module Main where
+
+import {-@ HTF_TESTS @-} TW.CodeGen.HaskellTest
+import {-@ HTF_TESTS @-} TW.CodeGen.PureScriptTest
+
+import Test.Framework
+
+main :: IO ()
+main = htfMain htf_importedTests
diff --git a/typed-wire.cabal b/typed-wire.cabal
--- a/typed-wire.cabal
+++ b/typed-wire.cabal
@@ -1,13 +1,13 @@
 name:                typed-wire
-version:             0.2.1.3
-synopsis:            WIP: Language idependent type-safe communication
+version:             0.3.0.0
+synopsis:            Language idependent type-safe communication
 description:         Please see README.md
-homepage:            http://github.com/agrafix/typed-wire#readme
+homepage:            http://github.com/typed-wire/typed-wire#readme
 license:             MIT
 license-file:        LICENSE
 author:              Alexander Thiemann <mail@athiemann.net>
 maintainer:          Alexander Thiemann <mail@athiemann.net>
-copyright:           (c) 2015 Alexander Thiemann <mail@athiemann.net>
+copyright:           (c) 2015 - 2016 Alexander Thiemann <mail@athiemann.net>
 category:            Web
 build-type:          Simple
 extra-source-files:
@@ -25,7 +25,10 @@
                   TW.BuiltIn,
                   TW.JsonRepr,
                   TW.CodeGen.Elm,
-                  TW.CodeGen.Haskell
+                  TW.CodeGen.Haskell,
+                  TW.CodeGen.PureScript,
+                  TW.Types,
+                  TW.Utils
   build-depends:
                 base >= 4.7 && < 5,
                 text >= 1.2,
@@ -34,7 +37,7 @@
                 containers >=0.5,
                 directory >=1.2,
                 filepath >=1.4,
-                file-embed >=0.0.9
+                http-types >=0.8.6
   default-language:    Haskell2010
 
 executable twirec
@@ -51,6 +54,26 @@
                 directory >=1.2
   default-language:    Haskell2010
 
+test-suite typed-wire-tests
+  type: exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is: Test.hs
+  other-modules:
+    TW.CodeGen.HaskellTest
+    TW.CodeGen.PureScriptTest
+  build-depends:
+                base
+              , aeson
+              , typed-wire
+              , HTF >=0.13
+              , temporary >=1.1
+              , text >=1.2
+              , filepath >=1.4
+              , directory >=1.2.2
+              , process >=1.2
+              , bytestring >=0.10
+  default-language: Haskell2010
+
 source-repository head
   type:     git
-  location: https://github.com/agrafix/typed-wire
+  location: https://github.com/typed-wire/typed-wire
