diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,17 +3,36 @@
 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:
+## Common Usage
 
+There are a few main entry points for this library:
+
+- `execCompilerWith` is the most common. This allows the caller to declaratively run an external process
+  and includes support for passing arguments.
+- `execCompiler` is an aliased version of `execCompilerWith` that provides no arguments to the external executable/process.
+- `unsafeExecCompiler` is the less type safe and more manual method to calling external executables. This provides
+  no helper functionality but may be useful if you are already manually building out a compiler in your site generator.
+
+### Example
+
 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 qualified Data.ByteString.Lazy.Char8 as B
 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"))
+      compile $ execCompilerWith (execName "xelatex") [ProcArg "-output-directory=resume/", HakFilePath] (newExtOutFilePath "pdf")
+
+    -- alternative, manual method, using unsafeExecCompiler
+    match "resume/*.tex" $ do
+      route   $ setExtension "pdf"
+      compile $ do
+        input <- getResourceFilePath
+        let outputReader _ = B.readFile (newExtension "pdf" input)
+        unsafeExecCompiler (execName "xelatex") ["-output-directory=resume/", input] outputReader
 ```
diff --git a/hakyll-process.cabal b/hakyll-process.cabal
--- a/hakyll-process.cabal
+++ b/hakyll-process.cabal
@@ -1,5 +1,5 @@
 name:                hakyll-process
-version:             0.0.1.0
+version:             0.0.2.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`.
diff --git a/src/Hakyll/Process.hs b/src/Hakyll/Process.hs
--- a/src/Hakyll/Process.hs
+++ b/src/Hakyll/Process.hs
@@ -1,3 +1,8 @@
+{-|
+Module      : Hakyll.Process
+Description : Common compilers and helpers for external executables.
+Stability   : experimental
+-}
 module Hakyll.Process
     (
       newExtension
@@ -5,6 +10,7 @@
     , execName
     , execCompiler
     , execCompilerWith
+    , unsafeExecCompiler
     , CompilerOut(..)
     , ExecutableArg(..)
     , ExecutableArgs
@@ -46,7 +52,10 @@
 
 -- | 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 ::
+     String   -- ^ New file extension, excluding the leading "."
+  -> FilePath -- ^ Original 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
@@ -54,11 +63,12 @@
 newExtOutFilePath :: String -> CompilerOut
 newExtOutFilePath ext = COutFile $ RelativePath (newExtension ext)
 
-execName ::  String  -> ExecutableName
+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.
+--   May be useful if you already have build scripts for artifacts in your repository.
 execCompiler     :: ExecutableName                   -> CompilerOut -> Compiler (Item B.ByteString)
 execCompiler name out          = execCompilerWith name [] out
 
@@ -68,22 +78,36 @@
 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
+  let outputReader = cOutToFileContents input out
+  unsafeExecCompiler name args outputReader
 
-runExecutable :: ExecutableName -> [String] -> CompilerOut -> FilePath -> IO B.ByteString
-runExecutable (ExecutableName exName) args compilerOut inputFile = withProcessWait procConf waitOutput where
+-- | Primarily for internal use, occasionally useful when already building a compiler imperatively.
+-- Allows the caller to opt out of the declarative components of 'execCompiler' and 'execCompilerWith'.
+unsafeExecCompiler ::
+       ExecutableName                    -- ^ Name or filepath of the executable
+    -> [String]                          -- ^ Arguments to pass to the executable
+    -> (B.ByteString -> IO B.ByteString) -- ^ Action to read the output of the compiler. Input is the stdout of the process.
+    -> Compiler (Item B.ByteString)
+unsafeExecCompiler (ExecutableName exName) args outputReader =
+  do
+    results <- unsafeCompiler $ procResults
+    -- just using this to get at the item
+    oldBody <- getResourceString
+    pure $ itemSetBody results oldBody
+  where
+  procResults = withProcessWait procConf waitOutput
   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)
+    outputReader out
+
+--                 input fpath                   stdout contents
+cOutToFileContents :: FilePath -> CompilerOut -> B.ByteString -> IO B.ByteString
+cOutToFileContents _      CStdOut out                  = pure out
+cOutToFileContents _     (COutFile (SpecificPath f)) _ = B.readFile  f
+cOutToFileContents input (COutFile (RelativePath f)) _ = B.readFile (f input)
 
 hargToArg :: FilePath -> ExecutableArg -> String
 hargToArg _ (ProcArg s) = s
