diff --git a/README.md b/README.md
deleted file mode 100644
--- a/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-herringbone
-===========
-
-herringbone is a Haskell library for compiling and serving web assets.  It
-aims to make it dead simple to create a 'Network.Wai.Middleware' or
-'Network.Wai.Application' which deals with all of your static assets, including
-preprocessing for languages like Fay, CoffeeScript, Sass, and LESS.
-
-It takes most of its inspiration from the Ruby library, [Sprockets], hence the
-name.
-
-Status
-------
-
-Alpha.
-
-How to use it
--------------
-
-```haskell
-import Web.Herringbone
-
-fay, sass :: PP
-
-hb = Herringbone
-hb = herringbone
-    ( addSourceDir "assets"
-    . setDestDir   "compiled_assets"
-    . addPreprocessors [fay, sass]
-    )
-
--- You can now access assets programmatically
-asset <- findAsset hb (fromJust . makeLogicalPath $ ["application.js"])
-
--- Or serve them with a Wai application
-app = toApplication hb
-```
-
-For more information, go and look at the documentation on [Hackage]!
-
-[Sprockets]: https://github.com/sstephenson/sprockets
-[Hackage]: http://hackage.haskell.org/package/herringbone
diff --git a/Web/Herringbone.hs b/Web/Herringbone.hs
--- a/Web/Herringbone.hs
+++ b/Web/Herringbone.hs
@@ -42,7 +42,9 @@
     fromLogicalPath,
     toFilePath,
     Asset(..),
+    assetContent,
     findAsset,
+    precompile,
     -- * Preprocessors
     PP(..),
     PPs,
@@ -55,3 +57,4 @@
 import Web.Herringbone.Internal.Configuration
 import Web.Herringbone.Internal.Types
 import Web.Herringbone.Internal.FindAsset
+import Web.Herringbone.Internal.Precompile
diff --git a/Web/Herringbone/Internal/FindAsset.hs b/Web/Herringbone/Internal/FindAsset.hs
--- a/Web/Herringbone/Internal/FindAsset.hs
+++ b/Web/Herringbone/Internal/FindAsset.hs
@@ -4,6 +4,10 @@
 import Web.Herringbone.Internal.BuildAsset
 import Web.Herringbone.Internal.Types
 
+-- | The most important function in this library. Attempts to find the asset
+-- referenced by the given 'LogicalPath', compiles it if necessary (based on
+-- file modification time), and returns it to you as an 'Asset' (or an
+-- 'AssetError', if something went wrong).
 findAsset :: Herringbone
           -> LogicalPath
           -> IO (Either AssetError Asset)
diff --git a/Web/Herringbone/Internal/Precompile.hs b/Web/Herringbone/Internal/Precompile.hs
new file mode 100644
--- /dev/null
+++ b/Web/Herringbone/Internal/Precompile.hs
@@ -0,0 +1,35 @@
+module Web.Herringbone.Internal.Precompile where
+
+import Control.Monad (forM)
+import qualified Filesystem.Path.CurrentOS as F
+import qualified Data.Text as T
+
+import Web.Herringbone.Internal.Types
+import Web.Herringbone.Internal.FindAsset
+import Web.Herringbone.Internal.GetBuildMapping (getBuildMapping)
+
+-- | Precompiles all assets, returning a list of the logical paths of assets
+-- that failed to compile (if any) together with 'AssetError' values describing
+-- what went wrong.
+precompile :: Herringbone -> IO [(LogicalPath, AssetError)]
+precompile hb = do
+    mapping <- getBuildMapping hb
+    results <- forM mapping $ \(BuildSpec _ destPath _) -> do
+        let path = toLogicalPath destPath
+        either invalidPath compile path
+    return $ concat results
+    where
+    toLogicalPath filePath =
+        case F.toText filePath of
+            Left approximation ->
+                Left (unsafeMakeLogicalPath [approximation])
+            Right (T.splitOn "/" -> pieces) ->
+                Right (unsafeMakeLogicalPath pieces)
+
+    invalidPath path = return [(path, AssetNotFound)]
+
+    compile path = do
+        asset <- findAsset hb path
+        return $ case asset of
+            Right _  -> []
+            Left err -> [(path, err)]
diff --git a/Web/Herringbone/Internal/Types.hs b/Web/Herringbone/Internal/Types.hs
--- a/Web/Herringbone/Internal/Types.hs
+++ b/Web/Herringbone/Internal/Types.hs
@@ -13,9 +13,12 @@
 import System.IO hiding (FilePath)
 import qualified Data.ByteString as B
 import qualified Filesystem.Path.CurrentOS as F
+import qualified Filesystem as F
 import Filesystem.Path.CurrentOS (FilePath)
 import Prelude hiding (FilePath)
 
+-- | A value describing an error that occurred while trying to produce an
+-- 'Asset'.
 data AssetError = AssetNotFound
                 | AssetCompileError CompileError
                 | AmbiguousSources [FilePath]
@@ -29,7 +32,9 @@
     , ppReaderSourcePath  :: FilePath
     -- ^ The file path to the source file
     , ppReaderPPs         :: [PP]
-    -- ^ Preprocessors being invoked.
+    -- ^ Preprocessors being invoked. Currently this will only ever have zero
+    -- or one elements; in the future, Herringbone may be able to run multiple
+    -- preprocessors on a single file.
     }
 
 -- | A monad in which preprocessor actions happen.
@@ -64,9 +69,9 @@
 
 -- | A function which performs the compilation.
 type PPAction =
-    B.ByteString ->
+    B.ByteString
     -- ^ Input file contents
-    PPM (Either CompileError B.ByteString)
+    -> PPM (Either CompileError B.ByteString)
     -- ^ Output file contents, or a compile error.
 
 -- | A string which should contain information about why an asset failed to
@@ -97,9 +102,10 @@
 
 -- | A BuildSpec specifies how an asset should be built.
 data BuildSpec = BuildSpec
-    FilePath    -- ^ Source path (relative)
-    FilePath    -- ^ Destination path (again, relative)
-    (Maybe PP)  -- ^ Preprocessor to run (if any)
+    { bsSourcePath :: FilePath  -- ^ Source path (relative)
+    , bsDestPath   :: FilePath  -- ^ Destination path (again, relative)
+    , bsPP         :: (Maybe PP)  -- ^ Preprocessor to run (if any)
+    }
     deriving (Show)
 
 -- | A BuildMapping contains the information to build all of the assets
@@ -128,15 +134,20 @@
 
 type ConfigBuilder = HerringboneSettings -> HerringboneSettings
 
+-- | The directory where Herringbone will look when searching for assets.
 hbSourceDir :: Herringbone -> FilePath
 hbSourceDir = settingsSourceDir . herringboneSettings
 
+-- | The directory to place assets in after compilation.
 hbDestDir :: Herringbone -> FilePath
 hbDestDir = settingsDestDir . herringboneSettings
 
+-- | The collection of preprocessors that will be used when preprocessing
+-- assets.
 hbPPs :: Herringbone -> PPs
 hbPPs = settingsPPs . herringboneSettings
 
+-- | True iff the 'Herringbone' has the verbose setting enabled.
 hbVerbose :: Herringbone -> Bool
 hbVerbose = settingsVerbose . herringboneSettings
 
@@ -147,13 +158,14 @@
     hFlush stdout
 
 -- | All assets in Herringbone are referenced by their logical path. This is
--- the path to an asset, relative to any of the source directories.
+-- the path to an asset, relative to the source directory.
 newtype LogicalPath = LogicalPath { fromLogicalPath :: [Text] }
     deriving (Show, Eq)
 
--- | Create a LogicalPath from a list of Text values. This returns Nothing if
--- the path would be unsafe (that is, if it contains \"..\"), to prevent
--- directory traversal attacks.
+-- | Create a LogicalPath from a list of path segments. For example,
+-- @[\"data\", \"dogs.txt\"]@ would map to data/dogs.txt (relative to the
+-- source directory).  This returns Nothing if the path would be unsafe (that
+-- is, if it contains \"..\"), to prevent directory traversal attacks.
 makeLogicalPath :: [Text] -> Maybe LogicalPath
 makeLogicalPath xs = if safe xs then Just $ LogicalPath xs else Nothing
     where
@@ -179,6 +191,9 @@
     , assetModifiedTime :: UTCTime
     -- ^ Modification time of the asset's source file.
     }
+
+assetContent :: Asset -> IO B.ByteString
+assetContent = F.readFile . assetFilePath
 
 instance Show Asset where
     show (Asset size sourcePath filePath modifiedTime) =
diff --git a/Web/Herringbone/Internal/Utils.hs b/Web/Herringbone/Internal/Utils.hs
--- a/Web/Herringbone/Internal/Utils.hs
+++ b/Web/Herringbone/Internal/Utils.hs
@@ -26,7 +26,9 @@
     let maybes = map (F.stripPrefix root') files
     return $ catMaybes maybes
 
--- should this go in a utils module?
+-- | Partition a list of values based on a monadic predicate, with the list of
+-- values satisfying the predicate as the first element of the result pair, and
+-- the list of values not satisfying the predicate as the second.
 partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
 partitionM f = foldM g ([], [])
     where
diff --git a/herringbone.cabal b/herringbone.cabal
--- a/herringbone.cabal
+++ b/herringbone.cabal
@@ -1,5 +1,5 @@
 name:                herringbone
-version:             0.1.0
+version:             0.1.1
 synopsis:            A library for compiling and serving static web assets.
 description:         A library for compiling and serving static web assets. For more information, please see <https://github.com/hdgarrood/herringbone>.
 license:             MIT
@@ -9,8 +9,6 @@
 category:            Web
 build-type:          Simple
 cabal-version:       >=1.10
-extra-source-files:
-    README.md
 
 source-repository head
   type:     git
@@ -22,6 +20,7 @@
                         Web.Herringbone.Preprocessor.StdIO
                         Web.Herringbone.Preprocessor.Sass
                         Web.Herringbone.Preprocessor.CoffeeScript
+                        Web.Herringbone.Internal.Precompile
                         Web.Herringbone.Internal.Types
                         Web.Herringbone.Internal.Configuration
                         Web.Herringbone.Internal.GetBuildMapping
