diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+# Changelog
+
+All notable changes to this project will be documented here.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.0.1.0] - 2020-10-15
+### Added
+
+- Initial implementation
+  - Compiler that pipes hakyll items to other executables
+  - Various helper functions
+  - Simple example
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Jim McStanton (c) 2020
+
+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 Jim McStanton 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+# hakyll-process
+
+Hakyll compilers for passing Hakyll items to external processes. This is useful for tools that do not have
+Haskell bindings or may not make sense to have Haskell bindings, like Typescript or LaTex compilers.
+
+## Example Usage:
+
+This example shows how this library can be used to include latex files in your
+site source and include the output pdf in your target site.
+
+```haskell
+import           Hakyll.Process
+
+main = do
+  hakyll $ do
+    match "resume/*.tex" $ do
+      route   $ setExtension "pdf"
+      compile $ execCompilerWith (execName "xelatex") [ProcArg "-output-directory=resume/", HakFilePath] (newExtOutFilePath ("pdf"))
+```
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/hakyll-process.cabal b/hakyll-process.cabal
new file mode 100644
--- /dev/null
+++ b/hakyll-process.cabal
@@ -0,0 +1,28 @@
+name:                hakyll-process
+version:             0.0.1.0
+synopsis:            Hakyll compiler for arbitrary external processes.
+description:         Exposes Hakyll compilers for passing file paths to external processes.
+                     Transformed results are made available as Hakyll `Items`.
+homepage:            https://github.com/jhmcstanton/hakyll-process#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Jim McStanton
+maintainer:          jim@jhmcstanton.com
+copyright:           2020 Jim McStanton
+category:            Web
+build-type:          Simple
+extra-source-files:  README.md CHANGELOG.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Hakyll.Process
+  build-depends:       base          >= 4.7       && < 5
+                     , bytestring    >= 0.10.10.1 && < 0.10.11
+                     , hakyll        >= 4.12      && < 5
+                     , typed-process >= 0.2.3     && < 0.3 
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/jhmcstanton/hakyll-process
diff --git a/src/Hakyll/Process.hs b/src/Hakyll/Process.hs
new file mode 100644
--- /dev/null
+++ b/src/Hakyll/Process.hs
@@ -0,0 +1,90 @@
+module Hakyll.Process
+    (
+      newExtension
+    , newExtOutFilePath
+    , execName
+    , execCompiler
+    , execCompilerWith
+    , CompilerOut(..)
+    , ExecutableArg(..)
+    , ExecutableArgs
+    , ExecutableName
+    , OutFilePath(..)
+    ) where
+
+import qualified Data.ByteString.Lazy.Char8 as B
+import           GHC.Conc                        (atomically)
+import           Hakyll.Core.Item
+import           Hakyll.Core.Compiler
+import           System.Process.Typed
+
+-- | Expected output from the external compiler.
+data CompilerOut   =
+  -- | Compiler uses stdout as the output type.
+    CStdOut
+  -- | Compiler outputs to a specific target file on the filesystem.
+  | COutFile OutFilePath
+
+-- | Arguments to provide to the process
+data ExecutableArg =
+  -- | Abstract representation of the path to the Hakyll item.
+    HakFilePath
+  -- | Literal argument to provide to the other process.
+  | ProcArg String deriving (Read, Show)
+
+-- | Specifies the output file path of a process.
+data OutFilePath   =
+  -- | A specific, known filepath.
+    SpecificPath FilePath
+  -- | Indicates that the output path is related to the input path.
+  | RelativePath (FilePath -> FilePath)
+
+-- | Name of the executable if in the PATH or path to it if not
+newtype ExecutableName = ExecutableName  String    deriving (Read, Show)
+-- | Arguments to pass to the executable. Empty if none.
+type ExecutableArgs    = [ExecutableArg]
+
+-- | Helper function to indicate that the output file name is the same as the input file name with a new extension
+-- Note: like hakyll, assumes that no "." is present in the extension
+newExtension :: String -> FilePath -> FilePath
+newExtension ext f = (reverse . dropWhile (/= '.') . reverse $ f) <> ext
+
+-- | Helper function to indicate that the output file name is the same as the input file name with a new extension
+-- Note: like hakyll, assumes that no "." is present in the extension
+newExtOutFilePath :: String -> CompilerOut
+newExtOutFilePath ext = COutFile $ RelativePath (newExtension ext)
+
+execName ::  String  -> ExecutableName
+execName = ExecutableName
+
+-- | Calls the external compiler with no arguments. Returns the output contents as a 'B.ByteString'.
+--   If an error occurs this raises an exception.
+execCompiler     :: ExecutableName                   -> CompilerOut -> Compiler (Item B.ByteString)
+execCompiler name out          = execCompilerWith name [] out
+
+-- | Calls the external compiler with the provided arguments. Returns the output contents as a 'B.ByteString'.
+--   If an error occurs this raises an exception.
+execCompilerWith :: ExecutableName -> ExecutableArgs -> CompilerOut -> Compiler (Item B.ByteString)
+execCompilerWith name exArgs out = do
+  input   <- getResourceFilePath
+  let args = fmap (hargToArg input) exArgs
+  results <- unsafeCompiler $ runExecutable name args out input
+  -- just using this to get at the item
+  oldBody <- getResourceString
+  pure $ itemSetBody results oldBody
+
+runExecutable :: ExecutableName -> [String] -> CompilerOut -> FilePath -> IO B.ByteString
+runExecutable (ExecutableName exName) args compilerOut inputFile = withProcessWait procConf waitOutput where
+  procConf = setStdout byteStringOutput . proc exName $ args
+  waitOutput process = do
+    let stmProc = getStdout process
+    out <- atomically stmProc
+    checkExitCode process
+    case compilerOut of
+      CStdOut    -> pure out
+      COutFile (SpecificPath f) -> B.readFile f
+      COutFile (RelativePath f) -> B.readFile (f inputFile)
+
+hargToArg :: FilePath -> ExecutableArg -> String
+hargToArg _ (ProcArg s) = s
+hargToArg f HakFilePath = f
