diff --git a/DepInfo.hs b/DepInfo.hs
new file mode 100644
--- /dev/null
+++ b/DepInfo.hs
@@ -0,0 +1,17 @@
+module DepInfo
+       ( DepInfo(..),
+         depInfoUpToDate
+       )
+       where
+
+data DepInfo = DepInfo { depInfoFilePath :: FilePath
+                       , depInfoSavedMD5 :: Maybe String
+                       , depInfoCurrentMD5 :: Maybe String
+                       }
+             deriving Show
+
+-- | Returns true if the dependency has not changed since the last
+-- recording.
+depInfoUpToDate :: DepInfo -> Bool
+depInfoUpToDate di =
+  depInfoSavedMD5 di == depInfoCurrentMD5 di
diff --git a/Lib.hs b/Lib.hs
--- a/Lib.hs
+++ b/Lib.hs
@@ -4,13 +4,15 @@
          -- * directory names
        , getMetaDir
        , getMissingDepsFile
-       , metaIgnoreFiles
        , getDefaultDirs
          -- * Actions
        , executeRecipe
        , getRecipeFile
        , upToDate
        , recordDependency
+       , recordMissingDependency
+       , purgeRecordedDependencies
+       , getHashesAndDepsForTarget
        )
        where
 
@@ -21,21 +23,29 @@
 import qualified Data.ByteString as BS
 import qualified Data.Map as Map (toList,fromList,insert)
 import           Data.Maybe (listToMaybe)
-import           System.Directory (getCurrentDirectory, makeAbsolute, doesFileExist, renameFile, removeFile, createDirectoryIfMissing, getDirectoryContents)
+import           System.Directory (getCurrentDirectory, makeAbsolute, doesFileExist, renameFile, removeFile, createDirectoryIfMissing, getDirectoryContents, removeDirectoryRecursive, withCurrentDirectory)
 import           System.Environment (getEnvironment,lookupEnv)
 import           System.Exit (ExitCode(ExitSuccess))
 import           System.FilePath ((</>), takeBaseName, dropFileName, replaceBaseName, addExtension,splitSearchPath)
-import           System.IO (hPutStrLn,stderr,hPutStr,withFile,IOMode(ReadMode,WriteMode),hFileSize)
+import           System.IO (hPutStrLn,stderr,hPutStr,withFile,IOMode(ReadMode,WriteMode,AppendMode),hFileSize)
 import           System.IO.Error (isDoesNotExistError)
-import qualified System.Process as Proc
+import qualified System.Process as Proc (env, waitForProcess, createProcess, proc)
 
+import           DepInfo
+
+-- | Print a string to standard error output with a newline character
+-- in the end.
 putStrLnErr :: (MonadIO m) => String -> m ()
 putStrLnErr msg =
   liftIO $ hPutStrLn stderr msg
 
+-- | Print a string to standard error output.
 putStrErr :: (MonadIO m) => String -> m ()
 putStrErr = liftIO . hPutStr stderr
 
+-- | Get the path for the directory where the targets meta information
+-- is stored.  This will only work, if you are in the same directory
+-- as the target.
 getMetaDir :: (MonadIO m) =>
               String -- ^ target name
            -> m FilePath
@@ -60,21 +70,23 @@
               -> FilePath -- ^ recipe file
               -> IO ExitCode
 executeRecipe target recipe = do
-  createFile tempFileName
+  currentDir <- getCurrentDirectory
+  let tempFilePath = currentDir </> tempFileName
+  createFile tempFilePath
   finally
     (do
         process <- modEnv $ Proc.proc recipe
-                   [targetDir,takeBaseName target, tempFileName]
+                   [targetDir,takeBaseName target, tempFilePath]
         (_,_,_,ph) <- liftIO $ Proc.createProcess process
         code <- liftIO $ Proc.waitForProcess ph
         if code /= ExitSuccess
           then putStrLnErr $ "*** redo failed for target "++show target
-          else do filesize <- getFileSize tempFileName
-                  when (filesize /= 0) $ renameFile tempFileName target
+          else do filesize <- getFileSize tempFilePath
+                  when (filesize /= 0) $ renameFile tempFilePath target
         return code
     )
-    (do exists <- doesFileExist tempFileName
-        when exists $ removeFile tempFileName
+    (do exists <- doesFileExist tempFilePath
+        when exists $ removeFile tempFilePath
     )
   where
     modEnv process = do
@@ -113,6 +125,11 @@
 getDefaultDirs =
   maybe [] splitSearchPath <$> liftIO (lookupEnv "GDO_DEFAULTS")
 
+hashFile :: (MonadIO m) => FilePath -> m (Digest MD5)
+hashFile target = do
+  bs <- liftIO $ BS.readFile target
+  return $ hash bs
+
 upToDate :: (MonadIO m) =>
             [FilePath]
          -> FilePath
@@ -120,18 +137,23 @@
 upToDate mDefaultsDir buildTarget = do
   metaDepDir <- getMetaDir buildTarget
   liftIO $
-    not . Prelude.null <$> getRecipeFile mDefaultsDir buildTarget >>= \canBuild ->
-    if canBuild
-    then do
-      r <- tryJust (guard . isDoesNotExistError) $ do
-        md5s <- Prelude.filter (not . (`elem` metaIgnoreFiles)) <$>
-                getDirectoryContents metaDepDir
-        depsNotChanged <- and <$> mapM upToDate' md5s
-        noNewFiles <- not <$> newFilesCreated
-        return $ depsNotChanged && noNewFiles
-      return $ either (const False) id r
-    else return True
+    maybe
+      -- When no recipe exists, we assume the target is up to date.
+      (return True)
+      ( const $ do
+           r <- tryJust
+                (guard . isDoesNotExistError)
+                ( do md5s <- Prelude.filter (not . (`elem` metaIgnoreFiles)) <$>
+                             getDirectoryContents metaDepDir
+                     depsNotChanged <- and <$> mapM upToDate' md5s
+                     noNewFiles <- not <$> newFilesCreated
+                     return $ depsNotChanged && noNewFiles
+                )
+           return $ fromRight (const False) r
+      ) =<< getRecipeFile mDefaultsDir buildTarget
   where
+    fromRight :: (a -> b) -> Either a b -> b
+    fromRight f = either f id
     upToDate' :: String -> IO Bool
     upToDate' oldHash = do
       metaDepDir <- getMetaDir buildTarget
@@ -148,7 +170,8 @@
     newFilesCreated = do
       missingDepsFile <- getMissingDepsFile buildTarget
       r <- tryJust (guard . isDoesNotExistError) $
-           Prelude.filter (\e -> (e `notElem` metaIgnoreFiles) || Prelude.null e) .
+           Prelude.filter (\e -> (e `notElem` metaIgnoreFiles) ||
+                                 Prelude.null e) .
            lines <$>
            readFile missingDepsFile
       case r of
@@ -156,6 +179,22 @@
        Right watchlist -> or <$> mapM
                           doesFileExist watchlist
 
+getHashesAndDepsForTarget :: FilePath -> IO [DepInfo]
+getHashesAndDepsForTarget target = do
+  metaDir <- getMetaDir target
+  (filenames, oldMd5s) <- withCurrentDirectory metaDir $ do
+    hashes <- filter (not . (`elem` metaIgnoreFiles)) <$>
+              getDirectoryContents metaDir
+    (,) <$> mapM readFile hashes <*> pure hashes
+  md5s <- mapM hashFromPath filenames
+  return (zipWith3 DepInfo
+          filenames
+          (map Just oldMd5s)
+          (map (Just . show)  md5s))
+  where
+    hashFromPath :: FilePath -> IO (Digest MD5)
+    hashFromPath f = hash <$> BS.readFile f
+
 recordDependency :: FilePath -- ^ target name
                  -> FilePath -- ^ dependency name
                  -> IO ()
@@ -167,7 +206,16 @@
   liftIO $ withFile md5file WriteMode
     (`hPutStr` dep)
 
-hashFile :: (MonadIO m) => FilePath -> m (Digest MD5)
-hashFile target = do
-  bs <- liftIO $ BS.readFile target
-  return $ hash bs
+recordMissingDependency :: FilePath -> FilePath -> IO ()
+recordMissingDependency target dep = do
+  metaDepsDir <- getMetaDir target
+  missingDepsFile <- getMissingDepsFile target
+  liftIO $ createDirectoryIfMissing True metaDepsDir
+  liftIO $ withFile
+    missingDepsFile
+    AppendMode
+    (`hPutStrLn` dep)
+
+purgeRecordedDependencies :: FilePath -> IO ()
+purgeRecordedDependencies target =
+  removeDirectoryRecursive =<< getMetaDir target
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -10,7 +10,6 @@
 import           System.Environment
 import           System.Exit
 import           System.FilePath
-import           System.IO
 import           System.IO.Error
 
 import Lib
@@ -20,16 +19,17 @@
 
 clOption :: [OptDescr Flag]
 clOption = [ Option "" ["if"] (ReqArg read "MODE")
-             "Redo mode, valid modes are: IfChanged, IfCreated"
+             "Redo mode, valid modes are: Changed, Created"
            , Option "h" ["help"] (NoArg Help)
              "Print usage info"
            ]
 
 variableInfo :: String
 variableInfo =
-  unlines
-  [ "Environment variables:"
-  , "\tGDO_DEFAULTS : Path to directory containing default do files"
+  unlines $
+  "Environment variables:" :
+  map ('\t':)
+  [ "GDO_DEFAULTS : List of paths to directories containing default do files"
   ]
 
 usageHeader :: String
@@ -92,7 +92,7 @@
   isUpToDate <- upToDate mDefaultsDir target
   unless (isUpToDate && targetDoesExist) $ do
     void . liftIO . tryJust (guard . isDoesNotExistError) $
-      deleteDepDir
+      purgeRecordedDependencies target
     maybe (do targetExists <- liftIO $ doesFileExist target
               unless targetExists $ do
                 (liftIO . putStrLnErr)
@@ -104,12 +104,10 @@
                redoIfChanged mDefaultsDir target recipe
                buildResult <- liftIO $ executeRecipe target recipe
                when (buildResult /= ExitSuccess)
-                 (do liftIO deleteDepDir
+                 (do liftIO $ purgeRecordedDependencies target
                      throwE buildResult)
                liftIO $ putStrLnErr $ "redone "++show target)
       =<< getRecipeFile mDefaultsDir target
-  where
-    deleteDepDir = removeDirectoryRecursive =<< getMetaDir target
 
 redoIfCreated :: (MonadIO m) =>
                  [FilePath]     -- ^ directory path of defaults
@@ -120,13 +118,7 @@
   depExists <- liftIO $ doesFileExist dep
   if depExists
     then redoIfChanged mDefaultsDir buildTarget dep
-    else do metadir <- getMetaDir buildTarget
-            missingDepsFile <- getMissingDepsFile buildTarget
-            liftIO $ createDirectoryIfMissing True metadir
-            liftIO $ withFile
-              missingDepsFile
-              AppendMode
-              (`hPutStrLn` dep)
+    else liftIO $ recordMissingDependency buildTarget dep
 
 redoIfChanged :: MonadIO m =>
                  [FilePath]     -- ^ directory of defaults
diff --git a/README.org b/README.org
--- a/README.org
+++ b/README.org
@@ -101,11 +101,37 @@
    default rule based on the targets file extension.  This only works
    for files which have an extension.  Default do files are only
    searched in the same directory as the target by default.  You can
-   extend the search path via the environment variable *GDO_DEFAULTS*.
+   extend the search path via the environment variable *GDO\_DEFAULTS*.
    When specified this variable must be a list of paths seperated by
    colons.  This path is searched for default do files after no
    default do files was found in the same directory as the target is
    in.
+
+** EXAMPLE
+   The source code you received with this product should contain a set
+   of examples for using *gdo*.  These examples can be found in the
+   *examples* directory.
+
+   This small example builds the "hello world" program in C.  There
+   are 3 files in this directory: The first one is the source for the
+   program itself, *test.c*, the other two files are a do script for
+   the final executable *test.do* and a default do script for building
+   object files from C sources, *defaults/default.o.do*.  To build the
+   example you have to first point to the defaults directory, so that
+   *gdo* can find the default do file.  We assume that you are already
+   in the examples file of the gdo source code.  Then issue *gdo* to
+   build the target *test*.
+   #+begin_src sh
+     export GDO_DEFAULTS=$PWD/defaults
+     gdo test
+     # output:
+     # redo "test"
+     # redo "test.o"
+     # redone "test.o"
+     # redone "test"
+   #+end_src
+   Now the targets should be build. You should take a look at the do
+   files to see some examples of what *gdo* is capable of.
 
 * COPYRIGHT
   Copyright (C) 2016 by Sebastian Jordan.  This file is part of *gdo*.
diff --git a/all.do b/all.do
--- a/all.do
+++ b/all.do
@@ -1,3 +1,3 @@
 #!/usr/bin/env sh
 
-gdo --if Changed gdo tests/test default.nix README man/gdo.1
+gdo --if Changed gdo default.nix README man/gdo.1
diff --git a/default.nix.do b/default.nix.do
--- a/default.nix.do
+++ b/default.nix.do
@@ -2,6 +2,9 @@
 
 # generate a nix expression for the project
 
+# This line is here because default.nix.do is also the default do file
+# for all .nix files in the current directory.
+gdo --if Created $2.do
 gdo --if Changed gdo.cabal
 
 cabal2nix . > $3
diff --git a/examples/defaults/default.o.do b/examples/defaults/default.o.do
new file mode 100644
--- /dev/null
+++ b/examples/defaults/default.o.do
@@ -0,0 +1,16 @@
+#!/usr/bin/env sh
+
+set -e
+
+CC=cc
+GDO_ENVIRONMENT=$1/environment
+
+gdo --if Changed $2.c $(cc -MM $2.c | tr -d '\n\\' | cut -d':' -f2)
+gdo --if Created $2.o.do $GDO_ENVIRONMENT
+
+# We want to check for custom environment variables like CC
+if [ -e $GDO_ENVIRONMENT ]; then
+    source $GDO_ENVIRONMENT
+fi
+
+${CC} -c $2.c -o $3 > /dev/null
diff --git a/examples/test.c b/examples/test.c
new file mode 100644
--- /dev/null
+++ b/examples/test.c
@@ -0,0 +1,7 @@
+#include "stdio.h"
+
+int main(){
+  printf("Hello World!");
+  return 0;
+}
+  
diff --git a/examples/test.do b/examples/test.do
new file mode 100644
--- /dev/null
+++ b/examples/test.do
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set -e
+
+gdo --if Changed test.o test.do
+gdo --if Created stdio.h
+
+gcc test.o -o $3
diff --git a/gdo.cabal b/gdo.cabal
--- a/gdo.cabal
+++ b/gdo.cabal
@@ -2,7 +2,7 @@
 -- see http://haskell.org/cabal/users-guide/
 
 name:                gdo
-version:             0.1.0
+version:             0.1.2
 synopsis:            recursive atomic build system
 description:
   *gdo* is a build system similar to **GNU Make**. It builds files from
@@ -22,12 +22,13 @@
                    , all.do
                    , clean.do
                    , default.nix.do
+                   , shell.nix.do
                    , gdo.cabal
                    , gdo.do
                    , man/gdo.1.do
-                   , tests/test.c
-                   , tests/test.do
-                   , tests/defaults/default.o.do
+                   , examples/test.c
+                   , examples/test.do
+                   , examples/defaults/default.o.do
 
 cabal-version:       >=1.10
 
@@ -38,7 +39,8 @@
 executable gdo
   main-is:             Main.hs
   other-modules:       Lib
-  build-depends:       base >=4.8 && <4.9,
+                     , DepInfo
+  build-depends:       base >=4.8 && <4.10,
                        process >= 1.1,
                        filepath >= 1.0,
                        directory >= 1.2,
diff --git a/gdo.do b/gdo.do
--- a/gdo.do
+++ b/gdo.do
@@ -4,7 +4,7 @@
 
 HC="ghc -v0"
 
-gdo --if Changed Main.hs Lib.hs
+gdo --if Changed Main.hs Lib.hs DepInfo.hs
 gdo --if Created environment
 
 if [ -e environment ]; then
diff --git a/shell.nix.do b/shell.nix.do
new file mode 100644
--- /dev/null
+++ b/shell.nix.do
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# generate a nix expression for the project
+
+gdo --if Changed gdo.cabal
+
+cabal2nix . --shell > $3
+
diff --git a/tests/defaults/default.o.do b/tests/defaults/default.o.do
deleted file mode 100644
--- a/tests/defaults/default.o.do
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env sh
-
-set -e
-
-CC=cc
-GDO_ENVIRONMENT=$1/environment
-
-gdo --if Changed $2.c $(cc -MM $2.c | tr -d '\n\\' | cut -d':' -f2)
-gdo --if Created $2.o.do $GDO_ENVIRONMENT
-
-# We want to check for custom environment variables like CC
-if [ -e $GDO_ENVIRONMENT ]; then
-    source $GDO_ENVIRONMENT
-fi
-
-${CC} -c $2.c -o $3 > /dev/null
diff --git a/tests/test.c b/tests/test.c
deleted file mode 100644
--- a/tests/test.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "stdio.h"
-
-int main(){
-  printf("Hello World!");
-  return 0;
-}
-  
diff --git a/tests/test.do b/tests/test.do
deleted file mode 100644
--- a/tests/test.do
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-set -e
-
-gdo --if Changed test.o test.do
-gdo --if Created stdio.h
-
-gcc test.o -o $3
