diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -40,7 +40,35 @@
   ...
   build-tool-depends: debug-pp:debug-pp
 ```
+Configuration
+-------------
 
+The tool is customizable to some extent. It tries to find a config file in the
+following order:
+
+2. `.debug-pp.yaml` in the current directory (useful for per-directory
+   settings)
+3. `.debug-pp.yaml` in the nearest ancestor directory (useful for
+   per-project settings)
+4. `debug-pp/config.yaml` in the platform’s configuration directory
+   (on Windows, it is %APPDATA%, elsewhere it defaults to `~/.config` and
+   can be overridden by the `XDG_CONFIG_HOME` environment variable;
+   useful for user-wide settings)
+5. `.debug-pp.yaml` in your home directory (useful for user-wide
+   settings)
+6. The default settings.
+
+Use `debug-pp --defaults > .debug-pp.yaml` to dump a
+well-documented default configuration to a file, this way you can get started
+quickly.
+
+The configuration options include:
+* Exclude modules by name.
+* Instrument the `main` function to launch a web browser upon completion.
+* Select which language extensions are included automatically.
+* Configure the `debug-hoed` instrumentation to include e.g. deriving `Generic` and `Observable` instances
+
+
 Motivation
 -------------
 
@@ -48,4 +76,4 @@
 
 * However, error messages are much worse for TH quoted code. Errors like `Not in scope: data constructor Foo in line X` become `Not in scope: Foo, in the TH quotation ENTIRE MODULE HERE`. 
 
-* Personally, quoting/unquoting the module by hand is annoying. Having a preprocessor do this for me is convenient, and can be easily tied to a Cabal flag ora stack command line arg.
+* Personally, quoting/unquoting the module by hand is annoying. Having a preprocessor do this for me is convenient, and can be easily tied to a Cabal flag or a stack command line arg.
diff --git a/debug-pp.cabal b/debug-pp.cabal
--- a/debug-pp.cabal
+++ b/debug-pp.cabal
@@ -2,13 +2,15 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 961f3a1ce57f79aa77bfe78b26a463a2bab8121dbb2e495de793608f4dc714e4
+-- hash: 2fdefebfe7db959b89432facceefb61718e6546123aa7074c20c8bbe9e31ab06
 
 name:           debug-pp
-version:        0.1.0.0
-description:    A preprocessor to automate the debug instrumentation of a module
+version:        0.1.1
+synopsis:       A preprocessor for the debug package
+description:    A preprocessor to automate the instrumentation of a module for the debug package
 category:       Debugging
 homepage:       https://github.com/pepeiborra/debug-hoed-pp#readme
+bug-reports:    https://github.com/pepeiborra/debug-pp/issues
 author:         Pepe Iborra
 maintainer:     pepeiborra@gmail.com
 copyright:      All Rights Reserved
@@ -20,12 +22,21 @@
 extra-source-files:
     README.md
 
+source-repository head
+  type: git
+  location: https://github.com/pepeiborra/debug-pp
+
 executable debug-pp
   main-is: Main.hs
   hs-source-dirs:
       src
   build-depends:
-      base >=4.7 && <5
+      aeson
+    , base >=4.7 && <5
+    , debug-hoed
+    , directory
+    , filepath
+    , yaml
   other-modules:
       Paths_debug_pp
   default-language: Haskell2010
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -1,12 +1,23 @@
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE ViewPatterns #-}
 
 module Main (main) where
 
 import Control.Monad
+import Data.Aeson
 import Data.Char
 import Data.List
+import Data.Maybe
+import Data.Yaml
+import Data.Yaml.Config
+import GHC.Generics
+import System.Directory
 import System.Environment
 import System.Exit
+import System.FilePath
 import System.IO
 import Text.Printf
 
@@ -21,11 +32,98 @@
   "If no SOURCE or if SOURCE is `-', read standard input."
   ]
 
+data Config = Config_
+  { _excluded :: Maybe [String]
+  , _instrumentMain :: Maybe Bool
+  , _disablePartialTypeSignatureWarnings :: Maybe Bool
+  , _enableExtendedDefaultingRules :: Maybe Bool
+  , _generateObservableInstances :: Maybe Bool
+  , _generateGenericInstances :: Maybe Bool
+  , _excludedFromInstanceGeneration :: Maybe [String]
+  , _verbose :: Maybe Bool
+  } deriving (Generic, Show)
+
+configJsonOptions = defaultOptions{fieldLabelModifier = tail}
+
+instance FromJSON Config where parseJSON = genericParseJSON configJsonOptions
+instance ToJSON Config where toJSON = genericToJSON configJsonOptions
+
+
+pattern Config { excluded
+               , instrumentMain
+               , disablePartialTypeSignatureWarnings
+               , enableExtendedDefaultingRules
+               , generateGenericInstances
+               , generateObservableInstances
+               , excludedFromInstanceGeneration
+               , verbose
+               } <-
+  Config_
+  { _excluded = (fromMaybe [] -> excluded)
+  , _instrumentMain = (fromMaybe True -> instrumentMain)
+  , _disablePartialTypeSignatureWarnings = (fromMaybe True -> disablePartialTypeSignatureWarnings)
+  , _enableExtendedDefaultingRules = (fromMaybe False -> enableExtendedDefaultingRules)
+  , _generateObservableInstances = (fromMaybe False -> generateObservableInstances)
+  , _generateGenericInstances = (fromMaybe False -> generateGenericInstances)
+  , _excludedFromInstanceGeneration = (fromMaybe [] -> excludedFromInstanceGeneration)
+  , _verbose = (fromMaybe False -> verbose)
+  }
+  where Config a b c d e f g h = Config_ (Just a) (Just b) (Just c) (Just d) (Just e) (Just f) (Just g) (Just h)
+
+defaultConfig :: Config
+defaultConfig = Config_ Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
+
+readConfig :: IO Config
+readConfig = do
+  cwd <- getCurrentDirectory
+  home <- getHomeDirectory
+  system <- getXdgDirectory XdgConfig "debug-pp"
+  from <- filterM doesFileExist $
+        [d </> ".debug-pp.yaml" | d <- reverse (ancestors cwd)] ++
+        [ system </> "config.yaml"
+        , home </> ".debug-pp.yaml"]
+  case from of
+    [] -> return defaultConfig
+    _  -> loadYamlSettings from [] ignoreEnv
+  where
+    ancestors = map joinPath . tail . inits . splitPath
+
+defConfig = unlines
+  ["# debug-pp configuration file"
+  ,"# ==========================="
+  ,""
+  ,"# List of Haskell module names to exclude from instrumentation"
+  ,"excluded: []"
+  , ""
+  , "# If true then insert a call to debugRun in the main function."
+  , "instrumentMain: true"
+  , ""
+  , "# If true, instruct the debug TH wrapper to insert Observable instances for types that derive Generic."
+  , "generateGenericInstances: false"
+  , ""
+  , "# If true, instruct the debug TH wrapper to insert Generic instances for types that don't derive Generic."
+  , "generateGenericInstances: false"
+  , ""
+  , "# List of types excluded from instance generation"
+  , "excludedFromInstanceGeneration: []"
+  , ""
+  , "# If true, print a line for every instrumented module."
+  , "verbose: false"
+  , ""
+  , "# If true, enable GHC extended defaulting rules. This is often required when using debug-hoed"
+  , "enableExtendedDefaultingRules: true"
+  , ""
+  , ""
+  ]
+
 main :: IO ()
 main = do
   args <- getArgs
   progName <- getProgName
   (orig, inp, out) <- case args of
+    ["--defaults"] -> do
+      putStrLn defConfig
+      exitSuccess
     ["--help"] -> do
       putStrLn $ usage progName
       exitSuccess
@@ -39,39 +137,94 @@
   hIn  <- maybe (return stdin)  (`openFile` ReadMode) inp
   hOut <- maybe (return stdout) (`openFile` WriteMode) out
   contents <- hGetContents hIn
-  hPutStr hOut $ instrument contents
+  config@Config{..} <- readConfig
+  hPutStr hOut $ instrument config contents
   unless (hOut == stdout) $ hClose hOut
+  when verbose $
+    putStrLn $ "[debug-pp] Instrumented " ++ orig
 
-instrument contents = unlines [top', modules', body']
+instrument Config {..} contents
+  | name `elem` excluded = contents
+  | otherwise = unlines [top', modules', body'']
   where
-    (top,modules,body) = parseModule contents
-    modules' = unlines $ modules ++ ["import qualified Debug"]
+    (top, name, modules, body) = parseModule contents
+    modules' = unlines $ modules ++
+      ["import qualified Debug"] ++
+      ["import qualified GHC.Generics" | generateGenericInstances]
     top' =
-      unlines
-        $ "{-# LANGUAGE TemplateHaskell #-}"
-        : "{-# LANGUAGE PartialTypeSignatures #-}"
-        : "{-# LANGUAGE ViewPatterns #-}"
-        : "{-# OPTIONS -Wno-partial-type-signatures #-}"
-        : top
-    body' = unlines $ "Debug.debug [d|" : map indent (body ++ ["  |]"])
+      unlines $
+      [ "{-# LANGUAGE TemplateHaskell #-}"
+      , "{-# LANGUAGE PartialTypeSignatures #-}"
+      , "{-# LANGUAGE ViewPatterns #-}"
+      , "{-# LANGUAGE FlexibleContexts #-}"
+      ] ++
+      [ "{-# OPTIONS -Wno-partial-type-signatures #-}"
+      | disablePartialTypeSignatureWarnings
+      ] ++
+      ["{-# LANGUAGE ExtendedDefaultRules #-}" | enableExtendedDefaultingRules] ++
+      ["{-# LANGUAGE DeriveAnyClass #-}" | generateObservableInstances] ++
+      ["{-# LANGUAGE DerivingStrategies #-}" | generateObservableInstances] ++
+      ["{-# LANGUAGE DeriveGeneric #-}" | generateGenericInstances] ++ top
+    body' =
+      map
+        (if instrumentMain
+           then instrumentMainFunction
+           else id)
+        body
+    debugWrapper
+      | not (generateGenericInstances || generateObservableInstances) =
+        "Debug.debug"
+      | otherwise =
+        printf
+          "Debug.debug' Debug.Config{Debug.generateGenericInstances=%s,Debug.generateObservableInstances=%s, Debug.excludeFromInstanceGeneration=%s}"
+          (show generateGenericInstances)
+          (show generateObservableInstances)
+          (show excludedFromInstanceGeneration)
+    body'' = unlines $ (debugWrapper ++ " [d|") : map indent (body' ++ ["  |]"])
 
-parseModule contents = (top, modules, body)
+instrumentMainFunction l
+  | ('m':'a':'i':'n':rest) <- l
+  , ('=':rest') <- dropWhile isSpace rest
+  , not ("debugRun" `isPrefixOf` rest') = "main = Debug.debugRun $ " ++ rest'
+  | otherwise = l
+
+parseModule contents = (map fst top, name, modules, body)
   where
-    isImportLine = ("import" `isPrefixOf`)
-    (top, rest) = break isImportLine (lines contents)
-    (reverse -> body0, reverse -> modules0) =
-      break (isImportLine . fst) (reverse $ annotateBlockComments rest)
+    contents' = annotateBlockComments (lines contents)
+    isImportLine = ("import " `isPrefixOf`)
+    (top, rest) = break (\(l, insideComment) -> not insideComment && isImportLine l) contents'
+    (reverse -> body0, reverse -> modules0) = break (\(l,insideComment) -> not insideComment && isImportLine l) (reverse rest)
+    nameLine =
+      head $
+      [l | (l, False) <- top, "module " `isPrefixOf` l] ++
+      ["Main"]
+    name = takeWhile (\x -> not (isSpace x || x == '(')) $ drop 7 nameLine
     body = map fst $ dropWhile snd body0
     modules = map fst modules0 ++ map fst (takeWhile snd body0)
 
 indent it@('#':_) = it
 indent other = "  " ++ other
 
+-- Annotate every line with True if its inside the span of a block comment.
+-- @
+--   {- LANGUAGE foo -}     -- False
+--   This is not inside {-  -- False
+--   but this is -}         -- True
 annotateBlockComments :: [String] -> [(String, Bool)]
 annotateBlockComments = annotateBlockComments' False
 annotateBlockComments' _ [] = []
-annotateBlockComments' False (l:rest)
-    | "{-" `isInfixOf` l = (l,True) : annotateBlockComments' True rest
-    | otherwise = (l,False) : annotateBlockComments' False rest
-annotateBlockComments' True (l:rest) =
-  (l,True) : annotateBlockComments' (not $ "-}" `isInfixOf` l) rest
+annotateBlockComments' False (l:rest) = (l,False) : annotateBlockComments' (startsBlockComment l) rest
+annotateBlockComments' True  (l:rest) = (l,True) : annotateBlockComments' (not $ endsBlockComment l) rest
+
+startsBlockComment line
+    | Just l' <- dropUntilIncluding "{-" line = not $ endsBlockComment l'
+    | otherwise = False
+
+endsBlockComment line
+    | Just l' <- dropUntilIncluding "-}" line = not $ startsBlockComment l'
+    | otherwise = False
+
+dropUntilIncluding needle haystack
+  | [] <- haystack = Nothing
+  | Just x <- stripPrefix needle haystack = Just x
+  | x:rest <- haystack = (x:) <$> dropUntilIncluding needle rest
