diff --git a/src/Cli/Compiler.hs b/src/Cli/Compiler.hs
--- a/src/Cli/Compiler.hs
+++ b/src/Cli/Compiler.hs
@@ -104,14 +104,12 @@
 runCompiler (CompileOptions h is is2 _ _ _ p (CompileFast c fn f2) f) = do
   dir <- mkdtemp "/tmp/zfast_"
   absolute <- canonicalizePath p
-  is' <- sequence $ map (canonicalizePath . (p </>)) is
-  is2' <- sequence $ map (canonicalizePath . (p </>)) is2
   f2' <- canonicalizePath (p </> f2)
   let config = ModuleConfig {
       rmRoot = absolute,
       rmPath = dir,
-      rmPublicDeps = is',
-      rmPrivateDeps = is2',
+      rmPublicDeps = is,
+      rmPrivateDeps = is2,
       rmExtraFiles = [OtherSource f2'],
       rmExtraPaths = [],
       rmMode = (CompileBinary c fn (absolute </> c) [])
@@ -155,8 +153,8 @@
               let fixed = fixPath (absolute </> p2)
               let recompile = CompileOptions {
                   coHelp = h,
-                  coPublicDeps = map ((fixed </> d) </>) is,
-                  coPrivateDeps = map ((fixed </> d) </>) is2,
+                  coPublicDeps = is,
+                  coPrivateDeps = is2,
                   coSources = [d],
                   coExtraFiles = es,
                   coExtraPaths = ep,
@@ -165,10 +163,10 @@
                   coForce = if f == ForceAll then ForceRecompile else AllowRecompile
                 }
               runCompiler recompile
-runCompiler (CompileOptions _ is is2 ds es ep p m f) = do
+runCompiler (CompileOptions _ is is2 [d] es ep p m f) = do
   (backend,resolver) <- loadConfig
-  as  <- fmap fixPaths $ sequence $ map (resolveModule resolver p) is
-  as2 <- fmap fixPaths $ sequence $ map (resolveModule resolver p) is2
+  as  <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is
+  as2 <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is2
   (fr,deps) <- loadPublicDeps (getCompilerHash backend) (as ++ as2)
   checkAllowedStale fr f
   if isCreateTemplates m
@@ -176,16 +174,13 @@
         base <- resolveBaseModule resolver
         (fr2,bpDeps) <- loadPublicDeps (getCompilerHash backend) [base]
         checkAllowedStale fr2 f
-        sequence_ $ map (processTemplates $ bpDeps ++ deps) ds
+        processTemplates (bpDeps ++ deps)
       else do
-        ma <- sequence $ map (processPath backend resolver deps as as2) ds
-        let ms = concat $ map snd ma
-        let deps2 = map (snd . fst) ma
-        let paths2 = concat $ map (fst . fst) ma
-        createBinary backend resolver paths2 (deps ++ deps2) m ms
+        ((paths2,deps2),ms) <- processPath backend resolver deps as as2
+        createBinary backend resolver paths2 (deps2:deps) m ms
   hPutStrLn stderr $ "Zeolite compilation succeeded." where
     ep' = fixPaths $ map (p </>) ep
-    processPath b r deps as as2 d = do
+    processPath b r deps as as2 = do
       isConfigured <- isPathConfigured d
       when (isConfigured && f == DoNotForce) $ do
         hPutStrLn stderr $ "Module " ++ d ++ " has an existing configuration. " ++
@@ -225,11 +220,11 @@
       ns0 <- canonicalizePath (p </> d) >>= return . StaticNamespace . publicNamespace
       let ns2 = map StaticNamespace $ filter (not . null) $ getNamespacesForDeps deps
       let fs = compileAll ns0 ns2 ss' ps' xs'
-      writeOutput b paths ns0 deps2 d as as2
+      writeOutput b paths ns0 deps2 as as2
                   (map takeFileName ps ++ ps2)
                   (map takeFileName xs ++ xs2)
                   (map takeFileName ts ++ ts2) fs
-    writeOutput b paths ns0 deps d as as2 ps xs ts fs
+    writeOutput b paths ns0 deps as as2 ps xs ts fs
       | isCompileError fs = do
           formatWarnings fs
           hPutStr stderr $ "Compiler errors:\n" ++ (show $ getCompileError fs)
@@ -244,11 +239,11 @@
           let paths' = paths ++ ep' ++ ss'
           let hxx   = filter (isSuffixOf ".hpp" . coFilename)       fs'
           let other = filter (not . isSuffixOf ".hpp" . coFilename) fs'
-          os1 <- sequence $ map (writeOutputFile b (show ns0) paths' d) $ hxx ++ other
+          os1 <- sequence $ map (writeOutputFile b (show ns0) paths') $ hxx ++ other
           let files = map (\f2 -> getCachedPath (p </> d) (show $ coNamespace f2) (coFilename f2)) fs' ++
                       map (\f2 -> p </> getSourceFile f2) es
           files' <- sequence $ map checkOwnedFile files
-          os2 <- fmap concat $ sequence $ map (compileExtraSource b (show ns0) paths' d) es
+          os2 <- fmap concat $ sequence $ map (compileExtraSource b (show ns0) paths') es
           let (hxx',cxx,os') = sortCompiledFiles files'
           let (osCat,osOther) = partitionEithers os2
           path <- canonicalizePath $ p </> d
@@ -274,7 +269,7 @@
     formatWarnings c
       | null $ getCompileWarnings c = return ()
       | otherwise = hPutStr stderr $ "Compiler warnings:\n" ++ (concat $ map (++ "\n") (getCompileWarnings c))
-    writeOutputFile b ns0 paths d ca@(CxxOutput _ f2 ns _ _ content) = do
+    writeOutputFile b ns0 paths ca@(CxxOutput _ f2 ns _ _ content) = do
       hPutStrLn stderr $ "Writing file " ++ f2
       writeCachedFile (p </> d) (show ns) f2 $ concat $ map (++ "\n") content
       if isSuffixOf ".cpp" f2 || isSuffixOf ".cc" f2
@@ -288,14 +283,14 @@
            o2 <- runCxxCommand b command
            return $ ([o2],ca)
          else return ([],ca)
-    compileExtraSource b ns0 paths d (CategorySource f2 cs ds2) = do
-      f2' <- compileExtraFile False b ns0 paths d f2
+    compileExtraSource b ns0 paths (CategorySource f2 cs ds2) = do
+      f2' <- compileExtraFile False b ns0 paths f2
       let ds2' = nub $ cs ++ ds2
       case f2' of
            Nothing -> return []
            Just o  -> return $ map (\c -> Left $ ([o],fakeCxxForSource ns0 ds2' c)) cs
-    compileExtraSource b ns0 paths d (OtherSource f2) = do
-      f2' <- compileExtraFile True b ns0 paths d f2
+    compileExtraSource b ns0 paths (OtherSource f2) = do
+      f2' <- compileExtraFile True b ns0 paths f2
       case f2' of
            Just o  -> return [Right $ OtherObjectFile o]
            Nothing -> return []
@@ -315,7 +310,7 @@
         hPutStrLn stderr $ "Zeolite compilation failed."
         exitFailure
       canonicalizePath f2
-    compileExtraFile e b ns0 paths d f2
+    compileExtraFile e b ns0 paths f2
       | isSuffixOf ".cpp" f2 || isSuffixOf ".cc" f2 = do
           let f2' = p </> f2
           createCachePath (p </> d)
@@ -323,7 +318,7 @@
           fmap Just $ runCxxCommand b command
       | isSuffixOf ".a" f2 || isSuffixOf ".o" f2 = return (Just f2)
       | otherwise = return Nothing
-    processTemplates deps d = do
+    processTemplates deps = do
       (ps,xs,_) <- findSourceFiles p d
       ps' <- zipWithContents p ps
       xs' <- zipWithContents p xs
@@ -338,7 +333,7 @@
            exitFailure
          else do
            formatWarnings ts
-           sequence $ map (writeTemplate d) $ getCompileSuccess ts
+           sequence_ $ map writeTemplate $ getCompileSuccess ts
     createTemplates is3 cs ds2 = do
       tm1 <- addIncludes defaultCategories is3
       cs' <- fmap concat $ collectAllOrErrorM $ map parsePublicSource cs
@@ -351,7 +346,7 @@
       let ca = Set.fromList $ map getCategoryName $ filter isValueConcrete cs'
       let ca' = foldr Set.delete ca $ map dcName ds2'
       collectAllOrErrorM $ map (compileConcreteTemplate tm3) $ Set.toList ca'
-    writeTemplate d (CxxOutput _ n _ _ _ content) = do
+    writeTemplate (CxxOutput _ n _ _ _ content) = do
       let n' = p </> d </> n
       exists <- doesFileExist n'
       if exists && f /= ForceAll
@@ -375,11 +370,11 @@
       let pc = map getCategoryName cs''
       ms <- maybeCreateMain cm m
       return (pc,ms,xx)
-    parsePrivate d = do
-      let ns1 = StaticNamespace $ privateNamespace (p </> fst d)
-      (cs,ds2) <- parseInternalSource d
+    parsePrivate ds = do
+      let ns1 = StaticNamespace $ privateNamespace (p </> fst ds)
+      (cs,ds') <- parseInternalSource ds
       let cs' = map (setCategoryNamespace ns1) cs
-      return $ PrivateSource ns1 cs' ds2
+      return $ PrivateSource ns1 cs' ds'
     addIncludes tm fs = do
       cs <- fmap concat $ collectAllOrErrorM $ map parsePublicSource fs
       includeNewTypes tm cs
@@ -392,8 +387,8 @@
         exitFailure
       | otherwise = do
           f0 <- if null o
-                   then canonicalizePath $ p </> head ds </> n
-                   else canonicalizePath $ p </> head ds </> o
+                   then canonicalizePath $ p </> d </> n
+                   else canonicalizePath $ p </> d </> o
           let (CxxOutput _ _ _ ns2 req content) = head ms
           -- TODO: Create a helper or a constant or something.
           (o',h) <- mkstemps "/tmp/zmain_" ".cpp"
@@ -415,6 +410,9 @@
     maybeCreateMain cm (CompileBinary n f2 _ _) =
       fmap (:[]) $ compileModuleMain cm (CategoryName n) (FunctionName f2)
     maybeCreateMain _ _ = return []
+runCompiler co = do
+  hPutStrLn stderr $ "Unsupported compiler options: " ++ show co
+  exitFailure
 
 checkAllowedStale :: Bool -> ForceMode -> IO ()
 checkAllowedStale fr f = do
diff --git a/src/Cli/ParseCompileOptions.hs b/src/Cli/ParseCompileOptions.hs
--- a/src/Cli/ParseCompileOptions.hs
+++ b/src/Cli/ParseCompileOptions.hs
@@ -42,7 +42,7 @@
     "",
     "zeolite [options...] -m [category(.function)] -o [binary] [path]",
     "zeolite [options...] --fast [category(.function)] [.0rx source]",
-    "zeolite [options...] -c [paths...]",
+    "zeolite [options...] -c [path]",
     "zeolite [options...] -r [paths...]",
     "zeolite [options...] -R [paths...]",
     "zeolite [options...] -t [paths...]",
@@ -244,11 +244,11 @@
   | (not $ null $ is ++ is2) && (isCompileRecompile m) =
     compileError "Include paths (-i/-I) are not allowed in recompile mode (-r/-R)."
 
+  | (length ds /= 0) && (isCompileFast m) =
+    compileError "Input path is not allowed with fast mode (--fast)."
   | null ds && (not $ isCompileFast m) =
     compileError "Please specify at least one input path."
-  | (length ds /= 1) && (isCompileBinary m) =
-    compileError "Specify exactly one input path for binary mode (-m)."
-  | (length ds /= 0) && (isCompileFast m) =
-    compileError "Specify exactly one input path for fast mode (--fast)."
+  | (length ds > 1) && (not $ isCompileRecompile m) && (not $ isExecuteTests m) =
+    compileError "Multiple input paths are only allowed with recompile mode (-r/-R) and test mode (-t)."
 
   | otherwise = return co
diff --git a/src/Cli/ParseMetadata.hs b/src/Cli/ParseMetadata.hs
--- a/src/Cli/ParseMetadata.hs
+++ b/src/Cli/ParseMetadata.hs
@@ -348,4 +348,5 @@
         indent "]",
         "}"
       ]
+  writeConfig CompileUnspecified = writeConfig (CompileIncremental [])
   writeConfig _ = compileError "Invalid compile mode"
diff --git a/src/Test/ParseMetadata.hs b/src/Test/ParseMetadata.hs
--- a/src/Test/ParseMetadata.hs
+++ b/src/Test/ParseMetadata.hs
@@ -259,8 +259,7 @@
     checkWriteFail "compile mode" $ ExecuteTests { etInclude = [] },
     checkWriteFail "compile mode" $ CompileRecompile,
     checkWriteFail "compile mode" $ CompileRecompileRecursive,
-    checkWriteFail "compile mode" $ CreateTemplates,
-    checkWriteFail "compile mode" $ CompileUnspecified
+    checkWriteFail "compile mode" $ CreateTemplates
   ]
 
 checkWriteThenRead :: (Eq a, Show a, ConfigFormat a) => a -> IO (CompileInfo ())
diff --git a/tests/cli-tests.sh b/tests/cli-tests.sh
new file mode 100644
--- /dev/null
+++ b/tests/cli-tests.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+# ------------------------------------------------------------------------------
+# Copyright 2020 Kevin P. Barry
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ------------------------------------------------------------------------------
+
+# Author: Kevin P. Barry [ta0kira@gmail.com]
+
+set -e -u
+
+if [ $# -lt 1 ]; then
+  echo "$0: Pass the command to execute the zeolite CLI." 1>&2
+  exit 1
+fi
+
+ZEOLITE=("$@")
+
+execute() {
+  echo "Executing:" $(printf ' %q' "$@") 1>&2
+  "$@" 2>&1
+}
+
+do_zeolite() {
+  execute "${ZEOLITE[@]}" "$@"
+}
+
+ZEOLITE_PATH=$(do_zeolite --get-path | grep '^/')
+
+
+test_check_defs() {
+  local output=$(do_zeolite -p "$ZEOLITE_PATH" -r tests/check-defs || true)
+  if ! echo "$output" | egrep -q "Type .+ is defined 2 times"; then
+    echo 'Expected Type definition error from tests/check-defs:' 1>&2
+    echo "$output" 1>&2
+    return 1
+  fi
+  if ! echo "$output" | egrep -q "Undefined .+ has not been defined"; then
+    echo 'Expected Undefined definition error from tests/check-defs:' 1>&2
+    echo "$output" 1>&2
+    return 1
+  fi
+}
+
+
+test_templates() {
+  execute rm -f $ZEOLITE_PATH/tests/templates/Category_Templated.cpp
+  do_zeolite -p "$ZEOLITE_PATH" --templates tests/templates
+  do_zeolite -p "$ZEOLITE_PATH" -r tests/templates
+  do_zeolite -p "$ZEOLITE_PATH" -t tests/templates
+}
+
+
+test_fast() {
+  local temp=$(execute mktemp -d)
+  local category='HelloWorld'
+  local file="$temp/hello-world.0rx"
+  cat > "$file" <<END
+// $file
+
+concrete $category {
+  @type run () -> ()
+}
+
+define $category {
+  run () {
+    \ LazyStream<Formatted>\$new()
+        .append("Hello World\n")
+        .writeTo(SimpleOutput\$stdout())
+  }
+}
+END
+  do_zeolite -i lib/util --fast $category "$file"
+  local output=$(execute "$PWD/$category")
+  if ! echo "$output" | fgrep -xq 'Hello World'; then
+    echo 'Expected "Hello World" in program output:' 1>&2
+    echo "$output" 1>&2
+    return 1
+  fi
+}
+
+
+run_all() {
+  local failed=0
+  for t in "$@"; do
+    echo -e "Testing $t >>>\n" 1>&2
+    if ! "$t"; then
+      failed=1
+    fi
+    echo -e "\n<<< Testing $t\n" 1>&2
+  done
+  if (($failed)); then
+    echo 'One or more tests failed.' 1>&2
+    return 1
+  else
+    echo 'All tests passed.' 1>&2
+  fi
+}
+
+run_all test_check_defs test_templates test_fast 1>&2
diff --git a/zeolite-lang.cabal b/zeolite-lang.cabal
--- a/zeolite-lang.cabal
+++ b/zeolite-lang.cabal
@@ -1,7 +1,7 @@
 cabal-version:       2.2
 
 name:                zeolite-lang
-version:             0.4.1.0
+version:             0.4.1.1
 synopsis:            Zeolite is a statically-typed, general-purpose programming language.
 
 description:
@@ -96,6 +96,7 @@
                      tests/*.0rp,
                      tests/*.0rt,
                      tests/*.0rx,
+                     tests/*.sh,
                      tests/check-defs/README.md,
                      tests/check-defs/.zeolite-module,
                      tests/check-defs/*.0rp,
