diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2018 Owens Murray, LLC.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# om-elm
+
+This package provides utilities for serving Elm programs directly
+from your Haskell binary. It uses TemplateHaskell to compile your Elm
+program at build time, and construct a WAI Middleware which intercepts
+requests appropriate to the Elm program, and passing other requests to
+a downstream WAI Application. It is useful for bundling the browser side
+of a web application with its backing web services implementation.
+
+
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/om-elm.cabal b/om-elm.cabal
new file mode 100644
--- /dev/null
+++ b/om-elm.cabal
@@ -0,0 +1,46 @@
+-- Initial om-elm.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                om-elm
+version:             1.0.0.1
+synopsis:            Haskell utilities for building embedded Elm programs.
+description:         This package provides utilities for serving Elm programs
+                     directly from your Haskell binary. It uses TemplateHaskell
+                     to compile your Elm program at build time, and construct a
+                     WAI Middleware which intercepts requests appropriate to
+                     the Elm program, and passing other requests to a
+                     downstream WAI Application. It is useful for bundling the
+                     browser side of a web application with its backing web
+                     services implementation.
+homepage:            https://github.com/owensmurray/om-elm
+license:             MIT
+license-file:        LICENSE
+author:              Rick Owens
+maintainer:          rick@owensmurray.com
+copyright:           2018 Owens Murray, LLC.
+category:            Web
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     
+    System.Elm.Middleware
+  -- other-modules:       
+  -- other-extensions:    
+  build-depends:
+    Cabal            >= 2.0.1.1  && < 2.1,
+    base             >= 4.9      && < 4.11,
+    bytestring       >= 0.10.8.1 && < 0.11,
+    containers       >= 0.5.7.1  && < 0.6,
+    directory        >= 1.3.0.0  && < 1.4,
+    http-types       >= 0.9.1    && < 0.10,
+    safe             >= 0.3.15   && < 0.4,
+    safe-exceptions  >= 0.1.6.0  && < 0.2,
+    template-haskell >= 2.11.1.0 && < 2.13,
+    text             >= 1.2.2.2  && < 1.3,
+    unix             >= 2.7.2.1  && < 2.8,
+    wai              >= 3.2.1.1  && < 3.3
+  hs-source-dirs: src
+  default-language: Haskell2010
+
diff --git a/src/System/Elm/Middleware.hs b/src/System/Elm/Middleware.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Elm/Middleware.hs
@@ -0,0 +1,210 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE ViewPatterns #-}
+
+{- |
+  This module contains utilities for compiling and bundling Elm programs
+  directly into your Haskell executable binary. It is useful for the
+  case where you want to bundle a front-end Elm web app along with the
+  backing services that support it, and especially for when the two
+  components are part of the same codebase. It produces WAI Middleware,
+  and is thus compatible with a wide range server-side frameworks.
+
+  Usage is designed to be as simple as possible. There are 3 steps:
+
+  1) Change your .cabal file to use a \"Custom\" build type, and add
+  the appropriate custom build dependencies.
+
+  > build-type: Custom
+  > ...
+  > custom-setup
+  >   setup-depends:
+  >     Cabal,
+  >     base,
+  >     om-elm
+
+  2) Modify your @Setup.hs@ file, using 'requireElm'.
+
+  3) Include a 'Middleware' template-haskell splice, using 'elmSite',
+  in the appropriate place in your code.
+
+  See the function documnetation for more details.
+
+-}
+module System.Elm.Middleware (
+  requireElm,
+  elmSite,
+  elmSiteDebug,
+  PathInfo,
+) where
+
+
+import Control.Exception.Safe (tryAny)
+import Control.Monad (void)
+import Data.Bool (bool)
+import Data.Map (Map)
+import Data.Monoid ((<>))
+import Data.String (IsString, fromString)
+import Data.Text (Text)
+import Data.Text.Encoding (decodeUtf8)
+import Distribution.Simple (hookedPrograms, simpleUserHooks, preConf,
+   UserHooks)
+import Distribution.Simple.Program (simpleProgram, Program,
+   configureAllKnownPrograms, requireProgram, defaultProgramDb)
+import Distribution.Simple.Setup (fromFlagOrDefault, configVerbosity)
+import Distribution.Verbosity (normal)
+import Language.Haskell.TH (Q, TExp, runIO)
+import Language.Haskell.TH.Syntax (addDependentFile)
+import Network.HTTP.Types (ok200, methodNotAllowed405)
+import Network.Wai (Middleware, Application, pathInfo, requestMethod,
+   responseLBS)
+import Safe (lastMay)
+import System.Directory (removeDirectoryRecursive, createDirectory)
+import System.Exit (ExitCode(ExitSuccess))
+import System.Posix (ProcessStatus(Exited), forkProcess, executeFile,
+   getProcessStatus)
+import qualified Data.ByteString as BS
+import qualified Data.Map as Map
+import qualified Data.Text as T
+
+
+{- |
+  Add the elm-make program requirements to a set of build hooks. This is
+  expected to be used in your Setup.hs file thusly:
+
+  > import Distribution.Simple (defaultMainWithHooks, simpleUserHooks)
+  > import System.Elm.Middleware (requireElm)
+  > 
+  > main = defaultMainWithHooks (requireElm simpleUserHooks)
+
+-}
+requireElm :: UserHooks -> UserHooks
+requireElm hooks =
+    hooks {
+      hookedPrograms = hookedPrograms hooks ++ [elmProg],
+
+      preConf = \args flags -> do
+        let verbosity = fromFlagOrDefault normal (configVerbosity flags)
+        db <- configureAllKnownPrograms verbosity defaultProgramDb
+        _ <- requireProgram verbosity elmProg db
+        preConf simpleUserHooks args flags
+    }
+  where
+    {- | A description of the elm-make program.  -}
+    elmProg :: Program
+    elmProg = simpleProgram "elm-make"
+
+
+{- |
+  Template Haskell method to create a 'Middleware' that serves a set of
+  elm programs. The elm programs are compiled into HTML at compile time,
+  and that HTML is included directly in your executable.
+
+  The parameter is a map of 'pathInfo's to elm program module file. The
+  elm program located at the file is served whenever the pathInfo matches
+  that of the request. Any non-matching request is forwarded to the
+  downstream 'Application'.
+
+  The typed template-haskell splice:
+
+  > $$(elmSite $ Map.fromList [
+  >     (["app.js"], "elm/Your/Elm/Module/App.elm")
+  >   ])
+
+  will construct a WAI 'Middleware' which serves the compiled elm program on
+  @/app.js@.
+
+-}
+elmSite :: Map PathInfo FilePath -> Q (TExp Middleware)
+elmSite = elmSite2 False
+
+
+{- | Like 'elmSite', but serve the debug elm runtime. -}
+elmSiteDebug :: Map PathInfo FilePath -> Q (TExp Middleware)
+elmSiteDebug = elmSite2 True
+
+
+elmSite2 :: Bool -> Map PathInfo FilePath -> Q (TExp Middleware)
+elmSite2 debug spec =
+    buildMiddleware =<< (
+      mapM (\(u, c) -> (u,) <$> c) [
+        (uriPath, compileElm uriPath elmFile)
+        | (fmap T.unpack -> uriPath, elmFile) <- Map.toList spec
+      ]
+    )
+  where
+    {- | Construct the middleware from a set of compiled elm resources. -}
+    buildMiddleware :: [([String], (String, String))] -> Q (TExp Middleware)
+    buildMiddleware resources = [||
+        let
+          apps = Map.fromList[
+              (uriPath, buildApp contentType content)
+              | (fmap T.pack -> uriPath, (contentType, content)) <- resources
+            ]
+          {- | Build the application that serves a single elm resource. -}
+          buildApp :: String -> String -> Application
+          buildApp contentType content req respond = respond $
+            case requestMethod req of
+              "GET" ->
+                responseLBS
+                  ok200
+                  [("Content-Type", fromString contentType)]
+                  (fromString content)
+              _ -> responseLBS methodNotAllowed405 [("Allow", "GET")] ""
+        in
+          \downstream req respond ->
+            case Map.lookup (pathInfo req) apps of
+              Nothing -> downstream req respond
+              Just app -> app req respond
+      ||]
+
+    compileElm :: [String] -> FilePath -> Q (String, String)
+    compileElm uriPath elmFile = do
+        addDependentFile elmFile
+        runIO $ do
+          void . tryAny $ removeDirectoryRecursive buildDir
+          createDirectory buildDir
+          putStrLn $ "Compiling elm file: " ++ elmFile
+          forkProcess (executeFile "elm-make" True ([
+              elmFile,
+              "--yes",
+              "--output=" <> buildFile
+            ] ++ bool [] ["--debug"] debug) Nothing) >>= getProcessStatus True True >>= \case
+              Nothing -> fail "elm-make should have ended."
+              Just (Exited ExitSuccess) ->
+                (contentType,)
+                . T.unpack
+                . decodeUtf8
+                <$> BS.readFile buildFile
+              e -> fail $ "elm-make failed with: " ++ show e
+      where
+        {- |
+          The name of the build directory. We have to have a build
+          directory because elm-make won't output compile results to
+          stdout. It will only output them to files.
+        -}
+        buildDir :: (IsString a) => a
+        buildDir = ".om-elm-build-dir"
+
+        {- | Figure out if we are compiling to javascript or html. -}
+        contentType :: String
+        contentType = case lastMay uriPath of
+          Just (endsWith ".js" -> True) -> "text/javascript"
+          _ -> "text/html"
+
+        buildFile :: FilePath
+        buildFile = buildDir <> case lastMay uriPath of
+          Just (endsWith ".js" -> True) -> "/elm.js"
+          _ -> "/elm.html"
+
+        endsWith :: String -> String -> Bool
+        endsWith ending str =
+          take (length ending) (reverse str) == reverse ending
+
+
+{- | A WAI uri path, as per the meaning of 'pathInfo'. -}
+type PathInfo = [Text]
+
+
