diff --git a/exe/Main.hs b/exe/Main.hs
--- a/exe/Main.hs
+++ b/exe/Main.hs
@@ -1,16 +1,23 @@
 {-# LANGUAGE DuplicateRecordFields #-}
-{-# LANGUAGE NamedFieldPuns        #-}
-{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
 
+module Main where
+
 import           Control.Monad                  (filterM)
 import           Control.Monad.Extra            (ifM)
 import qualified Data.ByteString                as BS
 import qualified Data.List.NonEmpty             as NEL
-import           Data.Text.Encoding             (encodeUtf8)
+import           Data.Maybe                     (mapMaybe)
+import           Data.Text                      (Text)
+import qualified Data.Text                      as T
+import           Data.Text.Encoding             (decodeUtf8, encodeUtf8)
 import           Distribution.Types.PackageName (mkPackageName)
-import           Hpack                          (Force (..), Options (..),
+import           Hpack                          (Force(..), Options(..),
                                                  defaultOptions, hpackResult,
                                                  setTarget)
+import           Prelude                        hiding (lines)
 import           StackageToHackage.Hackage      (printFreeze, printProject,
                                                  stackToCabal)
 import           StackageToHackage.Stackage     (localDirs, readStack)
@@ -33,16 +40,27 @@
   -- that misses projects that have explicit .cabal files, so just scan.
   let ignore = (mkPackageName . takeBaseName) <$> cabals
   (project, freeze) <- stackToCabal ignore dir stack
-  BS.writeFile (dir </> "cabal.project") (encodeUtf8 $ printProject project)
+  hack <- extractHack . decodeUtf8 <$> BS.readFile (dir </> "stack.yaml")
+  BS.writeFile (dir </> "cabal.project") (encodeUtf8 $ printProject project hack)
   BS.writeFile (dir </> "cabal.project.freeze") (encodeUtf8 $ printFreeze freeze)
   where
     hpackInput sub = sub </> "package.yaml"
     opts = defaultOptions {optionsForce = Force}
     runHpack sub = hpackResult $ setTarget (hpackInput sub) opts
 
+-- Backdoor allowing the stack.yaml to contain arbitrary text that will be
+-- included in the cabal.project
+extractHack :: Text -> Maybe Text
+extractHack (T.split ('\n' ==) -> lines) =
+  let (_, region) = break (T.isPrefixOf "#+BEGIN_STACK2CABAL") lines
+      (hack, _) = break (T.isPrefixOf "#+END_STACK2CABAL") region
+      verbatim = mapMaybe (T.stripPrefix "# ") hack
+  in if null verbatim
+     then Nothing
+     else Just $ T.intercalate "\n" verbatim
+
 globExt :: String -> FilePath -> IO [FilePath]
 globExt ext path = do
   files <- ifM (doesDirectoryExist path) (listDirectory path) (pure [])
   pure $ filter ((ext ==) . takeExtension) files
 
--- TODO invoke cabal v2-freeze to minimise the freeze file
diff --git a/lib/StackageToHackage/Hackage.hs b/lib/StackageToHackage/Hackage.hs
--- a/lib/StackageToHackage/Hackage.hs
+++ b/lib/StackageToHackage/Hackage.hs
@@ -17,7 +17,6 @@
 import qualified Data.Map.Strict                as M
 import           Data.Maybe                     (fromMaybe, mapMaybe)
 import           Data.Semigroup
-import           Data.Semigroup                 (sconcat)
 import           Data.Text                      (Text)
 import qualified Data.Text                      as T
 import           Distribution.Pretty            (prettyShow)
@@ -36,18 +35,18 @@
       freeze = genFreeze resolver ignore
   pure (project, freeze)
 
--- TODO: something like stackToCabal that puts constraints into .cabal files
-
-printProject :: Project -> Text
-printProject (Project (Ghc ghc) pkgs srcs) =
-  T.concat [ "-- Generated by stackage-to-hackage\n\n"
+printProject :: Project -> Maybe Text -> Text
+printProject (Project (Ghc ghc) pkgs srcs) hack =
+  T.concat $ [ "-- Generated by stackage-to-hackage\n\n"
          , "with-compiler: ", ghc, "\n\n"
          , "packages:\n    ", packages, "\n\n"
          , sources, "\n"
          , "allow-older: *\n"
          , "allow-newer: *\n"
-         ]
+         ] <> verbatim hack
   where
+    verbatim Nothing = []
+    verbatim (Just txt) = ["\n-- Verbatim\n", txt]
     packages = T.intercalate "\n  , " (T.pack . addTrailingPathSeparator <$>
                                      NEL.toList pkgs)
     sources = T.intercalate "\n" (source =<< srcs)
@@ -71,6 +70,10 @@
     pickGit (Hackage _ )  = Nothing
     pickGit (SourceDep g) = Just g
 
+-- TODO if there is a dependency listed in the snapshot or LTS but the user
+-- provides a git repo or local package, we are generating the wrong version
+-- constraint. We would need to parse the .cabal of all git repos in the same
+-- way that we exclude self packages.
 printFreeze :: Freeze -> Text
 printFreeze (Freeze deps (Flags flags)) =
   T.concat [ "constraints:\n    ", constraints, "\n"]
diff --git a/stack2cabal.cabal b/stack2cabal.cabal
--- a/stack2cabal.cabal
+++ b/stack2cabal.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name:          stack2cabal
-version:       1.0.4
+version:       1.0.5
 synopsis:
   Convert stack projects to cabal.project + cabal.project.freeze
 
@@ -17,6 +17,11 @@
 
 -- https://www.haskell.org/cabal/users-guide/cabal-projectindex.html
 
+flag ghcflags
+  description: Generate .ghc.flags files during compilation
+  manual:      True
+  default:     False
+
 common deps
   build-depends:
     , base             >=4.10    && <5.0
@@ -31,6 +36,11 @@
     , http-client      ^>=0.5.14 || ^>=0.6.0
     , http-client-tls  ^>=0.3.5.3
     , text             ^>=1.2.3.1
+
+  if flag(ghcflags)
+    build-tool-depends: hsinspect:hsinspect
+    build-depends: ghcflags
+    ghc-options: -fplugin GhcFlags.Plugin
 
   ghc-options:      -Wall -Werror=missing-home-modules
   default-language: Haskell2010
