diff --git a/Development/Shake.hs b/Development/Shake.hs
--- a/Development/Shake.hs
+++ b/Development/Shake.hs
@@ -1,6 +1,22 @@
 
 -- | Main module for defining Shake build systems. You may also want to include
---   "Development.Shake.FilePath".
+--   "Development.Shake.FilePath", for manipulating file paths. As a simple example,
+--   let us build a @result.tar@ file from the contents of @result.txt@:
+--
+-- @
+--import "Development.Shake"
+--import "Development.Shake.FilePath"
+--
+--main = 'shake' 'shakeOptions' $ do
+--    'want' [\"result.tar\"]
+--    \"*.tar\" *> \out -> do
+--        contents <- 'readFileLines' $ replaceExtension out \"txt\"
+--        'need' contents
+--        'system'' \"tar\" $ [\"-cf\",out] ++ contents
+-- @
+--
+--   For the background theory behind a previous version of Shake the online video:
+--   <http://vimeo.com/15465133>.
 module Development.Shake(
     shake,
     -- * Core of Shake
@@ -22,7 +38,7 @@
 import qualified Development.Shake.File as X
 import qualified Development.Shake.Directory as X
 
--- | Main entry point for running Shake build systems.
+-- | Main entry point for running Shake build systems. For an example see "Development.Shake".
 shake :: ShakeOptions -> Rules () -> IO ()
 shake opts r = do
     X.run opts $ do
diff --git a/Development/Shake/Core.hs b/Development/Shake/Core.hs
--- a/Development/Shake/Core.hs
+++ b/Development/Shake/Core.hs
@@ -30,15 +30,15 @@
 ---------------------------------------------------------------------
 -- OPTIONS
 
--- | Options to specify how to control 'shake'.
+-- | Options to control 'shake'.
 data ShakeOptions = ShakeOptions
-    {shakeFiles :: FilePath -- ^ Where shall I store the database and journal files (defaults to @.@)
-    ,shakeParallel :: Int -- ^ What is the maximum number of rules I should run in parallel (defaults to @1@)
-    ,shakeVersion :: Int -- ^ What is the version of your build system, increment to force everyone to rebuild
-    ,shakeVerbosity :: Int -- ^ 1 = normal, 0 = quiet, 2 = loud
+    {shakeFiles :: FilePath -- ^ Where shall I store the database and journal files (defaults to @.@).
+    ,shakeParallel :: Int -- ^ What is the maximum number of rules I should run in parallel (defaults to @1@).
+    ,shakeVersion :: Int -- ^ What is the version of your build system, increment to force a complete rebuild.
+    ,shakeVerbosity :: Int -- ^ 1 = normal, 0 = quiet, 2 = loud.
     }
 
--- | A default set of 'ShakeOptions'.
+-- | The default set of 'ShakeOptions'.
 shakeOptions :: ShakeOptions
 shakeOptions = ShakeOptions "." 1 1 1
 
@@ -46,13 +46,16 @@
 ---------------------------------------------------------------------
 -- RULES
 
--- | Define a pair of types that can be used as a Shake rule.
+-- | Define a pair of types that can be used by Shake rules.
 class (
     Show key, Typeable key, Eq key, Hashable key, Binary key,
     Show value, Typeable value, Eq value, Hashable value, Binary value
     ) => Rule key value | key -> value where
     -- | Given that the database contains @key@/@value@, does that still match the on-disk contents?
-    --   Return 'True' if no work needs to be done.
+    --
+    --   As an example for filenames/timestamps, if the file exists and had the same timestamp, you
+    --   would return 'True', but otherwise return 'False'. For rule values which are not also stored
+    --   on disk, 'validStored' should always return 'True'.
     validStored :: key -> value -> IO Bool
     validStored _ _ = return True
 
@@ -69,7 +72,7 @@
 ruleStored _ k v = unsafePerformIO $ validStored k v -- safe because of the invariants on validStored
 
 
--- | Define a set of rules. Rules can be created with calls to 'rule'/'action'. Rules are combined
+-- | Define a set of rules. Rules can be created with calls to 'rule', 'defaultRule' or 'action'. Rules are combined
 --   with either the 'Monoid' instance, or more commonly using the 'Monad' instance and @do@ notation.
 data Rules a = Rules
     {value :: a -- not really used, other than for the Monad instance
@@ -92,6 +95,7 @@
 
 
 -- | Like 'rule', but lower priority, if no 'rule' exists then 'defaultRule' is checked.
+--   All default rules must be disjoint.
 defaultRule :: Rule key value => (key -> Maybe (Action value)) -> Rules ()
 defaultRule r = mempty{rules=[(0,ARule r)]}
 
@@ -190,7 +194,7 @@
 
 
 -- | Execute a rule, returning the associated values. If possible, the rules will be run in parallel.
---   This function requires that appropriate rules have been added with 'rule'/'defaultRule'.
+--   This function requires that appropriate rules have been added with 'rule' or 'defaultRule'.
 apply :: Rule key value => [key] -> Action [value]
 apply ks = Action $ do
     modify $ \s -> s{depends=map newKey ks:depends s}
diff --git a/Development/Shake/Derived.hs b/Development/Shake/Derived.hs
--- a/Development/Shake/Derived.hs
+++ b/Development/Shake/Derived.hs
@@ -12,29 +12,38 @@
 import Development.Shake.FilePath
 
 
-system' :: [String] -> Action ()
-system' (x:xs) = do
-    let cmd = unwords $ toNative x : xs
+-- | Execute a system command. This function will raise an error if the exit code is non-zero.
+--   Before running 'system'' make sure you 'need' any required files.
+system' :: FilePath -> [String] -> Action ()
+system' path args = do
+    let path2 = toNative path
+    let cmd = unwords $ path2 : args
     putLoud cmd
-    res <- liftIO $ system cmd
+    res <- liftIO $ rawSystem path2 args
     when (res /= ExitSuccess) $ do
         k <- currentRule
         error $ "System command failed while building " ++ show k ++ ", " ++ cmd
 
 
+-- | @copyFile old new@ copies the existing file from @old@ to @new@. The @old@ file is has 'need' called on it
+--   before copying the file.
 copyFile' :: FilePath -> FilePath -> Action ()
 copyFile' old new = need [old] >> liftIO (copyFile old new)
 
 
+-- | Read a file, after calling 'need'.
 readFile' :: FilePath -> Action String
 readFile' x = need [x] >> liftIO (readFile x)
 
+-- | Write a file, lifted to the 'Action' monad.
 writeFile' :: FilePath -> String -> Action ()
 writeFile' name x = liftIO $ writeFile name x
 
 
+-- | A version of 'readFile'' which also splits the result into lines.
 readFileLines :: FilePath -> Action [String]
 readFileLines = fmap lines . readFile'
 
+-- | A version of 'writeFile'' which writes out a list of lines.
 writeFileLines :: FilePath -> [String] -> Action ()
 writeFileLines name = writeFile' name . unlines
diff --git a/Development/Shake/Directory.hs b/Development/Shake/Directory.hs
--- a/Development/Shake/Directory.hs
+++ b/Development/Shake/Directory.hs
@@ -70,15 +70,23 @@
         liftIO $ getDir x
 
 
+-- | Returns 'True' if the file exists.
 doesFileExist :: FilePath -> Action Bool
 doesFileExist = apply1 . Exist
 
+-- | Get the contents of a directory. The result will be sorted, and will not contain
+--   the files @.@ or @..@ (unlike the standard Haskell version). It is usually better to
+--   call either 'getDirectoryFiles' or 'getDirectoryDirs'. The resulting paths will be relative
+--   to the first argument.
 getDirectoryContents :: FilePath -> Action [FilePath]
 getDirectoryContents x = getDirAction $ GetDir x
 
+-- | Get the files in a directory that match a particular pattern.
+--   For the interpretation of the pattern see '?=='.
 getDirectoryFiles :: FilePath -> FilePattern -> Action [FilePath]
 getDirectoryFiles x f = getDirAction $ GetDirFiles x f
 
+-- | Get the directories contained by a directory, does not include @.@ or @..@.
 getDirectoryDirs :: FilePath -> Action [FilePath]
 getDirectoryDirs x = getDirAction $ GetDirDirs x
 
diff --git a/Development/Shake/File.hs b/Development/Shake/File.hs
--- a/Development/Shake/File.hs
+++ b/Development/Shake/File.hs
@@ -3,7 +3,7 @@
 module Development.Shake.File(
     FilePattern, need, want,
     defaultRuleFile,
-    (?==), (?>), (**>), (*>)
+    (?==), (*>), (**>), (?>)
     ) where
 
 import Control.Monad.IO.Class
@@ -19,6 +19,8 @@
 import System.FilePath(takeDirectory)
 
 
+-- | A type synonym for file patterns, containing @\/\/@ and @*@. For the syntax
+--   and semantics of 'FilePattern' see '?=='.
 type FilePattern = String
 
 newtype File = File FilePath
@@ -50,13 +52,34 @@
     return $ fromMaybe (error msg) res
 
 
+-- | Require that the following files are built before continuing. Particularly
+--   necessary when calling 'system''. As an example:
+--
+-- > "//*.rot13" *> \out -> do
+-- >     let src = dropExtension out
+-- >     need [src]
+-- >     system' ["rot13",src,"-o",out]
 need :: [FilePath] -> Action ()
 need xs = (apply $ map File xs :: Action [FileTime]) >> return ()
 
+-- | Require that the following are built by the rules, used to specify the target.
+--
+-- > main = shake shakeOptions $ do
+-- >    want ["Main.exe"]
+-- >    ...
+--
+--   This program will build @Main.exe@, given sufficient rules.
 want :: [FilePath] -> Rules ()
 want xs = action $ need xs
 
 
+-- | Define a rule to build files. If the first argument returns 'True' for a given file,
+--   the second argument will be used to build it. Usually '*>' is sufficient, but '?>' gives
+--   additional power. For any file used by the build system, only one rule should return 'True'.
+--
+-- > (all isUpper . takeBaseName) *> \out -> do
+-- >     let src = replaceBaseName out $ map toLower $ takeBaseName out
+-- >     writeFile' . map toUpper =<< readFile' src
 (?>) :: (FilePath -> Bool) -> (FilePath -> Action ()) -> Rules ()
 (?>) test act = rule $ \(File x) ->
     if not $ test x then Nothing else Just $ do
@@ -67,13 +90,35 @@
         return $ fromMaybe (error msg) res
 
 
+-- | Define a set of patterns, and if any of them match, run the associate rule. See '*>'.
 (**>) :: [FilePattern] -> (FilePath -> Action ()) -> Rules ()
 (**>) test act = (\x -> any (x ?==) test) ?> act
 
+-- | Define a rule that matches a 'FilePattern'. No file required by the system must be
+--   matched by more than one pattern. For the pattern rules, see '?=='.
+--
+-- > "*.asm.o" *> \out -> do
+-- >     let src = dropExtension out
+-- >     need [src]
+-- >     system' ["as",src,"-o",out]
+--
+--   To define a build system for multiple compiled languages, we recommend using @.asm.o@,
+--   @.cpp.o@, @.hs.o@, to indicate which language produces an object file.
 (*>) :: FilePattern -> (FilePath -> Action ()) -> Rules ()
 (*>) test act = (test ?==) ?> act
 
 
+-- | Match a 'FilePattern' against a 'FilePath', There are only two special forms:
+--
+-- * @*@ matches an entire path component, excluding any separators.
+--
+-- * @\/\/@ matches an arbitrary number of path componenets.
+--
+--   Some examples that match:
+--
+-- > "//*.c" ?== "foo/bar/baz.c"
+-- > "*.c" ?== "baz.c"
+-- > "test.c" ?== "test.c"
 (?==) :: FilePattern -> FilePath -> Bool
 (?==) ('/':'/':x) y = any (x ?==) $ y : [i | '/':i <- tails y]
 (?==) ('*':x) y = any (x ?==) $ a ++ take 1 b
diff --git a/Development/Shake/FilePath.hs b/Development/Shake/FilePath.hs
--- a/Development/Shake/FilePath.hs
+++ b/Development/Shake/FilePath.hs
@@ -1,7 +1,12 @@
 
--- | Module for 'FilePath' operations, to be used in place of
---   "System.FilePath". It uses @\/@ as the directory separator to ensure
---   uniqueness, and squashes any @\/.\/@ components.
+-- | A module for 'FilePath' operations, to be used instead of "System.FilePath"
+--   when writing build systems. In build systems, when using the file name
+--   as a key for indexing rules, it is important that two different strings do
+--   not refer to the same on-disk file. We therefore follow the conventions:
+--
+-- * Always use @\/@ as the directory separator, even on Windows.
+--
+-- * When combining 'FilePath' values with '</>' we squash any @\/.\/@ components.
 module Development.Shake.FilePath(
     module System.FilePath.Posix,
     dropDirectory1, takeDirectory1, normalise,
@@ -34,18 +39,28 @@
 takeDirectory1 = takeWhile (not . isPathSeparator)
 
 
+-- | Normalise a 'FilePath', translating any path separators to @\/@.
 normalise :: FilePath -> FilePath
-normalise = map (\x -> if x == '\\' then '/' else x)
+normalise = map (\x -> if isPathSeparator x then '/' else x)
 
 
+-- | Convert to native path separators, namely @\\@ on Windows. 
 toNative :: FilePath -> FilePath
-toNative = map (\x -> if x == '/' then Native.pathSeparator else x)
+toNative = map (\x -> if isPathSeparator x then Native.pathSeparator else x)
 
 
+-- | Combine two file paths, an alias for 'combine'.
 (</>) :: FilePath -> FilePath -> FilePath
 (</>) = combine
 
 
+-- | Combine two file paths. Any leading @.\/@ or @..\/@ components in the right file
+--   are eliminated.
+--
+-- > combine "aaa/bbb" "ccc" == "aaa/bbb/ccc"
+-- > combine "aaa/bbb" "./ccc" == "aaa/bbb/ccc"
+-- > combine "aaa/bbb" "../ccc" == "aaa/ccc"
 combine :: FilePath -> FilePath -> FilePath
 combine x ('.':'.':'/':y) = combine (takeDirectory x) y
+combine x ('.':'/':y) = combine x y
 combine x y = Posix.combine x y
diff --git a/Examples/Self/Main.hs b/Examples/Self/Main.hs
--- a/Examples/Self/Main.hs
+++ b/Examples/Self/Main.hs
@@ -23,7 +23,7 @@
         src <- readFileLines $ replaceExtension res "deps"
         let os = map (out . moduleToFile "o") $ "Main":src
         need os
-        system' $ ["ghc","-o",res] ++ os ++ flags
+        system' "ghc" $ ["-o",res] ++ os ++ flags
 
     out "/*.deps" *> \res -> do
         dep <- readFileLines $ replaceExtension res "dep"
@@ -45,7 +45,7 @@
         dep <- readFileLines $ replaceExtension res "dep"
         let hs = unout $ replaceExtension res "hs"
         need $ hs : map (out . moduleToFile "hi") dep
-        system' $ ["ghc","-c",hs,"-odir=output/self","-hidir=output/self","-i=output/self"] ++ flags
+        system' "ghc" $ ["-c",hs,"-odir=output/self","-hidir=output/self","-i=output/self"] ++ flags
 
 
 hsImports :: String -> [String]
diff --git a/Examples/Tar/Main.hs b/Examples/Tar/Main.hs
--- a/Examples/Tar/Main.hs
+++ b/Examples/Tar/Main.hs
@@ -10,4 +10,4 @@
     "output/tar/result.tar" *> \out -> do
         contents <- readFileLines "Examples/Tar/list.txt"
         need contents
-        system' $ ["tar","-cf",out] ++ contents
+        system' "tar" $ ["-cf",out] ++ contents
diff --git a/Examples/Tar/list.txt b/Examples/Tar/list.txt
new file mode 100644
--- /dev/null
+++ b/Examples/Tar/list.txt
@@ -0,0 +1,3 @@
+Examples/Tar/Main.hs
+Main.hs
+Examples/Tar/list.txt
diff --git a/shake.cabal b/shake.cabal
--- a/shake.cabal
+++ b/shake.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.6
 build-type:         Simple
 name:               shake
-version:            0.1
+version:            0.1.1
 license:            BSD3
 license-file:       LICENSE
 category:           Development
@@ -10,9 +10,32 @@
 copyright:          Neil Mitchell 2011
 synopsis:           Build system creator
 description:
-    Write build systems, mostly works but seriously early adopters only.
+    Shake is a Haskell library for writing build systems - designed as a
+    replacement for make. To use Shake the user writes a Haskell program
+    that imports the Shake library, defines some build rules, and calls
+    shake. Thanks to do notation and infix operators, a simple Shake program
+    is not too dissimilar from a simple Makefile. However, as build systems
+    get more complex, Shake is able to take advantage of the excellent
+    abstraction facilities offered by Haskell and easily support much larger
+    projects.
+    .
+    The Shake library provides all the standard features available in other
+    build systems, including automatic parallelism and minimal rebuilds.
+    Shake provides highly accurate dependency tracking, including seamless
+    support for generated files, and dependencies on system information
+    (i.e. compiler version). Shake will eventually be able to produce profile reports, indicating
+    which files and take longest to build, and providing an analysis of the
+    parallelism.
+    .
+    The theory behind an old version of Shake is described in a video at
+    <http://vimeo.com/15465133>, and an example is given at the top of
+    "Development.Shake". Some further examples are included in the Cabal tarball,
+    under the @Examples@ directory.
 homepage:           http://community.haskell.org/~ndm/shake/
 stability:          Beta
+extra-source-files:
+    Examples/Tar/list.txt
+
 
 source-repository head
     type:     darcs
