diff --git a/Control/Hmk.lhs-boot b/Control/Hmk.lhs-boot
new file mode 100644
--- /dev/null
+++ b/Control/Hmk.lhs-boot
@@ -0,0 +1,9 @@
+> module Control.Hmk where
+>
+> type Cmp m a = a -> a -> m Bool
+> data Result = TaskSuccess | TaskFailure
+> type Task m = m Result
+> data Rule m a = Rule { target :: a
+>                      , prereqs :: [a]
+>                      , recipe :: Maybe ([a] -> Task m)
+>                      , isStale :: Cmp m a }
diff --git a/Main.lhs b/Main.lhs
--- a/Main.lhs
+++ b/Main.lhs
@@ -45,14 +45,15 @@
 > main = do
 >   targets <- map File <$> getArgs
 >   metarules <- eval =<< parse "mkfile" <$> readFile "mkfile"
->   let rules = process Eval.isStale $ Seq.toList $
->               instantiateRecurse (Seq.fromList targets) metarules
+>   let rules = Seq.toList $ instantiateRecurse (Seq.fromList targets) metarules
 >   when (null rules) (fail "No rules in mkfile.")
+>   -- completed and coalesced rules.
+>   let crules = process Eval.isStale rules
 
 Per the mk man page, if no targets are specified on the command line, then
 assume the target is that of the first rule.
 
 >   schedule <- case targets of
->               [] -> mk rules [target (head rules)]
->               _  -> mk rules targets
+>                 [] -> mk crules [target (head rules)]
+>                 _  -> mk crules targets
 >   sequence_ schedule
diff --git a/hmk.cabal b/hmk.cabal
--- a/hmk.cabal
+++ b/hmk.cabal
@@ -1,5 +1,5 @@
 name:           hmk
-version:        0.9.1
+version:        0.9.2
 author:         Mathieu Boespflug
 maintainer:     Mathieu Boespflug <mboes@tweag.net>
 homepage:       http://code.haskell.org/~mboes/hmk
