diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+This module is under this "3 clause" BSD license:
+
+Copyright (c) 2025-2025, Daniil Iaitskov
+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.
+
+    * The names of the contributors may not 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,17 @@
+# add-dependent-file
+
+The library provides a safer wrapper around
+[addDependentFile](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH-Syntax.html#v:addDependentFile)
+that checks that `extra-source-files` section in the cabal file
+contains **addDependendFile** argument and issues a correspondent
+compilation warning if it does not, because `addDependentFile` has no
+effect otherwise.
+
+## Development environment
+
+```shell
+$ nix develop
+$ emacs &
+$ cabal build
+$ cabal test
+```
diff --git a/add-dependent-file.cabal b/add-dependent-file.cabal
new file mode 100644
--- /dev/null
+++ b/add-dependent-file.cabal
@@ -0,0 +1,63 @@
+cabal-version: 3.0
+name:          add-dependent-file
+version:       0.0.1
+synopsis:      Safer TH addDependentFile wrapper
+description:
+    The library provides a safer wrapper around
+    <https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH-Syntax.html#v:addDependentFile addDependentFile>
+    that checks that @extra-source-files@ section in the cabal file contains
+    __addDependendFile__ argument and issues a correspondent compilation
+    warning if it does not, because @addDependentFile@ has no effect
+    otherwise.
+    
+    == Development environment
+    #development-environment#
+    
+    > $ nix develop
+    > $ emacs &
+    > $ cabal build
+    > $ cabal test
+homepage:      http://github.com/yaitskov/add-dependent-file
+license:       BSD-3-Clause
+license-file:  LICENSE
+author:        Daniil Iaitskov
+maintainer:    dyaitskov@gmail.com
+copyright:     Daniil Iaitkov 2026
+category:      System
+build-type:    Simple
+bug-reports:   https://github.com/yaitskov/add-dependent-file/issues
+extra-source-files:
+  README.md
+extra-doc-files:
+  changelog.md
+tested-with:
+  GHC == 9.12.2
+
+source-repository head
+  type:
+    git
+  location:
+    https://github.com/yaitskov/add-dependent-file.git
+
+library
+  hs-source-dirs: src
+  exposed-modules:
+    AddDependentFile
+  other-modules:
+    AddDependentFile.Test
+  default-language: GHC2024
+  ghc-options: -Wall
+  default-extensions:
+    DefaultSignatures
+    NoImplicitPrelude
+    OverloadedStrings
+    TemplateHaskell
+  build-depends:
+    , Cabal                   < 4
+    , Cabal-syntax            < 4
+    , base           >=4.7 && < 5
+    , bytestring              < 1
+    , directory               < 2
+    , filepath                < 2
+    , regex-compat            < 1
+    , template-haskell        < 3
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,4 @@
+# add-dependent-file changelog
+
+## Version 0.0.1 2026-02-26
+  * init
diff --git a/src/AddDependentFile.hs b/src/AddDependentFile.hs
new file mode 100644
--- /dev/null
+++ b/src/AddDependentFile.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+module AddDependentFile
+  ( addDependentFile
+  , addDependentFile'
+  , getPackageRoot
+  , (</>)
+  ) where
+
+import Control.Monad ( unless )
+import Control.Monad.IO.Class ( MonadIO(..) )
+import Data.ByteString qualified as BS
+import Distribution.PackageDescription.Configuration ( flattenPackageDescription )
+import Distribution.Simple.PackageDescription ( readGenericPackageDescription )
+import Distribution.Types.PackageDescription ( PackageDescription(extraSrcFiles) )
+import Distribution.Utils.Path ( getSymbolicPath, makeSymbolicPath )
+import Distribution.Simple.Utils ( isAbsoluteOnAnyPlatform )
+import Distribution.Verbosity ( verbose )
+import Language.Haskell.TH.Syntax
+    ( Q, location, reportError, Loc(loc_package), runIO )
+import Language.Haskell.TH.Syntax qualified as TH
+import Prelude
+import System.Directory (makeAbsolute)
+import System.FilePath ( (</>), addTrailingPathSeparator )
+import Text.Regex ( mkRegex, subRegex )
+
+-- copy from Distribution.Simple.Utils
+stripCommonPrefix :: String -> String -> String
+stripCommonPrefix (x : xs) (y : ys)
+  | x == y = stripCommonPrefix xs ys
+  | otherwise = y : ys
+stripCommonPrefix _ ys = ys
+
+parseCabalFile :: MonadIO m => FilePath -> m PackageDescription
+parseCabalFile cabPath =
+  flattenPackageDescription <$> liftIO (readGenericPackageDescription verbose Nothing (makeSymbolicPath cabPath))
+
+stripInplace :: String -> String
+stripInplace pn = subRegex massagePackageName pn "\\1.cabal"
+  where
+    massagePackageName =
+      mkRegex
+      "^([A-Z_a-z0-9-]+)[-]([0-9]+[.])+[0-9]+[-]([A-Za-z0-9]{10,}|inplace)(-test)?$"
+
+findCabalFile :: Q FilePath
+findCabalFile = do
+  cabalFileName <- stripInplace . loc_package <$> location
+  (</> cabalFileName) <$> getPackageRoot
+
+assertCabalExtraSourceContains :: FilePath -> FilePath -> Q ()
+assertCabalExtraSourceContains fp cabalFile = do
+  pd <- runIO $ do
+    parseCabalFile cabalFile
+  let extraSourceFiles :: [FilePath] = getSymbolicPath <$> pd.extraSrcFiles in
+    unless (fp `elem` extraSourceFiles) $ do
+      reportError $ "File [" <> fp
+        <> "] is not mentioned in the extra-source-files section of "
+        <> cabalFile <> ". Changes in that file wouldn't trigger rebuild."
+
+-- | Calls 'Language.Haskell.TH.Syntax.addDependentFile' and checks the argument
+-- should be an absolute path and the location it refers
+-- is mentioned in the @extra-sources-files@ section of the cabal file
+addDependentFile :: FilePath -> Q ()
+addDependentFile p = do
+  if isAbsoluteOnAnyPlatform p
+    then do
+      pRelativeToCabal <- (`stripCommonPrefix` p) . addTrailingPathSeparator <$> getPackageRoot
+      assertCabalExtraSourceContains pRelativeToCabal =<< findCabalFile
+      TH.addDependentFile p
+    else
+    reportError $ "addDependentFile got [" <> p <> "] that is not an absolute path"
+
+-- | Besides 'addDependentFile' checks, it enusures that consumed content is not changed
+addDependentFile' :: FilePath -> BS.ByteString -> Q ()
+addDependentFile' p expectedContent = do
+  addDependentFile p
+  pContent <- runIO $ BS.readFile p
+  unless (pContent == expectedContent) $
+    reportError $ "File [" <> p <> "] has changed after it is consumed"
+
+
+liftIO1 :: (a -> IO b) -> a -> Q b
+liftIO1 f x = runIO (f x)
+
+-- | Absolute path to 'Language.Haskell.TH.Syntax.getPackageRoot'
+getPackageRoot :: Q FilePath
+getPackageRoot = TH.getPackageRoot >>= liftIO1 makeAbsolute
diff --git a/src/AddDependentFile/Test.hs b/src/AddDependentFile/Test.hs
new file mode 100644
--- /dev/null
+++ b/src/AddDependentFile/Test.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE TemplateHaskell #-}
+module AddDependentFile.Test where
+
+import AddDependentFile ( addDependentFile, addDependentFile', getPackageRoot, (</>) )
+import Data.ByteString qualified as BS
+import Language.Haskell.TH.Syntax (runIO)
+import Prelude
+
+
+$(
+  getPackageRoot >>= addDependentFile . (</> "README.md") >> pure []
+ )
+
+
+$(do
+     readmeAbsPath <- (</> "README.md") <$> getPackageRoot
+     !readmeContent <- runIO $ BS.readFile readmeAbsPath
+     addDependentFile' readmeAbsPath readmeContent
+     pure []
+ )
