diff --git a/madlang.cabal b/madlang.cabal
--- a/madlang.cabal
+++ b/madlang.cabal
@@ -1,5 +1,5 @@
 name:                madlang
-version:             3.2.0.1
+version:             4.0.0.0
 synopsis:            Randomized templating language DSL
 description:         Madlang is a text templating language written in Haskell,
                      meant to explore computational creativity and generative
@@ -81,6 +81,7 @@
                      , zlib
                      , zip-archive
                      , recursion-schemes
+                     , binary
   default-language:    Haskell2010
   if flag(development)
     ghc-options:       -Werror
diff --git a/src/Text/Madlibs/Ana/Resolve.hs b/src/Text/Madlibs/Ana/Resolve.hs
--- a/src/Text/Madlibs/Ana/Resolve.hs
+++ b/src/Text/Madlibs/Ana/Resolve.hs
@@ -8,6 +8,7 @@
   , runText
   , runFileN
   , pathSep
+  , cacheFile
   ) where
 
 import           Control.Arrow               (first)
@@ -40,7 +41,7 @@
 -- | Generate text from file with inclusions
 getInclusionCtx :: (MonadIO m) => Bool -> [T.Text] -> FilePath -> FilePath -> m (Either (ParseError Char (ErrorFancy Void)) [(Key, RandTok)])
 getInclusionCtx isTree ins folder filepath = liftIO $ do
-    libDir <- do { home <- getEnv "HOME" ; if os /= "windows" then pure (home <> "/.madlang/") else pure (home <> "\\.madlang\\") }
+    libDir <- do { home <- getEnv "HOME" ; pure (home <> (pathSep : ".madlang" <> pure pathSep)) }
     file <- catch (readFile' (folder ++ filepath)) (const (readLibFile (libDir <> folder <> filepath)) :: IOException -> IO T.Text)
     let filenames = map T.unpack $ either (error . show) id $ parseInclusions filepath file -- TODO pass up errors correctly
     let resolveKeys file' = fmap (first (((T.pack . (<> "-")) . dropExtension) file' <>))
@@ -53,6 +54,14 @@
 pathSep :: Char
 pathSep | os == "windows" = '\\'
         | otherwise = '/'
+
+filenameBytecode :: FilePath -> FilePath
+filenameBytecode = id
+
+-- | Cache the parsed strucutre (and libraries it depends on) as a binary file
+-- `.filename.mbc`, reading instead from it when possible.
+cacheFile :: FilePath -> IO T.Text
+cacheFile = runFile [] . filenameBytecode
 
 -- | Generate randomized text from a file containing a template
 runFile :: [T.Text] -- ^ List of variables to substitute into the template
diff --git a/src/Text/Madlibs/Exec/Main.hs b/src/Text/Madlibs/Exec/Main.hs
--- a/src/Text/Madlibs/Exec/Main.hs
+++ b/src/Text/Madlibs/Exec/Main.hs
@@ -15,14 +15,14 @@
 import           Text.Madlibs.Cata.Display
 import           Text.Madlibs.Internal.Utils
 import           Text.Madlibs.Packaging.Fetch
-import           Text.Megaparsec
+import           Text.Megaparsec hiding (many)
 
 -- | datatype for the program
 newtype Program = Program { sub :: Subcommand }
 
 -- | datatype for the subcommands
 data Subcommand = Debug { input :: FilePath }
-                | Run { _rep :: Maybe Int , clInputs :: [String] , input :: FilePath }
+                | Run { _rep :: Maybe Int , input :: FilePath }
                 | Lint { clInputs :: [String] , input :: FilePath }
                 | Sample { clInputs :: [String], input :: FilePath }
                 | Get { _remote :: String }
@@ -50,10 +50,6 @@
         <> short 'r'
         <> metavar "REPETITIONS"
         <> help "Number of times to repeat"))
-    <*> (many $ strOption
-        (short 'i'
-        <> metavar "VAR"
-        <> help "command-line inputs to the template."))
     <*> (argument str
         (metavar "FILEPATH"
         <> completer (bashCompleter "file -X '!*.mad' -o plusdirs")
@@ -128,7 +124,7 @@
             let filepath = reverse . (takeWhile (/='/')) . reverse $ toFolder
             let ins = map T.pack (clInputs . sub $ rec)
             case sub rec of
-                (Run reps _ _) ->
+                (Run reps _) ->
                     (TL.init . TL.unlines . fmap TL.fromStrict <$> runFileN (fromMaybe 1 reps) ins filepath) >>= TLIO.putStrLn
                 (Sample _ _) ->
                     (TL.init . TL.unlines . fmap TL.fromStrict <$> runFileN 60 ins filepath) >>= TLIO.putStrLn
diff --git a/src/Text/Madlibs/Internal/Types.hs b/src/Text/Madlibs/Internal/Types.hs
--- a/src/Text/Madlibs/Internal/Types.hs
+++ b/src/Text/Madlibs/Internal/Types.hs
@@ -1,5 +1,7 @@
+{-# LANGUAGE DeriveAnyClass       #-}
 {-# LANGUAGE DeriveFoldable       #-}
 {-# LANGUAGE DeriveFunctor        #-}
+{-# LANGUAGE DeriveGeneric        #-}
 {-# LANGUAGE DeriveLift           #-}
 {-# LANGUAGE DeriveTraversable    #-}
 {-# LANGUAGE FlexibleInstances    #-}
@@ -13,10 +15,12 @@
 
 import           Control.Arrow              (second)
 import           Control.Monad.State
+import           Data.Binary                (Binary)
 import           Data.Function
 import           Data.Functor.Foldable.TH   (makeBaseFunctor)
 import           Data.Monoid
 import qualified Data.Text                  as T
+import           GHC.Generics               (Generic)
 import           Instances.TH.Lift          ()
 import           Language.Haskell.TH.Syntax (Lift (..))
 
@@ -40,7 +44,7 @@
 
 -- | datatype for a token returning a random string
 data RandTok = List [(Prob, RandTok)] | Value T.Text
-    deriving (Show, Eq, Lift)
+    deriving (Show, Eq, Lift, Generic, Binary)
 
 apply :: (T.Text -> T.Text) -> RandTok -> RandTok -- TODO make a base functor so we can map f over stuff?
 apply f (Value str) = Value (f str)
