diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright Mark Wotton (c) 2018
+
+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 Author name here nor the names of other
+      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
+OWNER 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1 @@
+# hsmodetweaks
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+
+module Main where
+import           Data.List          (nub)
+import qualified Data.Map.Strict    as Map
+import qualified Data.Set           as Set
+import qualified Data.Text          as T
+import           GHC.Base           (String)
+import           Hpack.Config       (Executable, Library, Package (..),
+                                     Section (..), readPackageConfig)
+import           Protolude
+import           System.Directory   (canonicalizePath, getAppUserDataDirectory)
+import           System.Environment (getArgs)
+import           System.IO.Error    (userError)
+
+genLocals :: FilePath -> Package -> [(FilePath, Text)]
+genLocals f = map (second
+                   $ (prologue <>)
+                   . (<> "\n")
+                   . parens
+                   . parens
+                   . ("haskell-mode " <>)
+                   . parens
+                   . ("intero-targets " <>)
+                   . T.unwords
+                   . map show
+                   . Set.toList
+                  )
+              . extractTargets f
+  where
+    parens :: Text -> Text
+    parens = ("(" <>) . (<> ")")
+
+    prologue :: Text
+    prologue = ";;; Directory Local Variables\n;;; For more information see (info \"(emacs) Directory Variables\")\n\n"
+
+-- FIX these are all terrible names
+extractTargets :: FilePath -> Package -> [(FilePath, Set Text)]
+extractTargets root Package{..}
+  = collapse
+    [ex "exe" packageExecutables
+    ,ex "test" packageTests
+    ,ex "bench" packageBenchmarks
+    , lib]
+  where
+    lib = f ["lib"] <$> maybeToList packageLibrary
+
+    ex :: String -> Map String (Section Executable) -> [[(FilePath, [Text])]]
+    ex ty = map (\(target,section) -> f [ty,target] section) . Map.toList
+
+    f :: [String] -> Section a -> [(FilePath, [Text])]
+    f pieces Section{..} =
+      map (\name -> (root <> "/" <> name <> "/.dir-locals.el"
+                   ,lib <> [mkTarget pieces])) sectionSourceDirs
+      where lib = const (mkTarget ["lib"]) <$> maybeToList packageLibrary
+    collapse = Map.toList . Map.fromListWith Set.intersection
+             . map (second Set.fromList) . concat .  concat
+
+    mkTarget = T.intercalate ":" . map T.pack . (packageName:)
+
+abort :: String -> IO ()
+abort = ioError . userError
+
+main :: IO ()
+main = getArgs >>= \case
+  [f1] -> do
+    c <- canonicalizePath f1
+    getAppUserDataDirectory "hpack"
+      >>= (`readPackageConfig` (c <> "/package.yaml"))
+      >>= either abort (writeFiles c . fst)
+  x -> abort $ "exactly one argument needed, got " <> show x
+
+  where
+    writeFiles f = mapM_ (uncurry writeFile) . genLocals f
+--    writeFiles f = print . extractTargets f
diff --git a/hsmodetweaks.cabal b/hsmodetweaks.cabal
new file mode 100644
--- /dev/null
+++ b/hsmodetweaks.cabal
@@ -0,0 +1,37 @@
+-- This file has been generated from package.yaml by hpack version 0.20.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: f25e26460eeee79666ece3683be7df359a0bf68de99648725e06864dbdac9422
+
+name:           hsmodetweaks
+version:        0.1.0.0
+synopsis:       Tool for generating .dir-locals.el for intero
+description:    Keeps .dir-locals.el up to date so that intero can automatically choose the right targets
+category:       Tools
+homepage:       https://github.com/mwotton/hsmodetweaks#readme
+author:         mwotton@gmail.com
+maintainer:     mwotton@gmail.com
+copyright:      2018 Mark Wotton
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    README.md
+
+executable hsmodetweaks
+  main-is: Main.hs
+  hs-source-dirs:
+      app
+  build-depends:
+      base >=4.7 && <5
+    , containers
+    , directory
+    , hpack >=0.25
+    , protolude
+    , text
+  other-modules:
+      Paths_hsmodetweaks
+  default-language: Haskell2010
