diff --git a/Config/Dyre.hs b/Config/Dyre.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre.hs
@@ -0,0 +1,149 @@
+{- |
+Dyre is a library for configuring your Haskell programs. Like Xmonad,
+programs configured with Dyre will look for a configuration file written
+in Haskell, which essentially defines a custom program configured exactly
+as the user wishes it to be. And since the configuration is written in
+Haskell, the user is free to do anything they might wish in the context
+of configuring the program.
+
+Dyre places emphasis on elegance of operation and ease of integration
+with existing applications. The 'wrapMain' function is the sole entry
+point for Dyre. When partially applied with a parameter structure, it
+wraps around the 'realMain' value from that structure, yielding an almost
+identical function which has been augmented with dynamic recompilation
+functionality.
+
+The 'Config.Dyre.Relaunch' module provides the ability to restart the
+program (recompiling if applicable), and persist state across restarts,
+but it has no impact whatsoever on the rest of the library whether it
+is used or not.
+
+A full example of using Dyre's recompilation and relaunching features
+is as follows:
+
+>-- DyreExample.hs --
+>module DyreExample where
+>
+>import qualified Config.Dyre as Dyre
+>
+>import Config.Dyre.Relaunch
+>import System.IO
+>
+>data Config = Config { message :: String, errorMsg :: Maybe String }
+>data State  = State { bufferLines :: [String] } deriving (Read, Show)
+>
+>defaultConfig :: Config
+>defaultConfig = Config "Dyre Example v0.1" Nothing
+>
+>showError :: Config -> String -> Config
+>showError cfg msg = cfg { errorMsg = Just msg }
+>
+>realMain Config{message = message, errorMsg = errorMsg } = do
+>    (State buffer) <- restoreState $ State []
+>    case errorMsg of
+>         Nothing -> return ()
+>         Just em -> putStrLn $ "Error: " ++ em
+>    putStrLn message
+>    mapM putStrLn . reverse $ buffer
+>    putStr "> " >> hFlush stdout
+>    input <- getLine
+>    case input of
+>         "exit" -> return ()
+>         "quit" -> return ()
+>         other  -> relaunchWithState (State $ other:buffer) Nothing
+>
+>dyreExample = Dyre.wrapMain $ Dyre.defaultParams
+>    { Dyre.projectName = "dyreExample"
+>    , Dyre.realMain    = realMain
+>    , Dyre.showError   = showError
+>    }
+
+Notice that all of the program logic is contained in the 'DyreExample'
+module. The main module of the program is absolutely trivial.
+
+>-- Main.hs --
+>module Main where
+>import DyreExample
+>main = dyreExample defaultConfig
+
+When reading the above program, bear in mind exactly how much of the
+code is simply *program logic*. Dyre is designed to intelligently
+handle recompilation with a bare minimum of program modification.
+
+Some mention should be made of Dyre's defaults. The 'defaultParams'
+structure used in the example defines reasonable default values for
+several configuration items. In the absence of any other definitions,
+Dyre will default to outputting status messages to stderr, not hiding
+any packages during compilation, and passing no special options to GHC.
+
+Also, Dyre will expect configuration files to be placed at the path
+'$XDG_CONFIG_HOME/<app>/<app>.hs', and it will store cache files in
+the '$XDG_CACHE_HOME/<app>/' directory. The 'System.Environment.XDG'
+module will be used to determine these paths, so refer to it for
+behaviour on Windows platforms.
+-}
+module Config.Dyre ( wrapMain, Params(..), defaultParams ) where
+
+import System.IO           ( hPutStrLn, stderr )
+import System.Directory    ( doesFileExist )
+
+import Config.Dyre.Params  ( Params(..) )
+import Config.Dyre.Compile ( customCompile )
+import Config.Dyre.Compat  ( customExec )
+import Config.Dyre.Options ( getReconf, getDebug, withDyreOptions )
+import Config.Dyre.Paths   ( getPaths, maybeModTime )
+
+-- | A set of reasonable defaults for configuring Dyre. If the minimal set of
+--   fields are modified, the program will use the XDG-defined locations for
+--   configuration and cache files (see 'System.Environment.XDG.BaseDir' for
+--   details), pass no special options to GHC, and will output status messages
+--   to stderr.
+--
+--   The fields that will have to be filled are 'projectName', 'realMain', and
+--   'showError'
+defaultParams :: Params cfgType
+defaultParams = Params
+    { projectName  = undefined
+    , configDir    = Nothing
+    , cacheDir     = Nothing
+    , realMain     = undefined
+    , showError    = undefined
+    , hidePackages = []
+    , ghcOpts      = []
+    , statusOut    = hPutStrLn stderr
+    }
+
+-- | 'wrapMain' is how Dyre recieves control of the program. It is expected
+--   that it will be partially applied with its parameters to yield a "main"
+--   entry point, which will then be called by the 'main' function, as well
+--   as by any custom configurations.
+wrapMain :: Params cfgType -> cfgType -> IO ()
+wrapMain params@Params{projectName = pName} cfg = withDyreOptions $ do
+    -- Get the important paths
+    (thisBinary, tempBinary, configFile, cacheDir) <- getPaths params
+
+    -- Check their modification times
+    thisTime <- maybeModTime thisBinary
+    tempTime <- maybeModTime tempBinary
+    confTime <- maybeModTime configFile
+
+    -- If there's a config file, and the temp binary is older than something
+    -- else, or we were specially told to recompile, then we should recompile.
+    let confExists = confTime /= Nothing
+    forceReconf <- getReconf
+    errors <- if confExists &&
+                 (tempTime < confTime || tempTime < thisTime || forceReconf)
+                 then customCompile params
+                 else return Nothing
+
+    -- If there's a custom binary and we're not it, run it. Otherwise
+    -- just launch the main function, reporting errors if appropriate.
+    -- Also we don't want to use a custom binary if the conf file is
+    -- gone.
+    customExists <- doesFileExist tempBinary
+    if confExists && customExists && (thisBinary /= tempBinary)
+       then do statusOut params $ "Launching custom binary '" ++ tempBinary ++ "'\n"
+               customExec tempBinary Nothing
+       else realMain params $ case errors of
+                                   Nothing -> cfg
+                                   Just er -> (showError params) cfg er
diff --git a/Config/Dyre/Compat.hs b/Config/Dyre/Compat.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre/Compat.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+{- |
+Compatibility code for things that need to be done differently
+on different systems.
+-}
+module Config.Dyre.Compat ( customExec, getPIDString ) where
+
+import Config.Dyre.Options ( customOptions )
+
+#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
+
+import System.Win32
+import System.Process
+import System.Exit
+import System.Mem
+
+-- This can be removed as soon as a 'getProcessID' function
+-- gets added to 'System.Win32'
+foreign import stdcall unsafe "winbase.h GetCurrentProcessId"
+    c_GetCurrentProcessID :: IO DWORD
+getPIDString = fmap show c_GetCurrentProcessID
+
+customExec binary mArgs = do
+    args <- customOptions mArgs
+    -- This whole thing is a terrible, ugly hack. Since Windows
+    -- is too braindead to provide an exec() system call for us
+    -- to use, we simply create a new process that inherits
+    -- the stdio handles.
+    (_,_,_,child) <- createProcess $ CreateProcess
+        { cmdspec   = RawCommand binary args
+        , cwd       = Nothing
+        , env       = Nothing
+        , std_in    = Inherit
+        , std_out   = Inherit
+        , std_err   = Inherit
+        , close_fds = True
+        }
+    -- Do some garbage collection in an optimistic attempt to
+    -- offset some of the memory we waste here.
+    performGC
+    -- And to prevent terminal apps from losing IO, we have to
+    -- sit around waiting for the child to exit.
+    exitCode <- waitForProcess child
+    case exitCode of
+         ExitSuccess -> c_ExitProcess 0
+         ExitFailure c -> c_ExitProcess (fromIntegral c)
+
+foreign import stdcall unsafe "winbase.h ExitProcess"
+    c_ExitProcess :: UINT -> IO ()
+
+#else
+
+import System.Posix.Process ( executeFile, getProcessID )
+
+getPIDString = fmap show getProcessID
+
+customExec binary mArgs = do
+    args <- customOptions mArgs
+    executeFile binary False args Nothing
+
+#endif
+
+-- | Called whenever execution needs to be transferred over to
+--   a different binary.
+customExec :: FilePath -> Maybe [String] -> IO ()
+
+-- | What it says on the tin. Gets the current PID as a string.
+--   Used to determine the name for the state file during restarts.
+getPIDString :: IO String
diff --git a/Config/Dyre/Compile.hs b/Config/Dyre/Compile.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre/Compile.hs
@@ -0,0 +1,58 @@
+{- |
+Compiling the custom executable. The majority of the code actually
+deals with error handling, and not the compilation itself /per se/.
+-}
+module Config.Dyre.Compile ( customCompile ) where
+
+import System.IO         ( openFile, hClose, IOMode(..) )
+import System.Exit       ( ExitCode(..) )
+import System.Process    ( runProcess, waitForProcess )
+import System.FilePath   ( (</>) )
+import System.Directory  ( getCurrentDirectory, doesFileExist
+                         , createDirectoryIfMissing )
+import Control.Exception ( bracket )
+import GHC.Paths         ( ghc )
+
+import Config.Dyre.Paths  ( getPaths )
+import Config.Dyre.Params ( Params(..) )
+
+-- | Attempts to compile the configuration file. Will return a string
+--   containing any compiler output.
+customCompile :: Params cfgType -> IO (Maybe String)
+customCompile params@Params{statusOut = output} = do
+    (thisBinary, tempBinary, configFile, cacheDir) <- getPaths params
+    output $ "Configuration '" ++ configFile ++  "' changed. Recompiling."
+    createDirectoryIfMissing True cacheDir
+
+    -- Compile occurs in here
+    let errFile = cacheDir </> "errors.log"
+    result <- bracket (openFile errFile WriteMode) hClose $ \errHandle -> do
+        ghcOpts <- makeFlags params configFile tempBinary
+        ghcProc <- runProcess ghc ghcOpts (Just cacheDir) Nothing
+                              Nothing Nothing (Just errHandle)
+        waitForProcess ghcProc
+
+    -- Display a helpful little status message
+    if result /= ExitSuccess
+       then output $ "Error occurred while loading configuration file."
+       else output $ "Program reconfiguration successful."
+
+    -- If the error file exists and actually has some contents, return
+    -- 'Just' the error string. Otherwise return 'Nothing'.
+    errorsExist <- doesFileExist errFile
+    if not errorsExist
+       then return Nothing
+       else do errors <- readFile errFile
+               if errors == ""
+                  then return Nothing
+                  else return . Just $ errors
+
+-- | Assemble the arguments to GHC so everything compiles right.
+makeFlags :: Params cfgType -> FilePath -> FilePath -> IO [String]
+makeFlags Params{ghcOpts = flags, hidePackages = hides} cfgFile tmpFile = do
+    currentDir <- getCurrentDirectory
+    return . concat $ [ ["-v0", "-fforce-recomp", "-i" ++ currentDir]
+                      , prefix "-hide-package" hides, flags
+                      , ["--make", cfgFile, "-o", tmpFile]
+                      ]
+  where prefix y xs = concat . map (\x -> [y,x]) $ xs
diff --git a/Config/Dyre/Options.hs b/Config/Dyre/Options.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre/Options.hs
@@ -0,0 +1,115 @@
+{-
+Handling for the command-line options that can be used to configure
+Dyre. As of the last count, there are four of them, and more are
+unlikely to be needed. The only one that a user should ever need to
+use is the '--force-reconf' option, so the others all begin with
+'--dyre-<option-name>'.
+
+At the start of the program, before anything else occurs, the
+'withDyreOptions' function is used to hide Dyre's command-line
+options. They are loaded into the IO monad using the module
+'System.IO.Storage'. This keeps them safely out of the way of
+the user code and our own.
+
+Later, when Dyre needs to access the options, it does so through
+the accessor functions defined here. When it comes time to pass
+control over to a new binary, it gets an argument list which
+preserves the important flags with a call to 'customOptions'.
+-}
+module Config.Dyre.Options
+  ( withDyreOptions
+  , customOptions
+  , getReconf
+  , getDebug
+  , getMasterBinary
+  , getStatePersist
+  ) where
+
+import Data.List
+import Data.Maybe
+import System.IO.Storage
+import System.Environment
+import System.Environment.Executable
+
+-- | Store Dyre's command-line options to the IO-Store "dyre",
+--   and then execute the provided IO action with all Dyre's
+--   options removed from the command-line arguments.
+withDyreOptions :: IO a -> IO a
+withDyreOptions action = withStore "dyre" $ do
+    -- Pretty important
+    args <- getArgs
+
+    -- If the flag exists, it overrides the current file. Likewise,
+    --   if it doesn't exist, we end up with the path to our current
+    --   file. This seems like a sensible way to do it.
+    this <- getExecutablePath
+    putValue "dyre" "masterBinary" this
+    storeFlag args "--dyre-master-binary=" "masterBinary"
+
+    -- Load the other important arguments into IO storage.
+    storeFlag args "--dyre-state-persist=" "persistState"
+    putValue "dyre" "forceReconf"  $ "--force-reconf" `elem` args
+    putValue "dyre" "debugMode"    $ "--dyre-debug"   `elem` args
+
+    -- We filter the arguments, so now Dyre's arguments 'vanish'
+    withArgs (filterArgs args) action
+  where filterArgs = filter $ not . prefixElem dyreArgs
+        prefixElem xs = or . zipWith ($) (map isPrefixOf xs) . repeat
+
+-- | Get the value of the '--force-reconf' flag, which is used
+--   to force a recompile of the custom configuration.
+getReconf :: IO Bool
+getReconf = getDefaultValue "dyre" "forceReconf" False
+
+-- | Get the value of the '--dyre-debug' flag, which is used
+--   to debug a program without installation. Specifically,
+--   it forces the application to use './cache/' as the cache
+--   directory, and './' as the configuration directory.
+getDebug  :: IO Bool
+getDebug = getDefaultValue "dyre" "debugMode" False
+
+-- | Get the path to the master binary. This is set to the path of
+--   the *current* binary unless the '--dyre-master-binary=' flag
+--   is set. Obviously, we pass the '--dyre-master-binary=' flag to
+--   the custom configured application from the master binary.
+getMasterBinary :: IO (Maybe String)
+getMasterBinary = getValue "dyre" "masterBinary"
+
+-- | Get the path to a persistent state file. This is set only when
+--   the '--dyre-state-persist=' flag is passed to the program. It
+--   is used internally by 'Config.Dyre.Relaunch' to save and restore
+--   state when relaunching the program.
+getStatePersist :: IO (Maybe String)
+getStatePersist = getValue "dyre" "persistState"
+
+-- | Return the set of options which will be passed to another instance
+--   of Dyre. Preserves the master binary, state file, and debug mode
+--   flags, but doesn't pass along the forced-recompile flag. Can be
+--   passed a set of other arguments to use, or it defaults to using
+--   the current arguments when passed 'Nothing'.
+customOptions :: Maybe [String] -> IO [String]
+customOptions otherArgs = do
+    masterPath <- getMasterBinary
+    stateFile  <- getStatePersist
+    debugMode  <- getDebug
+    return . filter (not . null) $ fromMaybe [] otherArgs ++
+        [ if debugMode then "--dyre-debug" else ""
+        , case stateFile of
+               Nothing -> ""
+               Just sf -> "--dyre-state-persist=" ++ sf
+        , "--dyre-master-binary=" ++ (fromJust masterPath)
+        ]
+
+-- | Look for the given flag in the argument array, and store
+--   its value under the given name if it exists.
+storeFlag :: [String] -> String -> String -> IO ()
+storeFlag args flag name
+    | null match  = return ()
+    | otherwise   = putValue "dyre" name $ drop (length flag) (head match)
+  where match = filter (isPrefixOf flag) args
+
+-- | The array of all arguments that Dyre recognizes. Used to
+--   make sure none of them are visible past 'withDyreOptions'
+dyreArgs :: [String]
+dyreArgs = [ "--force-reconf", "--dyre-state-persist"
+           , "--dyre-debug", "--dyre-master-binary" ]
diff --git a/Config/Dyre/Params.hs b/Config/Dyre/Params.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre/Params.hs
@@ -0,0 +1,40 @@
+{- |
+Defines the 'Params' datatype which Dyre uses to define all
+program-specific configuration data. Shouldn't be imported
+directly, as 'Config.Dyre' re-exports it.
+-}
+module Config.Dyre.Params ( Params(..) ) where
+
+-- | This structure is how all kinds of useful data is fed into Dyre. Of
+--   course, only the 'projectName', 'realMain', and 'showError' fields
+--   are really necessary. By using the set of default values provided
+--   as 'Config.Dyre.defaultParams', you can get all the benefits of
+--   using Dyre to configure your program in only five or six lines of
+--   code.
+data Params cfgType = Params
+    { projectName  :: String
+    -- ^ The name of the project. This needs to also be the name of
+    --   the executable, and the name of the configuration file.
+    , configDir    :: Maybe (IO FilePath)
+    -- ^ The directory to look for a configuration file in.
+    , cacheDir     :: Maybe (IO FilePath)
+    -- ^ The directory to store build files in, including the final
+    --   generated executable.
+    , realMain     :: cfgType -> IO ()
+    -- ^ The main function of the program. When Dyre has completed
+    --   all of its recompilation, it passes the configuration data
+    --   to this function and gets out of the way.
+    , showError    :: cfgType -> String -> cfgType
+    -- ^ This function is used to display error messages that occur
+    --   during recompilation, by allowing the program to modify its
+    --   initial configuration.
+    , hidePackages :: [String]
+    -- ^ Packages that need to be hidden during compilation
+    , ghcOpts      :: [String]
+    -- ^ Miscellaneous GHC compilation settings go here
+    , statusOut    :: String -> IO ()
+    -- ^ A status output function. Will be called with messages
+    --   when Dyre recompiles or launches anything. A good value
+    --   is 'hPutStrLn stderr', assuming there is no pressing
+    --   reason to not put messages on stderr.
+    }
diff --git a/Config/Dyre/Paths.hs b/Config/Dyre/Paths.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre/Paths.hs
@@ -0,0 +1,39 @@
+module Config.Dyre.Paths where
+
+import System.Info
+import System.Time
+import System.FilePath
+import System.Directory
+import System.Environment.Executable
+import System.Environment.XDG.BaseDir
+
+import Config.Dyre.Params
+import Config.Dyre.Options
+
+-- | Return the paths to, respectively, the current binary, the custom
+--   binary, the config file, and the cache directory.
+getPaths :: Params c -> IO (FilePath, FilePath, FilePath, FilePath)
+getPaths params@Params{projectName = pName} = do
+    thisBinary <- getExecutablePath
+    debugMode  <- getDebug
+    cwd <- getCurrentDirectory
+    cacheDir  <- case (debugMode, cacheDir params) of
+                      (True,  _      ) -> return $ cwd </> "cache"
+                      (False, Nothing) -> getUserCacheDir pName
+                      (False, Just cd) -> cd
+    configDir <- case (debugMode, configDir params) of
+                      (True,  _      ) -> return $ cwd
+                      (False, Nothing) -> getUserConfigDir pName
+                      (False, Just cd) -> cd
+    let tempBinary = cacheDir </> pName ++ "-" ++ os ++ "-" ++ arch
+    let configFile = configDir </> pName ++ ".hs"
+    return $ (thisBinary, tempBinary, configFile, cacheDir)
+
+-- | Check if a file exists. If it exists, return Just the modification
+--   time. If it doesn't exist, return Nothing.
+maybeModTime :: FilePath -> IO (Maybe ClockTime)
+maybeModTime path = do
+    fileExists <- doesFileExist path
+    if fileExists
+       then fmap Just $ getModificationTime path
+       else return Nothing
diff --git a/Config/Dyre/Relaunch.hs b/Config/Dyre/Relaunch.hs
new file mode 100644
--- /dev/null
+++ b/Config/Dyre/Relaunch.hs
@@ -0,0 +1,76 @@
+{-
+This is the only other module aside from 'Config.Dyre' which needs
+to be imported specially. It contains functions for restarting the
+program (which, usefully, will cause a recompile if the config has
+been changed), as well as saving and restoring state across said
+restarts.
+
+The impossibly simple function arguments are a consequence of a
+little cheating we do using the 'System.IO.Storage' library. Of
+course, we can't use the stored data unless something else put
+it there, so this module will probably explode horribly if used
+outside of a program whose recompilation is managed by Dyre.
+-}
+module Config.Dyre.Relaunch
+  ( relaunchWithState
+  , restoreState
+  , relaunchMaster
+  , maybeRestoreState
+  ) where
+
+import Data.Maybe           ( fromMaybe, fromJust )
+import System.IO            ( writeFile, readFile )
+import System.IO.Error      ( try )
+import System.FilePath      ( (</>) )
+import System.Directory     ( getTemporaryDirectory, removeFile )
+
+import System.IO.Storage    ( putValue, delValue )
+import Config.Dyre.Options  ( customOptions, getMasterBinary, getStatePersist )
+import Config.Dyre.Compat   ( customExec, getPIDString )
+
+-- | Just relaunch the master binary. We don't have any important
+--   state to worry about. (Or, like when 'relaunchWithState' calls
+--   it, we're managing state on our own.)
+relaunchMaster :: Maybe [String] -> IO ()
+relaunchMaster otherArgs = do
+    masterPath <- fmap fromJust getMasterBinary
+    customExec masterPath otherArgs
+
+-- | Relaunch the master binary, but first preserve the program
+--   state so that we can use the 'restoreState' functions to get
+--   it back again later. Since we're not trying to be fancy here,
+--   we'll just use 'show' to write it out.
+relaunchWithState :: Show a => a -> Maybe [String] -> IO ()
+relaunchWithState state otherArgs = do
+    -- Calculate the path to the state file
+    pidString <- getPIDString
+    tempDir   <- getTemporaryDirectory
+    let statePath = tempDir </> pidString ++ ".state"
+    -- Write the state to the file and store the path
+    writeFile statePath . show $ state
+    putValue "dyre" "persistState" statePath
+    -- Relaunch
+    relaunchMaster otherArgs
+
+-- | Restore state that was previously saved by the 'relaunchWithState'
+--   function. If unsuccessful, it will simply return Nothing.
+maybeRestoreState :: Read a => IO (Maybe a)
+-- This could probably be a lot simpler if I grokked
+-- monad transformers better.
+maybeRestoreState = do
+    statePath <- getStatePersist
+    case statePath of
+         Nothing -> return Nothing
+         Just sp -> do
+             stateData <- readFile sp
+--             removeFile sp
+             delValue "dyre" "persistState"
+             result <- try $ readIO stateData
+             case result of
+                  Left  _ -> return $ Nothing
+                  Right v -> return $ Just v
+
+-- | Restore state using the 'maybeRestoreState' function, but return
+--   the provided default state if we can't get anything better.
+restoreState :: Read a => a -> IO a
+restoreState d = fmap (fromMaybe d) maybeRestoreState
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2009, Will Donnelly
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the software nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,5 @@
+#!/usr/bin/env runhaskell
+
+import Distribution.Simple
+
+main = defaultMain
diff --git a/dyre.cabal b/dyre.cabal
new file mode 100644
--- /dev/null
+++ b/dyre.cabal
@@ -0,0 +1,45 @@
+name:          dyre
+version:       0.4
+category:      Development
+synopsis:      Dynamic reconfiguration in Haskell
+
+description:   Dyre implements dynamic reconfiguration facilities after the
+               style of Xmonad. Dyre aims to be as simple as possible without
+               sacrificing features, and places an emphasis on simplicity of
+               integration with an application.
+
+               A full introduction with a complete example project can be found
+               in the documentation for 'Config.Dyre'
+
+homepage:      http://github.com/willdonnelly/dyre
+bug-reports:   http://github.com/willdonnelly/dyre/issues
+stability:     alpha
+author:        Will Donnelly
+maintainer:    Will Donnelly <will.donnelly@gmail.com>
+copyright:     (c) 2009 Will Donnelly
+license:       BSD3
+license-file:  LICENSE
+
+build-type:    Simple
+cabal-version: >= 1.6
+
+library
+  exposed-modules: Config.Dyre,
+                   Config.Dyre.Paths,
+                   Config.Dyre.Compat,
+                   Config.Dyre.Params,
+                   Config.Dyre.Options,
+                   Config.Dyre.Compile,
+                   Config.Dyre.Relaunch
+  build-depends:   base >= 4 && < 5, process, filepath,
+                   directory, ghc-paths, old-time,
+                   executable-path, xdg-basedir, io-storage
+
+  if os(windows)
+      build-depends: Win32
+  else
+      build-depends: unix
+
+source-repository head
+  type:      git
+  location:  git://github.com/willdonnelly/dyre.git
